Cumulative patch from commit 8b48e3200680f71ae083b84793e6bdc2099416d2

8b48e32 wpa_cli: Add MAC address randomization in scan
fb37588 ctrl_iface: Add MAC address randomization in scan processing
56c76fa scan: Add MAC address randomization in scan handling
86056fe nl80211: Handle MAC address randomization in scan/sched_scan
ff23ed2 driver: Add definitions for MAC address randomization in scan
7db53bb wpa_cli: Implement TDLS start/cancel channel switching commands
72b2605 nl80211: Pass TDLS channel-switch start/stop params to kernel
6b90dea TDLS: Propagate enable/disable channel-switch commands to driver
d9d3b78 TDLS: Track TDLS channel switch prohibition in BSS
4daa572 TDLS: Add channel-switch capability flag
ca16586 Sync with wireless-testing.git include/uapi/linux/nl80211.h
8c42b36 WMM AC: Reconfigure tspecs on reassociation to the same BSS
677e7a9 WMM AC: Do not fail on unknown IEs in Association Response
fecc2bb WMM AC: Delete tspecs on roaming
20fe745 WMM AC: Print user-priority in wmm_ac_status
730a0d1 nl80211: Always register management frames handler
...
209702d Add possibility to set the setband parameter
ee82e33 Do not trigger the scan during initialization on Android platforms
e69ae5f Reject new SCAN commands if there is a pending request
...
59d7148 nl80211: Provide subtype and reason code for AP SME drivers
9d4ff04 Add external EAPOL transmission option for testing purposes
61fc904 P2P: Handle improper WPS termination on GO during group formation
58b40fd P2P: Clear p2p_go_group_formation_completed on GO start
c155305 Complete sme-connect radio work when clearing connection state
debb2da P2P: Report group removal reason PSK_FAILURE in timeout case
51465a0 The master branch is now used for v2.4 development

Change-Id: I9b9cfa5c5cd4d26b2f3f5595f7c226ac60de6258
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index edaf6fc..d6d04c5 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -95,6 +95,7 @@
 OBJS += src/ap/pmksa_cache_auth.c
 OBJS += src/ap/ieee802_11_shared.c
 OBJS += src/ap/beacon.c
+OBJS += src/ap/bss_load.c
 OBJS_d =
 OBJS_p =
 LIBS =
@@ -200,6 +201,17 @@
 
 ifdef CONFIG_HS20
 NEED_AES_OMAC1=y
+CONFIG_PROXYARP=y
+endif
+
+ifdef CONFIG_PROXYARP
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_SUITEB
+L_CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
 endif
 
 ifdef CONFIG_IEEE80211W
@@ -854,6 +866,15 @@
 OBJS += src/ap/gas_serv.c
 endif
 
+ifdef CONFIG_PROXYARP
+L_CFLAGS += -DCONFIG_PROXYARP
+OBJS += src/ap/x_snoop.c
+OBJS += src/ap/dhcp_snoop.c
+ifdef CONFIG_IPV6
+OBJS += src/ap/ndisc_snoop.c
+endif
+endif
+
 OBJS += src/drivers/driver_common.c
 
 ifdef CONFIG_ACS
diff --git a/hostapd/Makefile b/hostapd/Makefile
index ac6373e..e64c249 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -9,6 +9,8 @@
 CFLAGS += -I$(abspath ../src)
 CFLAGS += -I$(abspath ../src/utils)
 
+export BINDIR ?= /usr/local/bin/
+
 # Uncomment following line and set the path to your kernel tree include
 # directory if your C library does not include all header files.
 # CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
@@ -59,6 +61,7 @@
 OBJS += ../src/ap/pmksa_cache_auth.o
 OBJS += ../src/ap/ieee802_11_shared.o
 OBJS += ../src/ap/beacon.o
+OBJS += ../src/ap/bss_load.o
 
 OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
 
@@ -187,6 +190,17 @@
 
 ifdef CONFIG_HS20
 NEED_AES_OMAC1=y
+CONFIG_PROXYARP=y
+endif
+
+ifdef CONFIG_PROXYARP
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_SUITEB
+CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
 endif
 
 ifdef CONFIG_IEEE80211W
@@ -246,6 +260,12 @@
 endif
 
 
+ifdef CONFIG_ERP
+CFLAGS += -DCONFIG_ERP
+NEED_SHA256=y
+NEED_HMAC_SHA256_KDF=y
+endif
+
 ifdef CONFIG_EAP_MD5
 CFLAGS += -DEAP_SERVER_MD5
 OBJS += ../src/eap_server/eap_server_md5.o
@@ -755,6 +775,9 @@
 ifdef NEED_TLS_PRF_SHA256
 OBJS += ../src/crypto/sha256-tlsprf.o
 endif
+ifdef NEED_HMAC_SHA256_KDF
+OBJS += ../src/crypto/sha256-kdf.o
+endif
 endif
 
 ifdef NEED_DH_GROUPS
@@ -839,6 +862,15 @@
 OBJS += ../src/ap/gas_serv.o
 endif
 
+ifdef CONFIG_PROXYARP
+CFLAGS += -DCONFIG_PROXYARP
+OBJS += ../src/ap/x_snoop.o
+OBJS += ../src/ap/dhcp_snoop.o
+ifdef CONFIG_IPV6
+OBJS += ../src/ap/ndisc_snoop.o
+endif
+endif
+
 OBJS += ../src/drivers/driver_common.o
 
 ifdef CONFIG_WPA_CLI_EDIT
@@ -881,6 +913,10 @@
 Q=
 E=true
 endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
 
 ifdef CONFIG_CODE_COVERAGE
 %.o: %.c
@@ -901,9 +937,10 @@
 		exit 1; \
 	fi
 
-install: all
-	mkdir -p $(DESTDIR)/usr/local/bin
-	for i in $(ALL); do cp -f $$i $(DESTDIR)/usr/local/bin/$$i; done
+$(DESTDIR)$(BINDIR)/%: %
+	install -D $(<) $(@)
+
+install: $(addprefix $(DESTDIR)$(BINDIR)/,$(ALL))
 
 ../src/drivers/build.hostapd:
 	@if [ -f ../src/drivers/build.wpa_supplicant ]; then \
diff --git a/hostapd/README b/hostapd/README
index 50868ee..ea016cc 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -74,12 +74,6 @@
 	Please note that station firmware version needs to be 1.7.0 or newer
 	to work in WPA mode.
 
-	madwifi driver for cards based on Atheros chip set (ar521x)
-	(http://sourceforge.net/projects/madwifi/)
-	Please note that you will need to add the correct path for
-	madwifi driver root directory in .config (see defconfig file for
-	an example: CFLAGS += -I<path>)
-
 	mac80211-based drivers that support AP mode (with driver=nl80211).
 	This includes drivers for Atheros (ath9k) and Broadcom (b43)
 	chipsets.
diff --git a/hostapd/README-WPS b/hostapd/README-WPS
index bb7d35f..d5f713a 100644
--- a/hostapd/README-WPS
+++ b/hostapd/README-WPS
@@ -58,10 +58,9 @@
 
 WPS is an optional component that needs to be enabled in hostapd build
 configuration (.config). Here is an example configuration that
-includes WPS support and uses madwifi driver interface:
+includes WPS support and uses nl80211 driver interface:
 
-CONFIG_DRIVER_MADWIFI=y
-CFLAGS += -I/usr/src/madwifi-0.9.3
+CONFIG_DRIVER_NL80211=y
 CONFIG_WPS=y
 CONFIG_WPS_UPNP=y
 
@@ -74,8 +73,8 @@
 (hostapd.conf) that enables WPS:
 
 # Configure the driver and network interface
-driver=madwifi
-interface=ath0
+driver=nl80211
+interface=wlan0
 
 # WPA2-Personal configuration for the AP
 ssid=wps-test
diff --git a/hostapd/android.config b/hostapd/android.config
index ad83308..938aa54 100644
--- a/hostapd/android.config
+++ b/hostapd/android.config
@@ -15,10 +15,6 @@
 # Driver interface for wired authenticator
 #CONFIG_DRIVER_WIRED=y
 
-# Driver interface for madwifi driver
-#CONFIG_DRIVER_MADWIFI=y
-#CFLAGS += -I../../madwifi # change to the madwifi source directory
-
 # Driver interface for drivers using the nl80211 kernel interface
 #CONFIG_DRIVER_NL80211=y
 # driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
@@ -132,7 +128,7 @@
 #CONFIG_IEEE80211R=y
 
 # Use the hostapd's IEEE 802.11 authentication (ACL), but without
-# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
+# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
 #CONFIG_DRIVER_RADIUS_ACL=y
 
 # IEEE 802.11n (High Throughput) support
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 44de826..e30efbe 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -680,6 +680,8 @@
 		else if (os_strcmp(start, "FT-SAE") == 0)
 			val |= WPA_KEY_MGMT_FT_SAE;
 #endif /* CONFIG_SAE */
+		else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
 		else {
 			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
 				   line, start);
@@ -1865,6 +1867,9 @@
 				   line, pos);
 			return 1;
 		}
+	} else if (os_strcmp(buf, "driver_params") == 0) {
+		os_free(conf->driver_params);
+		conf->driver_params = os_strdup(pos);
 	} else if (os_strcmp(buf, "debug") == 0) {
 		wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' configuration variable is not used anymore",
 			   line);
@@ -1984,6 +1989,9 @@
 	} else if (os_strcmp(buf, "dh_file") == 0) {
 		os_free(bss->dh_file);
 		bss->dh_file = os_strdup(pos);
+	} else if (os_strcmp(buf, "openssl_ciphers") == 0) {
+		os_free(bss->openssl_ciphers);
+		bss->openssl_ciphers = os_strdup(pos);
 	} else if (os_strcmp(buf, "fragment_size") == 0) {
 		bss->fragment_size = atoi(pos);
 #ifdef EAP_SERVER_FAST
@@ -2044,6 +2052,8 @@
 	} else if (os_strcmp(buf, "pwd_group") == 0) {
 		bss->pwd_group = atoi(pos);
 #endif /* EAP_SERVER_PWD */
+	} else if (os_strcmp(buf, "eap_server_erp") == 0) {
+		bss->eap_server_erp = atoi(pos);
 #endif /* EAP_SERVER */
 	} else if (os_strcmp(buf, "eap_message") == 0) {
 		char *term;
@@ -2063,6 +2073,11 @@
 				   (term - bss->eap_req_id_text) - 1);
 			bss->eap_req_id_text_len--;
 		}
+	} else if (os_strcmp(buf, "erp_send_reauth_start") == 0) {
+		bss->erp_send_reauth_start = atoi(pos);
+	} else if (os_strcmp(buf, "erp_domain") == 0) {
+		os_free(bss->erp_domain);
+		bss->erp_domain = os_strdup(pos);
 	} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
 		bss->default_wep_key_len = atoi(pos);
 		if (bss->default_wep_key_len > 13) {
@@ -2405,9 +2420,6 @@
 	} else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
 		bss->radius_server_ipv6 = atoi(pos);
 #endif /* RADIUS_SERVER */
-	} else if (os_strcmp(buf, "test_socket") == 0) {
-		os_free(bss->test_socket);
-		bss->test_socket = os_strdup(pos);
 	} else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
 		bss->use_pae_group_addr = atoi(pos);
 	} else if (os_strcmp(buf, "hw_mode") == 0) {
@@ -2486,6 +2498,15 @@
 				   line, bss->dtim_period);
 			return 1;
 		}
+	} else if (os_strcmp(buf, "bss_load_update_period") == 0) {
+		bss->bss_load_update_period = atoi(pos);
+		if (bss->bss_load_update_period < 0 ||
+		    bss->bss_load_update_period > 100) {
+			wpa_printf(MSG_ERROR,
+				   "Line %d: invalid bss_load_update_period %d",
+				   line, bss->bss_load_update_period);
+			return 1;
+		}
 	} else if (os_strcmp(buf, "rts_threshold") == 0) {
 		conf->rts_threshold = atoi(pos);
 		if (conf->rts_threshold < 0 || conf->rts_threshold > 2347) {
@@ -2996,6 +3017,8 @@
 		bss->hs20 = atoi(pos);
 	} else if (os_strcmp(buf, "disable_dgaf") == 0) {
 		bss->disable_dgaf = atoi(pos);
+	} else if (os_strcmp(buf, "proxy_arp") == 0) {
+		bss->proxy_arp = atoi(pos);
 	} else if (os_strcmp(buf, "osen") == 0) {
 		bss->osen = atoi(pos);
 	} else if (os_strcmp(buf, "anqp_domain_id") == 0) {
@@ -3106,6 +3129,8 @@
 		pos++;
 		WPA_PUT_LE16(&bss->bss_load_test[3], atoi(pos));
 		bss->bss_load_test_set = 1;
+	} else if (os_strcmp(buf, "radio_measurements") == 0) {
+		bss->radio_measurements = atoi(pos);
 #endif /* CONFIG_TESTING_OPTIONS */
 	} else if (os_strcmp(buf, "vendor_elements") == 0) {
 		struct wpabuf *elems;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 591c395..0e35aa6 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -10,6 +10,11 @@
 
 #ifndef CONFIG_NATIVE_WINDOWS
 
+#ifdef CONFIG_TESTING_OPTIONS
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#endif /* CONFIG_TESTING_OPTIONS */
+
 #include <sys/un.h>
 #include <sys/stat.h>
 #include <stddef.h>
@@ -21,6 +26,7 @@
 #include "drivers/driver.h"
 #include "radius/radius_client.h"
 #include "radius/radius_server.h"
+#include "l2_packet/l2_packet.h"
 #include "ap/hostapd.h"
 #include "ap/ap_config.h"
 #include "ap/ieee802_1x.h"
@@ -240,14 +246,14 @@
 		if (!wps_pin_valid(pin_val)) {
 			wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
 			ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
-			if (ret < 0 || (size_t) ret >= buflen)
+			if (os_snprintf_error(buflen, ret))
 				return -1;
 			return ret;
 		}
 	}
 
 	ret = os_snprintf(buf, buflen, "%s", pin);
-	if (ret < 0 || (size_t) ret >= buflen)
+	if (os_snprintf_error(buflen, ret))
 		return -1;
 
 	return ret;
@@ -578,7 +584,7 @@
 	ret = os_snprintf(pos, end - pos, "PBC Status: %s\n",
 			  pbc_status_str(hapd->wps_stats.pbc_status));
 
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -588,7 +594,7 @@
 			   (hapd->wps_stats.status == WPS_STATUS_FAILURE ?
 			    "Failed" : "None")));
 
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -599,7 +605,7 @@
 				  "Failure Reason: %s\n",
 				  wps_ei_str(hapd->wps_stats.failure_reason));
 
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -608,7 +614,7 @@
 		ret = os_snprintf(pos, end - pos, "Peer Address: " MACSTR "\n",
 				  MAC2STR(hapd->wps_stats.peer_addr));
 
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -857,6 +863,193 @@
 	return wnm_send_ess_disassoc_imminent(hapd, sta, url, disassoc_timer);
 }
 
+
+static int hostapd_ctrl_iface_bss_tm_req(struct hostapd_data *hapd,
+					 const char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	const char *pos, *end;
+	int disassoc_timer = 0;
+	struct sta_info *sta;
+	u8 req_mode = 0, valid_int = 0x01;
+	u8 bss_term_dur[12];
+	char *url = NULL;
+	int ret;
+	u8 nei_rep[1000];
+	u8 *nei_pos = nei_rep;
+
+	if (hwaddr_aton(cmd, addr)) {
+		wpa_printf(MSG_DEBUG, "Invalid STA MAC address");
+		return -1;
+	}
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "Station " MACSTR
+			   " not found for BSS TM Request message",
+			   MAC2STR(addr));
+		return -1;
+	}
+
+	pos = os_strstr(cmd, " disassoc_timer=");
+	if (pos) {
+		pos += 16;
+		disassoc_timer = atoi(pos);
+		if (disassoc_timer < 0 || disassoc_timer > 65535) {
+			wpa_printf(MSG_DEBUG, "Invalid disassoc_timer");
+			return -1;
+		}
+	}
+
+	pos = os_strstr(cmd, " valid_int=");
+	if (pos) {
+		pos += 11;
+		valid_int = atoi(pos);
+	}
+
+	pos = os_strstr(cmd, " bss_term=");
+	if (pos) {
+		pos += 10;
+		req_mode |= WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED;
+		/* TODO: TSF configurable/learnable */
+		bss_term_dur[0] = 4; /* Subelement ID */
+		bss_term_dur[1] = 10; /* Length */
+		os_memset(bss_term_dur, 2, 8);
+		end = os_strchr(pos, ',');
+		if (end == NULL) {
+			wpa_printf(MSG_DEBUG, "Invalid bss_term data");
+			return -1;
+		}
+		end++;
+		WPA_PUT_LE16(&bss_term_dur[10], atoi(end));
+	}
+
+
+	/*
+	 * BSS Transition Candidate List Entries - Neighbor Report elements
+	 * neighbor=<BSSID>,<BSSID Information>,<Operating Class>,
+	 * <Channel Number>,<PHY Type>[,<hexdump of Optional Subelements>]
+	 */
+	pos = cmd;
+	while (pos) {
+		u8 *nei_start;
+		long int val;
+		char *endptr, *tmp;
+
+		pos = os_strstr(pos, " neighbor=");
+		if (!pos)
+			break;
+		if (nei_pos + 15 > nei_rep + sizeof(nei_rep)) {
+			wpa_printf(MSG_DEBUG,
+				   "Not enough room for additional neighbor");
+			return -1;
+		}
+		pos += 10;
+
+		nei_start = nei_pos;
+		*nei_pos++ = WLAN_EID_NEIGHBOR_REPORT;
+		nei_pos++; /* length to be filled in */
+
+		if (hwaddr_aton(pos, nei_pos)) {
+			wpa_printf(MSG_DEBUG, "Invalid BSSID");
+			return -1;
+		}
+		nei_pos += ETH_ALEN;
+		pos += 17;
+		if (*pos != ',') {
+			wpa_printf(MSG_DEBUG, "Missing BSSID Information");
+			return -1;
+		}
+		pos++;
+
+		val = strtol(pos, &endptr, 0);
+		WPA_PUT_LE32(nei_pos, val);
+		nei_pos += 4;
+		if (*endptr != ',') {
+			wpa_printf(MSG_DEBUG, "Missing Operating Class");
+			return -1;
+		}
+		pos = endptr + 1;
+
+		*nei_pos++ = atoi(pos); /* Operating Class */
+		pos = os_strchr(pos, ',');
+		if (pos == NULL) {
+			wpa_printf(MSG_DEBUG, "Missing Channel Number");
+			return -1;
+		}
+		pos++;
+
+		*nei_pos++ = atoi(pos); /* Channel Number */
+		pos = os_strchr(pos, ',');
+		if (pos == NULL) {
+			wpa_printf(MSG_DEBUG, "Missing PHY Type");
+			return -1;
+		}
+		pos++;
+
+		*nei_pos++ = atoi(pos); /* PHY Type */
+		end = os_strchr(pos, ' ');
+		tmp = os_strchr(pos, ',');
+		if (tmp && (!end || tmp < end)) {
+			/* Optional Subelements (hexdump) */
+			size_t len;
+
+			pos = tmp + 1;
+			end = os_strchr(pos, ' ');
+			if (end)
+				len = end - pos;
+			else
+				len = os_strlen(pos);
+			if (nei_pos + len / 2 > nei_rep + sizeof(nei_rep)) {
+				wpa_printf(MSG_DEBUG,
+					   "Not enough room for neighbor subelements");
+				return -1;
+			}
+			if (len & 0x01 ||
+			    hexstr2bin(pos, nei_pos, len / 2) < 0) {
+				wpa_printf(MSG_DEBUG,
+					   "Invalid neighbor subelement info");
+				return -1;
+			}
+			nei_pos += len / 2;
+			pos = end;
+		}
+
+		nei_start[1] = nei_pos - nei_start - 2;
+	}
+
+	pos = os_strstr(cmd, " url=");
+	if (pos) {
+		size_t len;
+		pos += 5;
+		end = os_strchr(pos, ' ');
+		if (end)
+			len = end - pos;
+		else
+			len = os_strlen(pos);
+		url = os_malloc(len + 1);
+		if (url == NULL)
+			return -1;
+		os_memcpy(url, pos, len);
+		url[len] = '\0';
+		req_mode |= WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+	}
+
+	if (os_strstr(cmd, " pref=1"))
+		req_mode |= WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED;
+	if (os_strstr(cmd, " abridged=1"))
+		req_mode |= WNM_BSS_TM_REQ_ABRIDGED;
+	if (os_strstr(cmd, " disassoc_imminent=1"))
+		req_mode |= WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+
+	ret = wnm_send_bss_tm_req(hapd, sta, req_mode, disassoc_timer,
+				  valid_int, bss_term_dur, url,
+				  nei_pos > nei_rep ? nei_rep : NULL,
+				  nei_pos - nei_rep);
+	os_free(url);
+	return ret;
+}
+
 #endif /* CONFIG_WNM */
 
 
@@ -874,7 +1067,7 @@
 			  MAC2STR(hapd->own_addr),
 			  wpa_ssid_txt(hapd->conf->ssid.ssid,
 				       hapd->conf->ssid.ssid_len));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -883,7 +1076,7 @@
 			  hapd->conf->wps_state == 0 ? "disabled" :
 			  (hapd->conf->wps_state == 1 ? "not configured" :
 			   "configured"));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -891,7 +1084,7 @@
 	    hapd->conf->ssid.wpa_passphrase) {
 		ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
 				  hapd->conf->ssid.wpa_passphrase);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -903,7 +1096,7 @@
 		wpa_snprintf_hex(hex, sizeof(hex),
 				 hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
 		ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -911,39 +1104,39 @@
 
 	if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
 		ret = os_snprintf(pos, end - pos, "key_mgmt=");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 
 		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
 			ret = os_snprintf(pos, end - pos, "WPA-PSK ");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
 		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
 			ret = os_snprintf(pos, end - pos, "WPA-EAP ");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
 #ifdef CONFIG_IEEE80211R
 		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
 			ret = os_snprintf(pos, end - pos, "FT-PSK ");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
 		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
 			ret = os_snprintf(pos, end - pos, "FT-EAP ");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
 #ifdef CONFIG_SAE
 		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
 			ret = os_snprintf(pos, end - pos, "FT-SAE ");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
@@ -952,13 +1145,13 @@
 #ifdef CONFIG_IEEE80211W
 		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
 			ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
 		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
 			ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
@@ -966,14 +1159,20 @@
 #ifdef CONFIG_SAE
 		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
 			ret = os_snprintf(pos, end - pos, "SAE ");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
 #endif /* CONFIG_SAE */
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+			ret = os_snprintf(pos, end - pos, "WPA-EAP-SUITE-B ");
+			if (os_snprintf_error(end - pos, ret))
+				return pos - buf;
+			pos += ret;
+		}
 
 		ret = os_snprintf(pos, end - pos, "\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -981,14 +1180,14 @@
 	if (hapd->conf->wpa) {
 		ret = os_snprintf(pos, end - pos, "group_cipher=%s\n",
 				  wpa_cipher_txt(hapd->conf->wpa_group));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
 
 	if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
 		ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 
@@ -999,14 +1198,14 @@
 		pos += ret;
 
 		ret = os_snprintf(pos, end - pos, "\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
 
 	if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
 		ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 
@@ -1017,7 +1216,7 @@
 		pos += ret;
 
 		ret = os_snprintf(pos, end - pos, "\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -1074,6 +1273,8 @@
 #ifdef CONFIG_TESTING_OPTIONS
 	} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
 		hapd->ext_mgmt_frame_handling = atoi(value);
+	} else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
+		hapd->ext_eapol_frame_io = atoi(value);
 #endif /* CONFIG_TESTING_OPTIONS */
 	} else {
 		struct sta_info *sta;
@@ -1122,7 +1323,7 @@
 
 	if (os_strcmp(cmd, "version") == 0) {
 		res = os_snprintf(buf, buflen, "%s", VERSION_STR);
-		if (res < 0 || (unsigned int) res >= buflen)
+		if (os_snprintf_error(buflen, res))
 			return -1;
 		return res;
 	}
@@ -1249,6 +1450,248 @@
 	return res;
 }
 
+
+static int hostapd_ctrl_iface_eapol_rx(struct hostapd_data *hapd, char *cmd)
+{
+	char *pos;
+	u8 src[ETH_ALEN], *buf;
+	int used;
+	size_t len;
+
+	wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
+
+	pos = cmd;
+	used = hwaddr_aton2(pos, src);
+	if (used < 0)
+		return -1;
+	pos += used;
+	while (*pos == ' ')
+		pos++;
+
+	len = os_strlen(pos);
+	if (len & 1)
+		return -1;
+	len /= 2;
+
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return -1;
+
+	if (hexstr2bin(pos, buf, len) < 0) {
+		os_free(buf);
+		return -1;
+	}
+
+	ieee802_1x_receive(hapd, src, buf, len);
+	os_free(buf);
+
+	return 0;
+}
+
+
+static u16 ipv4_hdr_checksum(const void *buf, size_t len)
+{
+	size_t i;
+	u32 sum = 0;
+	const u16 *pos = buf;
+
+	for (i = 0; i < len / 2; i++)
+		sum += *pos++;
+
+	while (sum >> 16)
+		sum = (sum & 0xffff) + (sum >> 16);
+
+	return sum ^ 0xffff;
+}
+
+
+#define HWSIM_PACKETLEN 1500
+#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
+
+void hostapd_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf,
+			  size_t len)
+{
+	struct hostapd_data *hapd = ctx;
+	const struct ether_header *eth;
+	const struct iphdr *ip;
+	const u8 *pos;
+	unsigned int i;
+
+	if (len != HWSIM_PACKETLEN)
+		return;
+
+	eth = (const struct ether_header *) buf;
+	ip = (const struct iphdr *) (eth + 1);
+	pos = (const u8 *) (ip + 1);
+
+	if (ip->ihl != 5 || ip->version != 4 ||
+	    ntohs(ip->tot_len) != HWSIM_IP_LEN)
+		return;
+
+	for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) {
+		if (*pos != (u8) i)
+			return;
+		pos++;
+	}
+
+	wpa_msg(hapd->msg_ctx, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
+		MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
+}
+
+
+static int hostapd_ctrl_iface_data_test_config(struct hostapd_data *hapd,
+					       char *cmd)
+{
+	int enabled = atoi(cmd);
+	char *pos;
+	const char *ifname;
+
+	if (!enabled) {
+		if (hapd->l2_test) {
+			l2_packet_deinit(hapd->l2_test);
+			hapd->l2_test = NULL;
+			wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+				"test data: Disabled");
+		}
+		return 0;
+	}
+
+	if (hapd->l2_test)
+		return 0;
+
+	pos = os_strstr(cmd, " ifname=");
+	if (pos)
+		ifname = pos + 8;
+	else
+		ifname = hapd->conf->iface;
+
+	hapd->l2_test = l2_packet_init(ifname, hapd->own_addr,
+					ETHERTYPE_IP, hostapd_data_test_rx,
+					hapd, 1);
+	if (hapd->l2_test == NULL)
+		return -1;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: Enabled");
+
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_data_test_tx(struct hostapd_data *hapd, char *cmd)
+{
+	u8 dst[ETH_ALEN], src[ETH_ALEN];
+	char *pos;
+	int used;
+	long int val;
+	u8 tos;
+	u8 buf[HWSIM_PACKETLEN];
+	struct ether_header *eth;
+	struct iphdr *ip;
+	u8 *dpos;
+	unsigned int i;
+
+	if (hapd->l2_test == NULL)
+		return -1;
+
+	/* format: <dst> <src> <tos> */
+
+	pos = cmd;
+	used = hwaddr_aton2(pos, dst);
+	if (used < 0)
+		return -1;
+	pos += used;
+	while (*pos == ' ')
+		pos++;
+	used = hwaddr_aton2(pos, src);
+	if (used < 0)
+		return -1;
+	pos += used;
+
+	val = strtol(pos, NULL, 0);
+	if (val < 0 || val > 0xff)
+		return -1;
+	tos = val;
+
+	eth = (struct ether_header *) buf;
+	os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
+	os_memcpy(eth->ether_shost, src, ETH_ALEN);
+	eth->ether_type = htons(ETHERTYPE_IP);
+	ip = (struct iphdr *) (eth + 1);
+	os_memset(ip, 0, sizeof(*ip));
+	ip->ihl = 5;
+	ip->version = 4;
+	ip->ttl = 64;
+	ip->tos = tos;
+	ip->tot_len = htons(HWSIM_IP_LEN);
+	ip->protocol = 1;
+	ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
+	ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2);
+	ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
+	dpos = (u8 *) (ip + 1);
+	for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
+		*dpos++ = i;
+
+	if (l2_packet_send(hapd->l2_test, dst, ETHERTYPE_IP, buf,
+			   HWSIM_PACKETLEN) < 0)
+		return -1;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX dst=" MACSTR
+		" src=" MACSTR " tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
+
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_data_test_frame(struct hostapd_data *hapd,
+					      char *cmd)
+{
+	u8 *buf;
+	struct ether_header *eth;
+	struct l2_packet_data *l2 = NULL;
+	size_t len;
+	u16 ethertype;
+	int res = -1;
+	const char *ifname = hapd->conf->iface;
+
+	if (os_strncmp(cmd, "ifname=", 7) == 0) {
+		cmd += 7;
+		ifname = cmd;
+		cmd = os_strchr(cmd, ' ');
+		if (cmd == NULL)
+			return -1;
+		*cmd++ = '\0';
+	}
+
+	len = os_strlen(cmd);
+	if (len & 1 || len < ETH_HLEN * 2)
+		return -1;
+	len /= 2;
+
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return -1;
+
+	if (hexstr2bin(cmd, buf, len) < 0)
+		goto done;
+
+	eth = (struct ether_header *) buf;
+	ethertype = ntohs(eth->ether_type);
+
+	l2 = l2_packet_init(ifname, hapd->own_addr, ethertype,
+			    hostapd_data_test_rx, hapd, 1);
+	if (l2 == NULL)
+		goto done;
+
+	res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "test data: TX frame res=%d", res);
+done:
+	if (l2)
+		l2_packet_deinit(l2);
+	os_free(buf);
+
+	return res < 0 ? -1 : 0;
+}
+
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
@@ -1366,7 +1809,8 @@
 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (res < 0) {
-		perror("recvfrom(ctrl_iface)");
+		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+			   strerror(errno));
 		return;
 	}
 	buf[res] = '\0';
@@ -1376,8 +1820,11 @@
 
 	reply = os_malloc(reply_size);
 	if (reply == NULL) {
-		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
-		       fromlen);
+		if (sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+			   fromlen) < 0) {
+			wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+				   strerror(errno));
+		}
 		return;
 	}
 
@@ -1525,6 +1972,9 @@
 	} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
 		if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "BSS_TM_REQ ", 11) == 0) {
+		if (hostapd_ctrl_iface_bss_tm_req(hapd, buf + 11))
+			reply_len = -1;
 #endif /* CONFIG_WNM */
 	} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
 		reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
@@ -1551,6 +2001,18 @@
 	} else if (os_strncmp(buf, "MGMT_TX ", 8) == 0) {
 		if (hostapd_ctrl_iface_mgmt_tx(hapd, buf + 8))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
+		if (hostapd_ctrl_iface_eapol_rx(hapd, buf + 9) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
+		if (hostapd_ctrl_iface_data_test_config(hapd, buf + 17) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
+		if (hostapd_ctrl_iface_data_test_tx(hapd, buf + 13) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
+		if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
+			reply_len = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
 	} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
 		if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -1558,7 +2020,11 @@
 	} else if (os_strncmp(buf, "VENDOR ", 7) == 0) {
 		reply_len = hostapd_ctrl_iface_vendor(hapd, buf + 7, reply,
 						      reply_size);
-
+	} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
+		ieee802_1x_erp_flush(hapd);
+#ifdef RADIUS_SERVER
+		radius_server_erp_flush(hapd->radius_srv);
+#endif /* RADIUS_SERVER */
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
@@ -1568,7 +2034,11 @@
 		os_memcpy(reply, "FAIL\n", 5);
 		reply_len = 5;
 	}
-	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+	if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+		   fromlen) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+			   strerror(errno));
+	}
 	os_free(reply);
 }
 
@@ -1623,7 +2093,8 @@
 			wpa_printf(MSG_DEBUG, "Using existing control "
 				   "interface directory.");
 		} else {
-			perror("mkdir[ctrl_interface]");
+			wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
+				   strerror(errno));
 			goto fail;
 		}
 	}
@@ -1631,7 +2102,8 @@
 	if (hapd->conf->ctrl_interface_gid_set &&
 	    chown(hapd->conf->ctrl_interface, -1,
 		  hapd->conf->ctrl_interface_gid) < 0) {
-		perror("chown[ctrl_interface]");
+		wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -1639,7 +2111,8 @@
 	    hapd->iface->interfaces->ctrl_iface_group &&
 	    chown(hapd->conf->ctrl_interface, -1,
 		  hapd->iface->interfaces->ctrl_iface_group) < 0) {
-		perror("chown[ctrl_interface]");
+		wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -1664,7 +2137,7 @@
 
 	s = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket(PF_UNIX)");
+		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
 		goto fail;
 	}
 
@@ -1685,15 +2158,16 @@
 				   " allow connections - assuming it was left"
 				   "over from forced program termination");
 			if (unlink(fname) < 0) {
-				perror("unlink[ctrl_iface]");
-				wpa_printf(MSG_ERROR, "Could not unlink "
-					   "existing ctrl_iface socket '%s'",
-					   fname);
+				wpa_printf(MSG_ERROR,
+					   "Could not unlink existing ctrl_iface socket '%s': %s",
+					   fname, strerror(errno));
 				goto fail;
 			}
 			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
 			    0) {
-				perror("hostapd-ctrl-iface: bind(PF_UNIX)");
+				wpa_printf(MSG_ERROR,
+					   "hostapd-ctrl-iface: bind(PF_UNIX): %s",
+					   strerror(errno));
 				goto fail;
 			}
 			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -1711,19 +2185,22 @@
 
 	if (hapd->conf->ctrl_interface_gid_set &&
 	    chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
-		perror("chown[ctrl_interface/ifname]");
+		wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
+			   strerror(errno));
 		goto fail;
 	}
 
 	if (!hapd->conf->ctrl_interface_gid_set &&
 	    hapd->iface->interfaces->ctrl_iface_group &&
 	    chown(fname, -1, hapd->iface->interfaces->ctrl_iface_group) < 0) {
-		perror("chown[ctrl_interface/ifname]");
+		wpa_printf(MSG_ERROR, "chown[ctrl_interface/ifname]: %s",
+			   strerror(errno));
 		goto fail;
 	}
 
 	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
-		perror("chmod[ctrl_interface/ifname]");
+		wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
+			   strerror(errno));
 		goto fail;
 	}
 	os_free(fname);
@@ -1782,6 +2259,11 @@
 		dst = dst->next;
 		os_free(prev);
 	}
+
+#ifdef CONFIG_TESTING_OPTIONS
+	l2_packet_deinit(hapd->l2_test);
+	hapd->l2_test = NULL;
+#endif /* CONFIG_TESTING_OPTIONS */
 }
 
 
@@ -1831,7 +2313,8 @@
 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (res < 0) {
-		perror("recvfrom(ctrl_iface)");
+		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+			   strerror(errno));
 		return;
 	}
 	buf[res] = '\0';
@@ -1871,7 +2354,11 @@
 		reply_len = 5;
 	}
 
-	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+	if (sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+		   fromlen) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL: sendto failed: %s",
+			   strerror(errno));
+	}
 }
 
 
@@ -1912,13 +2399,15 @@
 			wpa_printf(MSG_DEBUG, "Using existing control "
 				   "interface directory.");
 		} else {
-			perror("mkdir[ctrl_interface]");
+			wpa_printf(MSG_ERROR, "mkdir[ctrl_interface]: %s",
+				   strerror(errno));
 			goto fail;
 		}
 	} else if (interface->ctrl_iface_group &&
 		   chown(interface->global_iface_path, -1,
 			 interface->ctrl_iface_group) < 0) {
-		perror("chown[ctrl_interface]");
+		wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+			   strerror(errno));
 		goto fail;
 	}
 
@@ -1928,7 +2417,7 @@
 
 	s = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket(PF_UNIX)");
+		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
 		goto fail;
 	}
 
@@ -1949,15 +2438,15 @@
 				   " allow connections - assuming it was left"
 				   "over from forced program termination");
 			if (unlink(fname) < 0) {
-				perror("unlink[ctrl_iface]");
-				wpa_printf(MSG_ERROR, "Could not unlink "
-					   "existing ctrl_iface socket '%s'",
-					   fname);
+				wpa_printf(MSG_ERROR,
+					   "Could not unlink existing ctrl_iface socket '%s': %s",
+					   fname, strerror(errno));
 				goto fail;
 			}
 			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
 			    0) {
-				perror("bind(PF_UNIX)");
+				wpa_printf(MSG_ERROR, "bind(PF_UNIX): %s",
+					   strerror(errno));
 				goto fail;
 			}
 			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -1975,12 +2464,14 @@
 
 	if (interface->ctrl_iface_group &&
 	    chown(fname, -1, interface->ctrl_iface_group) < 0) {
-		perror("chown[ctrl_interface]");
+		wpa_printf(MSG_ERROR, "chown[ctrl_interface]: %s",
+			   strerror(errno));
 		goto fail;
 	}
 
 	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
-		perror("chmod[ctrl_interface/ifname]");
+		wpa_printf(MSG_ERROR, "chmod[ctrl_interface/ifname]: %s",
+			   strerror(errno));
 		goto fail;
 	}
 	os_free(fname);
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 5b74b64..4cde2b5 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -15,10 +15,6 @@
 # Driver interface for wired authenticator
 #CONFIG_DRIVER_WIRED=y
 
-# Driver interface for madwifi driver
-#CONFIG_DRIVER_MADWIFI=y
-#CFLAGS += -I../../madwifi # change to the madwifi source directory
-
 # Driver interface for drivers using the nl80211 kernel interface
 CONFIG_DRIVER_NL80211=y
 
@@ -60,6 +56,9 @@
 # Integrated EAP server
 CONFIG_EAP=y
 
+# EAP Re-authentication Protocol (ERP) in integrated EAP server
+CONFIG_ERP=y
+
 # EAP-MD5 for the integrated EAP server
 CONFIG_EAP_MD5=y
 
@@ -142,7 +141,7 @@
 #CONFIG_IEEE80211R=y
 
 # Use the hostapd's IEEE 802.11 authentication (ACL), but without
-# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
+# the IEEE 802.11 Management capability (e.g., FreeBSD/net80211)
 #CONFIG_DRIVER_RADIUS_ACL=y
 
 # IEEE 802.11n (High Throughput) support
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index c041887..42d59db 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -711,7 +711,7 @@
 	rend = resp + resp_len;
 	rpos = resp;
 	ret = os_snprintf(rpos, rend - rpos, "GSM-AUTH-RESP %s", imsi);
-	if (ret < 0 || ret >= rend - rpos)
+	if (os_snprintf_error(rend - rpos, ret))
 		return -1;
 	rpos += ret;
 
@@ -737,7 +737,7 @@
 
 	printf("No GSM triplets found for %s\n", imsi);
 	ret = os_snprintf(rpos, rend - rpos, " FAILURE");
-	if (ret < 0 || ret >= rend - rpos)
+	if (os_snprintf_error(rend - rpos, ret))
 		return -1;
 	rpos += ret;
 
diff --git a/hostapd/hostapd.8 b/hostapd/hostapd.8
index b4456bb..d19d862 100644
--- a/hostapd/hostapd.8
+++ b/hostapd/hostapd.8
@@ -12,7 +12,7 @@
 .B hostapd
 is a user space daemon for access point and authentication servers.
 It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
-The current version supports Linux (Host AP, madwifi, mac80211-based drivers) and FreeBSD (net80211).
+The current version supports Linux (Host AP, mac80211-based drivers) and FreeBSD (net80211).
 
 .B hostapd
 is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication.
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index a7ab0f6..2f6126c 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -2,10 +2,10 @@
 # Empty lines and lines starting with # are ignored
 
 # AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
-# management frames); ath0 for madwifi
+# management frames with the Host AP driver); wlan0 with many nl80211 drivers
 interface=wlan0
 
-# In case of madwifi, atheros, and nl80211 driver interfaces, an additional
+# In case of atheros and nl80211 driver interfaces, an additional
 # configuration parameter, bridge, may be used to notify hostapd if the
 # interface is included in a bridge. This parameter is not used with Host AP
 # driver. If the bridge parameter is not set, the drivers will automatically
@@ -18,12 +18,15 @@
 # interface is also created.
 #bridge=br0
 
-# Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd);
+# Driver interface type (hostap/wired/none/nl80211/bsd);
 # default: hostap). nl80211 is used with all Linux mac80211 drivers.
 # Use driver=none if building hostapd as a standalone RADIUS server that does
 # not control any wireless/wired driver.
 # driver=hostap
 
+# Driver interface parameters (mainly for development testing use)
+# driver_params=<params>
+
 # hostapd event logger configuration
 #
 # Two output method: syslog and stdout (only usable if not forking to
@@ -221,7 +224,7 @@
 # Station MAC address -based authentication
 # Please note that this kind of access control requires a driver that uses
 # hostapd to take care of management frame processing and as such, this can be
-# used with driver=hostap or driver=nl80211, but not with driver=madwifi.
+# used with driver=hostap or driver=nl80211, but not with driver=atheros.
 # 0 = accept unless in deny list
 # 1 = deny unless in accept list
 # 2 = use external RADIUS server (accept/deny lists are searched first)
@@ -435,6 +438,11 @@
 # associated stations in the BSS. By default, this bridging is allowed.
 #ap_isolate=1
 
+# BSS Load update period (in BUs)
+# This field is used to enable and configure adding a BSS Load element into
+# Beacon and Probe Response frames.
+#bss_load_update_period=50
+
 # Fixed BSS Load value for testing purposes
 # This field can be used to configure hostapd to add a fixed BSS Load element
 # into Beacon and Probe Response frames for testing purposes. The format is
@@ -688,6 +696,17 @@
 # is only used by one station.
 #use_pae_group_addr=1
 
+# EAP Re-authentication Protocol (ERP) authenticator (RFC 6696)
+#
+# Whether to initiate EAP authentication with EAP-Initiate/Re-auth-Start before
+# EAP-Identity/Request
+#erp_send_reauth_start=1
+#
+# Domain name for EAP-Initiate/Re-auth-Start. Omitted from the message if not
+# set (no local ER server). This is also used by the integrated EAP server if
+# ERP is enabled (eap_server_erp=1).
+#erp_domain=example.com
+
 ##### Integrated EAP server ###################################################
 
 # Optionally, hostapd can be configured to use an integrated EAP server
@@ -763,6 +782,15 @@
 # "openssl dhparam -out /etc/hostapd.dh.pem 1024"
 #dh_file=/etc/hostapd.dh.pem
 
+# OpenSSL cipher string
+#
+# This is an OpenSSL specific configuration option for configuring the default
+# ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the default.
+# See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation
+# on cipher suite configuration. This is applicable only if hostapd is built to
+# use OpenSSL.
+#openssl_ciphers=DEFAULT:!EXP:!LOW
+
 # Fragment size for EAP methods
 #fragment_size=1400
 
@@ -824,6 +852,10 @@
 # EAP method is enabled, the peer will be allowed to connect without TNC.
 #tnc=1
 
+# EAP Re-authentication Protocol (ERP) - RFC 6696
+#
+# Whether to enable ERP on the EAP server.
+#eap_server_erp=1
 
 ##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
 
@@ -1439,6 +1471,11 @@
 # 1 = enabled
 #bss_transition=1
 
+# Proxy ARP
+# 0 = disabled (default)
+# 1 = enabled
+#proxy_arp=1
+
 ##### IEEE 802.11u-2011 #######################################################
 
 # Enable Interworking service
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 9e62bef..7009184 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -393,7 +393,7 @@
 	else
 		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
 				  argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+	if (os_snprintf_error(sizeof(cmd), res)) {
 		printf("Too long WPS_CHECK_PIN command.\n");
 		return -1;
 	}
@@ -456,7 +456,7 @@
 
 	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
 			  argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+	if (os_snprintf_error(sizeof(cmd), res)) {
 		printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
 		return -1;
 	}
@@ -477,7 +477,7 @@
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+	if (os_snprintf_error(sizeof(cmd), res)) {
 		printf("Too long WPS_NFC_TOKEN command.\n");
 		return -1;
 	}
@@ -499,7 +499,7 @@
 
 	res = os_snprintf(cmd, sizeof(cmd), "NFC_GET_HANDOVER_SEL %s %s",
 			  argv[0], argv[1]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+	if (os_snprintf_error(sizeof(cmd), res)) {
 		printf("Too long NFC_GET_HANDOVER_SEL command.\n");
 		return -1;
 	}
@@ -596,7 +596,7 @@
 
 	res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
 			  argv[0], argv[1]);
-	if (res < 0 || res >= (int) sizeof(buf))
+	if (os_snprintf_error(sizeof(buf), res))
 		return -1;
 	return wpa_ctrl_command(ctrl, buf);
 }
@@ -616,12 +616,39 @@
 
 	res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s %s",
 			  argv[0], argv[1], argv[2]);
-	if (res < 0 || res >= (int) sizeof(buf))
+	if (os_snprintf_error(sizeof(buf), res))
 		return -1;
 	return wpa_ctrl_command(ctrl, buf);
 }
 
 
+static int hostapd_cli_cmd_bss_tm_req(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	char buf[2000], *tmp;
+	int res, i, total;
+
+	if (argc < 1) {
+		printf("Invalid 'bss_tm_req' command - at least one argument (STA addr) is needed\n");
+		return -1;
+	}
+
+	res = os_snprintf(buf, sizeof(buf), "BSS_TM_REQ %s", argv[0]);
+	if (os_snprintf_error(sizeof(buf), res))
+		return -1;
+
+	total = res;
+	for (i = 1; i < argc; i++) {
+		tmp = &buf[total];
+		res = os_snprintf(tmp, sizeof(buf) - total, " %s", argv[i]);
+		if (os_snprintf_error(sizeof(buf) - total, res))
+			return -1;
+		total += res;
+	}
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
 				      char *argv[])
 {
@@ -709,7 +736,7 @@
 	}
 
 	res = os_snprintf(buf, sizeof(buf), "SET_QOS_MAP_SET %s", argv[0]);
-	if (res < 0 || res >= (int) sizeof(buf))
+	if (os_snprintf_error(sizeof(buf), res))
 		return -1;
 	return wpa_ctrl_command(ctrl, buf);
 }
@@ -728,7 +755,7 @@
 	}
 
 	res = os_snprintf(buf, sizeof(buf), "SEND_QOS_MAP_CONF %s", argv[0]);
-	if (res < 0 || res >= (int) sizeof(buf))
+	if (os_snprintf_error(sizeof(buf), res))
 		return -1;
 	return wpa_ctrl_command(ctrl, buf);
 }
@@ -748,7 +775,7 @@
 
 	res = os_snprintf(buf, sizeof(buf), "HS20_WNM_NOTIF %s %s",
 			  argv[0], argv[1]);
-	if (res < 0 || res >= (int) sizeof(buf))
+	if (os_snprintf_error(sizeof(buf), res))
 		return -1;
 	return wpa_ctrl_command(ctrl, buf);
 }
@@ -773,7 +800,7 @@
 		res = os_snprintf(buf, sizeof(buf),
 				  "HS20_DEAUTH_REQ %s %s %s",
 				  argv[0], argv[1], argv[2]);
-	if (res < 0 || res >= (int) sizeof(buf))
+	if (os_snprintf_error(sizeof(buf), res))
 		return -1;
 	return wpa_ctrl_command(ctrl, buf);
 }
@@ -866,7 +893,7 @@
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+	if (os_snprintf_error(sizeof(cmd), res)) {
 		printf("Too long SET command.\n");
 		return -1;
 	}
@@ -886,7 +913,7 @@
 	}
 
 	res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+	if (os_snprintf_error(sizeof(cmd), res)) {
 		printf("Too long GET command.\n");
 		return -1;
 	}
@@ -914,7 +941,7 @@
 
 	res = os_snprintf(cmd, sizeof(cmd), "CHAN_SWITCH %s %s",
 			  argv[0], argv[1]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+	if (os_snprintf_error(sizeof(cmd), res)) {
 		printf("Too long CHAN_SWITCH command.\n");
 		return -1;
 	}
@@ -923,7 +950,7 @@
 	for (i = 2; i < argc; i++) {
 		tmp = cmd + total;
 		res = os_snprintf(tmp, sizeof(cmd) - total, " %s", argv[i]);
-		if (res < 0 || (size_t) res >= sizeof(cmd) - total - 1) {
+		if (os_snprintf_error(sizeof(cmd) - total, res)) {
 			printf("Too long CHAN_SWITCH command.\n");
 			return -1;
 		}
@@ -933,6 +960,27 @@
 }
 
 
+static int hostapd_cli_cmd_enable(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "ENABLE");
+}
+
+
+static int hostapd_cli_cmd_reload(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "RELOAD");
+}
+
+
+static int hostapd_cli_cmd_disable(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "DISABLE");
+}
+
+
 static int hostapd_cli_cmd_vendor(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	char cmd[256];
@@ -946,7 +994,7 @@
 
 	res = os_snprintf(cmd, sizeof(cmd), "VENDOR %s %s %s", argv[0], argv[1],
 			  argc == 3 ? argv[2] : "");
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+	if (os_snprintf_error(sizeof(cmd), res)) {
 		printf("Too long VENDOR command.\n");
 		return -1;
 	}
@@ -954,6 +1002,13 @@
 }
 
 
+static int hostapd_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "ERP_FLUSH");
+}
+
+
 struct hostapd_cli_cmd {
 	const char *cmd;
 	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
@@ -989,6 +1044,7 @@
 #endif /* CONFIG_WPS */
 	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
 	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
+	{ "bss_tm_req", hostapd_cli_cmd_bss_tm_req },
 	{ "get_config", hostapd_cli_cmd_get_config },
 	{ "help", hostapd_cli_cmd_help },
 	{ "interface", hostapd_cli_cmd_interface },
@@ -1003,6 +1059,10 @@
 	{ "hs20_wnm_notif", hostapd_cli_cmd_hs20_wnm_notif },
 	{ "hs20_deauth_req", hostapd_cli_cmd_hs20_deauth_req },
 	{ "vendor", hostapd_cli_cmd_vendor },
+	{ "enable", hostapd_cli_cmd_enable },
+	{ "reload", hostapd_cli_cmd_reload },
+	{ "disable", hostapd_cli_cmd_disable },
+	{ "erp_flush", hostapd_cli_cmd_erp_flush },
 	{ NULL, NULL }
 };
 
diff --git a/hostapd/main.c b/hostapd/main.c
index c3af704..3ecd009 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -28,8 +28,6 @@
 #include "eap_register.h"
 #include "ctrl_iface.h"
 
-struct wowlan_triggers *wpa_get_wowlan_triggers(const char *wowlan_triggers,
-						struct wpa_driver_capa *capa);
 
 struct hapd_global {
 	void **drv_priv;
@@ -186,9 +184,7 @@
 	}
 	params.bssid = b;
 	params.ifname = hapd->conf->iface;
-	params.ssid = hapd->conf->ssid.ssid;
-	params.ssid_len = hapd->conf->ssid.ssid_len;
-	params.test_socket = hapd->conf->test_socket;
+	params.driver_params = hapd->iconf->driver_params;
 	params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
 
 	params.num_bridge = hapd->iface->num_bss;
@@ -217,6 +213,7 @@
 		struct wowlan_triggers *triggs;
 
 		iface->drv_flags = capa.flags;
+		iface->smps_modes = capa.smps_modes;
 		iface->probe_resp_offloads = capa.probe_resp_offloads;
 		iface->extended_capa = capa.extended_capa;
 		iface->extended_capa_mask = capa.extended_capa_mask;
@@ -411,7 +408,7 @@
 #endif /* EAP_SERVER_TNC */
 
 	if (daemonize && os_daemonize(pid_file)) {
-		perror("daemon");
+		wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
 		return -1;
 	}
 
@@ -641,6 +638,8 @@
 
 	if (log_file)
 		wpa_debug_open_file(log_file);
+	else
+		wpa_debug_setup_stdout();
 #ifdef CONFIG_DEBUG_LINUX_TRACING
 	if (enable_trace_dbg) {
 		int tret = wpa_debug_open_linux_tracing();
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index 6290d3f..7c55146 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -10,6 +10,8 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "hostapd.h"
@@ -50,12 +52,19 @@
 	if (sta) {
 		radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
 
-		os_snprintf(buf, sizeof(buf), "%08X-%08X",
-			    sta->acct_session_id_hi, sta->acct_session_id_lo);
-		if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
-					 (u8 *) buf, os_strlen(buf))) {
-			wpa_printf(MSG_INFO, "Could not add Acct-Session-Id");
-			goto fail;
+		if ((hapd->conf->wpa & 2) &&
+		    !hapd->conf->disable_pmksa_caching &&
+		    sta->eapol_sm && sta->eapol_sm->acct_multi_session_id_hi) {
+			os_snprintf(buf, sizeof(buf), "%08X+%08X",
+				    sta->eapol_sm->acct_multi_session_id_hi,
+				    sta->eapol_sm->acct_multi_session_id_lo);
+			if (!radius_msg_add_attr(
+				    msg, RADIUS_ATTR_ACCT_MULTI_SESSION_ID,
+				    (u8 *) buf, os_strlen(buf))) {
+				wpa_printf(MSG_INFO,
+					   "Could not add Acct-Multi-Session-Id");
+				goto fail;
+			}
 		}
 	} else {
 		radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
diff --git a/src/ap/acs.c b/src/ap/acs.c
index b94b8a4..97cf26f 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -816,6 +816,14 @@
 
 	wpa_printf(MSG_INFO, "ACS: Automatic channel selection started, this may take a bit");
 
+	if (iface->drv_flags & WPA_DRIVER_FLAGS_ACS_OFFLOAD) {
+		wpa_printf(MSG_INFO, "ACS: Offloading to driver");
+		err = hostapd_drv_do_acs(iface->bss[0]);
+		if (err)
+			return HOSTAPD_CHAN_INVALID;
+		return HOSTAPD_CHAN_ACS;
+	}
+
 	acs_cleanup(iface);
 
 	err = acs_request_scan(iface);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index c7da69e..1c0ed7a 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -425,6 +425,7 @@
 	os_free(conf->eap_user_sqlite);
 
 	os_free(conf->eap_req_id_text);
+	os_free(conf->erp_domain);
 	os_free(conf->accept_mac);
 	os_free(conf->deny_mac);
 	os_free(conf->nas_identifier);
@@ -444,12 +445,12 @@
 	os_free(conf->private_key_passwd);
 	os_free(conf->ocsp_stapling_response);
 	os_free(conf->dh_file);
+	os_free(conf->openssl_ciphers);
 	os_free(conf->pac_opaque_encr_key);
 	os_free(conf->eap_fast_a_id);
 	os_free(conf->eap_fast_a_id_info);
 	os_free(conf->eap_sim_db);
 	os_free(conf->radius_server_clients);
-	os_free(conf->test_socket);
 	os_free(conf->radius);
 	os_free(conf->radius_das_shared_secret);
 	hostapd_config_free_vlan(conf);
@@ -495,6 +496,12 @@
 	os_free(conf->model_description);
 	os_free(conf->model_url);
 	os_free(conf->upc);
+	{
+		unsigned int i;
+
+		for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+			wpabuf_free(conf->wps_vendor_ext[i]);
+	}
 	wpabuf_free(conf->wps_nfc_dh_pubkey);
 	wpabuf_free(conf->wps_nfc_dh_privkey);
 	wpabuf_free(conf->wps_nfc_dev_pw);
@@ -566,6 +573,7 @@
 	os_free(conf->supported_rates);
 	os_free(conf->basic_rates);
 	os_free(conf->chanlist);
+	os_free(conf->driver_params);
 
 	os_free(conf);
 }
@@ -888,12 +896,20 @@
 		int cipher = WPA_CIPHER_NONE;
 		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
 		bss->ssid.wep.default_len = bss->default_wep_key_len;
-		if (bss->default_wep_key_len)
+		if (full_config && bss->default_wep_key_len) {
 			cipher = bss->default_wep_key_len >= 13 ?
 				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+		} else if (full_config && bss->ssid.wep.keys_set) {
+			if (bss->ssid.wep.len[0] >= 13)
+				cipher = WPA_CIPHER_WEP104;
+			else
+				cipher = WPA_CIPHER_WEP40;
+		}
 		bss->wpa_group = cipher;
 		bss->wpa_pairwise = cipher;
 		bss->rsn_pairwise = cipher;
+		if (full_config)
+			bss->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
 	} else if (bss->ssid.wep.keys_set) {
 		int cipher = WPA_CIPHER_WEP40;
 		if (bss->ssid.wep.len[0] >= 13)
@@ -902,6 +918,8 @@
 		bss->wpa_group = cipher;
 		bss->wpa_pairwise = cipher;
 		bss->rsn_pairwise = cipher;
+		if (full_config)
+			bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
 	} else if (bss->osen) {
 		bss->ssid.security_policy = SECURITY_OSEN;
 		bss->wpa_group = WPA_CIPHER_CCMP;
@@ -912,5 +930,7 @@
 		bss->wpa_group = WPA_CIPHER_NONE;
 		bss->wpa_pairwise = WPA_CIPHER_NONE;
 		bss->rsn_pairwise = WPA_CIPHER_NONE;
+		if (full_config)
+			bss->wpa_key_mgmt = WPA_KEY_MGMT_NONE;
 	}
 }
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 2858c6e..58af6cb 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -15,6 +15,34 @@
 #include "common/ieee802_11_common.h"
 #include "wps/wps.h"
 
+/**
+ * mesh_conf - local MBSS state and settings
+ */
+struct mesh_conf {
+	u8 meshid[32];
+	u8 meshid_len;
+	/* Active Path Selection Protocol Identifier */
+	u8 mesh_pp_id;
+	/* Active Path Selection Metric Identifier */
+	u8 mesh_pm_id;
+	/* Congestion Control Mode Identifier */
+	u8 mesh_cc_id;
+	/* Synchronization Protocol Identifier */
+	u8 mesh_sp_id;
+	/* Authentication Protocol Identifier */
+	u8 mesh_auth_id;
+	u8 *ies;
+	int ie_len;
+#define MESH_CONF_SEC_NONE BIT(0)
+#define MESH_CONF_SEC_AUTH BIT(1)
+#define MESH_CONF_SEC_AMPE BIT(2)
+	unsigned int security;
+	int dot11MeshMaxRetries;
+	int dot11MeshRetryTimeout; /* msec */
+	int dot11MeshConfirmTimeout; /* msec */
+	int dot11MeshHoldingTimeout; /* msec */
+};
+
 #define MAX_STA_COUNT 2007
 #define MAX_VLAN_ID 4094
 
@@ -196,6 +224,7 @@
 	int max_num_sta; /* maximum number of STAs in station table */
 
 	int dtim_period;
+	int bss_load_update_period;
 
 	int ieee802_1x; /* use IEEE 802.1X */
 	int eapol_version;
@@ -204,6 +233,7 @@
 	struct hostapd_eap_user *eap_user;
 	char *eap_user_sqlite;
 	char *eap_sim_db;
+	int eap_server_erp; /* Whether ERP is enabled on internal EAP server */
 	struct hostapd_ip_addr own_ip_addr;
 	char *nas_identifier;
 	struct hostapd_radius_servers *radius;
@@ -230,6 +260,8 @@
 	int wep_rekeying_period;
 	int broadcast_key_idx_min, broadcast_key_idx_max;
 	int eap_reauth_period;
+	int erp_send_reauth_start;
+	char *erp_domain;
 
 	int ieee802_11f; /* use IEEE 802.11f (IAPP) */
 	char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
@@ -302,6 +334,7 @@
 	int check_crl;
 	char *ocsp_stapling_response;
 	char *dh_file;
+	char *openssl_ciphers;
 	u8 *pac_opaque_encr_key;
 	u8 *eap_fast_a_id;
 	size_t eap_fast_a_id_len;
@@ -319,8 +352,6 @@
 	int radius_server_acct_port;
 	int radius_server_ipv6;
 
-	char *test_socket; /* UNIX domain socket path for driver_test */
-
 	int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
 				 * address instead of individual address
 				 * (for driver_wired.c).
@@ -458,6 +489,7 @@
 	unsigned int qos_map_set_len;
 
 	int osen;
+	int proxy_arp;
 #ifdef CONFIG_HS20
 	int hs20;
 	int disable_dgaf;
@@ -514,6 +546,11 @@
 	u8 bss_load_test[5];
 	u8 bss_load_test_set;
 #endif /* CONFIG_TESTING_OPTIONS */
+
+#define MESH_ENABLED BIT(0)
+	int mesh;
+
+	int radio_measurements;
 };
 
 
@@ -540,6 +577,7 @@
 	int *basic_rates;
 
 	const struct wpa_driver_ops *driver;
+	char *driver_params;
 
 	int ap_table_max_size;
 	int ap_table_expiration_time;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index cc4ac10..8514cbe 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -477,7 +477,8 @@
 }
 
 
-int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
+int hostapd_set_freq_params(struct hostapd_freq_params *data,
+			    enum hostapd_hw_mode mode,
 			    int freq, int channel, int ht_enabled,
 			    int vht_enabled, int sec_channel_offset,
 			    int vht_oper_chwidth, int center_segment0,
@@ -562,8 +563,8 @@
 }
 
 
-int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
-		     int channel, int ht_enabled, int vht_enabled,
+int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
+		     int freq, int channel, int ht_enabled, int vht_enabled,
 		     int sec_channel_offset, int vht_oper_chwidth,
 		     int center_segment0, int center_segment1)
 {
@@ -573,7 +574,8 @@
 				    vht_enabled, sec_channel_offset,
 				    vht_oper_chwidth,
 				    center_segment0, center_segment1,
-				    hapd->iface->current_mode->vht_capab))
+				    hapd->iface->current_mode ?
+				    hapd->iface->current_mode->vht_capab : 0))
 		return -1;
 
 	if (hapd->driver == NULL)
@@ -747,7 +749,8 @@
 }
 
 
-int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
+int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+			  enum hostapd_hw_mode mode, int freq,
 			  int channel, int ht_enabled, int vht_enabled,
 			  int sec_channel_offset, int vht_oper_chwidth,
 			  int center_segment0, int center_segment1)
@@ -792,3 +795,18 @@
 	return hapd->driver->set_qos_map(hapd->drv_priv, qos_map_set,
 					 qos_map_set_len);
 }
+
+
+int hostapd_drv_do_acs(struct hostapd_data *hapd)
+{
+	struct drv_acs_params params;
+
+	if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
+		return 0;
+	os_memset(&params, 0, sizeof(params));
+	params.hw_mode = hapd->iface->conf->hw_mode;
+	params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
+	params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
+				 HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
+	return hapd->driver->do_acs(hapd->drv_priv, &params);
+}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 7cc9d7d..c133be7 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -57,8 +57,8 @@
 int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
 		       const u8 *addr, int idx, u8 *seq);
 int hostapd_flush(struct hostapd_data *hapd);
-int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
-		     int channel, int ht_enabled, int vht_enabled,
+int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
+		     int freq, int channel, int ht_enabled, int vht_enabled,
 		     int sec_channel_offset, int vht_oper_chwidth,
 		     int center_segment0, int center_segment1);
 int hostapd_set_rts(struct hostapd_data *hapd, int rts);
@@ -102,15 +102,18 @@
 		      int reassoc, u16 status, const u8 *ie, size_t len);
 int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
 		      u8 *tspec_ie, size_t tspec_ielen);
-int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
+int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+			  enum hostapd_hw_mode mode, int freq,
 			  int channel, int ht_enabled, int vht_enabled,
 			  int sec_channel_offset, int vht_oper_chwidth,
 			  int center_segment0, int center_segment1);
-int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
+int hostapd_set_freq_params(struct hostapd_freq_params *data,
+			    enum hostapd_hw_mode mode,
 			    int freq, int channel, int ht_enabled,
 			    int vht_enabled, int sec_channel_offset,
 			    int vht_oper_chwidth, int center_segment0,
 			    int center_segment1, u32 vht_caps);
+int hostapd_drv_do_acs(struct hostapd_data *hapd);
 
 
 #include "drivers/driver.h"
@@ -280,6 +283,47 @@
 	return hapd->driver->status(hapd->drv_priv, buf, buflen);
 }
 
+static inline int hostapd_drv_br_add_ip_neigh(struct hostapd_data *hapd,
+					      int version, const u8 *ipaddr,
+					      int prefixlen, const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+	    hapd->driver->br_add_ip_neigh == NULL)
+		return -1;
+	return hapd->driver->br_add_ip_neigh(hapd->drv_priv, version, ipaddr,
+					     prefixlen, addr);
+}
+
+static inline int hostapd_drv_br_delete_ip_neigh(struct hostapd_data *hapd,
+						 u8 version, const u8 *ipaddr)
+{
+	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+	    hapd->driver->br_delete_ip_neigh == NULL)
+		return -1;
+	return hapd->driver->br_delete_ip_neigh(hapd->drv_priv, version,
+						ipaddr);
+}
+
+static inline int hostapd_drv_br_port_set_attr(struct hostapd_data *hapd,
+					       enum drv_br_port_attr attr,
+					       unsigned int val)
+{
+	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+	    hapd->driver->br_port_set_attr == NULL)
+		return -1;
+	return hapd->driver->br_port_set_attr(hapd->drv_priv, attr, val);
+}
+
+static inline int hostapd_drv_br_set_net_param(struct hostapd_data *hapd,
+					       enum drv_br_net_param param,
+					       unsigned int val)
+{
+	if (hapd->driver == NULL || hapd->drv_priv == NULL ||
+	    hapd->driver->br_set_net_param == NULL)
+		return -1;
+	return hapd->driver->br_set_net_param(hapd->drv_priv, param, val);
+}
+
 static inline int hostapd_drv_vendor_cmd(struct hostapd_data *hapd,
 					 int vendor_id, int subcmd,
 					 const u8 *data, size_t data_len,
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 86f1cbe..bd1778e 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -124,6 +124,8 @@
 	srv.subscr_remediation_url = conf->subscr_remediation_url;
 	srv.subscr_remediation_method = conf->subscr_remediation_method;
 #endif /* CONFIG_HS20 */
+	srv.erp = conf->eap_server_erp;
+	srv.erp_domain = conf->erp_domain;
 
 	hapd->radius_srv = radius_server_init(&srv);
 	if (hapd->radius_srv == NULL) {
@@ -158,6 +160,7 @@
 		params.private_key = hapd->conf->private_key;
 		params.private_key_passwd = hapd->conf->private_key_passwd;
 		params.dh_file = hapd->conf->dh_file;
+		params.openssl_ciphers = hapd->conf->openssl_ciphers;
 		params.ocsp_stapling_response =
 			hapd->conf->ocsp_stapling_response;
 
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 4cae0d9..4a8703a 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -32,18 +32,47 @@
 
 #ifdef NEED_AP_MLME
 
+static u8 * hostapd_eid_rm_enabled_capab(struct hostapd_data *hapd, u8 *eid,
+					 size_t len)
+{
+	if (!hapd->conf->radio_measurements || len < 2 + 4)
+		return eid;
+
+	*eid++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
+	*eid++ = 5;
+	*eid++ = (hapd->conf->radio_measurements & BIT(0)) ?
+		WLAN_RRM_CAPS_NEIGHBOR_REPORT : 0x00;
+	*eid++ = 0x00;
+	*eid++ = 0x00;
+	*eid++ = 0x00;
+	*eid++ = 0x00;
+	return eid;
+}
+
+
 static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len)
 {
+	if (len < 2 + 5)
+		return eid;
+
 #ifdef CONFIG_TESTING_OPTIONS
 	if (hapd->conf->bss_load_test_set) {
-		if (2 + 5 > len)
-			return eid;
 		*eid++ = WLAN_EID_BSS_LOAD;
 		*eid++ = 5;
 		os_memcpy(eid, hapd->conf->bss_load_test, 5);
 		eid += 5;
+		return eid;
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
+	if (hapd->conf->bss_load_update_period) {
+		*eid++ = WLAN_EID_BSS_LOAD;
+		*eid++ = 5;
+		WPA_PUT_LE16(eid, hapd->num_sta);
+		eid += 2;
+		*eid++ = hapd->iface->channel_utilization;
+		WPA_PUT_LE16(eid, 0); /* no available admission capabity */
+		eid += 2;
+	}
 	return eid;
 }
 
@@ -398,6 +427,8 @@
 
 	pos = hostapd_eid_bss_load(hapd, pos, epos - pos);
 
+	pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos);
+
 #ifdef CONFIG_IEEE80211N
 	pos = hostapd_eid_ht_capabilities(hapd, pos);
 	pos = hostapd_eid_ht_operation(hapd, pos);
@@ -808,6 +839,10 @@
 	tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
 				  tailpos);
 
+	tailpos = hostapd_eid_rm_enabled_capab(hapd, tailpos,
+					       tail + BEACON_TAIL_BUF_SIZE -
+					       tailpos);
+
 	tailpos = hostapd_eid_bss_load(hapd, tailpos,
 				       tail + BEACON_TAIL_BUF_SIZE - tailpos);
 
@@ -908,6 +943,7 @@
 		break;
 	}
 	params->isolate = hapd->conf->isolate;
+	params->smps_mode = hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_MASK;
 #ifdef NEED_AP_MLME
 	params->cts_protect = !!(ieee802_11_erp_info(hapd) &
 				ERP_INFO_USE_PROTECTION);
diff --git a/src/ap/bss_load.c b/src/ap/bss_load.c
new file mode 100644
index 0000000..fb63942
--- /dev/null
+++ b/src/ap/bss_load.c
@@ -0,0 +1,65 @@
+/*
+ * BSS Load Element / Channel Utilization
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "bss_load.h"
+#include "ap_drv_ops.h"
+#include "beacon.h"
+
+
+static void update_channel_utilization(void *eloop_data, void *user_data)
+{
+	struct hostapd_data *hapd = eloop_data;
+	unsigned int sec, usec;
+	int err;
+
+	if (!(hapd->beacon_set_done && hapd->started))
+		return;
+
+	err = hostapd_drv_get_survey(hapd, hapd->iface->freq);
+	if (err) {
+		wpa_printf(MSG_ERROR, "BSS Load: Failed to get survey data");
+		return;
+	}
+
+	ieee802_11_set_beacon(hapd);
+
+	sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
+	usec = (hapd->bss_load_update_timeout % 1000) * 1024;
+	eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
+			       NULL);
+}
+
+
+int bss_load_update_init(struct hostapd_data *hapd)
+{
+	struct hostapd_bss_config *conf = hapd->conf;
+	struct hostapd_config *iconf = hapd->iconf;
+	unsigned int sec, usec;
+
+	if (!conf->bss_load_update_period || !iconf->beacon_int)
+		return -1;
+
+	hapd->bss_load_update_timeout = conf->bss_load_update_period *
+					iconf->beacon_int;
+	sec = ((hapd->bss_load_update_timeout / 1000) * 1024) / 1000;
+	usec = (hapd->bss_load_update_timeout % 1000) * 1024;
+	eloop_register_timeout(sec, usec, update_channel_utilization, hapd,
+			       NULL);
+	return 0;
+}
+
+
+void bss_load_update_deinit(struct hostapd_data *hapd)
+{
+	eloop_cancel_timeout(update_channel_utilization, hapd, NULL);
+}
diff --git a/src/ap/bss_load.h b/src/ap/bss_load.h
new file mode 100644
index 0000000..ac3c793
--- /dev/null
+++ b/src/ap/bss_load.h
@@ -0,0 +1,17 @@
+/*
+ * BSS load update
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BSS_LOAD_UPDATE_H
+#define BSS_LOAD_UPDATE_H
+
+
+int bss_load_update_init(struct hostapd_data *hapd);
+void bss_load_update_deinit(struct hostapd_data *hapd);
+
+
+#endif /* BSS_LOAD_UPDATE_H */
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 39edbd7..8c84e3e 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -1,6 +1,6 @@
 /*
  * Control interface for shared AP commands
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/sae.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "hostapd.h"
 #include "ieee802_1x.h"
@@ -36,7 +37,7 @@
 			  "rx_bytes=%lu\ntx_bytes=%lu\n",
 			  data.rx_packets, data.tx_packets,
 			  data.rx_bytes, data.tx_bytes);
-	if (ret < 0 || (size_t) ret >= buflen)
+	if (os_snprintf_error(buflen, ret))
 		return 0;
 	return ret;
 }
@@ -55,7 +56,7 @@
 
 	ret = os_snprintf(buf, buflen, "connected_time=%u\n",
 			  (unsigned int) age.sec);
-	if (ret < 0 || (size_t) ret >= buflen)
+	if (os_snprintf_error(buflen, ret))
 		return 0;
 	return ret;
 }
@@ -92,7 +93,7 @@
 	len = 0;
 	ret = os_snprintf(buf + len, buflen - len, MACSTR "\nflags=",
 			  MAC2STR(sta->addr));
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -104,7 +105,7 @@
 	ret = os_snprintf(buf + len, buflen - len, "\naid=%d\ncapability=0x%x\n"
 			  "listen_interval=%d\nsupported_rates=",
 			  sta->aid, sta->capability, sta->listen_interval);
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -112,14 +113,14 @@
 		ret = os_snprintf(buf + len, buflen - len, "%02x%s",
 				  sta->supported_rates[i],
 				  i + 1 < sta->supported_rates_len ? " " : "");
-		if (ret < 0 || (size_t) ret >= buflen - len)
+		if (os_snprintf_error(buflen - len, ret))
 			return len;
 		len += ret;
 	}
 
 	ret = os_snprintf(buf + len, buflen - len, "\ntimeout_next=%s\n",
 			  timeout_next_str(sta->timeout_next));
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -143,6 +144,15 @@
 	len += hostapd_get_sta_tx_rx(hapd, sta, buf + len, buflen - len);
 	len += hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
 
+#ifdef CONFIG_SAE
+	if (sta->sae && sta->sae->state == SAE_ACCEPTED) {
+		res = os_snprintf(buf + len, buflen - len, "sae_group=%d\n",
+				  sta->sae->group);
+		if (!os_snprintf_error(buflen - len, res))
+			len += res;
+	}
+#endif /* CONFIG_SAE */
+
 	return len;
 }
 
@@ -164,7 +174,7 @@
 
 	if (hwaddr_aton(txtaddr, addr)) {
 		ret = os_snprintf(buf, buflen, "FAIL\n");
-		if (ret < 0 || (size_t) ret >= buflen)
+		if (os_snprintf_error(buflen, ret))
 			return 0;
 		return ret;
 	}
@@ -203,7 +213,7 @@
 	if (hwaddr_aton(txtaddr, addr) ||
 	    (sta = ap_get_sta(hapd, addr)) == NULL) {
 		ret = os_snprintf(buf, buflen, "FAIL\n");
-		if (ret < 0 || (size_t) ret >= buflen)
+		if (os_snprintf_error(buflen, ret))
 			return 0;
 		return ret;
 	}
@@ -422,7 +432,7 @@
 			  iface->num_sta_ht40_intolerant,
 			  iface->olbc_ht,
 			  iface->ht_op_mode);
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -444,7 +454,7 @@
 				  iface->dfs_cac_ms / 1000,
 				  left_time);
 	}
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -463,7 +473,7 @@
 			  iface->conf->vht_oper_chwidth,
 			  iface->conf->vht_oper_centr_freq_seg0_idx,
 			  iface->conf->vht_oper_centr_freq_seg1_idx);
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -480,7 +490,7 @@
 				  wpa_ssid_txt(bss->conf->ssid.ssid,
 					       bss->conf->ssid.ssid_len),
 				  (int) i, bss->num_sta);
-		if (ret < 0 || (size_t) ret >= buflen - len)
+		if (os_snprintf_error(buflen - len, ret))
 			return len;
 		len += ret;
 	}
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index a6ec20b..0db5ef6 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -440,7 +440,8 @@
 	if (num_available_chandefs == 0)
 		return NULL;
 
-	os_get_random((u8 *) &_rand, sizeof(_rand));
+	if (os_get_random((u8 *) &_rand, sizeof(_rand)) < 0)
+		_rand = os_random();
 	chan_idx = _rand % num_available_chandefs;
 	dfs_find_channel(iface, &chan, chan_idx, skip_radar);
 
@@ -639,6 +640,16 @@
 	int res, n_chans, n_chans1, start_chan_idx, start_chan_idx1;
 	int skip_radar = 0;
 
+	if (!iface->current_mode) {
+		/*
+		 * This can happen with drivers that do not provide mode
+		 * information and as such, cannot really use hostapd for DFS.
+		 */
+		wpa_printf(MSG_DEBUG,
+			   "DFS: No current_mode information - assume no need to perform DFS operations by hostapd");
+		return 1;
+	}
+
 	iface->cac_started = 0;
 
 	do {
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
new file mode 100644
index 0000000..a706024
--- /dev/null
+++ b/src/ap/dhcp_snoop.c
@@ -0,0 +1,166 @@
+/*
+ * DHCP snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+
+#include "utils/common.h"
+#include "l2_packet/l2_packet.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "x_snoop.h"
+#include "dhcp_snoop.h"
+
+struct bootp_pkt {
+	struct iphdr iph;
+	struct udphdr udph;
+	u8 op;
+	u8 htype;
+	u8 hlen;
+	u8 hops;
+	be32 xid;
+	be16 secs;
+	be16 flags;
+	be32 client_ip;
+	be32 your_ip;
+	be32 server_ip;
+	be32 relay_ip;
+	u8 hw_addr[16];
+	u8 serv_name[64];
+	u8 boot_file[128];
+	u8 exten[312];
+} STRUCT_PACKED;
+
+#define DHCPACK	5
+static const u8 ic_bootp_cookie[] = { 99, 130, 83, 99 };
+
+
+static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
+			size_t len)
+{
+	struct hostapd_data *hapd = ctx;
+	const struct bootp_pkt *b;
+	struct sta_info *sta;
+	int exten_len;
+	const u8 *end, *pos;
+	int res, msgtype = 0, prefixlen = 32;
+	u32 subnet_mask = 0;
+	u16 tot_len;
+
+	exten_len = len - ETH_HLEN - (sizeof(*b) - sizeof(b->exten));
+	if (exten_len < 4)
+		return;
+
+	b = (const struct bootp_pkt *) &buf[ETH_HLEN];
+	tot_len = ntohs(b->iph.tot_len);
+	if (tot_len > (unsigned int) (len - ETH_HLEN))
+		return;
+
+	if (os_memcmp(b->exten, ic_bootp_cookie, ARRAY_SIZE(ic_bootp_cookie)))
+		return;
+
+	/* Parse DHCP options */
+	end = (const u8 *) b + tot_len;
+	pos = &b->exten[4];
+	while (pos < end && *pos != 0xff) {
+		const u8 *opt = pos++;
+
+		if (*opt == 0) /* padding */
+			continue;
+
+		pos += *pos + 1;
+		if (pos >= end)
+			break;
+
+		switch (*opt) {
+		case 1:  /* subnet mask */
+			if (opt[1] == 4)
+				subnet_mask = WPA_GET_BE32(&opt[2]);
+			if (subnet_mask == 0)
+				return;
+			while (!(subnet_mask & 0x1)) {
+				subnet_mask >>= 1;
+				prefixlen--;
+			}
+			break;
+		case 53: /* message type */
+			if (opt[1])
+				msgtype = opt[2];
+			break;
+		default:
+			break;
+		}
+	}
+
+	if (msgtype == DHCPACK) {
+		if (b->your_ip == 0)
+			return;
+
+		/* DHCPACK for DHCPREQUEST */
+		sta = ap_get_sta(hapd, b->hw_addr);
+		if (!sta)
+			return;
+
+		wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
+			   " @ IPv4 address %X/%d",
+			   MAC2STR(sta->addr), ntohl(b->your_ip), prefixlen);
+
+		if (sta->ipaddr == b->your_ip)
+			return;
+
+		if (sta->ipaddr != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "dhcp_snoop: Removing IPv4 address %X from the ip neigh table",
+				   sta->ipaddr);
+			hostapd_drv_br_delete_ip_neigh(hapd, 4,
+						       (u8 *) &sta->ipaddr);
+		}
+
+		res = hostapd_drv_br_add_ip_neigh(hapd, 4, (u8 *) &b->your_ip,
+						  prefixlen, sta->addr);
+		if (res) {
+			wpa_printf(MSG_DEBUG,
+				   "dhcp_snoop: Adding ip neigh table failed: %d",
+				   res);
+			return;
+		}
+		sta->ipaddr = b->your_ip;
+	}
+
+	if (hapd->conf->disable_dgaf && is_broadcast_ether_addr(buf)) {
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			if (!(sta->flags & WLAN_STA_AUTHORIZED))
+				continue;
+			x_snoop_mcast_to_ucast_convert_send(hapd, sta,
+							    (u8 *) buf, len);
+		}
+	}
+}
+
+
+int dhcp_snoop_init(struct hostapd_data *hapd)
+{
+	hapd->sock_dhcp = x_snoop_get_l2_packet(hapd, handle_dhcp,
+						L2_PACKET_FILTER_DHCP);
+	if (hapd->sock_dhcp == NULL) {
+		wpa_printf(MSG_DEBUG,
+			   "dhcp_snoop: Failed to initialize L2 packet processing for DHCP packet: %s",
+			   strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void dhcp_snoop_deinit(struct hostapd_data *hapd)
+{
+	l2_packet_deinit(hapd->sock_dhcp);
+}
diff --git a/src/ap/dhcp_snoop.h b/src/ap/dhcp_snoop.h
new file mode 100644
index 0000000..93d0050
--- /dev/null
+++ b/src/ap/dhcp_snoop.h
@@ -0,0 +1,30 @@
+/*
+ * DHCP snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DHCP_SNOOP_H
+#define DHCP_SNOOP_H
+
+#ifdef CONFIG_PROXYARP
+
+int dhcp_snoop_init(struct hostapd_data *hapd);
+void dhcp_snoop_deinit(struct hostapd_data *hapd);
+
+#else /* CONFIG_PROXYARP */
+
+static inline int dhcp_snoop_init(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+static inline void dhcp_snoop_deinit(struct hostapd_data *hapd)
+{
+}
+
+#endif /* CONFIG_PROXYARP */
+
+#endif /* DHCP_SNOOP_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 3bde720..40a2a9c 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -442,9 +442,10 @@
 	int channel, chwidth, seg0_idx = 0, seg1_idx = 0;
 
 	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_INFO, "driver had channel switch: "
-		       "freq=%d, ht=%d, offset=%d, width=%d, cf1=%d, cf2=%d",
-		       freq, ht, offset, width, cf1, cf2);
+		       HOSTAPD_LEVEL_INFO,
+		       "driver had channel switch: freq=%d, ht=%d, offset=%d, width=%d (%s), cf1=%d, cf2=%d",
+		       freq, ht, offset, width, channel_width_to_string(width),
+		       cf1, cf2);
 
 	hapd->iface->freq = freq;
 
@@ -489,6 +490,8 @@
 
 	hapd->iconf->channel = channel;
 	hapd->iconf->ieee80211n = ht;
+	if (!ht)
+		hapd->iconf->ieee80211ac = 0;
 	hapd->iconf->secondary_channel = offset;
 	hapd->iconf->vht_oper_chwidth = chwidth;
 	hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
@@ -522,6 +525,51 @@
 }
 
 
+#ifdef CONFIG_ACS
+static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
+					 u8 pri_channel, u8 sec_channel)
+{
+	int channel;
+	int ret;
+
+	if (hapd->iconf->channel) {
+		wpa_printf(MSG_INFO, "ACS: Channel was already set to %d",
+			   hapd->iconf->channel);
+		return;
+	}
+
+	hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
+
+	channel = pri_channel;
+	if (!channel) {
+		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING,
+			       "driver switched to bad channel");
+		return;
+	}
+
+	hapd->iconf->channel = channel;
+
+	if (sec_channel == 0)
+		hapd->iconf->secondary_channel = 0;
+	else if (sec_channel < pri_channel)
+		hapd->iconf->secondary_channel = -1;
+	else if (sec_channel > pri_channel)
+		hapd->iconf->secondary_channel = 1;
+	else {
+		wpa_printf(MSG_ERROR, "Invalid secondary channel!");
+		return;
+	}
+
+	ret = hostapd_acs_completed(hapd->iface, 0);
+	if (ret) {
+		wpa_printf(MSG_ERROR,
+			   "ACS: Possibly channel configuration is invalid");
+	}
+}
+#endif /* CONFIG_ACS */
+
+
 int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
 			 const u8 *bssid, const u8 *ie, size_t ie_len,
 			 int ssi_signal)
@@ -858,6 +906,42 @@
 }
 
 
+static void hostapd_single_channel_get_survey(struct hostapd_iface *iface,
+					      struct survey_results *survey_res)
+{
+	struct hostapd_channel_data *chan;
+	struct freq_survey *survey;
+	u64 divisor, dividend;
+
+	survey = dl_list_first(&survey_res->survey_list, struct freq_survey,
+			       list);
+	if (!survey || !survey->freq)
+		return;
+
+	chan = hostapd_get_mode_channel(iface, survey->freq);
+	if (!chan || chan->flag & HOSTAPD_CHAN_DISABLED)
+		return;
+
+	wpa_printf(MSG_DEBUG, "Single Channel Survey: (freq=%d channel_time=%ld channel_time_busy=%ld)",
+		   survey->freq,
+		   (unsigned long int) survey->channel_time,
+		   (unsigned long int) survey->channel_time_busy);
+
+	if (survey->channel_time > iface->last_channel_time &&
+	    survey->channel_time > survey->channel_time_busy) {
+		dividend = survey->channel_time_busy -
+			iface->last_channel_time_busy;
+		divisor = survey->channel_time - iface->last_channel_time;
+
+		iface->channel_utilization = dividend * 255 / divisor;
+		wpa_printf(MSG_DEBUG, "Channel Utilization: %d",
+			   iface->channel_utilization);
+	}
+	iface->last_channel_time = survey->channel_time;
+	iface->last_channel_time_busy = survey->channel_time_busy;
+}
+
+
 static void hostapd_event_get_survey(struct hostapd_data *hapd,
 				     struct survey_results *survey_results)
 {
@@ -870,6 +954,11 @@
 		return;
 	}
 
+	if (survey_results->freq_filter) {
+		hostapd_single_channel_get_survey(iface, survey_results);
+		return;
+	}
+
 	dl_list_for_each_safe(survey, tmp, &survey_results->survey_list,
 			      struct freq_survey, list) {
 		chan = hostapd_get_mode_channel(iface, survey->freq);
@@ -979,12 +1068,6 @@
 		if (hapd->iface->scan_cb)
 			hapd->iface->scan_cb(hapd->iface);
 		break;
-#ifdef CONFIG_IEEE80211R
-	case EVENT_FT_RRB_RX:
-		wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
-			      data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
-		break;
-#endif /* CONFIG_IEEE80211R */
 	case EVENT_WPS_BUTTON_PUSHED:
 		hostapd_wps_button_pushed(hapd, NULL);
 		break;
@@ -1125,6 +1208,19 @@
 			hapd->iface, data->channel_list_changed.initiator);
 		break;
 #endif /* NEED_AP_MLME */
+	case EVENT_INTERFACE_ENABLED:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
+		break;
+	case EVENT_INTERFACE_DISABLED:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
+		break;
+#ifdef CONFIG_ACS
+	case EVENT_ACS_CHANNEL_SELECTED:
+		hostapd_acs_channel_selected(
+			hapd, data->acs_selected_channels.pri_channel,
+			data->acs_selected_channels.sec_channel);
+		break;
+#endif /* CONFIG_ACS */
 	default:
 		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
 		break;
diff --git a/src/ap/gas_serv.c b/src/ap/gas_serv.c
index ad07107..9d19f98 100644
--- a/src/ap/gas_serv.c
+++ b/src/ap/gas_serv.c
@@ -58,7 +58,7 @@
 	}
 
 	if (sta->gas_dialog == NULL) {
-		sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
+		sta->gas_dialog = os_calloc(GAS_DIALOG_MAX,
 					    sizeof(struct gas_dialog_info));
 		if (sta->gas_dialog == NULL)
 			return NULL;
@@ -748,6 +748,7 @@
 	size_t home_realm_query_len;
 	const u8 *icon_name;
 	size_t icon_name_len;
+	int p2p_sd;
 };
 
 
@@ -919,6 +920,21 @@
 		return;
 	}
 
+#ifdef CONFIG_P2P
+	if (*pos == P2P_OUI_TYPE) {
+		/*
+		 * This is for P2P SD and will be taken care of by the P2P
+		 * implementation. This query needs to be ignored in the generic
+		 * GAS server to avoid duplicated response.
+		 */
+		wpa_printf(MSG_DEBUG,
+			   "ANQP: Ignore WFA vendor type %u (P2P SD) in generic GAS server",
+			   *pos);
+		qi->p2p_sd = 1;
+		return;
+	}
+#endif /* CONFIG_P2P */
+
 	if (*pos != HS20_ANQP_OUI_TYPE) {
 		wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
 			   *pos);
@@ -969,6 +985,14 @@
 			buf);
 	if (!buf)
 		return;
+#ifdef CONFIG_P2P
+	if (wpabuf_len(buf) == 0 && qi->p2p_sd) {
+		wpa_printf(MSG_DEBUG,
+			   "ANQP: Do not send response to P2P SD from generic GAS service (P2P SD implementation will process this)");
+		wpabuf_free(buf);
+		return;
+	}
+#endif /* CONFIG_P2P */
 
 	if (wpabuf_len(buf) > hapd->gas_frag_limit ||
 	    hapd->conf->gas_comeback_delay) {
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 3142391..2103747 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -35,6 +35,10 @@
 #include "gas_serv.h"
 #include "dfs.h"
 #include "ieee802_11.h"
+#include "bss_load.h"
+#include "x_snoop.h"
+#include "dhcp_snoop.h"
+#include "ndisc_snoop.h"
 
 
 static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
@@ -252,6 +256,16 @@
 
 static void hostapd_free_hapd_data(struct hostapd_data *hapd)
 {
+	os_free(hapd->probereq_cb);
+	hapd->probereq_cb = NULL;
+
+#ifdef CONFIG_P2P
+	wpabuf_free(hapd->p2p_beacon_ie);
+	hapd->p2p_beacon_ie = NULL;
+	wpabuf_free(hapd->p2p_probe_resp_ie);
+	hapd->p2p_probe_resp_ie = NULL;
+#endif /* CONFIG_P2P */
+
 	if (!hapd->started) {
 		wpa_printf(MSG_ERROR, "%s: Interface %s wasn't started",
 			   __func__, hapd->conf->iface);
@@ -294,28 +308,28 @@
 		}
 	}
 
-	os_free(hapd->probereq_cb);
-	hapd->probereq_cb = NULL;
-
-#ifdef CONFIG_P2P
-	wpabuf_free(hapd->p2p_beacon_ie);
-	hapd->p2p_beacon_ie = NULL;
-	wpabuf_free(hapd->p2p_probe_resp_ie);
-	hapd->p2p_probe_resp_ie = NULL;
-#endif /* CONFIG_P2P */
-
 	wpabuf_free(hapd->time_adv);
 
 #ifdef CONFIG_INTERWORKING
 	gas_serv_deinit(hapd);
 #endif /* CONFIG_INTERWORKING */
 
+	bss_load_update_deinit(hapd);
+	ndisc_snoop_deinit(hapd);
+	dhcp_snoop_deinit(hapd);
+	x_snoop_deinit(hapd);
+
 #ifdef CONFIG_SQLITE
 	bin_clear_free(hapd->tmp_eap_user.identity,
 		       hapd->tmp_eap_user.identity_len);
 	bin_clear_free(hapd->tmp_eap_user.password,
 		       hapd->tmp_eap_user.password_len);
 #endif /* CONFIG_SQLITE */
+
+#ifdef CONFIG_MESH
+	wpabuf_free(hapd->mesh_pending_auth);
+	hapd->mesh_pending_auth = NULL;
+#endif /* CONFIG_MESH */
 }
 
 
@@ -691,6 +705,7 @@
 	int ssid_len, set_ssid;
 	char force_ifname[IFNAMSIZ];
 	u8 if_addr[ETH_ALEN];
+	int flush_old_stations = 1;
 
 	wpa_printf(MSG_DEBUG, "%s(hapd=%p (%s), first=%d)",
 		   __func__, hapd, conf->iface, first);
@@ -745,7 +760,14 @@
 	if (conf->wmm_enabled < 0)
 		conf->wmm_enabled = hapd->iconf->ieee80211n;
 
-	hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID);
+#ifdef CONFIG_MESH
+	if (hapd->iface->mconf == NULL)
+		flush_old_stations = 0;
+#endif /* CONFIG_MESH */
+
+	if (flush_old_stations)
+		hostapd_flush_old_stations(hapd,
+					   WLAN_REASON_PREV_AUTH_NOT_VALID);
 	hostapd_set_privacy(hapd, 0);
 
 	hostapd_broadcast_wep_clear(hapd);
@@ -875,6 +897,31 @@
 	}
 #endif /* CONFIG_INTERWORKING */
 
+	if (conf->bss_load_update_period && bss_load_update_init(hapd)) {
+		wpa_printf(MSG_ERROR, "BSS Load initialization failed");
+		return -1;
+	}
+
+	if (conf->proxy_arp) {
+		if (x_snoop_init(hapd)) {
+			wpa_printf(MSG_ERROR,
+				   "Generic snooping infrastructure initialization failed");
+			return -1;
+		}
+
+		if (dhcp_snoop_init(hapd)) {
+			wpa_printf(MSG_ERROR,
+				   "DHCP snooping initialization failed");
+			return -1;
+		}
+
+		if (ndisc_snoop_init(hapd)) {
+			wpa_printf(MSG_ERROR,
+				   "Neighbor Discovery snooping initialization failed");
+			return -1;
+		}
+	}
+
 	if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
 		wpa_printf(MSG_ERROR, "VLAN initialization failed.");
 		return -1;
@@ -899,6 +946,11 @@
 	int i;
 	struct hostapd_tx_queue_params *p;
 
+#ifdef CONFIG_MESH
+	if (iface->mconf == NULL)
+		return;
+#endif /* CONFIG_MESH */
+
 	for (i = 0; i < NUM_TX_QUEUES; i++) {
 		p = &iface->conf->tx_queue[i];
 
@@ -1164,6 +1216,7 @@
 	struct hostapd_data *hapd = iface->bss[0];
 	size_t j;
 	u8 *prev_addr;
+	int delay_apply_cfg = 0;
 
 	if (err)
 		goto fail;
@@ -1193,7 +1246,17 @@
 		}
 #endif /* NEED_AP_MLME */
 
-		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
+#ifdef CONFIG_MESH
+		if (iface->mconf != NULL) {
+			wpa_printf(MSG_DEBUG,
+				   "%s: Mesh configuration will be applied while joining the mesh network",
+				   iface->bss[0]->conf->iface);
+			delay_apply_cfg = 1;
+		}
+#endif /* CONFIG_MESH */
+
+		if (!delay_apply_cfg &&
+		    hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
 				     hapd->iconf->channel,
 				     hapd->iconf->ieee80211n,
 				     hapd->iconf->ieee80211ac,
@@ -1820,7 +1883,7 @@
 	hapd_iface->conf = conf;
 	hapd_iface->num_bss = conf->num_bss;
 
-	hapd_iface->bss = os_zalloc(conf->num_bss *
+	hapd_iface->bss = os_calloc(conf->num_bss,
 				    sizeof(struct hostapd_data *));
 	if (hapd_iface->bss == NULL)
 		return NULL;
@@ -1882,11 +1945,19 @@
 		}
 
 		if (new_iface) {
-			if (interfaces->driver_init(hapd_iface) ||
-			    hostapd_setup_interface(hapd_iface)) {
+			if (interfaces->driver_init(hapd_iface)) {
 				interfaces->count--;
 				goto fail;
 			}
+
+			if (hostapd_setup_interface(hapd_iface)) {
+				interfaces->count--;
+				hostapd_deinit_driver(
+					hapd_iface->bss[0]->driver,
+					hapd_iface->bss[0]->drv_priv,
+					hapd_iface);
+				goto fail;
+			}
 		} else {
 			/* Assign new BSS with bss[0]'s driver info */
 			hapd = hapd_iface->bss[hapd_iface->num_bss - 1];
@@ -1978,14 +2049,14 @@
 				wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
 					   __func__, hapd_iface->bss[i],
 					   hapd->conf->iface);
+				hostapd_cleanup(hapd);
 				os_free(hapd);
 				hapd_iface->bss[i] = NULL;
 			}
 			os_free(hapd_iface->bss);
+			hapd_iface->bss = NULL;
 		}
-		wpa_printf(MSG_DEBUG, "%s: free iface %p",
-			   __func__, hapd_iface);
-		os_free(hapd_iface);
+		hostapd_cleanup_iface(hapd_iface);
 	}
 	return -1;
 }
@@ -2367,6 +2438,12 @@
 			   struct csa_settings *settings)
 {
 	int ret;
+
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA)) {
+		wpa_printf(MSG_INFO, "CSA is not supported");
+		return -1;
+	}
+
 	ret = hostapd_fill_csa_settings(hapd, settings);
 	if (ret)
 		return ret;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 3c8727b..8e2c70e 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -1,6 +1,6 @@
 /*
  * hostapd / Initialization and configuration
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,7 @@
 #define HOSTAPD_H
 
 #include "common/defs.h"
+#include "utils/list.h"
 #include "ap_config.h"
 #include "drivers/driver.h"
 
@@ -22,6 +23,9 @@
 struct full_dynamic_vlan;
 enum wps_event;
 union wps_event_data;
+#ifdef CONFIG_MESH
+struct mesh_conf;
+#endif /* CONFIG_MESH */
 
 struct hostapd_iface;
 
@@ -150,6 +154,7 @@
 	void *ssl_ctx;
 	void *eap_sim_db_priv;
 	struct radius_server_data *radius_srv;
+	struct dl_list erp_keys; /* struct eap_server_erp_key */
 
 	int parameter_set_count;
 
@@ -218,6 +223,9 @@
 	unsigned int cs_c_off_proberesp;
 	int csa_in_progress;
 
+	/* BSS Load */
+	unsigned int bss_load_update_timeout;
+
 #ifdef CONFIG_P2P
 	struct p2p_data *p2p;
 	struct p2p_group *p2p_group;
@@ -235,6 +243,17 @@
 #ifdef CONFIG_INTERWORKING
 	size_t gas_frag_limit;
 #endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_PROXYARP
+	struct l2_packet_data *sock_dhcp;
+	struct l2_packet_data *sock_ndisc;
+#endif /* CONFIG_PROXYARP */
+#ifdef CONFIG_MESH
+	int num_plinks;
+	int max_plinks;
+	void (*mesh_sta_free_cb)(struct sta_info *sta);
+	struct wpabuf *mesh_pending_auth;
+	struct os_reltime mesh_pending_auth_time;
+#endif /* CONFIG_MESH */
 
 #ifdef CONFIG_SQLITE
 	struct hostapd_eap_user tmp_eap_user;
@@ -247,7 +266,10 @@
 #endif /* CONFIG_SAE */
 
 #ifdef CONFIG_TESTING_OPTIONS
-	int ext_mgmt_frame_handling;
+	unsigned int ext_mgmt_frame_handling:1;
+	unsigned int ext_eapol_frame_io:1;
+
+	struct l2_packet_data *l2_test;
 #endif /* CONFIG_TESTING_OPTIONS */
 };
 
@@ -272,6 +294,10 @@
 		HAPD_IFACE_ENABLED
 	} state;
 
+#ifdef CONFIG_MESH
+	struct mesh_conf *mconf;
+#endif /* CONFIG_MESH */
+
 	size_t num_bss;
 	struct hostapd_data **bss;
 
@@ -288,7 +314,10 @@
 	struct ap_info *ap_list; /* AP info list head */
 	struct ap_info *ap_hash[STA_HASH_SIZE];
 
-	unsigned int drv_flags;
+	u64 drv_flags;
+
+	/* SMPS modes supported by the driver (WPA_DRIVER_SMPS_MODE_*) */
+	unsigned int smps_modes;
 
 	/*
 	 * A bitmap of supported protocols for probe response offload. See
@@ -351,6 +380,11 @@
 	/* lowest observed noise floor in dBm */
 	s8 lowest_nf;
 
+	/* channel utilization calculation */
+	u64 last_channel_time;
+	u64 last_channel_time_busy;
+	u8 channel_utilization;
+
 	unsigned int dfs_cac_ms;
 	struct os_reltime dfs_cac_start;
 
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 4e66d1b..f959215 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -107,7 +107,8 @@
 
 			/*
 			 * Disable all channels that are marked not to allow
-			 * IBSS operation or active scanning.
+			 * to initiate radiation (a.k.a. passive scan and no
+			 * IBSS).
 			 * Use radar channels only if the driver supports DFS.
 			 */
 			if ((feature->channels[j].flag &
@@ -118,8 +119,7 @@
 				    !(iface->drv_flags &
 				      WPA_DRIVER_FLAGS_DFS_OFFLOAD)) ||
 				   (feature->channels[j].flag &
-				    (HOSTAPD_CHAN_NO_IBSS |
-				     HOSTAPD_CHAN_PASSIVE_SCAN))) {
+				    HOSTAPD_CHAN_NO_IR)) {
 				feature->channels[j].flag |=
 					HOSTAPD_CHAN_DISABLED;
 			}
@@ -746,11 +746,24 @@
 		return 0;
 	}
 
-	if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
-	    (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
-		wpa_printf(MSG_ERROR, "Driver does not support configured "
-			   "HT capability [SMPS-*]");
-		return 0;
+	switch (conf & HT_CAP_INFO_SMPS_MASK) {
+	case HT_CAP_INFO_SMPS_STATIC:
+		if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_STATIC)) {
+			wpa_printf(MSG_ERROR,
+				   "Driver does not support configured HT capability [SMPS-STATIC]");
+			return 0;
+		}
+		break;
+	case HT_CAP_INFO_SMPS_DYNAMIC:
+		if (!(iface->smps_modes & WPA_DRIVER_SMPS_MODE_DYNAMIC)) {
+			wpa_printf(MSG_ERROR,
+				   "Driver does not support configured HT capability [SMPS-DYNAMIC]");
+			return 0;
+		}
+		break;
+	case HT_CAP_INFO_SMPS_DISABLED:
+	default:
+		break;
 	}
 
 	if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
@@ -839,16 +852,16 @@
 }
 
 
-static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 cap,
+static int ieee80211ac_cap_check_max(u32 hw, u32 conf, u32 mask,
+				     unsigned int shift,
 				     const char *name)
 {
-	u32 hw_max = hw & cap;
-	u32 conf_val = conf & cap;
+	u32 hw_max = hw & mask;
+	u32 conf_val = conf & mask;
 
 	if (conf_val > hw_max) {
-		int offset = find_first_bit(cap);
 		wpa_printf(MSG_ERROR, "Configured VHT capability [%s] exceeds max value supported by the driver (%d > %d)",
-			   name, conf_val >> offset, hw_max >> offset);
+			   name, conf_val >> shift, hw_max >> shift);
 		return 0;
 	}
 	return 1;
@@ -871,7 +884,8 @@
 
 #define VHT_CAP_CHECK_MAX(cap) \
 	do { \
-		if (!ieee80211ac_cap_check_max(hw, conf, cap, #cap)) \
+		if (!ieee80211ac_cap_check_max(hw, conf, cap, cap ## _SHIFT, \
+					       #cap)) \
 			return 0; \
 	} while (0)
 
@@ -945,12 +959,10 @@
 			return 1;
 
 		wpa_printf(MSG_DEBUG,
-			   "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s%s",
+			   "%schannel [%i] (%i) is disabled for use in AP mode, flags: 0x%x%s%s",
 			   primary ? "" : "Configured HT40 secondary ",
 			   i, chan->chan, chan->flag,
-			   chan->flag & HOSTAPD_CHAN_NO_IBSS ? " NO-IBSS" : "",
-			   chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN ?
-			   " PASSIVE-SCAN" : "",
+			   chan->flag & HOSTAPD_CHAN_NO_IR ? " NO-IR" : "",
 			   chan->flag & HOSTAPD_CHAN_RADAR ? " RADAR" : "");
 	}
 
diff --git a/src/ap/iapp.c b/src/ap/iapp.c
index 9b2900f..99aa04d 100644
--- a/src/ap/iapp.c
+++ b/src/ap/iapp.c
@@ -361,7 +361,7 @@
 
 	switch (hdr->command) {
 	case IAPP_CMD_ADD_notify:
-		iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
+		iapp_process_add_notify(iapp, &from, hdr, len - sizeof(*hdr));
 		break;
 	case IAPP_CMD_MOVE_notify:
 		/* TODO: MOVE is using TCP; so move this to TCP handler once it
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index de1ee5e..97f98f2 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / IEEE 802.11 Management
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -29,6 +29,7 @@
 #include "sta_info.h"
 #include "ieee802_1x.h"
 #include "wpa_auth.h"
+#include "pmksa_cache_auth.h"
 #include "wmm.h"
 #include "ap_list.h"
 #include "accounting.h"
@@ -198,6 +199,9 @@
 	    (hapd->iconf->spectrum_mgmt_required || dfs))
 		capab |= WLAN_CAPABILITY_SPECTRUM_MGMT;
 
+	if (hapd->conf->radio_measurements)
+		capab |= IEEE80211_CAP_RRM;
+
 	return capab;
 }
 
@@ -324,8 +328,8 @@
 
 #ifdef CONFIG_SAE
 
-static struct wpabuf * auth_process_sae_commit(struct hostapd_data *hapd,
-					       struct sta_info *sta)
+static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
+					     struct sta_info *sta, int update)
 {
 	struct wpabuf *buf;
 
@@ -334,7 +338,8 @@
 		return NULL;
 	}
 
-	if (sae_prepare_commit(hapd->own_addr, sta->addr,
+	if (update &&
+	    sae_prepare_commit(hapd->own_addr, sta->addr,
 			       (u8 *) hapd->conf->ssid.wpa_passphrase,
 			       os_strlen(hapd->conf->ssid.wpa_passphrase),
 			       sta->sae) < 0) {
@@ -342,15 +347,11 @@
 		return NULL;
 	}
 
-	if (sae_process_commit(sta->sae) < 0) {
-		wpa_printf(MSG_DEBUG, "SAE: Failed to process peer commit");
-		return NULL;
-	}
-
 	buf = wpabuf_alloc(SAE_COMMIT_MAX_LEN);
 	if (buf == NULL)
 		return NULL;
-	sae_write_commit(sta->sae, buf, NULL);
+	sae_write_commit(sta->sae, buf, sta->sae->tmp ?
+			 sta->sae->tmp->anti_clogging_token : NULL);
 
 	return buf;
 }
@@ -371,6 +372,46 @@
 }
 
 
+static int auth_sae_send_commit(struct hostapd_data *hapd,
+				struct sta_info *sta,
+				const u8 *bssid, int update)
+{
+	struct wpabuf *data;
+
+	data = auth_build_sae_commit(hapd, sta, update);
+	if (data == NULL)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+	send_auth_reply(hapd, sta->addr, bssid,
+			WLAN_AUTH_SAE, 1, WLAN_STATUS_SUCCESS,
+			wpabuf_head(data), wpabuf_len(data));
+
+	wpabuf_free(data);
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static int auth_sae_send_confirm(struct hostapd_data *hapd,
+				 struct sta_info *sta,
+				 const u8 *bssid)
+{
+	struct wpabuf *data;
+
+	data = auth_build_sae_confirm(hapd, sta);
+	if (data == NULL)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+	send_auth_reply(hapd, sta->addr, bssid,
+			WLAN_AUTH_SAE, 2, WLAN_STATUS_SUCCESS,
+			wpabuf_head(data), wpabuf_len(data));
+
+	wpabuf_free(data);
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
 static int use_sae_anti_clogging(struct hostapd_data *hapd)
 {
 	struct sta_info *sta;
@@ -411,7 +452,7 @@
 
 
 static struct wpabuf * auth_build_token_req(struct hostapd_data *hapd,
-					    const u8 *addr)
+					    int group, const u8 *addr)
 {
 	struct wpabuf *buf;
 	u8 *token;
@@ -428,10 +469,12 @@
 		hapd->last_sae_token_key_update = now;
 	}
 
-	buf = wpabuf_alloc(SHA256_MAC_LEN);
+	buf = wpabuf_alloc(sizeof(le16) + SHA256_MAC_LEN);
 	if (buf == NULL)
 		return NULL;
 
+	wpabuf_put_le16(buf, group); /* Finite Cyclic Group */
+
 	token = wpabuf_put(buf, SHA256_MAC_LEN);
 	hmac_sha256(hapd->sae_token_key, sizeof(hapd->sae_token_key),
 		    addr, ETH_ALEN, token);
@@ -440,15 +483,150 @@
 }
 
 
+static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
+		       const u8 *bssid, u8 auth_transaction)
+{
+	int ret;
+
+	if (auth_transaction != 1 && auth_transaction != 2)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+	switch (sta->sae->state) {
+	case SAE_NOTHING:
+		if (auth_transaction == 1) {
+			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+			if (ret)
+				return ret;
+			sta->sae->state = SAE_COMMITTED;
+
+			if (sae_process_commit(sta->sae) < 0)
+				return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+			/*
+			 * In mesh case, both Commit and Confirm can be sent
+			 * immediately. In infrastructure BSS, only a single
+			 * Authentication frame (Commit) is expected from the AP
+			 * here and the second one (Confirm) will be sent once
+			 * the STA has sent its second Authentication frame
+			 * (Confirm).
+			 */
+			if (hapd->conf->mesh & MESH_ENABLED) {
+				/*
+				 * Send both Commit and Confirm immediately
+				 * based on SAE finite state machine
+				 * Nothing -> Confirm transition.
+				 */
+				ret = auth_sae_send_confirm(hapd, sta, bssid);
+				if (ret)
+					return ret;
+				sta->sae->state = SAE_CONFIRMED;
+			} else {
+				/*
+				 * For infrastructure BSS, send only the Commit
+				 * message now to get alternating sequence of
+				 * Authentication frames between the AP and STA.
+				 * Confirm will be sent in
+				 * Commited -> Confirmed/Accepted transition
+				 * when receiving Confirm from STA.
+				 */
+			}
+		} else {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "SAE confirm before commit");
+		}
+		break;
+	case SAE_COMMITTED:
+		if (auth_transaction == 1) {
+			if (sae_process_commit(sta->sae) < 0)
+				return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+			ret = auth_sae_send_confirm(hapd, sta, bssid);
+			if (ret)
+				return ret;
+			sta->sae->state = SAE_CONFIRMED;
+		} else if (hapd->conf->mesh & MESH_ENABLED) {
+			/*
+			 * In mesh case, follow SAE finite state machine and
+			 * send Commit now.
+			 */
+			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+			if (ret)
+				return ret;
+		} else {
+			/*
+			 * For instructure BSS, send the postponed Confirm from
+			 * Nothing -> Confirmed transition that was reduced to
+			 * Nothing -> Committed above.
+			 */
+			ret = auth_sae_send_confirm(hapd, sta, bssid);
+			if (ret)
+				return ret;
+
+			sta->sae->state = SAE_CONFIRMED;
+
+			/*
+			 * Since this was triggered on Confirm RX, run another
+			 * step to get to Accepted without waiting for
+			 * additional events.
+			 */
+			return sae_sm_step(hapd, sta, bssid, auth_transaction);
+		}
+		break;
+	case SAE_CONFIRMED:
+		if (auth_transaction == 1) {
+			ret = auth_sae_send_commit(hapd, sta, bssid, 1);
+			if (ret)
+				return ret;
+
+			if (sae_process_commit(sta->sae) < 0)
+				return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+			ret = auth_sae_send_confirm(hapd, sta, bssid);
+			if (ret)
+				return ret;
+		} else {
+			sta->flags |= WLAN_STA_AUTH;
+			sta->auth_alg = WLAN_AUTH_SAE;
+			mlme_authenticate_indication(hapd, sta);
+			wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+			sta->sae->state = SAE_ACCEPTED;
+			wpa_auth_pmksa_add_sae(hapd->wpa_auth, sta->addr,
+					       sta->sae->pmk);
+		}
+		break;
+	case SAE_ACCEPTED:
+		if (auth_transaction == 1) {
+			wpa_printf(MSG_DEBUG, "SAE: remove the STA (" MACSTR
+				   ") doing reauthentication",
+				   MAC2STR(sta->addr));
+			ap_free_sta(hapd, sta);
+		} else {
+			ret = auth_sae_send_confirm(hapd, sta, bssid);
+			sae_clear_temp_data(sta->sae);
+			if (ret)
+				return ret;
+		}
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "SAE: invalid state %d",
+			   sta->sae->state);
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+	return WLAN_STATUS_SUCCESS;
+}
+
+
 static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
 			    const struct ieee80211_mgmt *mgmt, size_t len,
-			    u8 auth_transaction)
+			    u16 auth_transaction, u16 status_code)
 {
 	u16 resp = WLAN_STATUS_SUCCESS;
 	struct wpabuf *data = NULL;
 
 	if (!sta->sae) {
-		if (auth_transaction != 1)
+		if (auth_transaction != 1 || status_code != WLAN_STATUS_SUCCESS)
 			return;
 		sta->sae = os_zalloc(sizeof(*sta->sae));
 		if (sta->sae == NULL)
@@ -457,11 +635,62 @@
 	}
 
 	if (auth_transaction == 1) {
-		const u8 *token = NULL;
+		const u8 *token = NULL, *pos, *end;
 		size_t token_len = 0;
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
-			       "start SAE authentication (RX commit)");
+			       "start SAE authentication (RX commit, status=%u)",
+			       status_code);
+
+		if ((hapd->conf->mesh & MESH_ENABLED) &&
+		    status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
+		    sta->sae->tmp) {
+			pos = mgmt->u.auth.variable;
+			end = ((const u8 *) mgmt) + len;
+			if (pos + sizeof(le16) > end) {
+				wpa_printf(MSG_ERROR,
+					   "SAE: Too short anti-clogging token request");
+				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+				goto reply;
+			}
+			resp = sae_group_allowed(sta->sae,
+						 hapd->conf->sae_groups,
+						 WPA_GET_LE16(pos));
+			if (resp != WLAN_STATUS_SUCCESS) {
+				wpa_printf(MSG_ERROR,
+					   "SAE: Invalid group in anti-clogging token request");
+				goto reply;
+			}
+			pos += sizeof(le16);
+
+			wpabuf_free(sta->sae->tmp->anti_clogging_token);
+			sta->sae->tmp->anti_clogging_token =
+				wpabuf_alloc_copy(pos, end - pos);
+			if (sta->sae->tmp->anti_clogging_token == NULL) {
+				wpa_printf(MSG_ERROR,
+					   "SAE: Failed to alloc for anti-clogging token");
+				return;
+			}
+
+			/*
+			 * IEEE Std 802.11-2012, 11.3.8.6.4: If the Status code
+			 * is 76, a new Commit Message shall be constructed
+			 * with the Anti-Clogging Token from the received
+			 * Authentication frame, and the commit-scalar and
+			 * COMMIT-ELEMENT previously sent.
+			 */
+			if (auth_sae_send_commit(hapd, sta, mgmt->bssid, 0)) {
+				wpa_printf(MSG_ERROR,
+					   "SAE: Failed to send commit message");
+				return;
+			}
+			sta->sae->state = SAE_COMMITTED;
+			return;
+		}
+
+		if (status_code != WLAN_STATUS_SUCCESS)
+			return;
+
 		resp = sae_parse_commit(sta->sae, mgmt->u.auth.variable,
 					((const u8 *) mgmt) + len -
 					mgmt->u.auth.variable, &token,
@@ -474,67 +703,56 @@
 			return;
 		}
 
-		if (resp == WLAN_STATUS_SUCCESS) {
-			if (!token && use_sae_anti_clogging(hapd)) {
-				wpa_printf(MSG_DEBUG, "SAE: Request anti-"
-					   "clogging token from " MACSTR,
-					   MAC2STR(sta->addr));
-				data = auth_build_token_req(hapd, sta->addr);
-				resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
-			} else {
-				data = auth_process_sae_commit(hapd, sta);
-				if (data == NULL)
-					resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-				else
-					sta->sae->state = SAE_COMMITTED;
-			}
+		if (resp != WLAN_STATUS_SUCCESS)
+			goto reply;
+
+		if (!token && use_sae_anti_clogging(hapd)) {
+			wpa_printf(MSG_DEBUG,
+				   "SAE: Request anti-clogging token from "
+				   MACSTR, MAC2STR(sta->addr));
+			data = auth_build_token_req(hapd, sta->sae->group,
+						    sta->addr);
+			resp = WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ;
+			if (hapd->conf->mesh & MESH_ENABLED)
+				sta->sae->state = SAE_NOTHING;
+			goto reply;
 		}
+
+		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
 	} else if (auth_transaction == 2) {
-		if (sta->sae->state != SAE_COMMITTED) {
-			hostapd_logger(hapd, sta->addr,
-				       HOSTAPD_MODULE_IEEE80211,
-				       HOSTAPD_LEVEL_DEBUG,
-				       "SAE confirm before commit");
-			resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
-			goto failed;
-		}
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
-			       "SAE authentication (RX confirm)");
-		if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
-				       ((u8 *) mgmt) + len -
-				       mgmt->u.auth.variable) < 0) {
-			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-		} else {
-			resp = WLAN_STATUS_SUCCESS;
-			sta->flags |= WLAN_STA_AUTH;
-			wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
-			sta->auth_alg = WLAN_AUTH_SAE;
-			mlme_authenticate_indication(hapd, sta);
-
-			data = auth_build_sae_confirm(hapd, sta);
-			if (data == NULL)
+			       "SAE authentication (RX confirm, status=%u)",
+			       status_code);
+		if (status_code != WLAN_STATUS_SUCCESS)
+			return;
+		if (sta->sae->state >= SAE_CONFIRMED ||
+		    !(hapd->conf->mesh & MESH_ENABLED)) {
+			if (sae_check_confirm(sta->sae, mgmt->u.auth.variable,
+					      ((u8 *) mgmt) + len -
+					      mgmt->u.auth.variable) < 0) {
 				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
-			else {
-				sta->sae->state = SAE_ACCEPTED;
-				sae_clear_temp_data(sta->sae);
+				goto reply;
 			}
 		}
+		resp = sae_sm_step(hapd, sta, mgmt->bssid, auth_transaction);
 	} else {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_DEBUG,
-			       "unexpected SAE authentication transaction %u",
-			       auth_transaction);
+			       "unexpected SAE authentication transaction %u (status=%u)",
+			       auth_transaction, status_code);
+		if (status_code != WLAN_STATUS_SUCCESS)
+			return;
 		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
 	}
 
-failed:
-	sta->auth_alg = WLAN_AUTH_SAE;
-
-	send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
-			auth_transaction, resp,
-			data ? wpabuf_head(data) : (u8 *) "",
-			data ? wpabuf_len(data) : 0);
+reply:
+	if (resp != WLAN_STATUS_SUCCESS) {
+		send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+				auth_transaction, resp,
+				data ? wpabuf_head(data) : (u8 *) "",
+				data ? wpabuf_len(data) : 0);
+	}
 	wpabuf_free(data);
 }
 #endif /* CONFIG_SAE */
@@ -556,6 +774,7 @@
 	size_t resp_ies_len = 0;
 	char *identity = NULL;
 	char *radius_cui = NULL;
+	u16 seq_ctrl;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
 		wpa_printf(MSG_INFO, "handle_auth - too short payload (len=%lu)",
@@ -577,6 +796,7 @@
 	auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
 	status_code = le_to_host16(mgmt->u.auth.status_code);
 	fc = le_to_host16(mgmt->frame_control);
+	seq_ctrl = le_to_host16(mgmt->seq_ctrl);
 
 	if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
 	    2 + WLAN_AUTH_CHALLENGE_LEN &&
@@ -585,10 +805,12 @@
 		challenge = &mgmt->u.auth.variable[2];
 
 	wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
-		   "auth_transaction=%d status_code=%d wep=%d%s",
+		   "auth_transaction=%d status_code=%d wep=%d%s "
+		   "seq_ctrl=0x%x%s",
 		   MAC2STR(mgmt->sa), auth_alg, auth_transaction,
 		   status_code, !!(fc & WLAN_FC_ISWEP),
-		   challenge ? " challenge" : "");
+		   challenge ? " challenge" : "",
+		   seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
 
 	if (hapd->tkip_countermeasures) {
 		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
@@ -649,11 +871,46 @@
 		return;
 	}
 
-	sta = ap_sta_add(hapd, mgmt->sa);
-	if (!sta) {
-		resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
-		goto fail;
+	sta = ap_get_sta(hapd, mgmt->sa);
+	if (sta) {
+		if ((fc & WLAN_FC_RETRY) &&
+		    sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
+		    sta->last_seq_ctrl == seq_ctrl &&
+		    sta->last_subtype == WLAN_FC_STYPE_AUTH) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "Drop repeated authentication frame seq_ctrl=0x%x",
+				       seq_ctrl);
+			return;
+		}
+	} else {
+#ifdef CONFIG_MESH
+		if (hapd->conf->mesh & MESH_ENABLED) {
+			/* if the mesh peer is not available, we don't do auth.
+			 */
+			wpa_printf(MSG_DEBUG, "Mesh peer " MACSTR
+				   " not yet known - drop Authentiation frame",
+				   MAC2STR(mgmt->sa));
+			/*
+			 * Save a copy of the frame so that it can be processed
+			 * if a new peer entry is added shortly after this.
+			 */
+			wpabuf_free(hapd->mesh_pending_auth);
+			hapd->mesh_pending_auth = wpabuf_alloc_copy(mgmt, len);
+			os_get_reltime(&hapd->mesh_pending_auth_time);
+			return;
+		}
+#endif /* CONFIG_MESH */
+
+		sta = ap_sta_add(hapd, mgmt->sa);
+		if (!sta) {
+			resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+			goto fail;
+		}
 	}
+	sta->last_seq_ctrl = seq_ctrl;
+	sta->last_subtype = WLAN_FC_STYPE_AUTH;
 
 	if (vlan_id > 0) {
 		if (!hostapd_vlan_id_valid(hapd->conf->vlan, vlan_id)) {
@@ -737,7 +994,23 @@
 #endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_SAE
 	case WLAN_AUTH_SAE:
-		handle_auth_sae(hapd, sta, mgmt, len, auth_transaction);
+#ifdef CONFIG_MESH
+		if (status_code == WLAN_STATUS_SUCCESS &&
+		    hapd->conf->mesh & MESH_ENABLED) {
+			if (sta->wpa_sm == NULL)
+				sta->wpa_sm =
+					wpa_auth_sta_init(hapd->wpa_auth,
+							  sta->addr, NULL);
+			if (sta->wpa_sm == NULL) {
+				wpa_printf(MSG_DEBUG,
+					   "SAE: Failed to initialize WPA state machine");
+				resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+				goto fail;
+			}
+		}
+#endif /* CONFIG_MESH */
+		handle_auth_sae(hapd, sta, mgmt, len, auth_transaction,
+				status_code);
 		return;
 #endif /* CONFIG_SAE */
 	}
@@ -1072,9 +1345,21 @@
 
 #ifdef CONFIG_SAE
 		if (wpa_auth_uses_sae(sta->wpa_sm) &&
-		    sta->auth_alg != WLAN_AUTH_SAE &&
-		    !(sta->auth_alg == WLAN_AUTH_FT &&
-		      wpa_auth_uses_ft_sae(sta->wpa_sm))) {
+		    sta->auth_alg == WLAN_AUTH_OPEN) {
+			struct rsn_pmksa_cache_entry *sa;
+			sa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+			if (!sa || sa->akmp != WPA_KEY_MGMT_SAE) {
+				wpa_printf(MSG_DEBUG,
+					   "SAE: No PMKSA cache entry found for "
+					   MACSTR, MAC2STR(sta->addr));
+				return WLAN_STATUS_INVALID_PMKID;
+			}
+			wpa_printf(MSG_DEBUG, "SAE: " MACSTR
+				   " using PMKSA caching", MAC2STR(sta->addr));
+		} else if (wpa_auth_uses_sae(sta->wpa_sm) &&
+			   sta->auth_alg != WLAN_AUTH_SAE &&
+			   !(sta->auth_alg == WLAN_AUTH_FT &&
+			     wpa_auth_uses_ft_sae(sta->wpa_sm))) {
 			wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
 				   "SAE AKM after non-SAE auth_alg %u",
 				   MAC2STR(sta->addr), sta->auth_alg);
@@ -1275,7 +1560,7 @@
 			 const struct ieee80211_mgmt *mgmt, size_t len,
 			 int reassoc)
 {
-	u16 capab_info, listen_interval;
+	u16 capab_info, listen_interval, seq_ctrl, fc;
 	u16 resp = WLAN_STATUS_SUCCESS;
 	const u8 *pos;
 	int left, i;
@@ -1308,15 +1593,19 @@
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 
+	fc = le_to_host16(mgmt->frame_control);
+	seq_ctrl = le_to_host16(mgmt->seq_ctrl);
+
 	if (reassoc) {
 		capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
 		listen_interval = le_to_host16(
 			mgmt->u.reassoc_req.listen_interval);
 		wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
 			   " capab_info=0x%02x listen_interval=%d current_ap="
-			   MACSTR,
+			   MACSTR " seq_ctrl=0x%x%s",
 			   MAC2STR(mgmt->sa), capab_info, listen_interval,
-			   MAC2STR(mgmt->u.reassoc_req.current_ap));
+			   MAC2STR(mgmt->u.reassoc_req.current_ap),
+			   seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
 		left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
 		pos = mgmt->u.reassoc_req.variable;
 	} else {
@@ -1324,8 +1613,10 @@
 		listen_interval = le_to_host16(
 			mgmt->u.assoc_req.listen_interval);
 		wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
-			   " capab_info=0x%02x listen_interval=%d",
-			   MAC2STR(mgmt->sa), capab_info, listen_interval);
+			   " capab_info=0x%02x listen_interval=%d "
+			   "seq_ctrl=0x%x%s",
+			   MAC2STR(mgmt->sa), capab_info, listen_interval,
+			   seq_ctrl, (fc & WLAN_FC_RETRY) ? " retry" : "");
 		left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
 		pos = mgmt->u.assoc_req.variable;
 	}
@@ -1351,6 +1642,21 @@
 		return;
 	}
 
+	if ((fc & WLAN_FC_RETRY) &&
+	    sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
+	    sta->last_seq_ctrl == seq_ctrl &&
+	    sta->last_subtype == reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
+	    WLAN_FC_STYPE_ASSOC_REQ) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Drop repeated association frame seq_ctrl=0x%x",
+			       seq_ctrl);
+		return;
+	}
+	sta->last_seq_ctrl = seq_ctrl;
+	sta->last_subtype = reassoc ? WLAN_FC_STYPE_REASSOC_REQ :
+		WLAN_FC_STYPE_ASSOC_REQ;
+
 	if (hapd->tkip_countermeasures) {
 		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
 		goto fail;
@@ -1476,6 +1782,7 @@
 	}
 
 	ap_sta_set_authorized(hapd, sta, 0);
+	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
@@ -1486,6 +1793,9 @@
 	 * authenticated. */
 	accounting_sta_stop(hapd, sta);
 	ieee802_1x_free_station(sta);
+	if (sta->ipaddr)
+		hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
+	ap_sta_ip6addr_del(hapd, sta);
 	hostapd_drv_sta_remove(hapd, sta->addr);
 
 	if (sta->timeout_next == STA_NULLFUNC ||
@@ -1525,6 +1835,7 @@
 	}
 
 	ap_sta_set_authorized(hapd, sta, 0);
+	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
 			WLAN_STA_ASSOC_REQ_OK);
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
@@ -1624,6 +1935,26 @@
 	}
 #endif /* CONFIG_IEEE80211W */
 
+	if (sta) {
+		u16 fc = le_to_host16(mgmt->frame_control);
+		u16 seq_ctrl = le_to_host16(mgmt->seq_ctrl);
+
+		if ((fc & WLAN_FC_RETRY) &&
+		    sta->last_seq_ctrl != WLAN_INVALID_MGMT_SEQ &&
+		    sta->last_seq_ctrl == seq_ctrl &&
+		    sta->last_subtype == WLAN_FC_STYPE_ACTION) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "Drop repeated action frame seq_ctrl=0x%x",
+				       seq_ctrl);
+			return 1;
+		}
+
+		sta->last_seq_ctrl = seq_ctrl;
+		sta->last_subtype = WLAN_FC_STYPE_ACTION;
+	}
+
 	switch (mgmt->u.action.category) {
 #ifdef CONFIG_IEEE80211R
 	case WLAN_ACTION_FT:
@@ -1758,6 +2089,9 @@
 	    !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
 	      stype == WLAN_FC_STYPE_ACTION) &&
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_MESH
+	    !(hapd->conf->mesh & MESH_ENABLED) &&
+#endif /* CONFIG_MESH */
 	    os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
 		wpa_printf(MSG_INFO, "MGMT: BSSID=" MACSTR " not our address",
 			   MAC2STR(mgmt->bssid));
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index fe87883..3f299f3 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -211,7 +211,8 @@
 	struct ieee80211_2040_intol_chan_report *ic_report;
 	int is_ht_allowed = 1;
 	int i;
-	const u8 *data = ((const u8 *) mgmt) + 1;
+	const u8 *start = (const u8 *) mgmt;
+	const u8 *data = start + IEEE80211_HDRLEN + 2;
 
 	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_DEBUG, "hostapd_public_action - action=%d",
@@ -220,14 +221,22 @@
 	if (!(iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
 		return;
 
-	if (len < IEEE80211_HDRLEN + 1)
+	if (len < IEEE80211_HDRLEN + 2 + sizeof(*bc_ie))
 		return;
-	data++;
 
-	bc_ie = (struct ieee80211_2040_bss_coex_ie *) &data[0];
-	ic_report = (struct ieee80211_2040_intol_chan_report *)
-		(&data[0] + sizeof(*bc_ie));
+	bc_ie = (struct ieee80211_2040_bss_coex_ie *) data;
+	if (bc_ie->element_id != WLAN_EID_20_40_BSS_COEXISTENCE ||
+	    bc_ie->length < 1) {
+		wpa_printf(MSG_DEBUG, "Unexpected IE (%u,%u) in coex report",
+			   bc_ie->element_id, bc_ie->length);
+		return;
+	}
+	if (len < IEEE80211_HDRLEN + 2 + 2 + bc_ie->length)
+		return;
+	data += 2 + bc_ie->length;
 
+	wpa_printf(MSG_DEBUG, "20/40 BSS Coexistence Information field: 0x%x",
+		   bc_ie->coex_param);
 	if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ) {
 		hostapd_logger(hapd, mgmt->sa,
 			       HOSTAPD_MODULE_IEEE80211,
@@ -244,22 +253,34 @@
 		is_ht_allowed = 0;
 	}
 
-	if (ic_report &&
-	    (ic_report->element_id == WLAN_EID_20_40_BSS_INTOLERANT)) {
+	if (start + len - data >= 3 &&
+	    data[0] == WLAN_EID_20_40_BSS_INTOLERANT && data[1] >= 1) {
+		u8 ielen = data[1];
+
+		if (ielen > start + len - data - 2)
+			return;
+		ic_report = (struct ieee80211_2040_intol_chan_report *) data;
+		wpa_printf(MSG_DEBUG,
+			   "20/40 BSS Intolerant Channel Report: Operating Class %u",
+			   ic_report->op_class);
+
 		/* Go through the channel report to find any BSS there in the
 		 * affected channel range */
-		for (i = 0; i < ic_report->length - 1; i++) {
-			if (is_40_allowed(iface, ic_report->variable[i]))
+		for (i = 0; i < ielen - 1; i++) {
+			u8 chan = ic_report->variable[i];
+
+			if (is_40_allowed(iface, chan))
 				continue;
 			hostapd_logger(hapd, mgmt->sa,
 				       HOSTAPD_MODULE_IEEE80211,
 				       HOSTAPD_LEVEL_DEBUG,
 				       "20_40_INTOLERANT channel %d reported",
-				       ic_report->variable[i]);
+				       chan);
 			is_ht_allowed = 0;
-			break;
 		}
 	}
+	wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d",
+		   is_ht_allowed, iface->num_sta_ht40_intolerant);
 
 	if (!is_ht_allowed &&
 	    (iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
@@ -279,6 +300,9 @@
 					     NULL);
 			eloop_register_timeout(delay_time, 0, ap_ht2040_timeout,
 					       hapd->iface, NULL);
+			wpa_printf(MSG_DEBUG,
+				   "Reschedule HT 20/40 timeout to occur in %u seconds",
+				   delay_time);
 		}
 	}
 }
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
index 12403f9..d462ac8 100644
--- a/src/ap/ieee802_11_shared.c
+++ b/src/ap/ieee802_11_shared.c
@@ -174,6 +174,8 @@
 			*pos |= 0x01; /* Bit 0 - Coexistence management */
 		break;
 	case 1: /* Bits 8-15 */
+		if (hapd->conf->proxy_arp)
+			*pos |= 0x10; /* Bit 12 - Proxy ARP */
 		break;
 	case 2: /* Bits 16-23 */
 		if (hapd->conf->wnm_sleep_mode)
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 2d09b67..2287b28 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -66,6 +66,20 @@
 
 	if (wpa_auth_pairwise_set(sta->wpa_sm))
 		encrypt = 1;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->ext_eapol_frame_io) {
+		size_t hex_len = 2 * len + 1;
+		char *hex = os_malloc(hex_len);
+
+		if (hex) {
+			wpa_snprintf_hex(hex, hex_len, buf, len);
+			wpa_msg(hapd->msg_ctx, MSG_INFO,
+				"EAPOL-TX " MACSTR " %s",
+				MAC2STR(sta->addr), hex);
+			os_free(hex);
+		}
+	} else
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (sta->flags & WLAN_STA_PREAUTH) {
 		rsn_preauth_send(hapd, sta, buf, len);
 	} else {
@@ -282,9 +296,15 @@
 {
 	const u8 *identity;
 	size_t identity_len;
+	const struct eap_hdr *hdr = (const struct eap_hdr *) eap;
 
 	if (len <= sizeof(struct eap_hdr) ||
-	    eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY)
+	    (hdr->code == EAP_CODE_RESPONSE &&
+	     eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY) ||
+	    (hdr->code == EAP_CODE_INITIATE &&
+	     eap[sizeof(struct eap_hdr)] != EAP_ERP_TYPE_REAUTH) ||
+	    (hdr->code != EAP_CODE_RESPONSE &&
+	     hdr->code != EAP_CODE_INITIATE))
 		return;
 
 	identity = eap_get_identity(sm->eap, &identity_len);
@@ -697,6 +717,39 @@
 }
 
 
+static void handle_eap_initiate(struct hostapd_data *hapd,
+				struct sta_info *sta, struct eap_hdr *eap,
+				size_t len)
+{
+#ifdef CONFIG_ERP
+	u8 type, *data;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm == NULL)
+		return;
+
+	if (len < sizeof(*eap) + 1) {
+		wpa_printf(MSG_INFO,
+			   "handle_eap_initiate: too short response data");
+		return;
+	}
+
+	data = (u8 *) (eap + 1);
+	type = data[0];
+
+	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
+		       HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
+		       "id=%d len=%d) from STA: EAP Initiate type %u",
+		       eap->code, eap->identifier, be_to_host16(eap->length),
+		       type);
+
+	wpabuf_free(sm->eap_if->eapRespData);
+	sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
+	sm->eapolEap = TRUE;
+#endif /* CONFIG_ERP */
+}
+
+
 /* Process incoming EAP packet from Supplicant */
 static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
 		       u8 *buf, size_t len)
@@ -740,6 +793,13 @@
 	case EAP_CODE_FAILURE:
 		wpa_printf(MSG_DEBUG, " (failure)");
 		return;
+	case EAP_CODE_INITIATE:
+		wpa_printf(MSG_DEBUG, " (initiate)");
+		handle_eap_initiate(hapd, sta, eap, eap_len);
+		break;
+	case EAP_CODE_FINISH:
+		wpa_printf(MSG_DEBUG, " (finish)");
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, " (unknown code)");
 		return;
@@ -961,8 +1021,9 @@
 	int key_mgmt;
 
 #ifdef CONFIG_WPS
-	if (hapd->conf->wps_state && hapd->conf->wpa &&
-	    (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
+	if (hapd->conf->wps_state &&
+	    ((hapd->conf->wpa && (sta->flags & WLAN_STA_MAYBE_WPS)) ||
+	     (sta->flags & WLAN_STA_WPS))) {
 		/*
 		 * Need to enable IEEE 802.1X/EAPOL state machines for possible
 		 * WPS handshake even if IEEE 802.1X/EAPOL is not used for
@@ -1972,12 +2033,43 @@
 }
 
 
+#ifdef CONFIG_ERP
+
+static struct eap_server_erp_key *
+ieee802_1x_erp_get_key(void *ctx, const char *keyname)
+{
+	struct hostapd_data *hapd = ctx;
+	struct eap_server_erp_key *erp;
+
+	dl_list_for_each(erp, &hapd->erp_keys, struct eap_server_erp_key,
+			 list) {
+		if (os_strcmp(erp->keyname_nai, keyname) == 0)
+			return erp;
+	}
+
+	return NULL;
+}
+
+
+static int ieee802_1x_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
+{
+	struct hostapd_data *hapd = ctx;
+
+	dl_list_add(&hapd->erp_keys, &erp->list);
+	return 0;
+}
+
+#endif /* CONFIG_ERP */
+
+
 int ieee802_1x_init(struct hostapd_data *hapd)
 {
 	int i;
 	struct eapol_auth_config conf;
 	struct eapol_auth_cb cb;
 
+	dl_list_init(&hapd->erp_keys);
+
 	os_memset(&conf, 0, sizeof(conf));
 	conf.ctx = hapd;
 	conf.eap_reauth_period = hapd->conf->eap_reauth_period;
@@ -1989,6 +2081,9 @@
 	conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
 	conf.eap_req_id_text = hapd->conf->eap_req_id_text;
 	conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
+	conf.erp_send_reauth_start = hapd->conf->erp_send_reauth_start;
+	conf.erp_domain = hapd->conf->erp_domain;
+	conf.erp = hapd->conf->eap_server_erp;
 	conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
 	conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
 	conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
@@ -2021,6 +2116,10 @@
 	cb.abort_auth = _ieee802_1x_abort_auth;
 	cb.tx_key = _ieee802_1x_tx_key;
 	cb.eapol_event = ieee802_1x_eapol_event;
+#ifdef CONFIG_ERP
+	cb.erp_get_key = ieee802_1x_erp_get_key;
+	cb.erp_add_key = ieee802_1x_erp_add_key;
+#endif /* CONFIG_ERP */
 
 	hapd->eapol_auth = eapol_auth_init(&conf, &cb);
 	if (hapd->eapol_auth == NULL)
@@ -2052,6 +2151,18 @@
 }
 
 
+void ieee802_1x_erp_flush(struct hostapd_data *hapd)
+{
+	struct eap_server_erp_key *erp;
+
+	while ((erp = dl_list_first(&hapd->erp_keys, struct eap_server_erp_key,
+				    list)) != NULL) {
+		dl_list_del(&erp->list);
+		bin_clear_free(erp, sizeof(*erp));
+	}
+}
+
+
 void ieee802_1x_deinit(struct hostapd_data *hapd)
 {
 	eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
@@ -2062,6 +2173,8 @@
 
 	eapol_auth_deinit(hapd->eapol_auth);
 	hapd->eapol_auth = NULL;
+
+	ieee802_1x_erp_flush(hapd);
 }
 
 
@@ -2252,7 +2365,7 @@
 			  sta->aid,
 			  EAPOL_VERSION,
 			  sm->initialize);
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -2280,7 +2393,7 @@
 			  sm->reAuthPeriod,
 			  bool_txt(sm->reAuthEnabled),
 			  bool_txt(sm->keyTxEnabled));
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -2310,7 +2423,7 @@
 			  sm->dot1xAuthEapLengthErrorFramesRx,
 			  sm->dot1xAuthLastEapolFrameVersion,
 			  MAC2STR(sm->addr));
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -2348,7 +2461,7 @@
 			  sm->backendOtherRequestsToSupplicant,
 			  sm->backendAuthSuccesses,
 			  sm->backendAuthFails);
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -2370,7 +2483,7 @@
 			  1 : 2,
 			  (unsigned int) diff.sec,
 			  sm->identity);
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -2383,7 +2496,7 @@
 			  name1 ? name1 : "",
 			  sm->eap_type_supp,
 			  name2 ? name2 : "");
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index e1df940..de6e0e7 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -29,6 +29,7 @@
 				   struct sta_info *sta, int authorized);
 void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
 int ieee802_1x_init(struct hostapd_data *hapd);
+void ieee802_1x_erp_flush(struct hostapd_data *hapd);
 void ieee802_1x_deinit(struct hostapd_data *hapd);
 int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
 			 const u8 *buf, size_t len, int ack);
diff --git a/src/ap/ndisc_snoop.c b/src/ap/ndisc_snoop.c
new file mode 100644
index 0000000..b0d42dc
--- /dev/null
+++ b/src/ap/ndisc_snoop.c
@@ -0,0 +1,171 @@
+/*
+ * Neighbor Discovery snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+#include "utils/common.h"
+#include "l2_packet/l2_packet.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "list.h"
+#include "x_snoop.h"
+
+struct ip6addr {
+	struct in6_addr addr;
+	struct dl_list list;
+};
+
+struct icmpv6_ndmsg {
+	struct ip6_hdr ipv6h;
+	struct icmp6_hdr icmp6h;
+	struct in6_addr target_addr;
+	u8 opt_type;
+	u8 len;
+	u8 opt_lladdr[0];
+} STRUCT_PACKED;
+
+#define ROUTER_ADVERTISEMENT	134
+#define NEIGHBOR_SOLICITATION	135
+#define NEIGHBOR_ADVERTISEMENT	136
+#define SOURCE_LL_ADDR		1
+
+static int sta_ip6addr_add(struct sta_info *sta, struct in6_addr *addr)
+{
+	struct ip6addr *ip6addr;
+
+	ip6addr = os_zalloc(sizeof(*ip6addr));
+	if (!ip6addr)
+		return -1;
+
+	os_memcpy(&ip6addr->addr, addr, sizeof(*addr));
+
+	dl_list_add_tail(&sta->ip6addr, &ip6addr->list);
+
+	return 0;
+}
+
+
+void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct ip6addr *ip6addr, *prev;
+
+	dl_list_for_each_safe(ip6addr, prev, &sta->ip6addr, struct ip6addr,
+			      list) {
+		hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) &ip6addr->addr);
+		os_free(ip6addr);
+	}
+}
+
+
+static int sta_has_ip6addr(struct sta_info *sta, struct in6_addr *addr)
+{
+	struct ip6addr *ip6addr;
+
+	dl_list_for_each(ip6addr, &sta->ip6addr, struct ip6addr, list) {
+		if (ip6addr->addr.s6_addr32[0] == addr->s6_addr32[0] &&
+		    ip6addr->addr.s6_addr32[1] == addr->s6_addr32[1] &&
+		    ip6addr->addr.s6_addr32[2] == addr->s6_addr32[2] &&
+		    ip6addr->addr.s6_addr32[3] == addr->s6_addr32[3])
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void handle_ndisc(void *ctx, const u8 *src_addr, const u8 *buf,
+			 size_t len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct icmpv6_ndmsg *msg;
+	struct in6_addr *saddr;
+	struct sta_info *sta;
+	int res;
+	char addrtxt[INET6_ADDRSTRLEN + 1];
+
+	if (len < ETH_HLEN + sizeof(struct ip6_hdr) + sizeof(struct icmp6_hdr))
+		return;
+	msg = (struct icmpv6_ndmsg *) &buf[ETH_HLEN];
+	switch (msg->icmp6h.icmp6_type) {
+	case NEIGHBOR_SOLICITATION:
+		if (len < ETH_HLEN + sizeof(*msg))
+			return;
+		if (msg->opt_type != SOURCE_LL_ADDR)
+			return;
+
+		saddr = &msg->ipv6h.ip6_src;
+		if (!(saddr->s6_addr32[0] == 0 && saddr->s6_addr32[1] == 0 &&
+		      saddr->s6_addr32[2] == 0 && saddr->s6_addr32[3] == 0)) {
+			if (len < ETH_HLEN + sizeof(*msg) + ETH_ALEN)
+				return;
+			sta = ap_get_sta(hapd, msg->opt_lladdr);
+			if (!sta)
+				return;
+
+			if (sta_has_ip6addr(sta, saddr))
+				return;
+
+			if (inet_ntop(AF_INET6, saddr, addrtxt, sizeof(addrtxt))
+			    == NULL)
+				addrtxt[0] = '\0';
+			wpa_printf(MSG_DEBUG, "ndisc_snoop: Learned new IPv6 address %s for "
+				   MACSTR, addrtxt, MAC2STR(sta->addr));
+			hostapd_drv_br_delete_ip_neigh(hapd, 6, (u8 *) saddr);
+			res = hostapd_drv_br_add_ip_neigh(hapd, 6, (u8 *) saddr,
+							  128, sta->addr);
+			if (res) {
+				wpa_printf(MSG_ERROR,
+					   "ndisc_snoop: Adding ip neigh failed: %d",
+					   res);
+				return;
+			}
+
+			if (sta_ip6addr_add(sta, saddr))
+				return;
+		}
+		break;
+	case ROUTER_ADVERTISEMENT:
+		if (!hapd->conf->disable_dgaf)
+			return;
+		/* fall through */
+	case NEIGHBOR_ADVERTISEMENT:
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			if (!(sta->flags & WLAN_STA_AUTHORIZED))
+				continue;
+			x_snoop_mcast_to_ucast_convert_send(hapd, sta,
+							    (u8 *) buf, len);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+
+int ndisc_snoop_init(struct hostapd_data *hapd)
+{
+	hapd->sock_ndisc = x_snoop_get_l2_packet(hapd, handle_ndisc,
+						 L2_PACKET_FILTER_NDISC);
+	if (hapd->sock_ndisc == NULL) {
+		wpa_printf(MSG_DEBUG,
+			   "ndisc_snoop: Failed to initialize L2 packet processing for NDISC packets: %s",
+			   strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void ndisc_snoop_deinit(struct hostapd_data *hapd)
+{
+	l2_packet_deinit(hapd->sock_ndisc);
+}
diff --git a/src/ap/ndisc_snoop.h b/src/ap/ndisc_snoop.h
new file mode 100644
index 0000000..3cc9a55
--- /dev/null
+++ b/src/ap/ndisc_snoop.h
@@ -0,0 +1,36 @@
+/*
+ * Neighbor Discovery snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NDISC_SNOOP_H
+#define NDISC_SNOOP_H
+
+#if defined(CONFIG_PROXYARP) && defined(CONFIG_IPV6)
+
+int ndisc_snoop_init(struct hostapd_data *hapd);
+void ndisc_snoop_deinit(struct hostapd_data *hapd);
+void sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta);
+
+#else /* CONFIG_PROXYARP && CONFIG_IPV6 */
+
+static inline int ndisc_snoop_init(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+static inline void ndisc_snoop_deinit(struct hostapd_data *hapd)
+{
+}
+
+static inline void sta_ip6addr_del(struct hostapd_data *hapd,
+				   struct sta_info *sta)
+{
+}
+
+#endif /* CONFIG_PROXYARP && CONFIG_IPV6 */
+
+#endif /* NDISC_SNOOP_H */
diff --git a/src/ap/peerkey_auth.c b/src/ap/peerkey_auth.c
index 612babc..efc1d7e 100644
--- a/src/ap/peerkey_auth.c
+++ b/src/ap/peerkey_auth.c
@@ -79,15 +79,15 @@
 
 
 void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
-		struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
+		const u8 *key_data, size_t key_data_len)
 {
 	struct wpa_eapol_ie_parse kde;
 	struct wpa_stsl_search search;
 	u8 *buf, *pos;
 	size_t buf_len;
 
-	if (wpa_parse_kde_ies((const u8 *) (key + 1),
-			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
 		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
 		return;
 	}
@@ -253,14 +253,14 @@
 
 
 void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
-		struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
+		const u8 *key_data, size_t key_data_len)
 {
 	struct wpa_eapol_ie_parse kde;
 	struct wpa_stsl_search search;
 	u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
 
-	if (wpa_parse_kde_ies((const u8 *) (key + 1),
-			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
 		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
 		return;
 	}
@@ -324,15 +324,15 @@
 
 
 void wpa_smk_error(struct wpa_authenticator *wpa_auth,
-		   struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+		   struct wpa_state_machine *sm,
+		   const u8 *key_data, size_t key_data_len)
 {
 	struct wpa_eapol_ie_parse kde;
 	struct wpa_stsl_search search;
 	struct rsn_error_kde error;
 	u16 mui, error_type;
 
-	if (wpa_parse_kde_ies((const u8 *) (key + 1),
-			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+	if (wpa_parse_kde_ies(key_data, key_data_len, &kde) < 0) {
 		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
 		return;
 	}
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 9de4cff..4270382 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -146,6 +146,9 @@
 
 	entry->eap_type_authsrv = eapol->eap_type_authsrv;
 	entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
+
+	entry->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
+	entry->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo;
 }
 
 
@@ -183,6 +186,9 @@
 
 	eapol->eap_type_authsrv = entry->eap_type_authsrv;
 	((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
+
+	eapol->acct_multi_session_id_hi = entry->acct_multi_session_id_hi;
+	eapol->acct_multi_session_id_lo = entry->acct_multi_session_id_lo;
 }
 
 
@@ -227,6 +233,8 @@
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
  * @pmk: The new pairwise master key
  * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @kck: Key confirmation key or %NULL if not yet derived
+ * @kck_len: KCK length in bytes
  * @aa: Authenticator address
  * @spa: Supplicant address
  * @session_timeout: Session timeout
@@ -242,8 +250,9 @@
 struct rsn_pmksa_cache_entry *
 pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
 		     const u8 *pmk, size_t pmk_len,
-		const u8 *aa, const u8 *spa, int session_timeout,
-		struct eapol_state_machine *eapol, int akmp)
+		     const u8 *kck, size_t kck_len,
+		     const u8 *aa, const u8 *spa, int session_timeout,
+		     struct eapol_state_machine *eapol, int akmp)
 {
 	struct rsn_pmksa_cache_entry *entry, *pos;
 	struct os_reltime now;
@@ -251,13 +260,19 @@
 	if (pmk_len > PMK_LEN)
 		return NULL;
 
+	if (wpa_key_mgmt_suite_b(akmp) && !kck)
+		return NULL;
+
 	entry = os_zalloc(sizeof(*entry));
 	if (entry == NULL)
 		return NULL;
 	os_memcpy(entry->pmk, pmk, pmk_len);
 	entry->pmk_len = pmk_len;
-	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
-		  wpa_key_mgmt_sha256(akmp));
+	if (wpa_key_mgmt_suite_b(akmp))
+		rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
+	else
+		rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+			  wpa_key_mgmt_sha256(akmp));
 	os_get_reltime(&now);
 	entry->expiration = now.sec;
 	if (session_timeout > 0)
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index aa90024..519555f 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -30,6 +30,9 @@
 	u8 eap_type_authsrv;
 	int vlan_id;
 	int opportunistic;
+
+	u32 acct_multi_session_id_hi;
+	u32 acct_multi_session_id_lo;
 };
 
 struct rsn_pmksa_cache;
@@ -47,6 +50,7 @@
 struct rsn_pmksa_cache_entry *
 pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
 		     const u8 *pmk, size_t pmk_len,
+		     const u8 *kck, size_t kck_len,
 		     const u8 *aa, const u8 *spa, int session_timeout,
 		     struct eapol_state_machine *eapol, int akmp);
 struct rsn_pmksa_cache_entry *
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index efd2a72..debdc06 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -31,6 +31,7 @@
 #include "ap_drv_ops.h"
 #include "gas_serv.h"
 #include "wnm_ap.h"
+#include "ndisc_snoop.h"
 #include "sta_info.h"
 
 static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
@@ -144,6 +145,12 @@
 }
 
 
+void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	sta_ip6addr_del(hapd, sta);
+}
+
+
 void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	int set_beacon = 0;
@@ -156,6 +163,10 @@
 	if (sta->flags & WLAN_STA_WDS)
 		hostapd_set_wds_sta(hapd, NULL, sta->addr, sta->aid, 0);
 
+	if (sta->ipaddr)
+		hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
+	ap_sta_ip6addr_del(hapd, sta);
+
 	if (!hapd->iface->driver_ap_teardown &&
 	    !(sta->flags & WLAN_STA_PREAUTH))
 		hostapd_drv_sta_remove(hapd, sta->addr);
@@ -224,6 +235,11 @@
 		set_beacon++;
 #endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
 
+#ifdef CONFIG_MESH
+	if (hapd->mesh_sta_free_cb)
+		hapd->mesh_sta_free_cb(sta);
+#endif /* CONFIG_MESH */
+
 	if (set_beacon)
 		ieee802_11_set_beacons(hapd->iface);
 
@@ -596,6 +612,8 @@
 	ap_sta_hash_add(hapd, sta);
 	sta->ssid = &hapd->conf->ssid;
 	ap_sta_remove_in_other_bss(hapd, sta);
+	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
+	dl_list_init(&sta->ip6addr);
 
 	return sta;
 }
@@ -605,6 +623,10 @@
 {
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
 
+	if (sta->ipaddr)
+		hostapd_drv_br_delete_ip_neigh(hapd, 4, (u8 *) &sta->ipaddr);
+	ap_sta_ip6addr_del(hapd, sta);
+
 	wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
 		   MAC2STR(sta->addr));
 	if (hostapd_drv_sta_remove(hapd, sta->addr) &&
@@ -657,6 +679,7 @@
 {
 	wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
 		   hapd->conf->iface, MAC2STR(sta->addr));
+	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
 	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
 	ap_sta_set_authorized(hapd, sta, 0);
 	sta->timeout_next = STA_DEAUTH;
@@ -695,7 +718,8 @@
 {
 	wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
 		   hapd->conf->iface, MAC2STR(sta->addr));
-	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+	sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
+	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
 	ap_sta_set_authorized(hapd, sta, 0);
 	sta->timeout_next = STA_REMOVE;
 	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
@@ -904,7 +928,15 @@
 	sta->sa_query_trans_id = nbuf;
 	sta->sa_query_count++;
 
-	os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+	if (os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0) {
+		/*
+		 * We don't really care which ID is used here, so simply
+		 * hardcode this if the mostly theoretical os_get_random()
+		 * failure happens.
+		 */
+		trans_id[0] = 0x12;
+		trans_id[1] = 0x34;
+	}
 
 	timeout = hapd->conf->assoc_sa_query_retry_timeout;
 	sec = ((timeout / 1000) * 1024) / 1000;
@@ -949,6 +981,11 @@
 	if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
 		return;
 
+	if (authorized)
+		sta->flags |= WLAN_STA_AUTHORIZED;
+	else
+		sta->flags &= ~WLAN_STA_AUTHORIZED;
+
 #ifdef CONFIG_P2P
 	if (hapd->p2p_group == NULL) {
 		if (sta->p2p_ie != NULL &&
@@ -964,6 +1001,10 @@
 #endif /* CONFIG_P2P */
 		os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(sta->addr));
 
+	if (hapd->sta_authorized_cb)
+		hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
+					sta->addr, authorized, dev_addr);
+
 	if (authorized) {
 		char ip_addr[100];
 		ip_addr[0] = '\0';
@@ -984,8 +1025,6 @@
 			wpa_msg_no_global(hapd->msg_ctx_parent, MSG_INFO,
 					  AP_STA_CONNECTED "%s%s",
 					  buf, ip_addr);
-
-		sta->flags |= WLAN_STA_AUTHORIZED;
 	} else {
 		wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED "%s", buf);
 
@@ -993,13 +1032,7 @@
 		    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;
 	}
-
-	if (hapd->sta_authorized_cb)
-		hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
-					sta->addr, authorized, dev_addr);
 }
 
 
@@ -1087,6 +1120,8 @@
 			  (flags & WLAN_STA_VHT ? "[VHT]" : ""),
 			  (flags & WLAN_STA_WNM_SLEEP_MODE ?
 			   "[WNM_SLEEP_MODE]" : ""));
+	if (os_snprintf_error(buflen, res))
+		res = -1;
 
 	return res;
 }
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index faf32d8..588a9e2 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -9,6 +9,13 @@
 #ifndef STA_INFO_H
 #define STA_INFO_H
 
+#ifdef CONFIG_MESH
+/* needed for mesh_plink_state enum */
+#include "common/defs.h"
+#endif /* CONFIG_MESH */
+
+#include "list.h"
+
 /* STA flags */
 #define WLAN_STA_AUTH BIT(0)
 #define WLAN_STA_ASSOC BIT(1)
@@ -41,6 +48,8 @@
 	struct sta_info *next; /* next entry in sta list */
 	struct sta_info *hnext; /* next entry in hash table list */
 	u8 addr[6];
+	be32 ipaddr;
+	struct dl_list ip6addr; /* list head for struct ip6addr */
 	u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
 	u32 flags; /* Bitfield of WLAN_STA_* */
 	u16 capability;
@@ -49,6 +58,20 @@
 	int supported_rates_len;
 	u8 qosinfo; /* Valid when WLAN_STA_WMM is set */
 
+#ifdef CONFIG_MESH
+	enum mesh_plink_state plink_state;
+	u16 peer_lid;
+	u16 my_lid;
+	u16 mpm_close_reason;
+	int mpm_retries;
+	u8 my_nonce[32];
+	u8 peer_nonce[32];
+	u8 aek[32];	/* SHA256 digest length */
+	u8 mtk[16];
+	u8 mgtk[16];
+	u8 sae_auth_retry;
+#endif /* CONFIG_MESH */
+
 	unsigned int nonerp_set:1;
 	unsigned int no_short_slot_time_set:1;
 	unsigned int no_short_preamble_set:1;
@@ -138,6 +161,12 @@
 #endif /* CONFIG_SAE */
 
 	u32 session_timeout; /* valid only if session_timeout_set == 1 */
+
+	/* Last Authentication/(Re)Association Request/Action frame sequence
+	 * control */
+	u16 last_seq_ctrl;
+	/* Last Authentication/(Re)Association Request/Action frame subtype */
+	u8 last_subtype;
 };
 
 
@@ -167,6 +196,7 @@
 struct sta_info * ap_get_sta_p2p(struct hostapd_data *hapd, const u8 *addr);
 void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
 void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_ip6addr_del(struct hostapd_data *hapd, struct sta_info *sta);
 void hostapd_free_stas(struct hostapd_data *hapd);
 void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
 void ap_sta_replenish_timeout(struct hostapd_data *hapd, struct sta_info *sta,
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index cf25dbb..7e8fb5c 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -1,6 +1,6 @@
 /*
  * hostapd - WNM
- * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -11,6 +11,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "ap/hostapd.h"
 #include "ap/sta_info.h"
 #include "ap/ap_config.h"
@@ -358,7 +359,16 @@
 		}
 		wpa_printf(MSG_DEBUG, "WNM: Target BSSID: " MACSTR,
 			   MAC2STR(pos));
+		wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
+			" status_code=%u bss_termination_delay=%u target_bssid="
+			MACSTR,
+			MAC2STR(addr), status_code, bss_termination_delay,
+			MAC2STR(pos));
 		pos += ETH_ALEN;
+	} else {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, BSS_TM_RESP MACSTR
+			" status_code=%u bss_termination_delay=%u",
+			MAC2STR(addr), status_code, bss_termination_delay);
 	}
 
 	wpa_hexdump(MSG_DEBUG, "WNM: BSS Transition Candidate List Entries",
@@ -436,6 +446,34 @@
 }
 
 
+static void set_disassoc_timer(struct hostapd_data *hapd, struct sta_info *sta,
+			       int disassoc_timer)
+{
+	int timeout, beacon_int;
+
+	/*
+	 * Prevent STA from reconnecting using cached PMKSA to force
+	 * full authentication with the authentication server (which may
+	 * decide to reject the connection),
+	 */
+	wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+
+	beacon_int = hapd->iconf->beacon_int;
+	if (beacon_int < 1)
+		beacon_int = 100; /* best guess */
+	/* Calculate timeout in ms based on beacon_int in TU */
+	timeout = disassoc_timer * beacon_int * 128 / 125;
+	wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
+		   " set to %d ms", MAC2STR(sta->addr), timeout);
+
+	sta->timeout_next = STA_DISASSOC_FROM_CLI;
+	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_register_timeout(timeout / 1000,
+			       timeout % 1000 * 1000,
+			       ap_handle_timer, hapd, sta);
+}
+
+
 int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
 				   struct sta_info *sta, const char *url,
 				   int disassoc_timer)
@@ -477,30 +515,78 @@
 		return -1;
 	}
 
-	/* send disassociation frame after time-out */
 	if (disassoc_timer) {
-		int timeout, beacon_int;
+		/* send disassociation frame after time-out */
+		set_disassoc_timer(hapd, sta, disassoc_timer);
+	}
 
-		/*
-		 * Prevent STA from reconnecting using cached PMKSA to force
-		 * full authentication with the authentication server (which may
-		 * decide to reject the connection),
-		 */
-		wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
+	return 0;
+}
 
-		beacon_int = hapd->iconf->beacon_int;
-		if (beacon_int < 1)
-			beacon_int = 100; /* best guess */
-		/* Calculate timeout in ms based on beacon_int in TU */
-		timeout = disassoc_timer * beacon_int * 128 / 125;
-		wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
-			   " set to %d ms", MAC2STR(sta->addr), timeout);
 
-		sta->timeout_next = STA_DISASSOC_FROM_CLI;
-		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-		eloop_register_timeout(timeout / 1000,
-				       timeout % 1000 * 1000,
-				       ap_handle_timer, hapd, sta);
+int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
+			u8 req_mode, int disassoc_timer, u8 valid_int,
+			const u8 *bss_term_dur, const char *url,
+			const u8 *nei_rep, size_t nei_rep_len)
+{
+	u8 *buf, *pos;
+	struct ieee80211_mgmt *mgmt;
+	size_t url_len;
+
+	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Request to "
+		   MACSTR " req_mode=0x%x disassoc_timer=%d valid_int=0x%x",
+		   MAC2STR(sta->addr), req_mode, disassoc_timer, valid_int);
+	buf = os_zalloc(1000 + nei_rep_len);
+	if (buf == NULL)
+		return -1;
+	mgmt = (struct ieee80211_mgmt *) buf;
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt->da, sta->addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+	mgmt->u.action.u.bss_tm_req.req_mode = req_mode;
+	mgmt->u.action.u.bss_tm_req.disassoc_timer =
+		host_to_le16(disassoc_timer);
+	mgmt->u.action.u.bss_tm_req.validity_interval = valid_int;
+
+	pos = mgmt->u.action.u.bss_tm_req.variable;
+
+	if ((req_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) &&
+	    bss_term_dur) {
+		os_memcpy(pos, bss_term_dur, 12);
+		pos += 12;
+	}
+
+	if (url) {
+		/* Session Information URL */
+		url_len = os_strlen(url);
+		if (url_len > 255)
+			return -1;
+		*pos++ = url_len;
+		os_memcpy(pos, url, url_len);
+		pos += url_len;
+	}
+
+	if (nei_rep) {
+		os_memcpy(pos, nei_rep, nei_rep_len);
+		pos += nei_rep_len;
+	}
+
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "Failed to send BSS Transition Management Request frame");
+		os_free(buf);
+		return -1;
+	}
+	os_free(buf);
+
+	if (disassoc_timer) {
+		/* send disassociation frame after time-out */
+		set_disassoc_timer(hapd, sta, disassoc_timer);
 	}
 
 	return 0;
diff --git a/src/ap/wnm_ap.h b/src/ap/wnm_ap.h
index eeaf5ec..7789307 100644
--- a/src/ap/wnm_ap.h
+++ b/src/ap/wnm_ap.h
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.11v WNM related functions and structures
- * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2014, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -18,5 +18,9 @@
 int wnm_send_ess_disassoc_imminent(struct hostapd_data *hapd,
 				   struct sta_info *sta, const char *url,
 				   int disassoc_timer);
+int wnm_send_bss_tm_req(struct hostapd_data *hapd, struct sta_info *sta,
+			u8 req_mode, int disassoc_timer, u8 valid_int,
+			const u8 *bss_term_dur, const char *url,
+			const u8 *nei_rep, size_t nei_rep_len);
 
 #endif /* WNM_AP_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 1a16b5c..da2073c 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -33,7 +33,8 @@
 
 static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
 static int wpa_sm_step(struct wpa_state_machine *sm);
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);
+static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
+			      size_t data_len);
 static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
 static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
 			      struct wpa_group *group);
@@ -42,6 +43,8 @@
 			  struct wpa_group *group);
 static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
 				       struct wpa_group *group);
+static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
+			  const u8 *pmk, struct wpa_ptk *ptk);
 
 static const u32 dot11RSNAConfigGroupUpdateCount = 4;
 static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@@ -135,6 +138,17 @@
 }
 
 
+#ifdef CONFIG_MESH
+static inline int wpa_auth_start_ampe(struct wpa_authenticator *wpa_auth,
+				      const u8 *addr)
+{
+	if (wpa_auth->cb.start_ampe == NULL)
+		return -1;
+	return wpa_auth->cb.start_ampe(wpa_auth->cb.ctx, addr);
+}
+#endif /* CONFIG_MESH */
+
+
 int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
 			  int (*cb)(struct wpa_state_machine *sm, void *ctx),
 			  void *cb_ctx)
@@ -782,6 +796,51 @@
 }
 
 
+static int wpa_try_alt_snonce(struct wpa_state_machine *sm, u8 *data,
+			      size_t data_len)
+{
+	struct wpa_ptk PTK;
+	int ok = 0;
+	const u8 *pmk = NULL;
+
+	for (;;) {
+		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr,
+					       sm->p2p_dev_addr, pmk);
+			if (pmk == NULL)
+				break;
+		} else
+			pmk = sm->PMK;
+
+		wpa_derive_ptk(sm, sm->alt_SNonce, pmk, &PTK);
+
+		if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK, data, data_len)
+		    == 0) {
+			ok = 1;
+			break;
+		}
+
+		if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+			break;
+	}
+
+	if (!ok) {
+		wpa_printf(MSG_DEBUG,
+			   "WPA: Earlier SNonce did not result in matching MIC");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG,
+		   "WPA: Earlier SNonce resulted in matching MIC");
+	sm->alt_snonce_valid = 0;
+	os_memcpy(sm->SNonce, sm->alt_SNonce, WPA_NONCE_LEN);
+	os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
+	sm->PTK_valid = TRUE;
+
+	return 0;
+}
+
+
 void wpa_receive(struct wpa_authenticator *wpa_auth,
 		 struct wpa_state_machine *sm,
 		 u8 *data, size_t data_len)
@@ -884,6 +943,7 @@
 		    sm->pairwise == WPA_CIPHER_GCMP) {
 			if (wpa_use_aes_cmac(sm) &&
 			    sm->wpa_key_mgmt != WPA_KEY_MGMT_OSEN &&
+			    !wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
 			    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
 				wpa_auth_logger(wpa_auth, sm->addr,
 						LOGGER_WARNING,
@@ -902,6 +962,13 @@
 				return;
 			}
 		}
+
+		if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) &&
+		    ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
+					"did not use EAPOL-Key descriptor version 0 as required for AKM-defined cases");
+			return;
+		}
 	}
 
 	if (key_info & WPA_KEY_INFO_REQUEST) {
@@ -937,8 +1004,25 @@
 					 "based on retransmitted EAPOL-Key "
 					 "1/4");
 			sm->update_snonce = 1;
-			wpa_replay_counter_mark_invalid(sm->prev_key_replay,
-							key->replay_counter);
+			os_memcpy(sm->alt_SNonce, sm->SNonce, WPA_NONCE_LEN);
+			sm->alt_snonce_valid = TRUE;
+			os_memcpy(sm->alt_replay_counter,
+				  sm->key_replay[0].counter,
+				  WPA_REPLAY_COUNTER_LEN);
+			goto continue_processing;
+		}
+
+		if (msg == PAIRWISE_4 && sm->alt_snonce_valid &&
+		    sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
+		    os_memcmp(key->replay_counter, sm->alt_replay_counter,
+			      WPA_REPLAY_COUNTER_LEN) == 0) {
+			/*
+			 * Supplicant may still be using the old SNonce since
+			 * there was two EAPOL-Key 2/4 messages and they had
+			 * different SNonce values.
+			 */
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "Try to process received EAPOL-Key 4/4 based on old Replay Counter and SNonce from an earlier EAPOL-Key 1/4");
 			goto continue_processing;
 		}
 
@@ -1123,7 +1207,10 @@
 
 	sm->MICVerified = FALSE;
 	if (sm->PTK_valid && !sm->update_snonce) {
-		if (wpa_verify_key_mic(&sm->PTK, data, data_len)) {
+		if (wpa_verify_key_mic(sm->wpa_key_mgmt, &sm->PTK, data,
+				       data_len) &&
+		    (msg != PAIRWISE_4 || !sm->alt_snonce_valid ||
+		     wpa_try_alt_snonce(sm, data, data_len))) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"received EAPOL-Key with invalid MIC");
 			return;
@@ -1152,7 +1239,8 @@
 		 */
 		if (msg == SMK_ERROR) {
 #ifdef CONFIG_PEERKEY
-			wpa_smk_error(wpa_auth, sm, key);
+			wpa_smk_error(wpa_auth, sm, (const u8 *) (key + 1),
+				      key_data_length);
 #endif /* CONFIG_PEERKEY */
 			return;
 		} else if (key_info & WPA_KEY_INFO_ERROR) {
@@ -1167,7 +1255,8 @@
 			wpa_request_new_ptk(sm);
 #ifdef CONFIG_PEERKEY
 		} else if (msg == SMK_M1) {
-			wpa_smk_m1(wpa_auth, sm, key);
+			wpa_smk_m1(wpa_auth, sm, key, (const u8 *) (key + 1),
+				   key_data_length);
 #endif /* CONFIG_PEERKEY */
 		} else if (key_data_length > 0 &&
 			   wpa_parse_kde_ies((const u8 *) (key + 1),
@@ -1209,7 +1298,8 @@
 
 #ifdef CONFIG_PEERKEY
 	if (msg == SMK_M3) {
-		wpa_smk_m3(wpa_auth, sm, key);
+		wpa_smk_m3(wpa_auth, sm, key, (const u8 *) (key + 1),
+			   key_data_length);
 		return;
 	}
 #endif /* CONFIG_PEERKEY */
@@ -1295,7 +1385,8 @@
 
 	if (force_version)
 		version = force_version;
-	else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN)
+	else if (sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+		 wpa_key_mgmt_suite_b(sm->wpa_key_mgmt))
 		version = WPA_KEY_INFO_TYPE_AKM_DEFINED;
 	else if (wpa_use_aes_cmac(sm))
 		version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
@@ -1320,6 +1411,7 @@
 
 	if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
 	     sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+	     wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
 	     version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
 		pad_len = key_data_len % 8;
 		if (pad_len)
@@ -1361,6 +1453,8 @@
 	inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
 	os_memcpy(key->replay_counter, sm->key_replay[0].counter,
 		  WPA_REPLAY_COUNTER_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter",
+		    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
 	sm->key_replay[0].valid = TRUE;
 
 	if (nonce)
@@ -1389,6 +1483,7 @@
 				buf, key_data_len);
 		if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
 		    sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
+		    wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
 		    version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
 			if (aes_wrap(sm->PTK.kek, 16,
 				     (key_data_len - 8) / 8, buf,
@@ -1420,8 +1515,8 @@
 			os_free(hdr);
 			return;
 		}
-		wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
-				  key->key_mic);
+		wpa_eapol_key_mic(sm->PTK.kck, sm->wpa_key_mgmt, version,
+				  (u8 *) hdr, len, key->key_mic);
 #ifdef CONFIG_TESTING_OPTIONS
 		if (!pairwise &&
 		    wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
@@ -1473,7 +1568,8 @@
 }
 
 
-static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)
+static int wpa_verify_key_mic(int akmp, struct wpa_ptk *PTK, u8 *data,
+			      size_t data_len)
 {
 	struct ieee802_1x_hdr *hdr;
 	struct wpa_eapol_key *key;
@@ -1489,7 +1585,7 @@
 	key_info = WPA_GET_BE16(key->key_info);
 	os_memcpy(mic, key->key_mic, 16);
 	os_memset(key->key_mic, 0, 16);
-	if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK,
+	if (wpa_eapol_key_mic(PTK->kck, akmp, key_info & WPA_KEY_INFO_TYPE_MASK,
 			      data, data_len, key->key_mic) ||
 	    os_memcmp_const(mic, key->key_mic, 16) != 0)
 		ret = -1;
@@ -1520,6 +1616,14 @@
 
 	switch (event) {
 	case WPA_AUTH:
+#ifdef CONFIG_MESH
+		/* PTKs are derived through AMPE */
+		if (wpa_auth_start_ampe(sm->wpa_auth, sm->addr)) {
+			/* not mesh */
+			break;
+		}
+		return 0;
+#endif /* CONFIG_MESH */
 	case WPA_ASSOC:
 		break;
 	case WPA_DEAUTH:
@@ -1773,6 +1877,7 @@
 	SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
 	sm->PTKRequest = FALSE;
 	sm->TimeoutEvt = FALSE;
+	sm->alt_snonce_valid = FALSE;
 
 	sm->TimeoutCtr++;
 	if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
@@ -1795,10 +1900,13 @@
 		pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
 		pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
 		RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
-		if (sm->pmksa)
+		if (sm->pmksa) {
 			os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
 				  sm->pmksa->pmkid, PMKID_LEN);
-		else {
+		} else if (wpa_key_mgmt_suite_b(sm->wpa_key_mgmt)) {
+			/* No KCK available to derive PMKID */
+			pmkid = NULL;
+		} else {
 			/*
 			 * Calculate PMKID since no PMKSA cache entry was
 			 * available with pre-calculated PMKID.
@@ -1814,8 +1922,8 @@
 }
 
 
-static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
-			  struct wpa_ptk *ptk)
+static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
+			  const u8 *pmk, struct wpa_ptk *ptk)
 {
 	size_t ptk_len = wpa_cipher_key_len(sm->pairwise) + 32;
 #ifdef CONFIG_IEEE80211R
@@ -1824,7 +1932,7 @@
 #endif /* CONFIG_IEEE80211R */
 
 	wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
-		       sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
+		       sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
 		       (u8 *) ptk, ptk_len,
 		       wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
 
@@ -1854,9 +1962,10 @@
 		} else
 			pmk = sm->PMK;
 
-		wpa_derive_ptk(sm, pmk, &PTK);
+		wpa_derive_ptk(sm, sm->SNonce, pmk, &PTK);
 
-		if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key,
+		if (wpa_verify_key_mic(sm->wpa_key_mgmt, &PTK,
+				       sm->last_rx_eapol_key,
 				       sm->last_rx_eapol_key_len) == 0) {
 			ok = 1;
 			break;
@@ -2009,8 +2118,10 @@
 	if (sm->wpa == WPA_VERSION_WPA &&
 	    (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
 	    wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
-		/* WPA-only STA, remove RSN IE */
+		/* WPA-only STA, remove RSN IE and possible MDIE */
 		wpa_ie = wpa_ie + wpa_ie[1] + 2;
+		if (wpa_ie[0] == WLAN_EID_MOBILITY_DOMAIN)
+			wpa_ie = wpa_ie + wpa_ie[1] + 2;
 		wpa_ie_len = wpa_ie[1] + 2;
 	}
 	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
@@ -2331,7 +2442,8 @@
 {
 	u8 rsc[WPA_KEY_RSC_LEN];
 	struct wpa_group *gsm = sm->group;
-	u8 *kde, *pos, hdr[2];
+	const u8 *kde;
+	u8 *kde_buf = NULL, *pos, hdr[2];
 	size_t kde_len;
 	u8 *gtk, dummy_gtk[32];
 
@@ -2367,28 +2479,29 @@
 	if (sm->wpa == WPA_VERSION_WPA2) {
 		kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
 			ieee80211w_kde_len(sm);
-		kde = os_malloc(kde_len);
-		if (kde == NULL)
+		kde_buf = os_malloc(kde_len);
+		if (kde_buf == NULL)
 			return;
 
-		pos = kde;
+		kde = pos = kde_buf;
 		hdr[0] = gsm->GN & 0x03;
 		hdr[1] = 0;
 		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
 				  gtk, gsm->GTK_len);
 		pos = ieee80211w_kde_add(sm, pos);
+		kde_len = pos - kde;
 	} else {
 		kde = gtk;
-		pos = kde + gsm->GTK_len;
+		kde_len = gsm->GTK_len;
 	}
 
 	wpa_send_eapol(sm->wpa_auth, sm,
 		       WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
 		       WPA_KEY_INFO_ACK |
 		       (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
-		       rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1);
-	if (sm->wpa == WPA_VERSION_WPA2)
-		os_free(kde);
+		       rsc, gsm->GNonce, kde, kde_len, gsm->GN, 1);
+
+	os_free(kde_buf);
 }
 
 
@@ -2859,7 +2972,7 @@
 			  wpa_bool_txt(preauth),
 			  wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
 			  wpa_bool_txt(wpa_auth->conf.rsn_preauth));
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -2909,7 +3022,7 @@
 		RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested),
 		wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
 		wpa_auth->dot11RSNA4WayHandshakeFailures);
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -2919,7 +3032,7 @@
 	/* Private MIB */
 	ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n",
 			  wpa_auth->group->wpa_group_state);
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -2961,7 +3074,7 @@
 		RSN_SUITE_ARG(pairwise),
 		sm->dot11RSNAStatsTKIPLocalMICFailures,
 		sm->dot11RSNAStatsTKIPRemoteMICFailures);
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -2971,7 +3084,7 @@
 			  "hostapdWPAPTKGroupState=%d\n",
 			  sm->wpa_ptk_state,
 			  sm->wpa_ptk_group_state);
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -3055,6 +3168,7 @@
 		return -1;
 
 	if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
+				 sm->PTK.kck, sizeof(sm->PTK.kck),
 				 sm->wpa_auth->addr, sm->addr, session_timeout,
 				 eapol, sm->wpa_key_mgmt))
 		return 0;
@@ -3071,7 +3185,9 @@
 	if (wpa_auth == NULL)
 		return -1;
 
-	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
+	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len,
+				 NULL, 0,
+				 wpa_auth->addr,
 				 sta_addr, session_timeout, eapol,
 				 WPA_KEY_MGMT_IEEE8021X))
 		return 0;
@@ -3080,6 +3196,22 @@
 }
 
 
+int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
+			   const u8 *pmk)
+{
+	if (wpa_auth->conf.disable_pmksa_caching)
+		return -1;
+
+	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, PMK_LEN,
+				 NULL, 0,
+				 wpa_auth->addr, addr, 0, NULL,
+				 WPA_KEY_MGMT_SAE))
+		return 0;
+
+	return -1;
+}
+
+
 void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
 			   const u8 *sta_addr)
 {
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 929a253..757e49e 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -213,6 +213,9 @@
 	int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
 			 size_t tspec_ielen);
 #endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_MESH
+	int (*start_ampe)(void *ctx, const u8 *sta_addr);
+#endif /* CONFIG_MESH */
 };
 
 struct wpa_authenticator * wpa_init(const u8 *addr,
@@ -276,6 +279,8 @@
 			       const u8 *pmk, size_t len, const u8 *sta_addr,
 			       int session_timeout,
 			       struct eapol_state_machine *eapol);
+int wpa_auth_pmksa_add_sae(struct wpa_authenticator *wpa_auth, const u8 *addr,
+			   const u8 *pmk);
 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);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 781f15f..e061b5e 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "utils/list.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "crypto/aes_wrap.h"
@@ -1310,7 +1311,9 @@
 			      const u8 *src_addr,
 			      const u8 *data, size_t data_len)
 {
-	struct ft_r0kh_r1kh_pull_frame *frame, f;
+	struct ft_r0kh_r1kh_pull_frame f;
+	const u8 *crypt;
+	u8 *plain;
 	struct ft_remote_r1kh *r1kh;
 	struct ft_r0kh_r1kh_resp_frame resp, r;
 	u8 pmk_r0[PMK_LEN];
@@ -1318,7 +1321,7 @@
 
 	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
 
-	if (data_len < sizeof(*frame))
+	if (data_len < sizeof(f))
 		return -1;
 
 	r1kh = wpa_auth->conf.r1kh_list;
@@ -1334,12 +1337,14 @@
 		return -1;
 	}
 
-	frame = (struct ft_r0kh_r1kh_pull_frame *) data;
+	crypt = data + offsetof(struct ft_r0kh_r1kh_pull_frame, nonce);
+	os_memset(&f, 0, sizeof(f));
+	plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_pull_frame, nonce);
 	/* aes_unwrap() does not support inplace decryption, so use a temporary
 	 * buffer for the data. */
 	if (aes_unwrap(r1kh->key, sizeof(r1kh->key),
 		       (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
-		       frame->nonce, f.nonce) < 0) {
+		       crypt, plain) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
 			   "request from " MACSTR, MAC2STR(src_addr));
 		return -1;
@@ -1442,13 +1447,15 @@
 			      const u8 *src_addr,
 			      const u8 *data, size_t data_len)
 {
-	struct ft_r0kh_r1kh_resp_frame *frame, f;
+	struct ft_r0kh_r1kh_resp_frame f;
+	const u8 *crypt;
+	u8 *plain;
 	struct ft_remote_r0kh *r0kh;
 	int pairwise, res;
 
 	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
 
-	if (data_len < sizeof(*frame))
+	if (data_len < sizeof(f))
 		return -1;
 
 	r0kh = wpa_auth->conf.r0kh_list;
@@ -1464,12 +1471,14 @@
 		return -1;
 	}
 
-	frame = (struct ft_r0kh_r1kh_resp_frame *) data;
+	crypt = data + offsetof(struct ft_r0kh_r1kh_resp_frame, nonce);
+	os_memset(&f, 0, sizeof(f));
+	plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_resp_frame, nonce);
 	/* aes_unwrap() does not support inplace decryption, so use a temporary
 	 * buffer for the data. */
 	if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
 		       (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
-		       frame->nonce, f.nonce) < 0) {
+		       crypt, plain) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
 			   "response from " MACSTR, MAC2STR(src_addr));
 		return -1;
@@ -1507,7 +1516,9 @@
 			      const u8 *src_addr,
 			      const u8 *data, size_t data_len)
 {
-	struct ft_r0kh_r1kh_push_frame *frame, f;
+	struct ft_r0kh_r1kh_push_frame f;
+	const u8 *crypt;
+	u8 *plain;
 	struct ft_remote_r0kh *r0kh;
 	struct os_time now;
 	os_time_t tsend;
@@ -1515,7 +1526,7 @@
 
 	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
 
-	if (data_len < sizeof(*frame))
+	if (data_len < sizeof(f))
 		return -1;
 
 	r0kh = wpa_auth->conf.r0kh_list;
@@ -1531,12 +1542,15 @@
 		return -1;
 	}
 
-	frame = (struct ft_r0kh_r1kh_push_frame *) data;
+	crypt = data + offsetof(struct ft_r0kh_r1kh_push_frame, timestamp);
+	os_memset(&f, 0, sizeof(f));
+	plain = ((u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame,
+				       timestamp);
 	/* aes_unwrap() does not support inplace decryption, so use a temporary
 	 * buffer for the data. */
 	if (aes_unwrap(r0kh->key, sizeof(r0kh->key),
 		       (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
-		       frame->timestamp, f.timestamp) < 0) {
+		       crypt, plain) < 0) {
 		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
 			   MACSTR, MAC2STR(src_addr));
 		return -1;
@@ -1710,6 +1724,8 @@
 {
 	struct ft_r0kh_r1kh_push_frame frame, f;
 	struct os_time now;
+	const u8 *plain;
+	u8 *crypt;
 
 	os_memset(&frame, 0, sizeof(frame));
 	frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
@@ -1732,9 +1748,13 @@
 	WPA_PUT_LE32(f.timestamp, now.sec);
 	f.pairwise = host_to_le16(pairwise);
 	os_memset(f.pad, 0, sizeof(f.pad));
+	plain = ((const u8 *) &f) + offsetof(struct ft_r0kh_r1kh_push_frame,
+					     timestamp);
+	crypt = ((u8 *) &frame) + offsetof(struct ft_r0kh_r1kh_push_frame,
+					   timestamp);
 	if (aes_wrap(r1kh->key, sizeof(r1kh->key),
 		     (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
-		     f.timestamp, frame.timestamp) < 0)
+		     plain, crypt) < 0)
 		return;
 
 	wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 6ee9a4f..8592b90 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -299,6 +299,21 @@
 	struct sta_info *sta;
 	u32 flags = 0;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->ext_eapol_frame_io) {
+		size_t hex_len = 2 * data_len + 1;
+		char *hex = os_malloc(hex_len);
+
+		if (hex == NULL)
+			return -1;
+		wpa_snprintf_hex(hex, hex_len, data, data_len);
+		wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s",
+			MAC2STR(addr), hex);
+		os_free(hex);
+		return 0;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	sta = ap_get_sta(hapd, addr);
 	if (sta)
 		flags = hostapd_sta_flags_to_drv(sta->flags);
@@ -404,6 +419,21 @@
 	struct l2_ethhdr *buf;
 	int ret;
 
+#ifdef CONFIG_TESTING_OPTIONS
+	if (hapd->ext_eapol_frame_io && proto == ETH_P_EAPOL) {
+		size_t hex_len = 2 * data_len + 1;
+		char *hex = os_malloc(hex_len);
+
+		if (hex == NULL)
+			return -1;
+		wpa_snprintf_hex(hex, hex_len, data, data_len);
+		wpa_msg(hapd->msg_ctx, MSG_INFO, "EAPOL-TX " MACSTR " %s",
+			MAC2STR(dst), hex);
+		os_free(hex);
+		return 0;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 #ifdef CONFIG_IEEE80211R
 	if (proto == ETH_P_RRB && hapd->iface->interfaces &&
 	    hapd->iface->interfaces->for_each_interface) {
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 6960ff3..478bc95 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -58,6 +58,8 @@
 	Boolean GUpdateStationKeys;
 	u8 ANonce[WPA_NONCE_LEN];
 	u8 SNonce[WPA_NONCE_LEN];
+	u8 alt_SNonce[WPA_NONCE_LEN];
+	u8 alt_replay_counter[WPA_REPLAY_COUNTER_LEN];
 	u8 PMK[PMK_LEN];
 	struct wpa_ptk PTK;
 	Boolean PTK_valid;
@@ -84,6 +86,7 @@
 	unsigned int mgmt_frame_prot:1;
 	unsigned int rx_eapol_key_secure:1;
 	unsigned int update_snonce:1;
+	unsigned int alt_snonce_valid:1;
 #ifdef CONFIG_IEEE80211R
 	unsigned int ft_completed:1;
 	unsigned int pmk_r1_name_valid:1;
@@ -227,11 +230,14 @@
 int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
 		    struct wpa_stsl_negotiation *neg);
 void wpa_smk_error(struct wpa_authenticator *wpa_auth,
-		   struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+		   struct wpa_state_machine *sm,
+		   const u8 *key_data, size_t key_data_len);
 void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
-		struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
+		const u8 *key_data, size_t key_data_len);
 void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
-		struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key,
+		const u8 *key_data, size_t key_data_len);
 #endif /* CONFIG_PEERKEY */
 
 #ifdef CONFIG_IEEE80211R
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 1e4defc..c926765 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -200,6 +200,11 @@
 		num_suites++;
 	}
 #endif /* CONFIG_SAE */
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
 
 #ifdef CONFIG_RSN_TESTING
 	if (rsn_testing) {
@@ -477,6 +482,8 @@
 		selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
 		if (0) {
 		}
+		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+			selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
 #ifdef CONFIG_IEEE80211R
 		else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
 			selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
@@ -555,6 +562,8 @@
 	}
 	if (0) {
 	}
+	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
 #ifdef CONFIG_IEEE80211R
 	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
 		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 6f16f50..9ba7aba 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -185,7 +185,7 @@
 			  dev->model_number, dev->serial_number,
 			  wps_dev_type_bin2str(dev->pri_dev_type, devtype,
 					       sizeof(devtype)));
-	if (len > 0 && len < (int) sizeof(txt))
+	if (!os_snprintf_error(sizeof(txt), len))
 		wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
 
 	if (hapd->conf->wps_pin_requests) {
@@ -1049,7 +1049,7 @@
 		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
 			wps->auth_types |= WPS_AUTH_WPA2;
 
-		if (conf->rsn_pairwise & WPA_CIPHER_CCMP)
+		if (conf->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))
 			wps->encr_types |= WPS_ENCR_AES;
 		if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
 			wps->encr_types |= WPS_ENCR_TKIP;
@@ -1583,7 +1583,7 @@
 	int ret;
 
 	ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin);
-	if (ret < 0 || ret >= (int) sizeof(data.pin_txt))
+	if (os_snprintf_error(sizeof(data.pin_txt), ret))
 		return -1;
 	data.timeout = timeout;
 	return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
diff --git a/src/ap/x_snoop.c b/src/ap/x_snoop.c
new file mode 100644
index 0000000..8f77015
--- /dev/null
+++ b/src/ap/x_snoop.c
@@ -0,0 +1,123 @@
+/*
+ * Generic Snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "x_snoop.h"
+
+
+int x_snoop_init(struct hostapd_data *hapd)
+{
+	struct hostapd_bss_config *conf = hapd->conf;
+
+	if (!conf->isolate) {
+		wpa_printf(MSG_DEBUG,
+			   "x_snoop: ap_isolate must be enabled for x_snoop");
+		return -1;
+	}
+
+	if (conf->bridge[0] == '\0') {
+		wpa_printf(MSG_DEBUG,
+			   "x_snoop: Bridge must be configured for x_snoop");
+		return -1;
+	}
+
+	if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE,
+					 1)) {
+		wpa_printf(MSG_DEBUG,
+			   "x_snoop: Failed to enable hairpin_mode on the bridge port");
+		return -1;
+	}
+
+	if (hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 1)) {
+		wpa_printf(MSG_DEBUG,
+			   "x_snoop: Failed to enable proxyarp on the bridge port");
+		return -1;
+	}
+
+	if (hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT,
+					 1)) {
+		wpa_printf(MSG_DEBUG,
+			   "x_snoop: Failed to enable accepting gratuitous ARP on the bridge");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+struct l2_packet_data *
+x_snoop_get_l2_packet(struct hostapd_data *hapd,
+		      void (*handler)(void *ctx, const u8 *src_addr,
+				      const u8 *buf, size_t len),
+		      enum l2_packet_filter_type type)
+{
+	struct hostapd_bss_config *conf = hapd->conf;
+	struct l2_packet_data *l2;
+
+	l2 = l2_packet_init(conf->bridge, NULL, ETH_P_ALL, handler, hapd, 1);
+	if (l2 == NULL) {
+		wpa_printf(MSG_DEBUG,
+			   "x_snoop: Failed to initialize L2 packet processing %s",
+			   strerror(errno));
+		return NULL;
+	}
+
+	if (l2_packet_set_packet_filter(l2, type)) {
+		wpa_printf(MSG_DEBUG,
+			   "x_snoop: Failed to set L2 packet filter for type: %d",
+			   type);
+		l2_packet_deinit(l2);
+		return NULL;
+	}
+
+	return l2;
+}
+
+
+void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
+					 struct sta_info *sta, u8 *buf,
+					 size_t len)
+{
+	int res;
+	u8 addr[ETH_ALEN];
+	u8 *dst_addr = buf;
+
+	if (!(dst_addr[0] & 0x01))
+		return;
+
+	wpa_printf(MSG_EXCESSIVE, "x_snoop: Multicast-to-unicast conversion "
+		   MACSTR " -> " MACSTR " (len %u)",
+		   MAC2STR(dst_addr), MAC2STR(sta->addr), (unsigned int) len);
+
+	/* save the multicast destination address for restoring it later */
+	os_memcpy(addr, buf, ETH_ALEN);
+
+	os_memcpy(buf, sta->addr, ETH_ALEN);
+	res = l2_packet_send(hapd->sock_dhcp, NULL, 0, buf, len);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "x_snoop: Failed to send mcast to ucast converted packet to "
+			   MACSTR, MAC2STR(sta->addr));
+	}
+
+	/* restore the multicast destination address */
+	os_memcpy(buf, addr, ETH_ALEN);
+}
+
+
+void x_snoop_deinit(struct hostapd_data *hapd)
+{
+	hostapd_drv_br_set_net_param(hapd, DRV_BR_NET_PARAM_GARP_ACCEPT, 0);
+	hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_PROXYARP, 0);
+	hostapd_drv_br_port_set_attr(hapd, DRV_BR_PORT_ATTR_HAIRPIN_MODE, 0);
+}
diff --git a/src/ap/x_snoop.h b/src/ap/x_snoop.h
new file mode 100644
index 0000000..e43a78d
--- /dev/null
+++ b/src/ap/x_snoop.h
@@ -0,0 +1,56 @@
+/*
+ * Generic Snooping for Proxy ARP
+ * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef X_SNOOP_H
+#define X_SNOOP_H
+
+#include "l2_packet/l2_packet.h"
+
+#ifdef CONFIG_PROXYARP
+
+int x_snoop_init(struct hostapd_data *hapd);
+struct l2_packet_data *
+x_snoop_get_l2_packet(struct hostapd_data *hapd,
+		      void (*handler)(void *ctx, const u8 *src_addr,
+				      const u8 *buf, size_t len),
+		      enum l2_packet_filter_type type);
+void x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
+					 struct sta_info *sta, u8 *buf,
+					 size_t len);
+void x_snoop_deinit(struct hostapd_data *hapd);
+
+#else /* CONFIG_PROXYARP */
+
+static inline int x_snoop_init(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+static inline struct l2_packet_data *
+x_snoop_get_l2_packet(struct hostapd_data *hapd,
+		      void (*handler)(void *ctx, const u8 *src_addr,
+				      const u8 *buf, size_t len),
+		      enum l2_packet_filter_type type)
+{
+	return NULL;
+}
+
+static inline void
+x_snoop_mcast_to_ucast_convert_send(struct hostapd_data *hapd,
+				    struct sta_info *sta, void *buf,
+				    size_t len)
+{
+}
+
+static inline void x_snoop_deinit(struct hostapd_data *hapd)
+{
+}
+
+#endif /* CONFIG_PROXYARP */
+
+#endif /* X_SNOOP_H */
diff --git a/src/common/defs.h b/src/common/defs.h
index d4091e3..e1bbd50 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -49,6 +49,7 @@
 #define WPA_KEY_MGMT_WAPI_CERT BIT(13)
 #define WPA_KEY_MGMT_CCKM BIT(14)
 #define WPA_KEY_MGMT_OSEN BIT(15)
+#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
 
 static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
 {
@@ -56,7 +57,8 @@
 			 WPA_KEY_MGMT_FT_IEEE8021X |
 			 WPA_KEY_MGMT_CCKM |
 			 WPA_KEY_MGMT_OSEN |
-			 WPA_KEY_MGMT_IEEE8021X_SHA256));
+			 WPA_KEY_MGMT_IEEE8021X_SHA256 |
+			 WPA_KEY_MGMT_IEEE8021X_SUITE_B));
 }
 
 static inline int wpa_key_mgmt_wpa_psk(int akm)
@@ -85,7 +87,13 @@
 {
 	return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
 			 WPA_KEY_MGMT_IEEE8021X_SHA256 |
-			 WPA_KEY_MGMT_OSEN));
+			 WPA_KEY_MGMT_OSEN |
+			 WPA_KEY_MGMT_IEEE8021X_SUITE_B));
+}
+
+static inline int wpa_key_mgmt_suite_b(int akm)
+{
+	return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B);
 }
 
 static inline int wpa_key_mgmt_wpa(int akm)
@@ -300,4 +308,25 @@
 /* Maximum number of EAP methods to store for EAP server user information */
 #define EAP_MAX_METHODS 8
 
+/**
+ * enum ht_mode - channel width and offset
+ */
+enum ht_mode {
+	CHAN_UNDEFINED = 0,
+	CHAN_NO_HT,
+	CHAN_HT20,
+	CHAN_HT40PLUS,
+	CHAN_HT40MINUS,
+};
+
+enum mesh_plink_state {
+	PLINK_LISTEN = 1,
+	PLINK_OPEN_SENT,
+	PLINK_OPEN_RCVD,
+	PLINK_CNF_RCVD,
+	PLINK_ESTAB,
+	PLINK_HOLDING,
+	PLINK_BLOCKED,
+};
+
 #endif /* DEFS_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 173a400..e1d45cf 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -249,6 +249,18 @@
 			elems->ht_operation = pos;
 			elems->ht_operation_len = elen;
 			break;
+		case WLAN_EID_MESH_CONFIG:
+			elems->mesh_config = pos;
+			elems->mesh_config_len = elen;
+			break;
+		case WLAN_EID_MESH_ID:
+			elems->mesh_id = pos;
+			elems->mesh_id_len = elen;
+			break;
+		case WLAN_EID_PEER_MGMT:
+			elems->peer_mgmt = pos;
+			elems->peer_mgmt_len = elen;
+			break;
 		case WLAN_EID_VHT_CAP:
 			elems->vht_capabilities = pos;
 			elems->vht_capabilities_len = elen;
@@ -290,6 +302,16 @@
 			elems->ssid_list = pos;
 			elems->ssid_list_len = elen;
 			break;
+		case WLAN_EID_AMPE:
+			elems->ampe = pos;
+			elems->ampe_len = elen;
+			break;
+		case WLAN_EID_MIC:
+			elems->mic = pos;
+			elems->mic_len = elen;
+			/* after mic everything is encrypted, so stop. */
+			left = elen;
+			break;
 		default:
 			unknown++;
 			if (!show_errors)
@@ -515,6 +537,286 @@
 }
 
 
+static const char *us_op_class_cc[] = {
+	"US", "CA", NULL
+};
+
+static const char *eu_op_class_cc[] = {
+	"AL", "AM", "AT", "AZ", "BA", "BE", "BG", "BY", "CH", "CY", "CZ", "DE",
+	"DK", "EE", "EL", "ES", "FI", "FR", "GE", "HR", "HU", "IE", "IS", "IT",
+	"LI", "LT", "LU", "LV", "MD", "ME", "MK", "MT", "NL", "NO", "PL", "PT",
+	"RO", "RS", "RU", "SE", "SI", "SK", "TR", "UA", "UK", NULL
+};
+
+static const char *jp_op_class_cc[] = {
+	"JP", NULL
+};
+
+static const char *cn_op_class_cc[] = {
+	"CN", "CA", NULL
+};
+
+
+static int country_match(const char *cc[], const char *country)
+{
+	int i;
+
+	if (country == NULL)
+		return 0;
+	for (i = 0; cc[i]; i++) {
+		if (cc[i][0] == country[0] && cc[i][1] == country[1])
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static int ieee80211_chan_to_freq_us(u8 op_class, u8 chan)
+{
+	switch (op_class) {
+	case 12: /* channels 1..11 */
+	case 32: /* channels 1..7; 40 MHz */
+	case 33: /* channels 5..11; 40 MHz */
+		if (chan < 1 || chan > 11)
+			return -1;
+		return 2407 + 5 * chan;
+	case 1: /* channels 36,40,44,48 */
+	case 2: /* channels 52,56,60,64; dfs */
+	case 22: /* channels 36,44; 40 MHz */
+	case 23: /* channels 52,60; 40 MHz */
+	case 27: /* channels 40,48; 40 MHz */
+	case 28: /* channels 56,64; 40 MHz */
+		if (chan < 36 || chan > 64)
+			return -1;
+		return 5000 + 5 * chan;
+	case 4: /* channels 100-144 */
+	case 24: /* channels 100-140; 40 MHz */
+		if (chan < 100 || chan > 144)
+			return -1;
+		return 5000 + 5 * chan;
+	case 3: /* channels 149,153,157,161 */
+	case 25: /* channels 149,157; 40 MHz */
+	case 26: /* channels 149,157; 40 MHz */
+	case 30: /* channels 153,161; 40 MHz */
+	case 31: /* channels 153,161; 40 MHz */
+		if (chan < 149 || chan > 161)
+			return -1;
+		return 5000 + 5 * chan;
+	case 34: /* 60 GHz band, channels 1..3 */
+		if (chan < 1 || chan > 3)
+			return -1;
+		return 56160 + 2160 * chan;
+	}
+	return -1;
+}
+
+
+static int ieee80211_chan_to_freq_eu(u8 op_class, u8 chan)
+{
+	switch (op_class) {
+	case 4: /* channels 1..13 */
+	case 11: /* channels 1..9; 40 MHz */
+	case 12: /* channels 5..13; 40 MHz */
+		if (chan < 1 || chan > 13)
+			return -1;
+		return 2407 + 5 * chan;
+	case 1: /* channels 36,40,44,48 */
+	case 2: /* channels 52,56,60,64; dfs */
+	case 5: /* channels 36,44; 40 MHz */
+	case 6: /* channels 52,60; 40 MHz */
+	case 8: /* channels 40,48; 40 MHz */
+	case 9: /* channels 56,64; 40 MHz */
+		if (chan < 36 || chan > 64)
+			return -1;
+		return 5000 + 5 * chan;
+	case 3: /* channels 100-140 */
+	case 7: /* channels 100-132; 40 MHz */
+	case 10: /* channels 104-136; 40 MHz */
+	case 16: /* channels 100-140 */
+		if (chan < 100 || chan > 140)
+			return -1;
+		return 5000 + 5 * chan;
+	case 17: /* channels 149,153,157,161,165,169 */
+		if (chan < 149 || chan > 169)
+			return -1;
+		return 5000 + 5 * chan;
+	case 18: /* 60 GHz band, channels 1..4 */
+		if (chan < 1 || chan > 4)
+			return -1;
+		return 56160 + 2160 * chan;
+	}
+	return -1;
+}
+
+
+static int ieee80211_chan_to_freq_jp(u8 op_class, u8 chan)
+{
+	switch (op_class) {
+	case 30: /* channels 1..13 */
+	case 56: /* channels 1..9; 40 MHz */
+	case 57: /* channels 5..13; 40 MHz */
+		if (chan < 1 || chan > 13)
+			return -1;
+		return 2407 + 5 * chan;
+	case 31: /* channel 14 */
+		if (chan != 14)
+			return -1;
+		return 2414 + 5 * chan;
+	case 1: /* channels 34,38,42,46(old) or 36,40,44,48 */
+	case 32: /* channels 52,56,60,64 */
+	case 33: /* channels 52,56,60,64 */
+	case 36: /* channels 36,44; 40 MHz */
+	case 37: /* channels 52,60; 40 MHz */
+	case 38: /* channels 52,60; 40 MHz */
+	case 41: /* channels 40,48; 40 MHz */
+	case 42: /* channels 56,64; 40 MHz */
+	case 43: /* channels 56,64; 40 MHz */
+		if (chan < 34 || chan > 64)
+			return -1;
+		return 5000 + 5 * chan;
+	case 34: /* channels 100-140 */
+	case 35: /* channels 100-140 */
+	case 39: /* channels 100-132; 40 MHz */
+	case 40: /* channels 100-132; 40 MHz */
+	case 44: /* channels 104-136; 40 MHz */
+	case 45: /* channels 104-136; 40 MHz */
+	case 58: /* channels 100-140 */
+		if (chan < 100 || chan > 140)
+			return -1;
+		return 5000 + 5 * chan;
+	case 59: /* 60 GHz band, channels 1..4 */
+		if (chan < 1 || chan > 3)
+			return -1;
+		return 56160 + 2160 * chan;
+	}
+	return -1;
+}
+
+
+static int ieee80211_chan_to_freq_cn(u8 op_class, u8 chan)
+{
+	switch (op_class) {
+	case 7: /* channels 1..13 */
+	case 8: /* channels 1..9; 40 MHz */
+	case 9: /* channels 5..13; 40 MHz */
+		if (chan < 1 || chan > 13)
+			return -1;
+		return 2407 + 5 * chan;
+	case 1: /* channels 36,40,44,48 */
+	case 2: /* channels 52,56,60,64; dfs */
+	case 4: /* channels 36,44; 40 MHz */
+	case 5: /* channels 52,60; 40 MHz */
+		if (chan < 36 || chan > 64)
+			return -1;
+		return 5000 + 5 * chan;
+	case 3: /* channels 149,153,157,161,165 */
+	case 6: /* channels 149,157; 40 MHz */
+		if (chan < 149 || chan > 165)
+			return -1;
+		return 5000 + 5 * chan;
+	}
+	return -1;
+}
+
+
+static int ieee80211_chan_to_freq_global(u8 op_class, u8 chan)
+{
+	/* Table E-4 in IEEE Std 802.11-2012 - Global operating classes */
+	switch (op_class) {
+	case 81:
+		/* channels 1..13 */
+		if (chan < 1 || chan > 13)
+			return -1;
+		return 2407 + 5 * chan;
+	case 82:
+		/* channel 14 */
+		if (chan != 14)
+			return -1;
+		return 2414 + 5 * chan;
+	case 83: /* channels 1..9; 40 MHz */
+	case 84: /* channels 5..13; 40 MHz */
+		if (chan < 1 || chan > 13)
+			return -1;
+		return 2407 + 5 * chan;
+	case 115: /* channels 36,40,44,48; indoor only */
+	case 116: /* channels 36,44; 40 MHz; indoor only */
+	case 117: /* channels 40,48; 40 MHz; indoor only */
+	case 118: /* channels 52,56,60,64; dfs */
+	case 119: /* channels 52,60; 40 MHz; dfs */
+	case 120: /* channels 56,64; 40 MHz; dfs */
+		if (chan < 36 || chan > 64)
+			return -1;
+		return 5000 + 5 * chan;
+	case 121: /* channels 100-140 */
+	case 122: /* channels 100-142; 40 MHz */
+	case 123: /* channels 104-136; 40 MHz */
+		if (chan < 100 || chan > 140)
+			return -1;
+		return 5000 + 5 * chan;
+	case 124: /* channels 149,153,157,161 */
+	case 125: /* channels 149,153,157,161,165,169 */
+	case 126: /* channels 149,157; 40 MHz */
+	case 127: /* channels 153,161; 40 MHz */
+		if (chan < 149 || chan > 161)
+			return -1;
+		return 5000 + 5 * chan;
+	case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+	case 130: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
+		if (chan < 36 || chan > 161)
+			return -1;
+		return 5000 + 5 * chan;
+	case 129: /* center freqs 50, 114; 160 MHz */
+		if (chan < 50 || chan > 114)
+			return -1;
+		return 5000 + 5 * chan;
+	case 180: /* 60 GHz band, channels 1..4 */
+		if (chan < 1 || chan > 4)
+			return -1;
+		return 56160 + 2160 * chan;
+	}
+	return -1;
+}
+
+/**
+ * ieee80211_chan_to_freq - Convert channel info to frequency
+ * @country: Country code, if known; otherwise, global operating class is used
+ * @op_class: Operating class
+ * @chan: Channel number
+ * Returns: Frequency in MHz or -1 if the specified channel is unknown
+ */
+int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan)
+{
+	int freq;
+
+	if (country_match(us_op_class_cc, country)) {
+		freq = ieee80211_chan_to_freq_us(op_class, chan);
+		if (freq > 0)
+			return freq;
+	}
+
+	if (country_match(eu_op_class_cc, country)) {
+		freq = ieee80211_chan_to_freq_eu(op_class, chan);
+		if (freq > 0)
+			return freq;
+	}
+
+	if (country_match(jp_op_class_cc, country)) {
+		freq = ieee80211_chan_to_freq_jp(op_class, chan);
+		if (freq > 0)
+			return freq;
+	}
+
+	if (country_match(cn_op_class_cc, country)) {
+		freq = ieee80211_chan_to_freq_cn(op_class, chan);
+		if (freq > 0)
+			return freq;
+	}
+
+	return ieee80211_chan_to_freq_global(op_class, chan);
+}
+
+
 static int is_11b(u8 rate)
 {
 	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index cf83057..2357afc 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -28,6 +28,9 @@
 	const u8 *timeout_int;
 	const u8 *ht_capabilities;
 	const u8 *ht_operation;
+	const u8 *mesh_config;
+	const u8 *mesh_id;
+	const u8 *peer_mgmt;
 	const u8 *vht_capabilities;
 	const u8 *vht_operation;
 	const u8 *vht_opmode_notif;
@@ -42,6 +45,8 @@
 	const u8 *bss_max_idle_period;
 	const u8 *ssid_list;
 	const u8 *osen;
+	const u8 *ampe;
+	const u8 *mic;
 
 	u8 ssid_len;
 	u8 supp_rates_len;
@@ -60,6 +65,9 @@
 	u8 timeout_int_len;
 	u8 ht_capabilities_len;
 	u8 ht_operation_len;
+	u8 mesh_config_len;
+	u8 mesh_id_len;
+	u8 peer_mgmt_len;
 	u8 vht_capabilities_len;
 	u8 vht_operation_len;
 	u8 vendor_ht_cap_len;
@@ -71,6 +79,8 @@
 	u8 ext_capab_len;
 	u8 ssid_list_len;
 	u8 osen_len;
+	u8 ampe_len;
+	u8 mic_len;
 };
 
 typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -95,6 +105,7 @@
 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 ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
 
 int supp_rates_11b_only(struct ieee802_11_elems *elems);
 
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 6de71e9..dfe0faf 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -25,6 +25,8 @@
 #define WLAN_FC_GET_TYPE(fc)	(((fc) & 0x000c) >> 2)
 #define WLAN_FC_GET_STYPE(fc)	(((fc) & 0x00f0) >> 4)
 
+#define WLAN_INVALID_MGMT_SEQ   0xFFFF
+
 #define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
 #define WLAN_GET_SEQ_SEQ(seq) \
 	(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
@@ -194,6 +196,16 @@
 #define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
 /* IEEE 802.11e */
 #define WLAN_REASON_DISASSOC_LOW_ACK 34
+/* IEEE 802.11s */
+#define WLAN_REASON_MESH_PEERING_CANCELLED 52
+#define WLAN_REASON_MESH_MAX_PEERS 53
+#define WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION 54
+#define WLAN_REASON_MESH_CLOSE_RCVD 55
+#define WLAN_REASON_MESH_MAX_RETRIES 56
+#define WLAN_REASON_MESH_CONFIRM_TIMEOUT 57
+#define WLAN_REASON_MESH_INVALID_GTK 58
+#define WLAN_REASON_MESH_INCONSISTENT_PARAMS 59
+#define WLAN_REASON_MESH_INVALID_SECURITY_CAP 60
 
 
 /* Information Element IDs */
@@ -234,6 +246,7 @@
 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
 #define WLAN_EID_WAPI 68
 #define WLAN_EID_TIME_ADVERTISEMENT 69
+#define WLAN_EID_RRM_ENABLED_CAPABILITIES 70
 #define WLAN_EID_20_40_BSS_COEXISTENCE 72
 #define WLAN_EID_20_40_BSS_INTOLERANT 73
 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
@@ -249,7 +262,12 @@
 #define WLAN_EID_ADV_PROTO 108
 #define WLAN_EID_QOS_MAP_SET 110
 #define WLAN_EID_ROAMING_CONSORTIUM 111
+#define WLAN_EID_MESH_CONFIG 113
+#define WLAN_EID_MESH_ID 114
+#define WLAN_EID_PEER_MGMT 117
 #define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_AMPE 139
+#define WLAN_EID_MIC 140
 #define WLAN_EID_CCKM 156
 #define WLAN_EID_VHT_CAP 191
 #define WLAN_EID_VHT_OPERATION 192
@@ -277,6 +295,7 @@
 #define WLAN_ACTION_WNM 10
 #define WLAN_ACTION_UNPROTECTED_WNM 11
 #define WLAN_ACTION_TDLS 12
+#define WLAN_ACTION_SELF_PROTECTED 15
 #define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
 #define WLAN_ACTION_VENDOR_SPECIFIC 127
 
@@ -321,6 +340,19 @@
 #define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
 #define WLAN_TDLS_DISCOVERY_REQUEST 10
 
+/* Radio Measurement Action codes */
+#define WLAN_RRM_RADIO_MEASUREMENT_REQUEST 0
+#define WLAN_RRM_RADIO_MEASUREMENT_REPORT 1
+#define WLAN_RRM_LINK_MEASUREMENT_REQUEST 2
+#define WLAN_RRM_LINK_MEASUREMENT_REPORT 3
+#define WLAN_RRM_NEIGHBOR_REPORT_REQUEST 4
+#define WLAN_RRM_NEIGHBOR_REPORT_RESPONSE 5
+
+/* Radio Measurement capabilities (from RRM Capabilities IE) */
+/* byte 1 (out of 5) */
+#define WLAN_RRM_CAPS_LINK_MEASUREMENT BIT(0)
+#define WLAN_RRM_CAPS_NEIGHBOR_REPORT BIT(1)
+
 /* Timeout Interval Type */
 #define WLAN_TIMEOUT_REASSOC_DEADLINE 1
 #define WLAN_TIMEOUT_KEY_LIFETIME 2
@@ -577,6 +609,10 @@
 					 * Entries (optional) */
 					u8 variable[0];
 				} STRUCT_PACKED bss_tm_query;
+				struct {
+					u8 action; /* 15 */
+					u8 variable[0];
+				} STRUCT_PACKED slf_prot_action;
 			} u;
 		} STRUCT_PACKED action;
 	} u;
@@ -638,6 +674,15 @@
 	le16 vht_basic_mcs_set;
 } STRUCT_PACKED;
 
+struct ieee80211_ampe_ie {
+	u8 selected_pairwise_suite[4];
+	u8 local_nonce[32];
+	u8 peer_nonce[32];
+	u8 mgtk[16];
+	u8 key_rsc[8];
+	u8 key_expiration[4];
+} STRUCT_PACKED;
+
 #ifdef _MSC_VER
 #pragma pack(pop)
 #endif /* _MSC_VER */
@@ -754,6 +799,7 @@
 #define VHT_CAP_MAX_MPDU_LENGTH_7991                ((u32) BIT(0))
 #define VHT_CAP_MAX_MPDU_LENGTH_11454               ((u32) BIT(1))
 #define VHT_CAP_MAX_MPDU_LENGTH_MASK                ((u32) BIT(0) | BIT(1))
+#define VHT_CAP_MAX_MPDU_LENGTH_MASK_SHIFT          0
 #define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ              ((u32) BIT(2))
 #define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ     ((u32) BIT(3))
 #define VHT_CAP_SUPP_CHAN_WIDTH_MASK                ((u32) BIT(2) | BIT(3))
@@ -767,13 +813,16 @@
 #define VHT_CAP_RXSTBC_4                            ((u32) BIT(10))
 #define VHT_CAP_RXSTBC_MASK                         ((u32) BIT(8) | BIT(9) | \
 							   BIT(10))
+#define VHT_CAP_RXSTBC_MASK_SHIFT                   8
 #define VHT_CAP_SU_BEAMFORMER_CAPABLE               ((u32) BIT(11))
 #define VHT_CAP_SU_BEAMFORMEE_CAPABLE               ((u32) BIT(12))
 #define VHT_CAP_BEAMFORMEE_STS_MAX                  ((u32) BIT(13) | \
 							   BIT(14) | BIT(15))
+#define VHT_CAP_BEAMFORMEE_STS_MAX_SHIFT            13
 #define VHT_CAP_BEAMFORMEE_STS_OFFSET               13
 #define VHT_CAP_SOUNDING_DIMENSION_MAX              ((u32) BIT(16) | \
 							   BIT(17) | BIT(18))
+#define VHT_CAP_SOUNDING_DIMENSION_MAX_SHIFT        16
 #define VHT_CAP_SOUNDING_DIMENSION_OFFSET           16
 #define VHT_CAP_MU_BEAMFORMER_CAPABLE               ((u32) BIT(19))
 #define VHT_CAP_MU_BEAMFORMEE_CAPABLE               ((u32) BIT(20))
@@ -788,6 +837,7 @@
 #define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_6        ((u32) BIT(24) | BIT(25))
 #define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX      ((u32) BIT(23) | \
 							   BIT(24) | BIT(25))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT 23
 #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB   ((u32) BIT(27))
 #define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB     ((u32) BIT(26) | BIT(27))
 #define VHT_CAP_RX_ANTENNA_PATTERN                  ((u32) BIT(28))
@@ -855,6 +905,8 @@
 
 } STRUCT_PACKED;
 
+#define WMM_QOSINFO_AP_UAPSD 0x80
+
 #define WMM_QOSINFO_STA_AC_MASK 0x0f
 #define WMM_QOSINFO_STA_SP_MASK 0x03
 #define WMM_QOSINFO_STA_SP_SHIFT 5
@@ -922,11 +974,12 @@
 
 
 /* Access Categories / ACI to AC coding */
-enum {
+enum wmm_ac {
 	WMM_AC_BE = 0 /* Best Effort */,
 	WMM_AC_BK = 1 /* Background */,
 	WMM_AC_VI = 2 /* Video */,
-	WMM_AC_VO = 3 /* Voice */
+	WMM_AC_VO = 3 /* Voice */,
+	WMM_AC_NUM = 4
 };
 
 
@@ -1087,6 +1140,19 @@
 	WFD_SUBELEM_SESSION_INFO = 9
 };
 
+/* 802.11s */
+#define MESH_SYNC_METHOD_NEIGHBOR_OFFSET 1
+#define MESH_SYNC_METHOD_VENDOR		255
+#define MESH_PATH_PROTOCOL_HWMP		1
+#define MESH_PATH_PROTOCOL_VENDOR	255
+#define MESH_PATH_METRIC_AIRTIME	1
+#define MESH_PATH_METRIC_VENDOR		255
+
+enum plink_action_field {
+	PLINK_OPEN = 1,
+	PLINK_CONFIRM,
+	PLINK_CLOSE
+};
 
 #define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
 
@@ -1122,6 +1188,7 @@
 #define WLAN_AKM_SUITE_FT_PSK		0x000FAC04
 #define WLAN_AKM_SUITE_8021X_SHA256	0x000FAC05
 #define WLAN_AKM_SUITE_PSK_SHA256	0x000FAC06
+#define WLAN_AKM_SUITE_8021X_SUITE_B	0x000FAC11
 #define WLAN_AKM_SUITE_CCKM		0x00409600
 #define WLAN_AKM_SUITE_OSEN		0x506f9a01
 
@@ -1247,4 +1314,30 @@
 #define CHAN_SWITCH_MODE_ALLOW_TX	0
 #define CHAN_SWITCH_MODE_BLOCK_TX	1
 
+struct tpc_report {
+	u8 eid;
+	u8 len;
+	u8 tx_power;
+	u8 link_margin;
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2012, 8.5.7.4 - Link Measurement Request frame format */
+struct rrm_link_measurement_request {
+	u8 dialog_token;
+	s8 tx_power;
+	s8 max_tp;
+	u8 variable[0];
+} STRUCT_PACKED;
+
+/* IEEE Std 802.11-2012, 8.5.7.5 - Link Measurement Report frame format */
+struct rrm_link_measurement_report {
+	u8 dialog_token;
+	struct tpc_report tpc;
+	u8 rx_ant_id;
+	u8 tx_ant_id;
+	u8 rcpi;
+	u8 rsni;
+	u8 variable[0];
+} STRUCT_PACKED;
+
 #endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
index 858b51d..4dc34c4 100644
--- a/src/common/privsep_commands.h
+++ b/src/common/privsep_commands.h
@@ -31,7 +31,9 @@
 	u8 bssid[ETH_ALEN];
 	u8 ssid[32];
 	size_t ssid_len;
+	int hwmode;
 	int freq;
+	int channel;
 	int pairwise_suite;
 	int group_suite;
 	int key_mgmt_suite;
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index ad3bdfd..ec1be86 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -50,6 +50,25 @@
  * @QCA_NL80211_VENDOR_SUBCMD_NAN: NAN command/event which is used to pass
  *	NAN Request/Response and NAN Indication messages. These messages are
  *	interpreted between the framework and the firmware component.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY: Set key operation that can be
+ *	used to configure PMK to the driver even when not connected. This can
+ *	be used to request offloading of key management operations. Only used
+ *	if device supports QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH: An extended version of
+ *	NL80211_CMD_ROAM event with optional attributes including information
+ *	from offloaded key management operation. Uses
+ *	enum qca_wlan_vendor_attr_roam_auth attributes. Only used
+ *	if device supports QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DO_ACS: ACS command/event which is used to
+ *	invoke the ACS function in device and pass selected channels to
+ *	hostapd.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
+ *	supported by the driver. enum qca_wlan_vendor_features defines
+ *	the possible features.
  */
 enum qca_nl80211_vendor_subcmds {
 	QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -60,7 +79,42 @@
 	QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY =  11,
 	QCA_NL80211_VENDOR_SUBCMD_NAN =  12,
 	QCA_NL80211_VENDOR_SUBMCD_STATS_EXT = 13,
-	/* 14..49 - reserved for QCA */
+	QCA_NL80211_VENDOR_SUBCMD_LL_STATS_SET = 14,
+	QCA_NL80211_VENDOR_SUBCMD_LL_STATS_GET = 15,
+	QCA_NL80211_VENDOR_SUBCMD_LL_STATS_CLR = 16,
+	QCA_NL80211_VENDOR_SUBCMD_LL_STATS_RADIO_RESULTS = 17,
+	QCA_NL80211_VENDOR_SUBCMD_LL_STATS_IFACE_RESULTS = 18,
+	QCA_NL80211_VENDOR_SUBCMD_LL_STATS_PEERS_RESULTS = 19,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_START = 20,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_STOP = 21,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_VALID_CHANNELS = 22,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CAPABILITIES = 23,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_GET_CACHED_RESULTS = 24,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_RESULTS_AVAILABLE = 25,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_FULL_SCAN_RESULT = 26,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_SCAN_EVENT = 27,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_FOUND = 28,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_BSSID_HOTLIST = 29,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_BSSID_HOTLIST = 30,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_SIGNIFICANT_CHANGE = 31,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_SET_SIGNIFICANT_CHANGE = 32,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_RESET_SIGNIFICANT_CHANGE = 33,
+	QCA_NL80211_VENDOR_SUBCMD_TDLS_ENABLE = 34,
+	QCA_NL80211_VENDOR_SUBCMD_TDLS_DISABLE = 35,
+	QCA_NL80211_VENDOR_SUBCMD_TDLS_GET_STATUS = 36,
+	QCA_NL80211_VENDOR_SUBCMD_TDLS_STATE = 37,
+	QCA_NL80211_VENDOR_SUBCMD_GET_SUPPORTED_FEATURES = 38,
+	QCA_NL80211_VENDOR_SUBCMD_SCANNING_MAC_OUI = 39,
+	QCA_NL80211_VENDOR_SUBCMD_NO_DFS_FLAG = 40,
+	QCA_NL80211_VENDOR_SUBCMD_GSCAN_HOTLIST_AP_LOST = 41,
+	QCA_NL80211_VENDOR_SUBCMD_GET_CONCURRENCY_MATRIX = 42,
+	/* 43..49 - reserved for QCA */
+	QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY = 50,
+	QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH = 51,
+	QCA_NL80211_VENDOR_SUBCMD_APFIND = 52,
+	/* 53 - reserved for QCA */
+	QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54,
+	QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55,
 };
 
 
@@ -78,6 +132,8 @@
 	 * by enum qca_roaming_policy. */
 	QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY = 5,
 	QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
+	/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
+	QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
 	/* keep last */
 	QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
 	QCA_WLAN_VENDOR_ATTR_MAX	= QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
@@ -89,4 +145,53 @@
 	QCA_ROAMING_ALLOWED_WITHIN_ESS,
 };
 
+enum qca_wlan_vendor_attr_roam_auth {
+	QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID,
+	QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE,
+	QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE,
+	QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED,
+	QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR,
+	QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK,
+	QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK,
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX =
+	QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AFTER_LAST - 1
+};
+
+enum qca_wlan_vendor_attr_acs_offload {
+	QCA_WLAN_VENDOR_ATTR_ACS_CHANNEL_INVALID = 0,
+	QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL,
+	QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL,
+	QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
+	QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
+	QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
+	/* keep last */
+	QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
+	QCA_WLAN_VENDOR_ATTR_ACS_MAX =
+	QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST - 1
+};
+
+enum qca_wlan_vendor_acs_hw_mode {
+	QCA_ACS_MODE_IEEE80211B,
+	QCA_ACS_MODE_IEEE80211G,
+	QCA_ACS_MODE_IEEE80211A,
+	QCA_ACS_MODE_IEEE80211AD,
+};
+
+/**
+ * enum qca_wlan_vendor_features - Vendor device/driver feature flags
+ *
+ * @QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD: Device supports key
+ *	management offload, a mechanism where the station's firmware
+ *	does the exchange with the AP to establish the temporal keys
+ *	after roaming, rather than having the user space wpa_supplicant do it.
+ * @NUM_QCA_WLAN_VENDOR_FEATURES: Number of assigned feature bits
+ */
+enum qca_wlan_vendor_features {
+	QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD	= 0,
+	NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
+};
+
 #endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.c b/src/common/sae.c
index b67623f..5888958 100644
--- a/src/common/sae.c
+++ b/src/common/sae.c
@@ -87,7 +87,8 @@
 	crypto_ec_point_deinit(tmp->pwe_ecc, 1);
 	crypto_ec_point_deinit(tmp->own_commit_element_ecc, 0);
 	crypto_ec_point_deinit(tmp->peer_commit_element_ecc, 0);
-	os_free(sae->tmp);
+	wpabuf_free(tmp->anti_clogging_token);
+	bin_clear_free(tmp, sizeof(*tmp));
 	sae->tmp = NULL;
 }
 
@@ -623,8 +624,10 @@
 	wpa_hexdump(MSG_DEBUG, "SAE: PMKID", val, SAE_PMKID_LEN);
 	sha256_prf(keyseed, sizeof(keyseed), "SAE KCK and PMK",
 		   val, sae->tmp->prime_len, keys, sizeof(keys));
+	os_memset(keyseed, 0, sizeof(keyseed));
 	os_memcpy(sae->tmp->kck, keys, SAE_KCK_LEN);
 	os_memcpy(sae->pmk, keys + SAE_KCK_LEN, SAE_PMK_LEN);
+	os_memset(keys, 0, sizeof(keys));
 	wpa_hexdump_key(MSG_DEBUG, "SAE: KCK", sae->tmp->kck, SAE_KCK_LEN);
 	wpa_hexdump_key(MSG_DEBUG, "SAE: PMK", sae->pmk, SAE_PMK_LEN);
 
@@ -656,8 +659,11 @@
 		return;
 
 	wpabuf_put_le16(buf, sae->group); /* Finite Cyclic Group */
-	if (token)
+	if (token) {
 		wpabuf_put_buf(buf, token);
+		wpa_hexdump(MSG_DEBUG, "SAE: Anti-clogging token",
+			    wpabuf_head(token), wpabuf_len(token));
+	}
 	pos = wpabuf_put(buf, sae->tmp->prime_len);
 	crypto_bignum_to_bin(sae->tmp->own_commit_scalar, pos,
 			     sae->tmp->prime_len, sae->tmp->prime_len);
@@ -682,8 +688,7 @@
 }
 
 
-static u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups,
-			     u16 group)
+u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group)
 {
 	if (allowed_groups) {
 		int i;
diff --git a/src/common/sae.h b/src/common/sae.h
index d82a98e..89d74ab 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -35,6 +35,7 @@
 	const struct crypto_bignum *order;
 	struct crypto_bignum *prime_buf;
 	struct crypto_bignum *order_buf;
+	struct wpabuf *anti_clogging_token;
 };
 
 struct sae_data {
@@ -60,5 +61,6 @@
 		     const u8 **token, size_t *token_len, int *allowed_groups);
 void sae_write_confirm(struct sae_data *sae, struct wpabuf *buf);
 int sae_check_confirm(struct sae_data *sae, const u8 *data, size_t len);
+u16 sae_group_allowed(struct sae_data *sae, int *allowed_groups, u16 group);
 
 #endif /* SAE_H */
diff --git a/src/common/version.h b/src/common/version.h
index 726289d..c662270 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -5,6 +5,6 @@
 #define VERSION_STR_POSTFIX ""
 #endif /* VERSION_STR_POSTFIX */
 
-#define VERSION_STR "2.3" VERSION_STR_POSTFIX
+#define VERSION_STR "2.4-devel" VERSION_STR_POSTFIX
 
 #endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index 998a51a..a573e11 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -14,7 +14,6 @@
 #include "crypto/sha256.h"
 #include "crypto/aes_wrap.h"
 #include "crypto/crypto.h"
-#include "drivers/driver.h"
 #include "ieee802_11_defs.h"
 #include "defs.h"
 #include "wpa_common.h"
@@ -23,6 +22,7 @@
 /**
  * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
  * @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
  * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
  * @buf: Pointer to the beginning of the EAPOL header (version field)
  * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
@@ -38,10 +38,10 @@
  * happened during final editing of the standard and the correct behavior is
  * defined in the last draft (IEEE 802.11i/D10).
  */
-int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
-		      u8 *mic)
+int wpa_eapol_key_mic(const u8 *key, int akmp, int ver, const u8 *buf,
+		      size_t len, u8 *mic)
 {
-	u8 hash[SHA1_MAC_LEN];
+	u8 hash[SHA256_MAC_LEN];
 
 	switch (ver) {
 #ifndef CONFIG_FIPS
@@ -57,11 +57,23 @@
 	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
 		return omac1_aes_128(key, buf, len, mic);
 #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
-#ifdef CONFIG_HS20
 	case WPA_KEY_INFO_TYPE_AKM_DEFINED:
-		/* FIX: This should be based on negotiated AKM */
-		return omac1_aes_128(key, buf, len, mic);
+		switch (akmp) {
+#ifdef CONFIG_HS20
+		case WPA_KEY_MGMT_OSEN:
+			return omac1_aes_128(key, buf, len, mic);
 #endif /* CONFIG_HS20 */
+#ifdef CONFIG_SUITEB
+		case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+			if (hmac_sha256(key, 16, buf, len, hash))
+				return -1;
+			os_memcpy(mic, hash, MD5_MAC_LEN);
+			break;
+#endif /* CONFIG_SUITEB */
+		default:
+			return -1;
+		}
+		break;
 	default:
 		return -1;
 	}
@@ -399,6 +411,8 @@
 	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
 		return WPA_KEY_MGMT_FT_SAE;
 #endif /* CONFIG_SAE */
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
+		return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
 	return 0;
 }
 
@@ -496,7 +510,7 @@
 		count = WPA_GET_LE16(pos);
 		pos += 2;
 		left -= 2;
-		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+		if (count == 0 || count > left / RSN_SELECTOR_LEN) {
 			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
 				   "count %u left %u", __func__, count, left);
 			return -4;
@@ -524,7 +538,7 @@
 		count = WPA_GET_LE16(pos);
 		pos += 2;
 		left -= 2;
-		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+		if (count == 0 || count > left / RSN_SELECTOR_LEN) {
 			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
 				   "count %u left %u", __func__, count, left);
 			return -6;
@@ -547,17 +561,17 @@
 	}
 
 	if (left >= 2) {
-		data->num_pmkid = WPA_GET_LE16(pos);
+		u16 num_pmkid = WPA_GET_LE16(pos);
 		pos += 2;
 		left -= 2;
-		if (left < (int) data->num_pmkid * PMKID_LEN) {
+		if (num_pmkid > (unsigned int) left / PMKID_LEN) {
 			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
-				   "(num_pmkid=%lu left=%d)",
-				   __func__, (unsigned long) data->num_pmkid,
-				   left);
+				   "(num_pmkid=%u left=%d)",
+				   __func__, num_pmkid, left);
 			data->num_pmkid = 0;
 			return -9;
 		} else {
+			data->num_pmkid = num_pmkid;
 			data->pmkid = pos;
 			pos += data->num_pmkid * PMKID_LEN;
 			left -= data->num_pmkid * PMKID_LEN;
@@ -674,7 +688,7 @@
 		count = WPA_GET_LE16(pos);
 		pos += 2;
 		left -= 2;
-		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+		if (count == 0 || count > left / WPA_SELECTOR_LEN) {
 			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
 				   "count %u left %u", __func__, count, left);
 			return -4;
@@ -695,7 +709,7 @@
 		count = WPA_GET_LE16(pos);
 		pos += 2;
 		left -= 2;
-		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+		if (count == 0 || count > left / WPA_SELECTOR_LEN) {
 			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
 				   "count %u left %u", __func__, count, left);
 			return -6;
@@ -928,6 +942,39 @@
 }
 
 
+#ifdef CONFIG_SUITEB
+/**
+ * rsn_pmkid_suite_b - Calculate PMK identifier for Suite B AKM
+ * @kck: Key confirmation key
+ * @kck_len: Length of kck in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: Buffer for PMKID
+ * Returns: 0 on success, -1 on failure
+ *
+ * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
+ * PMKID = Truncate(HMAC-SHA-256(KCK, "PMK Name" || AA || SPA))
+ */
+int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
+		      const u8 *spa, u8 *pmkid)
+{
+	char *title = "PMK Name";
+	const u8 *addr[3];
+	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+	unsigned char hash[SHA256_MAC_LEN];
+
+	addr[0] = (u8 *) title;
+	addr[1] = aa;
+	addr[2] = spa;
+
+	if (hmac_sha256_vector(kck, kck_len, 3, addr, len, hash) < 0)
+		return -1;
+	os_memcpy(pmkid, hash, PMKID_LEN);
+	return 0;
+}
+#endif /* CONFIG_SUITEB */
+
+
 /**
  * wpa_cipher_txt - Convert cipher suite to a text string
  * @cipher: Cipher suite (WPA_CIPHER_* enum)
@@ -997,6 +1044,16 @@
 	case WPA_KEY_MGMT_PSK_SHA256:
 		return "WPA2-PSK-SHA256";
 #endif /* CONFIG_IEEE80211W */
+	case WPA_KEY_MGMT_WPS:
+		return "WPS";
+	case WPA_KEY_MGMT_SAE:
+		return "SAE";
+	case WPA_KEY_MGMT_FT_SAE:
+		return "FT-SAE";
+	case WPA_KEY_MGMT_OSEN:
+		return "OSEN";
+	case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+		return "WPA2-EAP-SUITE-B";
 	default:
 		return "UNKNOWN";
 	}
@@ -1023,6 +1080,8 @@
 		return WLAN_AKM_SUITE_CCKM;
 	if (akm & WPA_KEY_MGMT_OSEN)
 		return WLAN_AKM_SUITE_OSEN;
+	if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+		return WLAN_AKM_SUITE_8021X_SUITE_B;
 	return 0;
 }
 
@@ -1417,56 +1476,56 @@
 	if (ciphers & WPA_CIPHER_CCMP_256) {
 		ret = os_snprintf(pos, end - pos, "%sCCMP-256",
 				  pos == start ? "" : delim);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
 	if (ciphers & WPA_CIPHER_GCMP_256) {
 		ret = os_snprintf(pos, end - pos, "%sGCMP-256",
 				  pos == start ? "" : delim);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
 	if (ciphers & WPA_CIPHER_CCMP) {
 		ret = os_snprintf(pos, end - pos, "%sCCMP",
 				  pos == start ? "" : delim);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
 	if (ciphers & WPA_CIPHER_GCMP) {
 		ret = os_snprintf(pos, end - pos, "%sGCMP",
 				  pos == start ? "" : delim);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
 	if (ciphers & WPA_CIPHER_TKIP) {
 		ret = os_snprintf(pos, end - pos, "%sTKIP",
 				  pos == start ? "" : delim);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
 	if (ciphers & WPA_CIPHER_WEP104) {
 		ret = os_snprintf(pos, end - pos, "%sWEP104",
 				  pos == start ? "" : delim);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
 	if (ciphers & WPA_CIPHER_WEP40) {
 		ret = os_snprintf(pos, end - pos, "%sWEP40",
 				  pos == start ? "" : delim);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
 	if (ciphers & WPA_CIPHER_NONE) {
 		ret = os_snprintf(pos, end - pos, "%sNONE",
 				  pos == start ? "" : delim);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
@@ -1497,78 +1556,3 @@
 		return WPA_CIPHER_CCMP_256;
 	return WPA_CIPHER_CCMP;
 }
-
-
-static int wpa_check_wowlan_trigger(const char *start, const char *trigger,
-				    int capa_trigger, u8 *param_trigger)
-{
-	if (os_strcmp(start, trigger) != 0)
-		return 0;
-	if (!capa_trigger)
-		return 0;
-
-	*param_trigger = 1;
-	return 1;
-}
-
-
-struct wowlan_triggers *wpa_get_wowlan_triggers(const char *wowlan_triggers,
-						struct wpa_driver_capa *capa)
-{
-	struct wowlan_triggers *triggers;
-	char *start, *end, *buf;
-	int last;
-
-	if (!wowlan_triggers)
-		return NULL;
-
-	buf = os_strdup(wowlan_triggers);
-	if (buf == NULL)
-		return NULL;
-
-	triggers = os_zalloc(sizeof(*triggers));
-	if (triggers == NULL)
-		goto out;
-
-#define CHECK_TRIGGER(trigger) \
-	wpa_check_wowlan_trigger(start, #trigger,			\
-				  capa->wowlan_triggers.trigger,	\
-				  &triggers->trigger)
-
-	start = buf;
-	while (*start != '\0') {
-		while (isblank(*start))
-			start++;
-		if (*start == '\0')
-			break;
-		end = start;
-		while (!isblank(*end) && *end != '\0')
-			end++;
-		last = *end == '\0';
-		*end = '\0';
-
-		if (!CHECK_TRIGGER(any) &&
-		    !CHECK_TRIGGER(disconnect) &&
-		    !CHECK_TRIGGER(magic_pkt) &&
-		    !CHECK_TRIGGER(gtk_rekey_failure) &&
-		    !CHECK_TRIGGER(eap_identity_req) &&
-		    !CHECK_TRIGGER(four_way_handshake) &&
-		    !CHECK_TRIGGER(rfkill_release)) {
-			wpa_printf(MSG_DEBUG,
-				   "Unknown/unsupported wowlan trigger '%s'",
-				   start);
-			os_free(triggers);
-			triggers = NULL;
-			goto out;
-		}
-
-		if (last)
-			break;
-		start = end + 1;
-	}
-#undef CHECK_TRIGGER
-
-out:
-	os_free(buf);
-	return triggers;
-}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 0ef5a9d..17bed34 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -327,8 +327,8 @@
 #endif /* _MSC_VER */
 
 
-int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
-		      u8 *mic);
+int wpa_eapol_key_mic(const u8 *key, int akmp, int ver, const u8 *buf,
+		      size_t len, u8 *mic);
 void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
 		    const u8 *addr1, const u8 *addr2,
 		    const u8 *nonce1, const u8 *nonce2,
@@ -374,6 +374,16 @@
 
 void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
 	       u8 *pmkid, int use_sha256);
+#ifdef CONFIG_SUITEB
+int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
+		       const u8 *spa, u8 *pmkid);
+#else /* CONFIG_SUITEB */
+static inline int rsn_pmkid_suite_b(const u8 *kck, size_t kck_len, const u8 *aa,
+				    const u8 *spa, u8 *pmkid)
+{
+	return -1;
+}
+#endif /* CONFIG_SUITEB */
 
 const char * wpa_cipher_txt(int cipher);
 const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index 5820a13..ccaaf1b 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -94,10 +94,9 @@
 	if (ctrl_path == NULL)
 		return NULL;
 
-	ctrl = os_malloc(sizeof(*ctrl));
+	ctrl = os_zalloc(sizeof(*ctrl));
 	if (ctrl == NULL)
 		return NULL;
-	os_memset(ctrl, 0, sizeof(*ctrl));
 
 	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (ctrl->s < 0) {
@@ -112,7 +111,7 @@
 			  CONFIG_CTRL_IFACE_CLIENT_DIR "/"
 			  CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
 			  (int) getpid(), counter);
-	if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
+	if (os_snprintf_error(sizeof(ctrl->local.sun_path), ret)) {
 		close(ctrl->s);
 		os_free(ctrl);
 		return NULL;
@@ -283,10 +282,9 @@
 	struct hostent *h;
 #endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
 
-	ctrl = os_malloc(sizeof(*ctrl));
+	ctrl = os_zalloc(sizeof(*ctrl));
 	if (ctrl == NULL)
 		return NULL;
-	os_memset(ctrl, 0, sizeof(*ctrl));
 
 #ifdef CONFIG_CTRL_IFACE_UDP_IPV6
 	ctrl->s = socket(PF_INET6, SOCK_DGRAM, 0);
@@ -643,7 +641,7 @@
 		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
 				  ctrl_path);
 #endif /* UNICODE */
-	if (ret < 0 || ret >= 256) {
+	if (os_snprintf_error(256, ret)) {
 		os_free(ctrl);
 		return NULL;
 	}
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 4812f8d..1f747eb 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -58,6 +58,8 @@
 #define WPA_EVENT_SCAN_STARTED "CTRL-EVENT-SCAN-STARTED "
 /** New scan results available */
 #define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
+/** Scan command failed */
+#define WPA_EVENT_SCAN_FAILED "CTRL-EVENT-SCAN-FAILED "
 /** wpa_supplicant state change */
 #define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE "
 /** A new BSS entry was added (followed by BSS entry id and BSSID) */
@@ -118,6 +120,17 @@
 #define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
 #define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "
 
+/* MESH events */
+#define MESH_GROUP_STARTED "MESH-GROUP-STARTED "
+#define MESH_GROUP_REMOVED "MESH-GROUP-REMOVED "
+#define MESH_PEER_CONNECTED "MESH-PEER-CONNECTED "
+#define MESH_PEER_DISCONNECTED "MESH-PEER-DISCONNECTED "
+
+/* WMM AC events */
+#define WMM_AC_EVENT_TSPEC_ADDED "TSPEC-ADDED "
+#define WMM_AC_EVENT_TSPEC_REMOVED "TSPEC-REMOVED "
+#define WMM_AC_EVENT_TSPEC_REQ_FAILED "TSPEC-REQ-FAILED "
+
 /** P2P device found */
 #define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
 
@@ -187,6 +200,9 @@
 #define EXT_RADIO_WORK_START "EXT-RADIO-WORK-START "
 #define EXT_RADIO_WORK_TIMEOUT "EXT-RADIO-WORK-TIMEOUT "
 
+#define RRM_EVENT_NEIGHBOR_REP_RXED "RRM-NEIGHBOR-REP-RECEIVED "
+#define RRM_EVENT_NEIGHBOR_REP_FAILED "RRM-NEIGHBOR-REP-REQUEST-FAILED "
+
 /* hostapd control interface - fixed message prefixes */
 #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
 #define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
@@ -204,6 +220,9 @@
 #define AP_EVENT_ENABLED "AP-ENABLED "
 #define AP_EVENT_DISABLED "AP-DISABLED "
 
+#define INTERFACE_ENABLED "INTERFACE-ENABLED "
+#define INTERFACE_DISABLED "INTERFACE-DISABLED "
+
 #define ACS_EVENT_STARTED "ACS-STARTED "
 #define ACS_EVENT_COMPLETED "ACS-COMPLETED "
 #define ACS_EVENT_FAILED "ACS-FAILED "
@@ -216,6 +235,9 @@
 
 #define AP_CSA_FINISHED "AP-CSA-FINISHED "
 
+/* BSS Transition Management Response frame received */
+#define BSS_TM_RESP "BSS-TM-RESP "
+
 /* BSS command information masks */
 
 #define WPA_BSS_MASK_ALL		0xFFFDFFFF
@@ -237,6 +259,7 @@
 #define WPA_BSS_MASK_INTERNETW		BIT(15)
 #define WPA_BSS_MASK_WIFI_DISPLAY	BIT(16)
 #define WPA_BSS_MASK_DELIM		BIT(17)
+#define WPA_BSS_MASK_MESH_SCAN		BIT(18)
 
 
 /* VENDOR_ELEM_* frame id values */
@@ -383,8 +406,6 @@
  */
 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
 
-char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
-
 #ifdef ANDROID
 /**
  * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
@@ -402,6 +423,8 @@
 #define WPA_CTRL_IFACE_PORT_LIMIT 50 /* decremented from start */
 #define WPA_GLOBAL_CTRL_IFACE_PORT 9878
 #define WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT 20 /* incremented from start */
+
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
 #endif /* CONFIG_CTRL_IFACE_UDP */
 
 
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index 2a92109..3e90350 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -26,6 +26,7 @@
 	aes-internal-dec.o \
 	aes-internal-enc.o \
 	aes-omac1.o \
+	aes-siv.o \
 	aes-unwrap.o \
 	aes-wrap.o \
 	des-internal.o \
diff --git a/src/crypto/aes-omac1.c b/src/crypto/aes-omac1.c
index 27895eb..c2b0686 100644
--- a/src/crypto/aes-omac1.c
+++ b/src/crypto/aes-omac1.c
@@ -65,6 +65,13 @@
 		for (i = 0; i < AES_BLOCK_SIZE; i++) {
 			cbc[i] ^= *pos++;
 			if (pos >= end) {
+				/*
+				 * Stop if there are no more bytes to process
+				 * since there are no more entries in the array.
+				 */
+				if (i + 1 == AES_BLOCK_SIZE &&
+				    left == AES_BLOCK_SIZE)
+					break;
 				e++;
 				pos = addr[e];
 				end = pos + len[e];
@@ -83,6 +90,12 @@
 		for (i = 0; i < left; i++) {
 			cbc[i] ^= *pos++;
 			if (pos >= end) {
+				/*
+				 * Stop if there are no more bytes to process
+				 * since there are no more entries in the array.
+				 */
+				if (i + 1 == left)
+					break;
 				e++;
 				pos = addr[e];
 				end = pos + len[e];
diff --git a/src/crypto/aes-siv.c b/src/crypto/aes-siv.c
new file mode 100644
index 0000000..ff4b823
--- /dev/null
+++ b/src/crypto/aes-siv.c
@@ -0,0 +1,187 @@
+/*
+ * AES SIV (RFC 5297)
+ * Copyright (c) 2013 Cozybit, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+
+static const u8 zero[AES_BLOCK_SIZE];
+
+
+static void dbl(u8 *pad)
+{
+	int i, carry;
+
+	carry = pad[0] & 0x80;
+	for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
+		pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+	pad[AES_BLOCK_SIZE - 1] <<= 1;
+	if (carry)
+		pad[AES_BLOCK_SIZE - 1] ^= 0x87;
+}
+
+
+static void xor(u8 *a, const u8 *b)
+{
+	int i;
+
+	for (i = 0; i < AES_BLOCK_SIZE; i++)
+		*a++ ^= *b++;
+}
+
+
+static void xorend(u8 *a, int alen, const u8 *b, int blen)
+{
+	int i;
+
+	if (alen < blen)
+		return;
+
+	for (i = 0; i < blen; i++)
+		a[alen - blen + i] ^= b[i];
+}
+
+
+static void pad_block(u8 *pad, const u8 *addr, size_t len)
+{
+	os_memset(pad, 0, AES_BLOCK_SIZE);
+	os_memcpy(pad, addr, len);
+
+	if (len < AES_BLOCK_SIZE)
+		pad[len] = 0x80;
+}
+
+
+int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
+	    size_t *len, u8 *mac)
+{
+	u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
+	u8 *buf = NULL;
+	int ret;
+	size_t i;
+
+	if (!num_elem) {
+		os_memcpy(tmp, zero, sizeof(zero));
+		tmp[AES_BLOCK_SIZE - 1] = 1;
+		return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+	}
+
+	ret = omac1_aes_128(key, zero, sizeof(zero), tmp);
+	if (ret)
+		return ret;
+
+	for (i = 0; i < num_elem - 1; i++) {
+		ret = omac1_aes_128(key, addr[i], len[i], tmp2);
+		if (ret)
+			return ret;
+
+		dbl(tmp);
+		xor(tmp, tmp2);
+	}
+	if (len[i] >= AES_BLOCK_SIZE) {
+		buf = os_malloc(len[i]);
+		if (!buf)
+			return -ENOMEM;
+
+		os_memcpy(buf, addr[i], len[i]);
+		xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
+		ret = omac1_aes_128(key, buf, len[i], mac);
+		os_free(buf);
+		return ret;
+	}
+
+	dbl(tmp);
+	pad_block(tmp2, addr[i], len[i]);
+	xor(tmp, tmp2);
+
+	return omac1_aes_128(key, tmp, sizeof(tmp), mac);
+}
+
+
+int aes_siv_encrypt(const u8 *key, const u8 *pw,
+		    size_t pwlen, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *out)
+{
+	const u8 *_addr[6];
+	size_t _len[6];
+	const u8 *k1 = key, *k2 = key + 16;
+	u8 v[AES_BLOCK_SIZE];
+	size_t i;
+	u8 *iv, *crypt_pw;
+
+	if (num_elem > ARRAY_SIZE(_addr) - 1)
+		return -1;
+
+	for (i = 0; i < num_elem; i++) {
+		_addr[i] = addr[i];
+		_len[i] = len[i];
+	}
+	_addr[num_elem] = pw;
+	_len[num_elem] = pwlen;
+
+	if (aes_s2v(k1, num_elem + 1, _addr, _len, v))
+		return -1;
+
+	iv = out;
+	crypt_pw = out + AES_BLOCK_SIZE;
+
+	os_memcpy(iv, v, AES_BLOCK_SIZE);
+	os_memcpy(crypt_pw, pw, pwlen);
+
+	/* zero out 63rd and 31st bits of ctr (from right) */
+	v[8] &= 0x7f;
+	v[12] &= 0x7f;
+	return aes_128_ctr_encrypt(k2, v, crypt_pw, pwlen);
+}
+
+
+int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+		    size_t num_elem, const u8 *addr[], const size_t *len,
+		    u8 *out)
+{
+	const u8 *_addr[6];
+	size_t _len[6];
+	const u8 *k1 = key, *k2 = key + 16;
+	size_t crypt_len;
+	size_t i;
+	int ret;
+	u8 iv[AES_BLOCK_SIZE];
+	u8 check[AES_BLOCK_SIZE];
+
+	if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1)
+		return -1;
+	crypt_len = iv_c_len - AES_BLOCK_SIZE;
+
+	for (i = 0; i < num_elem; i++) {
+		_addr[i] = addr[i];
+		_len[i] = len[i];
+	}
+	_addr[num_elem] = out;
+	_len[num_elem] = crypt_len;
+
+	os_memcpy(iv, iv_crypt, AES_BLOCK_SIZE);
+	os_memcpy(out, iv_crypt + AES_BLOCK_SIZE, crypt_len);
+
+	iv[8] &= 0x7f;
+	iv[12] &= 0x7f;
+
+	ret = aes_128_ctr_encrypt(k2, iv, out, crypt_len);
+	if (ret)
+		return ret;
+
+	ret = aes_s2v(k1, num_elem + 1, _addr, _len, check);
+	if (ret)
+		return ret;
+	if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
+		return 0;
+
+	return -1;
+}
diff --git a/src/crypto/aes_siv.h b/src/crypto/aes_siv.h
new file mode 100644
index 0000000..463cf65
--- /dev/null
+++ b/src/crypto/aes_siv.h
@@ -0,0 +1,19 @@
+/*
+ * AES SIV (RFC 5297)
+ * Copyright (c) 2013 Cozybit, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AES_SIV_H
+#define AES_SIV_H
+
+int aes_siv_encrypt(const u8 *key, const u8 *pw,
+		    size_t pwlen, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *out);
+int aes_siv_decrypt(const u8 *key, const u8 *iv_crypt, size_t iv_c_len,
+		    size_t num_elem, const u8 *addr[], const size_t *len,
+		    u8 *out);
+
+#endif /* AES_SIV_H */
diff --git a/src/crypto/random.c b/src/crypto/random.c
index 053740e..bc758aa 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -232,12 +232,8 @@
 	 */
 	fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
 	if (fd < 0) {
-#ifndef CONFIG_NO_STDOUT_DEBUG
-		int error = errno;
-		perror("open(/dev/random)");
 		wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
-			   strerror(error));
-#endif /* CONFIG_NO_STDOUT_DEBUG */
+			   strerror(errno));
 		return -1;
 	}
 
@@ -417,12 +413,8 @@
 
 	random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
 	if (random_fd < 0) {
-#ifndef CONFIG_NO_STDOUT_DEBUG
-		int error = errno;
-		perror("open(/dev/random)");
 		wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
-			   strerror(error));
-#endif /* CONFIG_NO_STDOUT_DEBUG */
+			   strerror(errno));
 		return;
 	}
 	wpa_printf(MSG_DEBUG, "random: Trying to read entropy from "
diff --git a/src/crypto/sha256-kdf.c b/src/crypto/sha256-kdf.c
new file mode 100644
index 0000000..d8a1beb
--- /dev/null
+++ b/src/crypto/sha256-kdf.c
@@ -0,0 +1,76 @@
+/*
+ * HMAC-SHA256 KDF (RFC 5295)
+ * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+
+
+/**
+ * hmac_sha256_kdf - HMAC-SHA256 based KDF (RFC 5295)
+ * @secret: Key for KDF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the KDF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2.
+ */
+int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
+		    const char *label, const u8 *seed, size_t seed_len,
+		    u8 *out, size_t outlen)
+{
+	u8 T[SHA256_MAC_LEN];
+	u8 iter = 1;
+	const unsigned char *addr[4];
+	size_t len[4];
+	size_t pos, clen;
+
+	addr[0] = T;
+	len[0] = SHA256_MAC_LEN;
+	addr[1] = (const unsigned char *) label;
+	len[1] = os_strlen(label) + 1;
+	addr[2] = seed;
+	len[2] = seed_len;
+	addr[3] = &iter;
+	len[3] = 1;
+
+	if (hmac_sha256_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0)
+		return -1;
+
+	pos = 0;
+	for (;;) {
+		clen = outlen - pos;
+		if (clen > SHA256_MAC_LEN)
+			clen = SHA256_MAC_LEN;
+		os_memcpy(out + pos, T, clen);
+		pos += clen;
+
+		if (pos == outlen)
+			break;
+
+		if (iter == 255) {
+			os_memset(out, 0, outlen);
+			return -1;
+		}
+		iter++;
+
+		if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
+		{
+			os_memset(out, 0, outlen);
+			return -1;
+		}
+	}
+
+	return 0;
+}
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index 7596a52..b15f511 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -1,6 +1,6 @@
 /*
  * SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -23,5 +23,8 @@
 void tls_prf_sha256(const u8 *secret, size_t secret_len,
 		    const char *label, const u8 *seed, size_t seed_len,
 		    u8 *out, size_t outlen);
+int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
+		    const char *label, const u8 *seed, size_t seed_len,
+		    u8 *out, size_t outlen);
 
 #endif /* SHA256_H */
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 65e0f79..345ebc7 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -74,6 +74,7 @@
 	const char *pkcs11_module_path;
 	int fips_mode;
 	int cert_in_cb;
+	const char *openssl_ciphers;
 
 	void (*event_cb)(void *ctx, enum tls_event ev,
 			 union tls_event_data *data);
@@ -87,6 +88,7 @@
 #define TLS_CONN_REQUIRE_OCSP BIT(4)
 #define TLS_CONN_DISABLE_TLSv1_1 BIT(5)
 #define TLS_CONN_DISABLE_TLSv1_2 BIT(6)
+#define TLS_CONN_EAP_FAST BIT(7)
 
 /**
  * struct tls_connection_params - Parameters for TLS connection
@@ -123,6 +125,7 @@
  * specific for now)
  * @cert_id: the certificate's id when using engine
  * @ca_cert_id: the CA certificate's id when using engine
+ * @openssl_ciphers: OpenSSL cipher configuration
  * @flags: Parameter options (TLS_CONN_*)
  * @ocsp_stapling_response: DER encoded file with cached OCSP stapling response
  *	or %NULL if OCSP is not enabled
@@ -161,6 +164,7 @@
 	const char *key_id;
 	const char *cert_id;
 	const char *ca_cert_id;
+	const char *openssl_ciphers;
 
 	unsigned int flags;
 	const char *ocsp_stapling_response;
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index cb23eb9..20d0a31 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -81,7 +81,7 @@
 };
 
 struct tls_connection {
-	gnutls_session session;
+	gnutls_session_t session;
 	char *subject_match, *altsubject_match;
 	int read_alerts, write_alerts, failed;
 
@@ -199,7 +199,7 @@
 }
 
 
-static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
+static ssize_t tls_pull_func(gnutls_transport_ptr_t ptr, void *buf,
 			     size_t len)
 {
 	struct tls_connection *conn = (struct tls_connection *) ptr;
@@ -228,7 +228,7 @@
 }
 
 
-static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
+static ssize_t tls_push_func(gnutls_transport_ptr_t ptr, const void *buf,
 			     size_t len)
 {
 	struct tls_connection *conn = (struct tls_connection *) ptr;
@@ -286,7 +286,7 @@
 
 	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
 	gnutls_transport_set_push_function(conn->session, tls_push_func);
-	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
+	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr_t) conn);
 
 	return 0;
 
@@ -563,16 +563,29 @@
 	}
 
 	if (params->client_cert && params->private_key) {
-		/* TODO: private_key_passwd? */
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+		ret = gnutls_certificate_set_x509_key_file2(
+			conn->xcred, params->client_cert, params->private_key,
+			GNUTLS_X509_FMT_PEM, params->private_key_passwd, 0);
+#else
+		/* private_key_passwd not (easily) supported here */
 		ret = gnutls_certificate_set_x509_key_file(
 			conn->xcred, params->client_cert, params->private_key,
 			GNUTLS_X509_FMT_PEM);
+#endif
 		if (ret < 0) {
 			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
 				   "in PEM format: %s", gnutls_strerror(ret));
+#if GNUTLS_VERSION_NUMBER >= 0x03010b
+			ret = gnutls_certificate_set_x509_key_file2(
+				conn->xcred, params->client_cert,
+				params->private_key, GNUTLS_X509_FMT_DER,
+				params->private_key_passwd, 0);
+#else
 			ret = gnutls_certificate_set_x509_key_file(
 				conn->xcred, params->client_cert,
 				params->private_key, GNUTLS_X509_FMT_DER);
+#endif
 			if (ret < 0) {
 				wpa_printf(MSG_DEBUG, "Failed to read client "
 					   "cert/key in DER format: %s",
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index e153422..c72134a 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -45,14 +45,6 @@
 #define ERR_remove_thread_state(tid) ERR_remove_state(0)
 #endif
 
-#if OPENSSL_VERSION_NUMBER >= 0x10000000L
-/*
- * Session ticket override patch was merged into OpenSSL 0.9.9 tree on
- * 2008-11-15. This version uses a bit different API compared to the old patch.
- */
-#define CONFIG_OPENSSL_TICKET_OVERRIDE
-#endif
-
 #if defined(OPENSSL_IS_BORINGSSL)
 /* stack_index_t is the return type of OpenSSL's sk_XXX_num() functions. */
 typedef size_t stack_index_t;
@@ -700,12 +692,15 @@
 		NULL, NULL
 	};
 
-	if (!pkcs11_so_path || !pkcs11_module_path)
+	if (!pkcs11_so_path)
 		return 0;
 
 	pre_cmd[1] = pkcs11_so_path;
 	pre_cmd[3] = engine_id;
-	post_cmd[1] = pkcs11_module_path;
+	if (pkcs11_module_path)
+		post_cmd[1] = pkcs11_module_path;
+	else
+		post_cmd[0] = NULL;
 
 	wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
 		   pkcs11_so_path);
@@ -747,6 +742,7 @@
 {
 	SSL_CTX *ssl;
 	struct tls_context *context;
+	const char *ciphers;
 
 	if (tls_openssl_ref_count == 0) {
 		tls_global = context = tls_context_new(conf);
@@ -809,7 +805,7 @@
 	}
 	tls_openssl_ref_count++;
 
-	ssl = SSL_CTX_new(TLSv1_method());
+	ssl = SSL_CTX_new(SSLv23_method());
 	if (ssl == NULL) {
 		tls_openssl_ref_count--;
 #ifdef OPENSSL_SUPPORTS_CTX_APP_DATA
@@ -823,19 +819,22 @@
 		return NULL;
 	}
 
+	SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv2);
+	SSL_CTX_set_options(ssl, SSL_OP_NO_SSLv3);
+
 	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
+	wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+	ERR_load_ENGINE_strings();
+	ENGINE_load_dynamic();
+
 	if (conf &&
 	    (conf->opensc_engine_path || conf->pkcs11_engine_path ||
 	     conf->pkcs11_module_path)) {
-		wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
-		ERR_load_ENGINE_strings();
-		ENGINE_load_dynamic();
-
 		if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
 		    tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
 						   conf->pkcs11_module_path)) {
@@ -845,6 +844,18 @@
 	}
 #endif /* OPENSSL_NO_ENGINE */
 
+	if (conf && conf->openssl_ciphers)
+		ciphers = conf->openssl_ciphers;
+	else
+		ciphers = "DEFAULT:!EXP:!LOW";
+	if (SSL_CTX_set_cipher_list(ssl, ciphers) != 1) {
+		wpa_printf(MSG_ERROR,
+			   "OpenSSL: Failed to set cipher string '%s'",
+			   ciphers);
+		tls_deinit(ssl);
+		return NULL;
+	}
+
 	return ssl;
 }
 
@@ -886,16 +897,6 @@
 		wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
 		return -1;
 	}
-#ifndef ANDROID
-	if (pin == NULL) {
-		wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
-		return -1;
-	}
-#endif
-	if (key_id == NULL) {
-		wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
-		return -1;
-	}
 
 	ERR_clear_error();
 #ifdef ANDROID
@@ -916,21 +917,34 @@
 	wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
 
 #ifndef ANDROID
-	if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
+	if (pin && ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
 		wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
 			   ERR_error_string(ERR_get_error(), NULL));
 		goto err;
 	}
 #endif
-	/* load private key first in-case PIN is required for cert */
-	conn->private_key = ENGINE_load_private_key(conn->engine,
-						    key_id, NULL, NULL);
-	if (!conn->private_key) {
-		wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id"
-				" '%s' [%s]", key_id,
-			   ERR_error_string(ERR_get_error(), NULL));
-		ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
-		goto err;
+	if (key_id) {
+		/*
+		 * Ensure that the ENGINE does not attempt to use the OpenSSL
+		 * UI system to obtain a PIN, if we didn't provide one.
+		 */
+		struct {
+			const void *password;
+			const char *prompt_info;
+		} key_cb = { "", NULL };
+
+		/* load private key first in-case PIN is required for cert */
+		conn->private_key = ENGINE_load_private_key(conn->engine,
+							    key_id, NULL,
+							    &key_cb);
+		if (!conn->private_key) {
+			wpa_printf(MSG_ERROR,
+				   "ENGINE: cannot load private key with id '%s' [%s]",
+				   key_id,
+				   ERR_error_string(ERR_get_error(), NULL));
+			ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+			goto err;
+		}
 	}
 
 	/* handle a certificate and/or CA certificate */
@@ -2852,7 +2866,7 @@
 			return -1;
 		}
 		ret = os_snprintf(pos, end - pos, ":%s", suite);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			break;
 		pos += ret;
 
@@ -2907,15 +2921,9 @@
 	if (conn == NULL || conn->ssl == NULL || ext_type != 35)
 		return -1;
 
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
 	if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
 				       data_len) != 1)
 		return -1;
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-	if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
-				    data_len) != 1)
-		return -1;
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
 
 	return 0;
 }
@@ -3201,20 +3209,64 @@
 {
 	int ret;
 	unsigned long err;
+	int can_pkcs11 = 0;
+	const char *key_id = params->key_id;
+	const char *cert_id = params->cert_id;
+	const char *ca_cert_id = params->ca_cert_id;
+	const char *engine_id = params->engine ? params->engine_id : NULL;
 
 	if (conn == NULL)
 		return -1;
 
+	/*
+	 * If the engine isn't explicitly configured, and any of the
+	 * cert/key fields are actually PKCS#11 URIs, then automatically
+	 * use the PKCS#11 ENGINE.
+	 */
+	if (!engine_id || os_strcmp(engine_id, "pkcs11") == 0)
+		can_pkcs11 = 1;
+
+	if (!key_id && params->private_key && can_pkcs11 &&
+	    os_strncmp(params->private_key, "pkcs11:", 7) == 0) {
+		can_pkcs11 = 2;
+		key_id = params->private_key;
+	}
+
+	if (!cert_id && params->client_cert && can_pkcs11 &&
+	    os_strncmp(params->client_cert, "pkcs11:", 7) == 0) {
+		can_pkcs11 = 2;
+		cert_id = params->client_cert;
+	}
+
+	if (!ca_cert_id && params->ca_cert && can_pkcs11 &&
+	    os_strncmp(params->ca_cert, "pkcs11:", 7) == 0) {
+		can_pkcs11 = 2;
+		ca_cert_id = params->ca_cert;
+	}
+
+	/* If we need to automatically enable the PKCS#11 ENGINE, do so. */
+	if (can_pkcs11 == 2 && !engine_id)
+		engine_id = "pkcs11";
+
+	if (params->flags & TLS_CONN_EAP_FAST) {
+		wpa_printf(MSG_DEBUG,
+			   "OpenSSL: Use TLSv1_method() for EAP-FAST");
+		if (SSL_set_ssl_method(conn->ssl, TLSv1_method()) != 1) {
+			tls_show_errors(MSG_INFO, __func__,
+					"Failed to set TLSv1_method() for EAP-FAST");
+			return -1;
+		}
+	}
+
 	while ((err = ERR_get_error())) {
 		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
 			   __func__, ERR_error_string(err, NULL));
 	}
 
-	if (params->engine) {
+	if (engine_id) {
 		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
-		ret = tls_engine_init(conn, params->engine_id, params->pin,
-				      params->key_id, params->cert_id,
-				      params->ca_cert_id);
+		ret = tls_engine_init(conn, engine_id, params->pin,
+				      key_id, cert_id, ca_cert_id);
 		if (ret)
 			return ret;
 	}
@@ -3224,9 +3276,9 @@
 					     params->suffix_match))
 		return -1;
 
-	if (params->engine && params->ca_cert_id) {
+	if (engine_id && ca_cert_id) {
 		if (tls_connection_engine_ca_cert(tls_ctx, conn,
-						  params->ca_cert_id))
+						  ca_cert_id))
 			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
 	} else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
 					  params->ca_cert_blob,
@@ -3234,15 +3286,15 @@
 					  params->ca_path))
 		return -1;
 
-	if (params->engine && params->cert_id) {
-		if (tls_connection_engine_client_cert(conn, params->cert_id))
+	if (engine_id && cert_id) {
+		if (tls_connection_engine_client_cert(conn, cert_id))
 			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
 	} else if (tls_connection_client_cert(conn, params->client_cert,
 					      params->client_cert_blob,
 					      params->client_cert_blob_len))
 		return -1;
 
-	if (params->engine && params->key_id) {
+	if (engine_id && key_id) {
 		wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
 		if (tls_connection_engine_private_key(conn))
 			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
@@ -3262,6 +3314,14 @@
 		return -1;
 	}
 
+	if (params->openssl_ciphers &&
+	    SSL_set_cipher_list(conn->ssl, params->openssl_ciphers) != 1) {
+		wpa_printf(MSG_INFO,
+			   "OpenSSL: Failed to set cipher string '%s'",
+			   params->openssl_ciphers);
+		return -1;
+	}
+
 #ifdef SSL_OP_NO_TICKET
 	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
 		SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
@@ -3328,6 +3388,14 @@
 		return -1;
 	}
 
+	if (params->openssl_ciphers &&
+	    SSL_CTX_set_cipher_list(ssl_ctx, params->openssl_ciphers) != 1) {
+		wpa_printf(MSG_INFO,
+			   "OpenSSL: Failed to set cipher string '%s'",
+			   params->openssl_ciphers);
+		return -1;
+	}
+
 #ifdef SSL_OP_NO_TICKET
 	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
 		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
@@ -3432,7 +3500,6 @@
 }
 
 
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
 static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
 				     int len, void *arg)
 {
@@ -3458,62 +3525,6 @@
 
 	return 1;
 }
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
-static void tls_hello_ext_cb(SSL *s, int client_server, int type,
-			     unsigned char *data, int len, void *arg)
-{
-	struct tls_connection *conn = arg;
-
-	if (conn == NULL || conn->session_ticket_cb == NULL)
-		return;
-
-	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
-		   type, len);
-
-	if (type == TLSEXT_TYPE_session_ticket && !client_server) {
-		os_free(conn->session_ticket);
-		conn->session_ticket = NULL;
-
-		wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
-			    "extension", data, len);
-		conn->session_ticket = os_malloc(len);
-		if (conn->session_ticket == NULL)
-			return;
-
-		os_memcpy(conn->session_ticket, data, len);
-		conn->session_ticket_len = len;
-	}
-}
-#else /* SSL_OP_NO_TICKET */
-static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
-{
-	struct tls_connection *conn = arg;
-
-	if (conn == NULL || conn->session_ticket_cb == NULL)
-		return 0;
-
-	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
-		   ext->type, ext->length);
-
-	os_free(conn->session_ticket);
-	conn->session_ticket = NULL;
-
-	if (ext->type == 35) {
-		wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
-			    "extension", ext->data, ext->length);
-		conn->session_ticket = os_malloc(ext->length);
-		if (conn->session_ticket == NULL)
-			return SSL_AD_INTERNAL_ERROR;
-
-		os_memcpy(conn->session_ticket, ext->data, ext->length);
-		conn->session_ticket_len = ext->length;
-	}
-
-	return 0;
-}
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
 #endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
 
 
@@ -3530,33 +3541,12 @@
 		if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
 					      conn) != 1)
 			return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
 		SSL_set_session_ticket_ext_cb(conn->ssl,
 					      tls_session_ticket_ext_cb, conn);
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
-		SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
-		SSL_set_tlsext_debug_arg(conn->ssl, conn);
-#else /* SSL_OP_NO_TICKET */
-		if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
-					       conn) != 1)
-			return -1;
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
 	} else {
 		if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
 			return -1;
-#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
 		SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
-#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
-#ifdef SSL_OP_NO_TICKET
-		SSL_set_tlsext_debug_callback(conn->ssl, NULL);
-		SSL_set_tlsext_debug_arg(conn->ssl, conn);
-#else /* SSL_OP_NO_TICKET */
-		if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
-			return -1;
-#endif /* SSL_OP_NO_TICKET */
-#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
 	}
 
 	return 0;
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 6af7294..eeaba66 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -23,8 +23,7 @@
 #include "utils/list.h"
 
 #define HOSTAPD_CHAN_DISABLED 0x00000001
-#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
-#define HOSTAPD_CHAN_NO_IBSS 0x00000004
+#define HOSTAPD_CHAN_NO_IR 0x00000002
 #define HOSTAPD_CHAN_RADAR 0x00000008
 #define HOSTAPD_CHAN_HT40PLUS 0x00000010
 #define HOSTAPD_CHAN_HT40MINUS 0x00000020
@@ -42,6 +41,12 @@
 #define HOSTAPD_CHAN_VHT_50_30 0x00002000
 #define HOSTAPD_CHAN_VHT_70_10 0x00004000
 
+#define HOSTAPD_CHAN_INDOOR_ONLY 0x00010000
+#define HOSTAPD_CHAN_GO_CONCURRENT 0x00020000
+
+/**
+ * enum reg_change_initiator - Regulatory change initiator
+ */
 enum reg_change_initiator {
 	REGDOM_SET_BY_CORE,
 	REGDOM_SET_BY_USER,
@@ -50,6 +55,9 @@
 	REGDOM_BEACON_HINT,
 };
 
+/**
+ * enum reg_type - Regulatory change types
+ */
 enum reg_type {
 	REGDOM_TYPE_UNKNOWN,
 	REGDOM_TYPE_COUNTRY,
@@ -82,8 +90,8 @@
 	 */
 	u8 max_tx_power;
 
-	/*
-	 * survey_list - Linked list of surveys
+	/**
+	 * survey_list - Linked list of surveys (struct freq_survey)
 	 */
 	struct dl_list survey_list;
 
@@ -102,7 +110,9 @@
 	long double interference_factor;
 #endif /* CONFIG_ACS */
 
-	/* DFS CAC time in milliseconds */
+	/**
+	 * dfs_cac_ms - DFS CAC time in milliseconds
+	 */
 	unsigned int dfs_cac_ms;
 };
 
@@ -170,10 +180,12 @@
 #define IEEE80211_MODE_INFRA	0
 #define IEEE80211_MODE_IBSS	1
 #define IEEE80211_MODE_AP	2
+#define IEEE80211_MODE_MESH	5
 
 #define IEEE80211_CAP_ESS	0x0001
 #define IEEE80211_CAP_IBSS	0x0002
 #define IEEE80211_CAP_PRIVACY	0x0010
+#define IEEE80211_CAP_RRM	0x1000
 
 /* DMG (60 GHz) IEEE 802.11ad */
 /* type - bits 0..1 */
@@ -213,6 +225,11 @@
  * constructed of the IEs that are available. This field will also need to
  * include SSID in IE format. All drivers are encouraged to be extended to
  * report all IEs to make it easier to support future additions.
+ *
+ * This structure data is followed by ie_len octets of IEs from Probe Response
+ * frame (or if the driver does not indicate source of IEs, these may also be
+ * from Beacon frame). After the first set of IEs, another set of IEs may follow
+ * (with beacon_ie_len octets of data) if the driver provides both IE sets.
  */
 struct wpa_scan_res {
 	unsigned int flags;
@@ -227,13 +244,7 @@
 	unsigned int age;
 	size_t ie_len;
 	size_t beacon_ie_len;
-	/*
-	 * Followed by ie_len octets of IEs from Probe Response frame (or if
-	 * the driver does not indicate source of IEs, these may also be from
-	 * Beacon frame). After the first set of IEs, another set of IEs may
-	 * follow (with beacon_ie_len octets of data) if the driver provides
-	 * both IE sets.
-	 */
+	/* Followed by ie_len + beacon_ie_len octets of IE data */
 };
 
 /**
@@ -370,6 +381,27 @@
 	 */
 	unsigned int low_priority:1;
 
+	/**
+	 * mac_addr_rand - Requests driver to randomize MAC address
+	 */
+	unsigned int mac_addr_rand:1;
+
+	/**
+	 * mac_addr - MAC address used with randomization. The address cannot be
+	 * a multicast one, i.e., bit 0 of byte 0 should not be set.
+	 */
+	const u8 *mac_addr;
+
+	/**
+	 * mac_addr_mask - MAC address mask used with randomization.
+	 *
+	 * Bits that are 0 in the mask should be randomized. Bits that are 1 in
+	 * the mask should be taken as is from mac_addr. The mask should not
+	 * allow the generation of a multicast address, i.e., bit 0 of byte 0
+	 * must be set.
+	 */
+	const u8 *mac_addr_mask;
+
 	/*
 	 * NOTE: Whenever adding new parameters here, please make sure
 	 * wpa_scan_clone_params() and wpa_scan_free_params() get updated with
@@ -399,34 +431,95 @@
 	 */
 	int p2p;
 
+	/**
+	 * sae_data - SAE elements for Authentication frame
+	 *
+	 * This buffer starts with the Authentication transaction sequence
+	 * number field. If SAE is not used, this pointer is %NULL.
+	 */
 	const u8 *sae_data;
+
+	/**
+	 * sae_data_len - Length of sae_data buffer in octets
+	 */
 	size_t sae_data_len;
-
 };
 
+/**
+ * enum wps_mode - WPS mode
+ */
 enum wps_mode {
-	WPS_MODE_NONE /* no WPS provisioning being used */,
-	WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */,
-	WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection
-			  */
+	/**
+	 * WPS_MODE_NONE - No WPS provisioning being used
+	 */
+	WPS_MODE_NONE,
+
+	/**
+	 * WPS_MODE_OPEN - WPS provisioning with AP that is in open mode
+	 */
+	WPS_MODE_OPEN,
+
+	/**
+	 * WPS_MODE_PRIVACY - WPS provisioning with AP that is using protection
+	 */
+	WPS_MODE_PRIVACY
 };
 
+/**
+ * struct hostapd_freq_params - Channel parameters
+ */
 struct hostapd_freq_params {
-	int mode;
-	int freq;
-	int channel;
-	/* for HT */
-	int ht_enabled;
-	int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
-				 * secondary channel below primary, 1 = HT40
-				 * enabled, secondary channel above primary */
+	/**
+	 * mode - Mode/band (HOSTAPD_MODE_IEEE80211A, ..)
+	 */
+	enum hostapd_hw_mode mode;
 
-	/* for VHT */
+	/**
+	 * freq - Primary channel center frequency in MHz
+	 */
+	int freq;
+
+	/**
+	 * channel - Channel number
+	 */
+	int channel;
+
+	/**
+	 * ht_enabled - Whether HT is enabled
+	 */
+	int ht_enabled;
+
+	/**
+	 * sec_channel_offset - Secondary channel offset for HT40
+	 *
+	 * 0 = HT40 disabled,
+	 * -1 = HT40 enabled, secondary channel below primary,
+	 * 1 = HT40 enabled, secondary channel above primary
+	 */
+	int sec_channel_offset;
+
+	/**
+	 * vht_enabled - Whether VHT is enabled
+	 */
 	int vht_enabled;
 
-	/* valid for both HT and VHT, center_freq2 is non-zero
-	 * only for bandwidth 80 and an 80+80 channel */
-	int center_freq1, center_freq2;
+	/**
+	 * center_freq1 - Segment 0 center frequency in MHz
+	 *
+	 * Valid for both HT and VHT.
+	 */
+	int center_freq1;
+
+	/**
+	 * center_freq2 - Segment 1 center frequency in MHz
+	 *
+	 * Non-zero only for bandwidth 80 and an 80+80 channel
+	 */
+	int center_freq2;
+
+	/**
+	 * bandwidth - Channel bandwidth in MHz (20, 40, 80, 160)
+	 */
 	int bandwidth;
 };
 
@@ -680,12 +773,21 @@
 	int disable_ht;
 
 	/**
-	 * HT Capabilities over-rides. Only bits set in the mask will be used,
-	 * and not all values are used by the kernel anyway. Currently, MCS,
-	 * MPDU and MSDU fields are used.
+	 * htcaps - HT Capabilities over-rides
+	 *
+	 * Only bits set in the mask will be used, and not all values are used
+	 * by the kernel anyway. Currently, MCS, MPDU and MSDU fields are used.
+	 *
+	 * Pointer to struct ieee80211_ht_capabilities.
 	 */
-	const u8 *htcaps;       /* struct ieee80211_ht_capabilities * */
-	const u8 *htcaps_mask;  /* struct ieee80211_ht_capabilities * */
+	const u8 *htcaps;
+
+	/**
+	 * htcaps_mask - HT Capabilities over-rides mask
+	 *
+	 * Pointer to struct ieee80211_ht_capabilities.
+	 */
+	const u8 *htcaps_mask;
 
 #ifdef CONFIG_VHT_OVERRIDES
 	/**
@@ -699,6 +801,20 @@
 	const struct ieee80211_vht_capabilities *vhtcaps;
 	const struct ieee80211_vht_capabilities *vhtcaps_mask;
 #endif /* CONFIG_VHT_OVERRIDES */
+
+	/**
+	 * req_key_mgmt_offload - Request key management offload for connection
+	 *
+	 * Request key management offload for this connection if the device
+	 * supports it.
+	 */
+	int req_key_mgmt_offload;
+
+	/**
+	 * Flag for indicating whether this association includes support for
+	 * RRM (Radio Resource Measurements)
+	 */
+	int rrm_used;
 };
 
 enum hide_ssid {
@@ -895,6 +1011,14 @@
 	int ap_max_inactivity;
 
 	/**
+	 * smps_mode - SMPS mode
+	 *
+	 * SMPS mode to be used by the AP, specified as the relevant bits of
+	 * ht_capab (i.e. HT_CAP_INFO_SMPS_*).
+	 */
+	unsigned int smps_mode;
+
+	/**
 	 * disable_dgaf - Whether group-addressed frames are disabled
 	 */
 	int disable_dgaf;
@@ -910,6 +1034,33 @@
 	struct hostapd_freq_params *freq;
 };
 
+struct wpa_driver_mesh_bss_params {
+#define WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS	0x00000001
+	/*
+	 * TODO: Other mesh configuration parameters would go here.
+	 * See NL80211_MESHCONF_* for all the mesh config parameters.
+	 */
+	unsigned int flags;
+};
+
+struct wpa_driver_mesh_join_params {
+	const u8 *meshid;
+	int meshid_len;
+	const int *basic_rates;
+	const u8 *ies;
+	int ie_len;
+	int freq;
+	int beacon_int;
+	int max_peer_links;
+	enum ht_mode ht_mode;
+	struct wpa_driver_mesh_bss_params conf;
+#define WPA_DRIVER_MESH_FLAG_USER_MPM	0x00000001
+#define WPA_DRIVER_MESH_FLAG_DRIVER_MPM	0x00000002
+#define WPA_DRIVER_MESH_FLAG_SAE_AUTH	0x00000004
+#define WPA_DRIVER_MESH_FLAG_AMPE	0x00000008
+	unsigned int flags;
+};
+
 /**
  * struct wpa_driver_capa - Driver capability information
  */
@@ -922,6 +1073,7 @@
 #define WPA_DRIVER_CAPA_KEY_MGMT_FT		0x00000020
 #define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK		0x00000040
 #define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK	0x00000080
+	/** Bitfield of supported key management suites */
 	unsigned int key_mgmt;
 
 #define WPA_DRIVER_CAPA_ENC_WEP40	0x00000001
@@ -937,94 +1089,121 @@
 #define WPA_DRIVER_CAPA_ENC_BIP_GMAC_256	0x00000400
 #define WPA_DRIVER_CAPA_ENC_BIP_CMAC_256	0x00000800
 #define WPA_DRIVER_CAPA_ENC_GTK_NOT_USED	0x00001000
+	/** Bitfield of supported cipher suites */
 	unsigned int enc;
 
 #define WPA_DRIVER_AUTH_OPEN		0x00000001
 #define WPA_DRIVER_AUTH_SHARED		0x00000002
 #define WPA_DRIVER_AUTH_LEAP		0x00000004
+	/** Bitfield of supported IEEE 802.11 authentication algorithms */
 	unsigned int auth;
 
-/* Driver generated WPA/RSN IE */
+/** Driver generated WPA/RSN IE */
 #define WPA_DRIVER_FLAGS_DRIVER_IE	0x00000001
-/* Driver needs static WEP key setup after association command */
+/** Driver needs static WEP key setup after association command */
 #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
-/* Driver takes care of all DFS operations */
+/** Driver takes care of all DFS operations */
 #define WPA_DRIVER_FLAGS_DFS_OFFLOAD			0x00000004
-/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
+/** Driver takes care of RSN 4-way handshake internally; PMK is configured with
  * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
 #define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
+/** Driver is for a wired Ethernet interface */
 #define WPA_DRIVER_FLAGS_WIRED		0x00000010
-/* Driver provides separate commands for authentication and association (SME in
+/** Driver provides separate commands for authentication and association (SME in
  * wpa_supplicant). */
 #define WPA_DRIVER_FLAGS_SME		0x00000020
-/* Driver supports AP mode */
+/** Driver supports AP mode */
 #define WPA_DRIVER_FLAGS_AP		0x00000040
-/* Driver needs static WEP key setup after association has been completed */
+/** Driver needs static WEP key setup after association has been completed */
 #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE	0x00000080
-/* Driver supports dynamic HT 20/40 MHz channel changes during BSS lifetime */
+/** Driver supports dynamic HT 20/40 MHz channel changes during BSS lifetime */
 #define WPA_DRIVER_FLAGS_HT_2040_COEX			0x00000100
-/* Driver supports concurrent P2P operations */
+/** Driver supports concurrent P2P operations */
 #define WPA_DRIVER_FLAGS_P2P_CONCURRENT	0x00000200
-/*
+/**
  * Driver uses the initial interface as a dedicated management interface, i.e.,
  * it cannot be used for P2P group operations or non-P2P purposes.
  */
 #define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE	0x00000400
-/* This interface is P2P capable (P2P GO or P2P Client) */
+/** This interface is P2P capable (P2P GO or P2P Client) */
 #define WPA_DRIVER_FLAGS_P2P_CAPABLE	0x00000800
-/* Driver supports station and key removal when stopping an AP */
+/** Driver supports station and key removal when stopping an AP */
 #define WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT		0x00001000
-/*
+/**
  * Driver uses the initial interface for P2P management interface and non-P2P
  * purposes (e.g., connect to infra AP), but this interface cannot be used for
  * P2P group operations.
  */
 #define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P		0x00002000
-/*
+/**
  * Driver is known to use sane error codes, i.e., when it indicates that
  * something (e.g., association) fails, there was indeed a failure and the
  * operation does not end up getting completed successfully later.
  */
 #define WPA_DRIVER_FLAGS_SANE_ERROR_CODES		0x00004000
-/* Driver supports off-channel TX */
+/** Driver supports off-channel TX */
 #define WPA_DRIVER_FLAGS_OFFCHANNEL_TX			0x00008000
-/* Driver indicates TX status events for EAPOL Data frames */
+/** Driver indicates TX status events for EAPOL Data frames */
 #define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS		0x00010000
-/* Driver indicates TX status events for Deauth/Disassoc frames */
+/** Driver indicates TX status events for Deauth/Disassoc frames */
 #define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS		0x00020000
-/* Driver supports roaming (BSS selection) in firmware */
+/** Driver supports roaming (BSS selection) in firmware */
 #define WPA_DRIVER_FLAGS_BSS_SELECTION			0x00040000
-/* Driver supports operating as a TDLS peer */
+/** Driver supports operating as a TDLS peer */
 #define WPA_DRIVER_FLAGS_TDLS_SUPPORT			0x00080000
-/* Driver requires external TDLS setup/teardown/discovery */
+/** Driver requires external TDLS setup/teardown/discovery */
 #define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP		0x00100000
-/* Driver indicates support for Probe Response offloading in AP mode */
+/** Driver indicates support for Probe Response offloading in AP mode */
 #define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD		0x00200000
-/* Driver supports U-APSD in AP mode */
+/** Driver supports U-APSD in AP mode */
 #define WPA_DRIVER_FLAGS_AP_UAPSD			0x00400000
-/* Driver supports inactivity timer in AP mode */
+/** Driver supports inactivity timer in AP mode */
 #define WPA_DRIVER_FLAGS_INACTIVITY_TIMER		0x00800000
-/* Driver expects user space implementation of MLME in AP mode */
+/** Driver expects user space implementation of MLME in AP mode */
 #define WPA_DRIVER_FLAGS_AP_MLME			0x01000000
-/* Driver supports SAE with user space SME */
+/** Driver supports SAE with user space SME */
 #define WPA_DRIVER_FLAGS_SAE				0x02000000
-/* Driver makes use of OBSS scan mechanism in wpa_supplicant */
+/** Driver makes use of OBSS scan mechanism in wpa_supplicant */
 #define WPA_DRIVER_FLAGS_OBSS_SCAN			0x04000000
-/* Driver supports IBSS (Ad-hoc) mode */
+/** Driver supports IBSS (Ad-hoc) mode */
 #define WPA_DRIVER_FLAGS_IBSS				0x08000000
-/* Driver supports radar detection */
+/** Driver supports radar detection */
 #define WPA_DRIVER_FLAGS_RADAR				0x10000000
-/* Driver supports a dedicated interface for P2P Device */
+/** Driver supports a dedicated interface for P2P Device */
 #define WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE		0x20000000
-/* Driver supports QoS Mapping */
+/** Driver supports QoS Mapping */
 #define WPA_DRIVER_FLAGS_QOS_MAPPING			0x40000000
-/* Driver supports CSA in AP mode */
+/** Driver supports CSA in AP mode */
 #define WPA_DRIVER_FLAGS_AP_CSA				0x80000000
-	unsigned int flags;
+/** Driver supports mesh */
+#define WPA_DRIVER_FLAGS_MESH			0x0000000100000000ULL
+/** Driver support ACS offload */
+#define WPA_DRIVER_FLAGS_ACS_OFFLOAD		0x0000000200000000ULL
+/** Driver supports key management offload */
+#define WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD	0x0000000400000000ULL
+/** Driver supports TDLS channel switching */
+#define WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH	0x0000000800000000ULL
+	u64 flags;
 
+#define WPA_DRIVER_SMPS_MODE_STATIC			0x00000001
+#define WPA_DRIVER_SMPS_MODE_DYNAMIC			0x00000002
+	unsigned int smps_modes;
+
+	unsigned int wmm_ac_supported:1;
+
+	unsigned int mac_addr_rand_scan_supported:1;
+	unsigned int mac_addr_rand_sched_scan_supported:1;
+
+	/** Maximum number of supported active probe SSIDs */
 	int max_scan_ssids;
+
+	/** Maximum number of supported active probe SSIDs for sched_scan */
 	int max_sched_scan_ssids;
+
+	/** Whether sched_scan (offloaded scanning) is supported */
 	int sched_scan_supported;
+
+	/** Maximum number of supported match sets for sched_scan */
 	int max_match_sets;
 
 	/**
@@ -1042,13 +1221,13 @@
 	 * probe_resp_offloads - Bitmap of supported protocols by the driver
 	 * for Probe Response offloading.
 	 */
-/* Driver Probe Response offloading support for WPS ver. 1 */
+/** Driver Probe Response offloading support for WPS ver. 1 */
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS		0x00000001
-/* Driver Probe Response offloading support for WPS ver. 2 */
+/** Driver Probe Response offloading support for WPS ver. 2 */
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2		0x00000002
-/* Driver Probe Response offloading support for P2P */
+/** Driver Probe Response offloading support for P2P */
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P		0x00000004
-/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
+/** Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
 #define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING	0x00000008
 	unsigned int probe_resp_offloads;
 
@@ -1069,6 +1248,24 @@
 	unsigned int extended_capa_len;
 
 	struct wowlan_triggers wowlan_triggers;
+
+/** Driver adds the DS Params Set IE in Probe Request frames */
+#define WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES	0x00000001
+/** Driver adds the WFA TPC IE in Probe Request frames */
+#define WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES		0x00000002
+/** Driver handles quiet period requests */
+#define WPA_DRIVER_FLAGS_QUIET				0x00000004
+/**
+ * Driver is capable of inserting the current TX power value into the body of
+ * transmitted frames.
+ * Background: Some Action frames include a TPC Report IE. This IE contains a
+ * TX power field, which has to be updated by lower layers. One such Action
+ * frame is Link Measurement Report (part of RRM). Another is TPC Report (part
+ * of spectrum management). Note that this insertion takes place at a fixed
+ * offset, namely the 6th byte in the Action frame body.
+ */
+#define WPA_DRIVER_FLAGS_TX_POWER_INSERTION		0x00000008
+	u32 rrm_flags;
 };
 
 
@@ -1098,6 +1295,10 @@
 	int vht_opmode_enabled;
 	u8 vht_opmode;
 	u32 flags; /* bitmask of WPA_STA_* flags */
+	u32 flags_mask; /* unset bits in flags */
+#ifdef CONFIG_MESH
+	enum mesh_plink_state plink_state;
+#endif /* CONFIG_MESH */
 	int set; /* Set STA parameters instead of add */
 	u8 qosinfo;
 	const u8 *ext_capab;
@@ -1159,16 +1360,19 @@
 	 * WPA_IF_P2P_DEVICE - P2P Device interface is used to indentify the
 	 * abstracted P2P Device function in the driver
 	 */
-	WPA_IF_P2P_DEVICE
+	WPA_IF_P2P_DEVICE,
+
+	/*
+	 * WPA_IF_MESH - Mesh interface
+	 */
+	WPA_IF_MESH,
 };
 
 struct wpa_init_params {
 	void *global_priv;
 	const u8 *bssid;
 	const char *ifname;
-	const u8 *ssid;
-	size_t ssid_len;
-	const char *test_socket;
+	const char *driver_params;
 	int use_pae_group_addr;
 	char **bridge;
 	size_t num_bridge;
@@ -1197,6 +1401,7 @@
 #define WPA_STA_SHORT_PREAMBLE BIT(2)
 #define WPA_STA_MFP BIT(3)
 #define WPA_STA_TDLS_PEER BIT(4)
+#define WPA_STA_AUTHENTICATED BIT(5)
 
 enum tdls_oper {
 	TDLS_DISCOVERY_REQ,
@@ -1311,6 +1516,23 @@
 	TDLS_PEER_WMM = BIT(2),
 };
 
+/* valid info in the wmm_params struct */
+enum wmm_params_valid_info {
+	WMM_PARAMS_UAPSD_QUEUES_INFO = BIT(0),
+};
+
+/**
+ * struct wmm_params - WMM parameterss configured for this association
+ * @info_bitmap: Bitmap of valid wmm_params info; indicates what fields
+ *	of the struct contain valid information.
+ * @uapsd_queues: Bitmap of ACs configured for uapsd (valid only if
+ *	%WMM_PARAMS_UAPSD_QUEUES_INFO is set)
+ */
+struct wmm_params {
+	u8 info_bitmap;
+	u8 uapsd_queues;
+};
+
 #ifdef CONFIG_MACSEC
 struct macsec_init_params {
 	Boolean always_include_sci;
@@ -1319,6 +1541,26 @@
 };
 #endif /* CONFIG_MACSEC */
 
+enum drv_br_port_attr {
+	DRV_BR_PORT_ATTR_PROXYARP,
+	DRV_BR_PORT_ATTR_HAIRPIN_MODE,
+};
+
+enum drv_br_net_param {
+	DRV_BR_NET_PARAM_GARP_ACCEPT,
+};
+
+struct drv_acs_params {
+	/* Selected mode (HOSTAPD_MODE_*) */
+	enum hostapd_hw_mode hw_mode;
+
+	/* Indicates whether HT is enabled */
+	int ht_enabled;
+
+	/* Indicates whether HT40 is enabled */
+	int ht40_enabled;
+};
+
 
 /**
  * struct wpa_driver_ops - Driver interface API definition
@@ -1605,27 +1847,6 @@
 	const u8 * (*get_mac_addr)(void *priv);
 
 	/**
-	 * send_eapol - Optional function for sending EAPOL packets
-	 * @priv: private driver interface data
-	 * @dest: Destination MAC address
-	 * @proto: Ethertype
-	 * @data: EAPOL packet starting with IEEE 802.1X header
-	 * @data_len: Size of the EAPOL packet
-	 *
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This optional function can be used to override l2_packet operations
-	 * with driver specific functionality. If this function pointer is set,
-	 * l2_packet module is not used at all and the driver interface code is
-	 * responsible for receiving and sending all EAPOL packets. The
-	 * received EAPOL packets are sent to core code with EVENT_EAPOL_RX
-	 * event. The driver interface is required to implement get_mac_addr()
-	 * handler if send_eapol() is used.
-	 */
-	int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
-			  const u8 *data, size_t data_len);
-
-	/**
 	 * set_operstate - Sets device operating state to DORMANT or UP
 	 * @priv: private driver interface data
 	 * @state: 0 = dormant, 1 = up
@@ -1700,22 +1921,6 @@
 			     size_t ies_len);
 
 	/**
-	 * send_ft_action - Send FT Action frame (IEEE 802.11r)
-	 * @priv: Private driver interface data
-	 * @action: Action field value
-	 * @target_ap: Target AP address
-	 * @ies: FT IEs (MDIE, FTIE, ...) (FT Request action frame body)
-	 * @ies_len: Length of FT IEs in bytes
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * The supplicant uses this callback to request the driver to transmit
-	 * an FT Action frame (action category 6) for over-the-DS fast BSS
-	 * transition.
-	 */
-	int (*send_ft_action)(void *priv, u8 action, const u8 *target_ap,
-			      const u8 *ies, size_t ies_len);
-
-	/**
 	 * get_scan_results2 - Fetch the latest scan results
 	 * @priv: private driver interface data
 	 *
@@ -2547,6 +2752,45 @@
 			   u8 qos_map_set_len);
 
 	/**
+	 * br_add_ip_neigh - Add a neigh to the bridge ip neigh table
+	 * @priv: Private driver interface data
+	 * @version: IP version of the IP address, 4 or 6
+	 * @ipaddr: IP address for the neigh entry
+	 * @prefixlen: IP address prefix length
+	 * @addr: Corresponding MAC address
+	 * Returns: 0 on success, negative (<0) on failure
+	 */
+	int (*br_add_ip_neigh)(void *priv, u8 version, const u8 *ipaddr,
+			       int prefixlen, const u8 *addr);
+
+	/**
+	 * br_delete_ip_neigh - Remove a neigh from the bridge ip neigh table
+	 * @priv: Private driver interface data
+	 * @version: IP version of the IP address, 4 or 6
+	 * @ipaddr: IP address for the neigh entry
+	 * Returns: 0 on success, negative (<0) on failure
+	 */
+	int (*br_delete_ip_neigh)(void *priv, u8 version, const u8 *ipaddr);
+
+	/**
+	 * br_port_set_attr - Set a bridge port attribute
+	 * @attr: Bridge port attribute to set
+	 * @val: Value to be set
+	 * Returns: 0 on success, negative (<0) on failure
+	 */
+	int (*br_port_set_attr)(void *priv, enum drv_br_port_attr attr,
+				unsigned int val);
+
+	/**
+	 * br_port_set_attr - Set a bridge network parameter
+	 * @param: Bridge parameter to set
+	 * @val: Value to be set
+	 * Returns: 0 on success, negative (<0) on failure
+	 */
+	int (*br_set_net_param)(void *priv, enum drv_br_net_param param,
+				unsigned int val);
+
+	/**
 	 * set_wowlan - Set wake-on-wireless triggers
 	 * @priv: Private driver interface data
 	 * @triggers: wowlan triggers
@@ -2751,6 +2995,55 @@
 	int (*switch_channel)(void *priv, struct csa_settings *settings);
 
 	/**
+	 * add_tx_ts - Add traffic stream
+	 * @priv: Private driver interface data
+	 * @tsid: Traffic stream ID
+	 * @addr: Receiver address
+	 * @user_prio: User priority of the traffic stream
+	 * @admitted_time: Admitted time for this TS in units of
+	 *	32 microsecond periods (per second).
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*add_tx_ts)(void *priv, u8 tsid, const u8 *addr, u8 user_prio,
+			 u16 admitted_time);
+
+	/**
+	 * del_tx_ts - Delete traffic stream
+	 * @priv: Private driver interface data
+	 * @tsid: Traffic stream ID
+	 * @addr: Receiver address
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*del_tx_ts)(void *priv, u8 tsid, const u8 *addr);
+
+	/**
+	 * Enable channel-switching with TDLS peer
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the TDLS peer
+	 * @oper_class: Operating class of the switch channel
+	 * @params: Channel specification
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * The function indicates to driver that it can start switching to a
+	 * different channel with a specified TDLS peer. The switching is
+	 * assumed on until canceled with tdls_disable_channel_switch().
+	 */
+	int (*tdls_enable_channel_switch)(
+		void *priv, const u8 *addr, u8 oper_class,
+		const struct hostapd_freq_params *params);
+
+	/**
+	 * Disable channel switching with TDLS peer
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the TDLS peer
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function indicates to the driver that it should stop switching
+	 * with a given TDLS peer.
+	 */
+	int (*tdls_disable_channel_switch)(void *priv, const u8 *addr);
+
+	/**
 	 * start_dfs_cac - Listen for radar interference on the channel
 	 * @priv: Private driver interface data
 	 * @freq: Channel parameters
@@ -3023,6 +3316,40 @@
 	 */
 	int (*disable_transmit_sa)(void *priv, u32 channel, u8 an);
 #endif /* CONFIG_MACSEC */
+
+	/**
+	 * init_mesh - Driver specific initialization for mesh
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*init_mesh)(void *priv);
+
+	/**
+	 * join_mesh - Join a mesh network
+	 * @priv: Private driver interface data
+	 * @params: Mesh configuration parameters
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*join_mesh)(void *priv,
+			 struct wpa_driver_mesh_join_params *params);
+
+	/**
+	 * leave_mesh - Leave a mesh network
+	 * @priv: Private driver interface data
+	 * Returns 0 on success, -1 on failure
+	 */
+	int (*leave_mesh)(void *priv);
+
+	/**
+	 * do_acs - Automatically select channel
+	 * @priv: Private driver interface data
+	 * @params: Parameters for ACS
+	 * Returns 0 on success, -1 on failure
+	 *
+	 * This command can be used to offload ACS to the driver if the driver
+	 * indicates support for such offloading (WPA_DRIVER_FLAGS_ACS_OFFLOAD).
+	 */
+	int (*do_acs)(void *priv, struct drv_acs_params *params);
 };
 
 
@@ -3211,11 +3538,6 @@
 	EVENT_ASSOC_TIMED_OUT,
 
 	/**
-	 * EVENT_FT_RRB_RX - FT (IEEE 802.11r) RRB frame received
-	 */
-	EVENT_FT_RRB_RX,
-
-	/**
 	 * EVENT_WPS_BUTTON_PUSHED - Report hardware push button press for WPS
 	 */
 	EVENT_WPS_BUTTON_PUSHED,
@@ -3255,13 +3577,6 @@
 	EVENT_CANCEL_REMAIN_ON_CHANNEL,
 
 	/**
-	 * EVENT_MLME_RX - Report reception of frame for MLME (test use only)
-	 *
-	 * This event is used only by driver_test.c and userspace MLME.
-	 */
-	EVENT_MLME_RX,
-
-	/**
 	 * EVENT_RX_PROBE_REQ - Indicate received Probe Request frame
 	 *
 	 * This event is used to indicate when a Probe Request frame has been
@@ -3289,9 +3604,7 @@
 	 * EVENT_EAPOL_RX - Report received EAPOL frame
 	 *
 	 * When in AP mode with hostapd, this event is required to be used to
-	 * deliver the receive EAPOL frames from the driver. With
-	 * %wpa_supplicant, this event is used only if the send_eapol() handler
-	 * is used to override the use of l2_packet for EAPOL frame TX.
+	 * deliver the receive EAPOL frames from the driver.
 	 */
 	EVENT_EAPOL_RX,
 
@@ -3498,7 +3811,20 @@
 	 * to reduce issues due to interference or internal co-existence
 	 * information in the driver.
 	 */
-	EVENT_AVOID_FREQUENCIES
+	EVENT_AVOID_FREQUENCIES,
+
+	/**
+	 * EVENT_NEW_PEER_CANDIDATE - new (unknown) mesh peer notification
+	 */
+	EVENT_NEW_PEER_CANDIDATE,
+
+	/**
+	 * EVENT_ACS_CHANNEL_SELECTED - Received selected channels by ACS
+	 *
+	 * Indicates a pair of primary and secondary channels chosen by ACS
+	 * in device.
+	 */
+	EVENT_ACS_CHANNEL_SELECTED,
 };
 
 
@@ -3618,9 +3944,62 @@
 		unsigned int freq;
 
 		/**
+		 * wmm_params - WMM parameters used in this association.
+		 */
+		struct wmm_params wmm_params;
+
+		/**
 		 * addr - Station address (for AP mode)
 		 */
 		const u8 *addr;
+
+		/**
+		 * The following is the key management offload information
+		 * @authorized
+		 * @key_replay_ctr
+		 * @key_replay_ctr_len
+		 * @ptk_kck
+		 * @ptk_kek_len
+		 * @ptk_kek
+		 * @ptk_kek_len
+		 */
+
+		/**
+		 * authorized - Status of key management offload,
+		 * 1 = successful
+		 */
+		int authorized;
+
+		/**
+		 * key_replay_ctr - Key replay counter value last used
+		 * in a valid EAPOL-Key frame
+		 */
+		const u8 *key_replay_ctr;
+
+		/**
+		 * key_replay_ctr_len - The length of key_replay_ctr
+		 */
+		size_t key_replay_ctr_len;
+
+		/**
+		 * ptk_kck - The derived PTK KCK
+		 */
+		const u8 *ptk_kck;
+
+		/**
+		 * ptk_kek_len - The length of ptk_kck
+		 */
+		size_t ptk_kck_len;
+
+		/**
+		 * ptk_kek - The derived PTK KEK
+		 */
+		const u8 *ptk_kek;
+
+		/**
+		 * ptk_kek_len - The length of ptk_kek
+		 */
+		size_t ptk_kek_len;
 	} assoc_info;
 
 	/**
@@ -3830,15 +4209,6 @@
 	} timeout_event;
 
 	/**
-	 * struct ft_rrb_rx - Data for EVENT_FT_RRB_RX events
-	 */
-	struct ft_rrb_rx {
-		const u8 *src;
-		const u8 *data;
-		size_t data_len;
-	} ft_rrb_rx;
-
-	/**
 	 * struct tx_status - Data for EVENT_TX_STATUS events
 	 */
 	struct tx_status {
@@ -3922,17 +4292,6 @@
 	} scan_info;
 
 	/**
-	 * struct mlme_rx - Data for EVENT_MLME_RX events
-	 */
-	struct mlme_rx {
-		const u8 *buf;
-		size_t len;
-		int freq;
-		int channel;
-		int ssi;
-	} mlme_rx;
-
-	/**
 	 * struct rx_probe_req - Data for EVENT_RX_PROBE_REQ events
 	 */
 	struct rx_probe_req {
@@ -4112,7 +4471,7 @@
 	 * survey_results - Survey result data for EVENT_SURVEY
 	 * @freq_filter: Requested frequency survey filter, 0 if request
 	 *	was for all survey data
-	 * @survey_list: Linked list of survey data
+	 * @survey_list: Linked list of survey data (struct freq_survey)
 	 */
 	struct survey_results {
 		unsigned int freq_filter;
@@ -4137,6 +4496,31 @@
 	 * This is used as the data with EVENT_AVOID_FREQUENCIES.
 	 */
 	struct wpa_freq_range_list freq_range;
+
+	/**
+	 * struct mesh_peer
+	 *
+	 * @peer: Peer address
+	 * @ies: Beacon IEs
+	 * @ie_len: Length of @ies
+	 *
+	 * Notification of new candidate mesh peer.
+	 */
+	struct mesh_peer {
+		const u8 *peer;
+		const u8 *ies;
+		size_t ie_len;
+	} mesh_peer;
+
+	/**
+	 * struct acs_selected_channels - Data for EVENT_ACS_CHANNEL_SELECTED
+	 * @pri_channel: Selected primary channel
+	 * @sec_channel: Selected secondary channel
+	 */
+	struct acs_selected_channels {
+		u8 pri_channel;
+		u8 sec_channel;
+	} acs_selected_channels;
 };
 
 /**
@@ -4198,6 +4582,13 @@
 /* Convert chan_width to a string for logging and control interfaces */
 const char * channel_width_to_string(enum chan_width width);
 
+int ht_supported(const struct hostapd_hw_modes *mode);
+int vht_supported(const struct hostapd_hw_modes *mode);
+
+struct wowlan_triggers *
+wpa_get_wowlan_triggers(const char *wowlan_triggers,
+			const struct wpa_driver_capa *capa);
+
 /* NULL terminated array of linked in driver wrappers */
 extern struct wpa_driver_ops *wpa_drivers[];
 
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index b569a0a..350d505 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -224,10 +224,10 @@
 	memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
 
 	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
-		perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
-		wpa_printf(MSG_DEBUG, "%s: %s: Failed to set parameter (op %d "
-			   "(%s) arg %d)", __func__, drv->iface, op,
-			   athr_get_param_name(op), arg);
+		wpa_printf(MSG_INFO,
+			   "%s: %s: Failed to set parameter (op %d (%s) arg %d): ioctl[IEEE80211_IOCTL_SETPARAM]: %s",
+			   __func__, drv->iface, op, athr_get_param_name(op),
+			   arg, strerror(errno));
 		return -1;
 	}
 	return 0;
@@ -290,14 +290,15 @@
 	}
 	wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
 	if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
-		printf("Unable to set group key cipher to %u\n", v);
+		wpa_printf(MSG_INFO, "Unable to set group key cipher to %u", v);
 		return -1;
 	}
 	if (v == IEEE80211_CIPHER_WEP) {
 		/* key length is done only for specific ciphers */
 		v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
 		if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
-			printf("Unable to set group key length to %u\n", v);
+			wpa_printf(MSG_INFO,
+				   "Unable to set group key length to %u", v);
 			return -1;
 		}
 	}
@@ -319,7 +320,8 @@
 		v |= 1<<IEEE80211_CIPHER_NONE;
 	wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
 	if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
-		printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+		wpa_printf(MSG_INFO,
+			   "Unable to set pairwise key ciphers to 0x%x", v);
 		return -1;
 	}
 
@@ -327,8 +329,9 @@
 		   __func__, params->wpa_key_mgmt);
 	if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
 			  params->wpa_key_mgmt)) {
-		printf("Unable to set key management algorithms to 0x%x\n",
-			params->wpa_key_mgmt);
+		wpa_printf(MSG_INFO,
+			   "Unable to set key management algorithms to 0x%x",
+			   params->wpa_key_mgmt);
 		return -1;
 	}
 
@@ -345,13 +348,14 @@
 
 	wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x", __func__, v);
 	if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
-		printf("Unable to set RSN capabilities to 0x%x\n", v);
+		wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x",
+			   v);
 		return -1;
 	}
 
 	wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
 	if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
-		printf("Unable to set WPA to %u\n", params->wpa);
+		wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa);
 		return -1;
 	}
 	return 0;
@@ -518,14 +522,14 @@
 #endif /* ATH_GCM_SUPPORT */
 #endif /* CONFIG_IEEE80211W */
 	default:
-		printf("%s: unknown/unsupported algorithm %d\n",
-			__func__, alg);
+		wpa_printf(MSG_INFO, "%s: unknown/unsupported algorithm %d",
+			   __func__, alg);
 		return -1;
 	}
 
 	if (key_len > sizeof(wk.ik_keydata)) {
-		printf("%s: key length %lu too big\n", __func__,
-		       (unsigned long) key_len);
+		wpa_printf(MSG_INFO, "%s: key length %lu too big", __func__,
+			   (unsigned long) key_len);
 		return -3;
 	}
 
@@ -636,7 +640,8 @@
 			return 0;
 		}
 
-		printf("Failed to get station stats information element.\n");
+		wpa_printf(MSG_INFO,
+			   "Failed to get station stats information element");
 		return -1;
 	}
 
@@ -769,145 +774,6 @@
 	return ret;
 }
 
-#ifdef CONFIG_WPS
-static void atheros_raw_recv_wps(void *ctx, const u8 *src_addr, const u8 *buf,
-				 size_t len)
-{
-	struct atheros_driver_data *drv = ctx;
-	const struct ieee80211_mgmt *mgmt;
-	u16 fc;
-	union wpa_event_data event;
-
-	/* Send Probe Request information to WPS processing */
-
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
-		return;
-	mgmt = (const struct ieee80211_mgmt *) buf;
-
-	fc = le_to_host16(mgmt->frame_control);
-	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
-	    WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
-		return;
-
-	os_memset(&event, 0, sizeof(event));
-	event.rx_probe_req.sa = mgmt->sa;
-	event.rx_probe_req.da = mgmt->da;
-	event.rx_probe_req.bssid = mgmt->bssid;
-	event.rx_probe_req.ie = mgmt->u.probe_req.variable;
-	event.rx_probe_req.ie_len =
-		len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
-	wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
-}
-#endif /* CONFIG_WPS */
-
-#ifdef CONFIG_IEEE80211R
-static void atheros_raw_recv_11r(void *ctx, const u8 *src_addr, const u8 *buf,
-				 size_t len)
-{
-	struct atheros_driver_data *drv = ctx;
-	union wpa_event_data event;
-	const struct ieee80211_mgmt *mgmt;
-	u16 fc;
-	u16 stype;
-	int ielen;
-	const u8 *iebuf;
-
-	/* Do 11R processing for ASSOC/AUTH/FT ACTION frames */
-	if (len < IEEE80211_HDRLEN)
-		return;
-	mgmt = (const struct ieee80211_mgmt *) buf;
-
-	fc = le_to_host16(mgmt->frame_control);
-
-	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
-		return;
-	stype = WLAN_FC_GET_STYPE(fc);
-
-	wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
-		   (int) len);
-
-	if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
-			   __func__);
-		return;
-	}
-	switch (stype) {
-	case WLAN_FC_STYPE_ASSOC_REQ:
-		if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.assoc_req))
-			break;
-		ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
-		iebuf = mgmt->u.assoc_req.variable;
-		drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0);
-		break;
-	case WLAN_FC_STYPE_REASSOC_REQ:
-		if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.reassoc_req))
-			break;
-		ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
-		iebuf = mgmt->u.reassoc_req.variable;
-		drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
-		break;
-	case WLAN_FC_STYPE_ACTION:
-		os_memset(&event, 0, sizeof(event));
-		event.rx_mgmt.frame = buf;
-		event.rx_mgmt.frame_len = len;
-		wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
-		break;
-	case WLAN_FC_STYPE_AUTH:
-		if (len - IEEE80211_HDRLEN < sizeof(mgmt->u.auth))
-			break;
-		os_memset(&event, 0, sizeof(event));
-		os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
-		os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN);
-		event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
-		event.auth.status_code =
-			le_to_host16(mgmt->u.auth.status_code);
-		event.auth.auth_transaction =
-			le_to_host16(mgmt->u.auth.auth_transaction);
-		event.auth.ies = mgmt->u.auth.variable;
-		event.auth.ies_len = len - IEEE80211_HDRLEN -
-			sizeof(mgmt->u.auth);
-		wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event);
-		break;
-	default:
-		break;
-	}
-}
-#endif /* CONFIG_IEEE80211R */
-
-#ifdef CONFIG_HS20
-static void atheros_raw_recv_hs20(void *ctx, const u8 *src_addr, const u8 *buf,
-				 size_t len)
-{
-	struct atheros_driver_data *drv = ctx;
-	const struct ieee80211_mgmt *mgmt;
-	u16 fc;
-	union wpa_event_data event;
-
-	/* Send the Action frame for HS20 processing */
-
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.action.category) +
-	    sizeof(mgmt->u.action.u.public_action))
-		return;
-
-	mgmt = (const struct ieee80211_mgmt *) buf;
-
-	fc = le_to_host16(mgmt->frame_control);
-	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
-	    WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_ACTION ||
-	    mgmt->u.action.category != WLAN_ACTION_PUBLIC)
-		return;
-
-	wpa_printf(MSG_DEBUG, "%s:Received Public Action frame", __func__);
-
-	os_memset(&event, 0, sizeof(event));
-	event.rx_mgmt.frame = (const u8 *) mgmt;
-	event.rx_mgmt.frame_len = len;
-	wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
-}
-
-#endif /* CONFIG_HS20 */
-
-
 static int atheros_set_qos_map(void *ctx, const u8 *qos_map_set,
 			       u8 qos_map_set_len)
 {
@@ -947,9 +813,9 @@
 	}
 
 	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_DBGREQ, &iwr) < 0) {
-		perror("ioctl[IEEE80211_IOCTL_DBGREQ]");
-		wpa_printf(MSG_DEBUG, "%s: %s: Failed to set QoS Map",
-			   __func__, drv->iface);
+		wpa_printf(MSG_ERROR,
+			   "%s: %s: Failed to set QoS Map: ioctl[IEEE80211_IOCTL_DBGREQ]: %s",
+			   __func__, drv->iface, strerror(errno));
 		return -1;
 	}
 #endif /* CONFIG_ATHEROS_QOS_MAP */
@@ -957,30 +823,47 @@
 	return 0;
 }
 
-#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
-static void atheros_raw_recv_11v(void *ctx, const u8 *src_addr, const u8 *buf,
-				 size_t len)
+#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM) || defined(CONFIG_HS20)
+static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+				size_t len)
 {
 	struct atheros_driver_data *drv = ctx;
-	union wpa_event_data event;
 	const struct ieee80211_mgmt *mgmt;
-	u16 fc;
-	u16 stype;
+	union wpa_event_data event;
+	u16 fc, stype;
+	int ielen;
+	const u8 *iebuf;
 
-	/* Do 11R processing for WNM ACTION frames */
 	if (len < IEEE80211_HDRLEN)
 		return;
+
 	mgmt = (const struct ieee80211_mgmt *) buf;
 
 	fc = le_to_host16(mgmt->frame_control);
 
 	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT)
 		return;
+
 	stype = WLAN_FC_GET_STYPE(fc);
 
 	wpa_printf(MSG_DEBUG, "%s: subtype 0x%x len %d", __func__, stype,
 		   (int) len);
 
+	if (stype == WLAN_FC_STYPE_PROBE_REQ) {
+		if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+			return;
+
+		os_memset(&event, 0, sizeof(event));
+		event.rx_probe_req.sa = mgmt->sa;
+		event.rx_probe_req.da = mgmt->da;
+		event.rx_probe_req.bssid = mgmt->bssid;
+		event.rx_probe_req.ie = mgmt->u.probe_req.variable;
+		event.rx_probe_req.ie_len =
+			len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+		wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
+		return;
+	}
+
 	if (os_memcmp(drv->own_addr, mgmt->bssid, ETH_ALEN) != 0) {
 		wpa_printf(MSG_DEBUG, "%s: BSSID does not match - ignore",
 			   __func__);
@@ -988,36 +871,47 @@
 	}
 
 	switch (stype) {
+	case WLAN_FC_STYPE_ASSOC_REQ:
+		if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req))
+			break;
+		ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
+		iebuf = mgmt->u.assoc_req.variable;
+		drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 0);
+		break;
+	case WLAN_FC_STYPE_REASSOC_REQ:
+		if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req))
+			break;
+		ielen = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
+		iebuf = mgmt->u.reassoc_req.variable;
+		drv_event_assoc(drv->hapd, mgmt->sa, iebuf, ielen, 1);
+		break;
 	case WLAN_FC_STYPE_ACTION:
 		os_memset(&event, 0, sizeof(event));
 		event.rx_mgmt.frame = buf;
 		event.rx_mgmt.frame_len = len;
 		wpa_supplicant_event(drv->hapd, EVENT_RX_MGMT, &event);
 		break;
+	case WLAN_FC_STYPE_AUTH:
+		if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth))
+			break;
+		os_memset(&event, 0, sizeof(event));
+		os_memcpy(event.auth.peer, mgmt->sa, ETH_ALEN);
+		os_memcpy(event.auth.bssid, mgmt->bssid, ETH_ALEN);
+		event.auth.auth_type = le_to_host16(mgmt->u.auth.auth_alg);
+		event.auth.status_code =
+			le_to_host16(mgmt->u.auth.status_code);
+		event.auth.auth_transaction =
+			le_to_host16(mgmt->u.auth.auth_transaction);
+		event.auth.ies = mgmt->u.auth.variable;
+		event.auth.ies_len = len - IEEE80211_HDRLEN -
+			sizeof(mgmt->u.auth);
+		wpa_supplicant_event(drv->hapd, EVENT_AUTH, &event);
+		break;
 	default:
 		break;
 	}
 }
-#endif /* CONFIG_WNM */
-
-#if defined(CONFIG_WPS) || defined(CONFIG_IEEE80211R) || defined(CONFIG_WNM)
-static void atheros_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
-				size_t len)
-{
-#ifdef CONFIG_WPS
-	atheros_raw_recv_wps(ctx, src_addr, buf, len);
-#endif /* CONFIG_WPS */
-#ifdef CONFIG_IEEE80211R
-	atheros_raw_recv_11r(ctx, src_addr, buf, len);
-#endif /* CONFIG_IEEE80211R */
-#if defined(CONFIG_WNM) && !defined(CONFIG_IEEE80211R)
-	atheros_raw_recv_11v(ctx, src_addr, buf, len);
-#endif /* CONFIG_WNM */
-#ifdef CONFIG_HS20
-	atheros_raw_recv_hs20(ctx, src_addr, buf, len);
-#endif /* CONFIG_HS20 */
-}
-#endif /* CONFIG_WPS || CONFIG_IEEE80211R */
+#endif
 
 static int atheros_receive_pkt(struct atheros_driver_data *drv)
 {
@@ -1606,8 +1500,9 @@
 		sizeof(range->enc_capa);
 
 	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWRANGE]");
-		free(range);
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s",
+			   strerror(errno));
+		os_free(range);
 		return -1;
 	} else if (iwr.u.data.length >= minlen &&
 		   range->we_version_compiled >= 18) {
@@ -1667,8 +1562,9 @@
 	if (len > sizeof(buf)) {
 		bp = malloc(len);
 		if (bp == NULL) {
-			printf("EAPOL frame discarded, cannot malloc temp "
-			       "buffer of size %lu!\n", (unsigned long) len);
+			wpa_printf(MSG_INFO,
+				   "EAPOL frame discarded, cannot malloc temp buffer of size %lu!",
+				   (unsigned long) len);
 			return -1;
 		}
 	}
@@ -1705,14 +1601,16 @@
 
 	drv = os_zalloc(sizeof(struct atheros_driver_data));
 	if (drv == NULL) {
-		printf("Could not allocate memory for atheros driver data\n");
+		wpa_printf(MSG_INFO,
+			   "Could not allocate memory for atheros driver data");
 		return NULL;
 	}
 
 	drv->hapd = hapd;
 	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (drv->ioctl_sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
+		wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
 		goto bad;
 	}
 	memcpy(drv->iface, params->ifname, sizeof(drv->iface));
@@ -1720,7 +1618,8 @@
 	memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
 	if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
+		wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+			   strerror(errno));
 		goto bad;
 	}
 	drv->ifindex = ifr.ifr_ifindex;
@@ -1756,8 +1655,9 @@
 	iwr.u.mode = IW_MODE_MASTER;
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWMODE]");
-		printf("Could not set interface to master mode!\n");
+		wpa_printf(MSG_ERROR,
+			   "Could not set interface to master mode! ioctl[SIOCSIWMODE]: %s",
+			   strerror(errno));
 		goto bad;
 	}
 
@@ -1823,8 +1723,8 @@
 	iwr.u.essid.length = len + 1;
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCSIWESSID]");
-		printf("len=%d\n", len);
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s",
+			   len, strerror(errno));
 		return -1;
 	}
 	return 0;
@@ -1844,7 +1744,8 @@
 		IW_ESSID_MAX_SIZE : len;
 
 	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCGIWESSID]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s",
+			   strerror(errno));
 		ret = -1;
 	} else
 		ret = iwr.u.essid.length;
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
index ca64d5c..c377970 100644
--- a/src/drivers/driver_bsd.c
+++ b/src/drivers/driver_bsd.c
@@ -264,7 +264,8 @@
 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 
 	if (ioctl(drv->sock, SIOCGIFFLAGS, &ifr) < 0) {
-		perror("ioctl[SIOCGIFFLAGS]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -279,7 +280,8 @@
 	}
 
 	if (ioctl(drv->sock, SIOCSIFFLAGS, &ifr) < 0) {
-		perror("ioctl[SIOCSIFFLAGS]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -404,22 +406,24 @@
 		v = IEEE80211_CIPHER_NONE;
 		break;
 	default:
-		printf("Unknown group key cipher %u\n",
-			params->wpa_group);
+		wpa_printf(MSG_INFO, "Unknown group key cipher %u",
+			   params->wpa_group);
 		return -1;
 	}
 	wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
 		   __func__, ciphernames[v], v);
 	if (set80211param(priv, IEEE80211_IOC_MCASTCIPHER, v)) {
-		printf("Unable to set group key cipher to %u (%s)\n",
-			v, ciphernames[v]);
+		wpa_printf(MSG_INFO,
+			   "Unable to set group key cipher to %u (%s)",
+			   v, ciphernames[v]);
 		return -1;
 	}
 	if (v == IEEE80211_CIPHER_WEP) {
 		/* key length is done only for specific ciphers */
 		v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
 		if (set80211param(priv, IEEE80211_IOC_MCASTKEYLEN, v)) {
-			printf("Unable to set group key length to %u\n", v);
+			wpa_printf(MSG_INFO,
+				   "Unable to set group key length to %u", v);
 			return -1;
 		}
 	}
@@ -433,7 +437,8 @@
 		v |= 1<<IEEE80211_CIPHER_NONE;
 	wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
 	if (set80211param(priv, IEEE80211_IOC_UCASTCIPHERS, v)) {
-		printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+		wpa_printf(MSG_INFO,
+			   "Unable to set pairwise key ciphers to 0x%x", v);
 		return -1;
 	}
 
@@ -441,8 +446,9 @@
 		   __func__, params->wpa_key_mgmt);
 	if (set80211param(priv, IEEE80211_IOC_KEYMGTALGS,
 			  params->wpa_key_mgmt)) {
-		printf("Unable to set key management algorithms to 0x%x\n",
-			params->wpa_key_mgmt);
+		wpa_printf(MSG_INFO,
+			   "Unable to set key management algorithms to 0x%x",
+			   params->wpa_key_mgmt);
 		return -1;
 	}
 
@@ -452,14 +458,15 @@
 	wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
 		   __func__, params->rsn_preauth);
 	if (set80211param(priv, IEEE80211_IOC_RSNCAPS, v)) {
-		printf("Unable to set RSN capabilities to 0x%x\n", v);
+		wpa_printf(MSG_INFO, "Unable to set RSN capabilities to 0x%x",
+			   v);
 		return -1;
 	}
 #endif /* IEEE80211_IOC_APPIE */
 
 	wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, params->wpa);
 	if (set80211param(priv, IEEE80211_IOC_WPA, params->wpa)) {
-		printf("Unable to set WPA to %u\n", params->wpa);
+		wpa_printf(MSG_INFO, "Unable to set WPA to %u", params->wpa);
 		return -1;
 	}
 	return 0;
@@ -507,7 +514,8 @@
 	memset(&ie, 0, sizeof(ie));
 	memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
 	if (get80211var(priv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
-		printf("Failed to get WPA/RSN information element.\n");
+		wpa_printf(MSG_INFO,
+			   "Failed to get WPA/RSN information element");
 		goto no_ie;
 	}
 	iebuf = ie.wpa_ie;
@@ -594,7 +602,7 @@
 	int mib[6] = {CTL_NET, AF_ROUTE, 0, AF_INET, NET_RT_DUMP, 0};
 
 	if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
-		wpa_printf(MSG_WARNING, "%s failed: %s\n", __func__,
+		wpa_printf(MSG_WARNING, "%s failed: %s", __func__,
 			   strerror(errno));
 		len = 2048;
 	}
@@ -652,7 +660,7 @@
 	wk.ik_keyix = idx;
 
 	if (get80211var(priv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
-		printf("Failed to get encryption.\n");
+		wpa_printf(MSG_INFO, "Failed to get encryption");
 		return -1;
 	}
 
@@ -734,7 +742,7 @@
 	n = read(sock, drv->event_buf, drv->event_buf_len);
 	if (n < 0) {
 		if (errno != EINTR && errno != EAGAIN)
-			wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+			wpa_printf(MSG_ERROR, "%s read() failed: %s",
 				   __func__, strerror(errno));
 		return;
 	}
@@ -814,7 +822,8 @@
 	drv->hapd = hapd;
 	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (drv->sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
+		wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
 		goto bad;
 	}
 	os_strlcpy(drv->ifname, params->ifname, sizeof(drv->ifname));
@@ -832,7 +841,8 @@
 
 	drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
 	if (drv->route < 0) {
-		perror("socket(PF_ROUTE,SOCK_RAW)");
+		wpa_printf(MSG_ERROR, "socket(PF_ROUTE,SOCK_RAW): %s",
+			   strerror(errno));
 		goto bad;
 	}
 	eloop_register_read_sock(drv->route, bsd_wireless_event_receive, drv,
@@ -1189,7 +1199,7 @@
 	n = read(sock, drv->event_buf, drv->event_buf_len);
 	if (n < 0) {
 		if (errno != EINTR && errno != EAGAIN)
-			wpa_printf(MSG_ERROR, "%s read() failed: %s\n",
+			wpa_printf(MSG_ERROR, "%s read() failed: %s",
 				   __func__, strerror(errno));
 		return;
 	}
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
index 77e6905..f897c11 100644
--- a/src/drivers/driver_common.c
+++ b/src/drivers/driver_common.c
@@ -44,14 +44,12 @@
 	E2S(ASSOC_REJECT);
 	E2S(AUTH_TIMED_OUT);
 	E2S(ASSOC_TIMED_OUT);
-	E2S(FT_RRB_RX);
 	E2S(WPS_BUTTON_PUSHED);
 	E2S(TX_STATUS);
 	E2S(RX_FROM_UNKNOWN);
 	E2S(RX_MGMT);
 	E2S(REMAIN_ON_CHANNEL);
 	E2S(CANCEL_REMAIN_ON_CHANNEL);
-	E2S(MLME_RX);
 	E2S(RX_PROBE_REQ);
 	E2S(NEW_STA);
 	E2S(EAPOL_RX);
@@ -79,6 +77,8 @@
 	E2S(SURVEY);
 	E2S(SCAN_STARTED);
 	E2S(AVOID_FREQUENCIES);
+	E2S(NEW_PEER_CANDIDATE);
+	E2S(ACS_CHANNEL_SELECTED);
 	}
 
 	return "UNKNOWN";
@@ -105,3 +105,115 @@
 		return "unknown";
 	}
 }
+
+
+int ht_supported(const struct hostapd_hw_modes *mode)
+{
+	if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
+		/*
+		 * The driver did not indicate whether it supports HT. Assume
+		 * it does to avoid connection issues.
+		 */
+		return 1;
+	}
+
+	/*
+	 * IEEE Std 802.11n-2009 20.1.1:
+	 * An HT non-AP STA shall support all EQM rates for one spatial stream.
+	 */
+	return mode->mcs_set[0] == 0xff;
+}
+
+
+int vht_supported(const struct hostapd_hw_modes *mode)
+{
+	if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) {
+		/*
+		 * The driver did not indicate whether it supports VHT. Assume
+		 * it does to avoid connection issues.
+		 */
+		return 1;
+	}
+
+	/*
+	 * A VHT non-AP STA shall support MCS 0-7 for one spatial stream.
+	 * TODO: Verify if this complies with the standard
+	 */
+	return (mode->vht_mcs_set[0] & 0x3) != 3;
+}
+
+
+static int wpa_check_wowlan_trigger(const char *start, const char *trigger,
+				    int capa_trigger, u8 *param_trigger)
+{
+	if (os_strcmp(start, trigger) != 0)
+		return 0;
+	if (!capa_trigger)
+		return 0;
+
+	*param_trigger = 1;
+	return 1;
+}
+
+
+struct wowlan_triggers *
+wpa_get_wowlan_triggers(const char *wowlan_triggers,
+			const struct wpa_driver_capa *capa)
+{
+	struct wowlan_triggers *triggers;
+	char *start, *end, *buf;
+	int last;
+
+	if (!wowlan_triggers)
+		return NULL;
+
+	buf = os_strdup(wowlan_triggers);
+	if (buf == NULL)
+		return NULL;
+
+	triggers = os_zalloc(sizeof(*triggers));
+	if (triggers == NULL)
+		goto out;
+
+#define CHECK_TRIGGER(trigger) \
+	wpa_check_wowlan_trigger(start, #trigger,			\
+				  capa->wowlan_triggers.trigger,	\
+				  &triggers->trigger)
+
+	start = buf;
+	while (*start != '\0') {
+		while (isblank(*start))
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (!isblank(*end) && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+
+		if (!CHECK_TRIGGER(any) &&
+		    !CHECK_TRIGGER(disconnect) &&
+		    !CHECK_TRIGGER(magic_pkt) &&
+		    !CHECK_TRIGGER(gtk_rekey_failure) &&
+		    !CHECK_TRIGGER(eap_identity_req) &&
+		    !CHECK_TRIGGER(four_way_handshake) &&
+		    !CHECK_TRIGGER(rfkill_release)) {
+			wpa_printf(MSG_DEBUG,
+				   "Unknown/unsupported wowlan trigger '%s'",
+				   start);
+			os_free(triggers);
+			triggers = NULL;
+			goto out;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+#undef CHECK_TRIGGER
+
+out:
+	os_free(buf);
+	return triggers;
+}
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index 16f5563..84b98fb 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -214,7 +214,7 @@
 
 	len = recv(sock, buf, sizeof(buf), 0);
 	if (len < 0) {
-		perror("recv");
+		wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
 		return;
 	}
 
@@ -229,19 +229,21 @@
 
 	drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
 	if (drv->sock < 0) {
-		perror("socket[PF_PACKET,SOCK_RAW]");
+		wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
 	if (eloop_register_read_sock(drv->sock, handle_read, drv, NULL)) {
-		printf("Could not register read socket\n");
+		wpa_printf(MSG_ERROR, "Could not register read socket");
 		return -1;
 	}
 
         memset(&ifr, 0, sizeof(ifr));
         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
         if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
+		wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+			   strerror(errno));
 		return -1;
         }
 
@@ -256,7 +258,7 @@
 		   addr.sll_ifindex);
 
 	if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
+		wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
 		return -1;
 	}
 
@@ -361,9 +363,9 @@
 		os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
 		ifr.ifr_mtu = HOSTAPD_MTU;
 		if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
-			perror("ioctl[SIOCSIFMTU]");
-			printf("Setting MTU failed - trying to survive with "
-			       "current value\n");
+			wpa_printf(MSG_INFO,
+				   "Setting MTU failed - trying to survive with current value: ioctl[SIOCSIFMTU]: %s",
+				   strerror(errno));
 		}
 	}
 
@@ -383,7 +385,8 @@
 	iwr.u.data.length = len;
 
 	if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
-		perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
+		wpa_printf(MSG_ERROR, "ioctl[PRISM2_IOCTL_HOSTAPD]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -497,7 +500,8 @@
 	*i++ = value;
 
 	if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
-		perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
+		wpa_printf(MSG_ERROR, "ioctl[PRISM2_IOCTL_PRISM2_PARAM]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -554,8 +558,8 @@
 	iwr.u.essid.length = len + 1;
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCSIWESSID]");
-		printf("len=%d\n", len);
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID,len=%d]: %s",
+			   len, strerror(errno));
 		return -1;
 	}
 
@@ -919,8 +923,9 @@
 		sizeof(range->enc_capa);
 
 	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWRANGE]");
-		free(range);
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s",
+			   strerror(errno));
+		os_free(range);
 		return -1;
 	} else if (iwr.u.data.length >= minlen &&
 		   range->we_version_compiled >= 18) {
@@ -975,23 +980,25 @@
 
 	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (drv->ioctl_sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
-		free(drv);
+		wpa_printf(MSG_ERROR, "socket[PF_INET,SOCK_DGRAM]: %s",
+			   strerror(errno));
+		os_free(drv);
 		return NULL;
 	}
 
 	if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) {
-		printf("Could not enable hostapd mode for interface %s\n",
-		       drv->iface);
+		wpa_printf(MSG_ERROR,
+			   "Could not enable hostapd mode for interface %s",
+			   drv->iface);
 		close(drv->ioctl_sock);
-		free(drv);
+		os_free(drv);
 		return NULL;
 	}
 
 	if (hostap_init_sockets(drv, params->own_addr) ||
 	    hostap_wireless_event_init(drv)) {
 		close(drv->ioctl_sock);
-		free(drv);
+		os_free(drv);
 		return NULL;
 	}
 
@@ -1060,7 +1067,8 @@
 	iwr.u.freq.e = 0;
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
-		perror("ioctl[SIOCSIWFREQ]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWFREQ]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
diff --git a/src/drivers/driver_macsec_qca.c b/src/drivers/driver_macsec_qca.c
index cf24799..3eae2f8 100644
--- a/src/drivers/driver_macsec_qca.c
+++ b/src/drivers/driver_macsec_qca.c
@@ -91,7 +91,7 @@
 	if (setsockopt(sock, SOL_PACKET,
 		       add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
 		       &mreq, sizeof(mreq)) < 0) {
-		perror("setsockopt");
+		wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
 		return -1;
 	}
 	return 0;
@@ -131,14 +131,15 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
 		return -1;
 	}
 
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
-		perror("ioctl[SIOCGIFFLAGS]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+			   strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -155,7 +156,7 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
 		return -1;
 	}
 
@@ -163,7 +164,8 @@
 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
 	ifr.ifr_flags = flags & 0xffff;
 	if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
-		perror("ioctl[SIOCSIFFLAGS]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+			   strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -180,14 +182,15 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_print(MSG_ERROR, "socket: %s", strerror(errno));
 		return -1;
 	}
 
 	os_memset(&ifmr, 0, sizeof(ifmr));
 	os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
-		perror("ioctl[SIOCGIFMEDIA]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
+			   strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -211,7 +214,7 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
 		return -1;
 	}
 
@@ -245,7 +248,8 @@
 #endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
 
 	if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
-		perror("ioctl[SIOC{ADD/DEL}MULTI]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
+			   strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -323,7 +327,7 @@
 #ifdef __linux__
 	drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
 	if (drv->pf_sock < 0)
-		perror("socket(PF_PACKET)");
+		wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
 #else /* __linux__ */
 	drv->pf_sock = -1;
 #endif /* __linux__ */
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
deleted file mode 100644
index 1635c1f..0000000
--- a/src/drivers/driver_madwifi.c
+++ /dev/null
@@ -1,1309 +0,0 @@
-/*
- * hostapd - driver interaction with MADWIFI 802.11 driver
- * Copyright (c) 2004, Sam Leffler <sam@errno.com>
- * Copyright (c) 2004, Video54 Technologies
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- *
- * This driver wrapper is only for hostapd AP mode functionality. Station
- * (wpa_supplicant) operations with madwifi are supported by the driver_wext.c
- * wrapper.
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "common.h"
-#include "driver.h"
-#include "driver_wext.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "linux_wext.h"
-
-/*
- * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
- */
-#undef WME_OUI_TYPE
-
-#include <include/compat.h>
-#include <net80211/ieee80211.h>
-#ifdef WME_NUM_AC
-/* Assume this is built against BSD branch of madwifi driver. */
-#define MADWIFI_BSD
-#include <net80211/_ieee80211.h>
-#endif /* WME_NUM_AC */
-#include <net80211/ieee80211_crypto.h>
-#include <net80211/ieee80211_ioctl.h>
-
-#ifdef CONFIG_WPS
-#ifdef IEEE80211_IOCTL_FILTERFRAME
-#include <netpacket/packet.h>
-
-#ifndef ETH_P_80211_RAW
-#define ETH_P_80211_RAW 0x0019
-#endif
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
-#endif /* CONFIG_WPS */
-
-/*
- * Avoid conflicts with hostapd definitions by undefining couple of defines
- * from madwifi header files.
- */
-#undef RSN_VERSION
-#undef WPA_VERSION
-#undef WPA_OUI_TYPE
-#undef WME_OUI_TYPE
-
-
-#ifdef IEEE80211_IOCTL_SETWMMPARAMS
-/* Assume this is built against madwifi-ng */
-#define MADWIFI_NG
-#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
-
-#define WPA_KEY_RSC_LEN 8
-
-#include "priv_netlink.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-#include "l2_packet/l2_packet.h"
-
-
-struct madwifi_driver_data {
-	struct hostapd_data *hapd;		/* back pointer */
-
-	char	iface[IFNAMSIZ + 1];
-	int     ifindex;
-	struct l2_packet_data *sock_xmit;	/* raw packet xmit socket */
-	struct l2_packet_data *sock_recv;	/* raw packet recv socket */
-	int	ioctl_sock;			/* socket for ioctl() use */
-	struct netlink_data *netlink;
-	int	we_version;
-	u8	acct_mac[ETH_ALEN];
-	struct hostap_sta_driver_data acct_data;
-
-	struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
-};
-
-static int madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
-			      int reason_code);
-
-static int
-set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
-{
-	struct iwreq iwr;
-	int do_inline = len < IFNAMSIZ;
-
-	memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-#ifdef IEEE80211_IOCTL_FILTERFRAME
-	/* FILTERFRAME must be NOT inline, regardless of size. */
-	if (op == IEEE80211_IOCTL_FILTERFRAME)
-		do_inline = 0;
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
-	if (op == IEEE80211_IOCTL_SET_APPIEBUF)
-		do_inline = 0;
-	if (do_inline) {
-		/*
-		 * Argument data fits inline; put it there.
-		 */
-		memcpy(iwr.u.name, data, len);
-	} else {
-		/*
-		 * Argument data too big for inline transfer; setup a
-		 * parameter block instead; the kernel will transfer
-		 * the data for the driver.
-		 */
-		iwr.u.data.pointer = data;
-		iwr.u.data.length = len;
-	}
-
-	if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
-#ifdef MADWIFI_NG
-		int first = IEEE80211_IOCTL_SETPARAM;
-		static const char *opnames[] = {
-			"ioctl[IEEE80211_IOCTL_SETPARAM]",
-			"ioctl[IEEE80211_IOCTL_GETPARAM]",
-			"ioctl[IEEE80211_IOCTL_SETMODE]",
-			"ioctl[IEEE80211_IOCTL_GETMODE]",
-			"ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
-			"ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
-			"ioctl[IEEE80211_IOCTL_SETCHANLIST]",
-			"ioctl[IEEE80211_IOCTL_GETCHANLIST]",
-			"ioctl[IEEE80211_IOCTL_CHANSWITCH]",
-			"ioctl[IEEE80211_IOCTL_GET_APPIEBUF]",
-			"ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
-			"ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
-			"ioctl[IEEE80211_IOCTL_FILTERFRAME]",
-			"ioctl[IEEE80211_IOCTL_GETCHANINFO]",
-			"ioctl[IEEE80211_IOCTL_SETOPTIE]",
-			"ioctl[IEEE80211_IOCTL_GETOPTIE]",
-			"ioctl[IEEE80211_IOCTL_SETMLME]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_SETKEY]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_DELKEY]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_ADDMAC]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_DELMAC]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_WDSMAC]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_WDSDELMAC]",
-			NULL,
-			"ioctl[IEEE80211_IOCTL_KICKMAC]",
-		};
-#else /* MADWIFI_NG */
-		int first = IEEE80211_IOCTL_SETPARAM;
-		static const char *opnames[] = {
-			"ioctl[IEEE80211_IOCTL_SETPARAM]",
-			"ioctl[IEEE80211_IOCTL_GETPARAM]",
-			"ioctl[IEEE80211_IOCTL_SETKEY]",
-			"ioctl[SIOCIWFIRSTPRIV+3]",
-			"ioctl[IEEE80211_IOCTL_DELKEY]",
-			"ioctl[SIOCIWFIRSTPRIV+5]",
-			"ioctl[IEEE80211_IOCTL_SETMLME]",
-			"ioctl[SIOCIWFIRSTPRIV+7]",
-			"ioctl[IEEE80211_IOCTL_SETOPTIE]",
-			"ioctl[IEEE80211_IOCTL_GETOPTIE]",
-			"ioctl[IEEE80211_IOCTL_ADDMAC]",
-			"ioctl[SIOCIWFIRSTPRIV+11]",
-			"ioctl[IEEE80211_IOCTL_DELMAC]",
-			"ioctl[SIOCIWFIRSTPRIV+13]",
-			"ioctl[IEEE80211_IOCTL_CHANLIST]",
-			"ioctl[SIOCIWFIRSTPRIV+15]",
-			"ioctl[IEEE80211_IOCTL_GETRSN]",
-			"ioctl[SIOCIWFIRSTPRIV+17]",
-			"ioctl[IEEE80211_IOCTL_GETKEY]",
-		};
-#endif /* MADWIFI_NG */
-		int idx = op - first;
-		if (first <= op &&
-		    idx < (int) ARRAY_SIZE(opnames) &&
-		    opnames[idx])
-			perror(opnames[idx]);
-		else
-			perror("ioctl[unknown???]");
-		return -1;
-	}
-	return 0;
-}
-
-static int
-set80211param(struct madwifi_driver_data *drv, int op, int arg)
-{
-	struct iwreq iwr;
-
-	memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-	iwr.u.mode = op;
-	memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
-
-	if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
-		perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
-		wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d "
-			   "arg %d)", __func__, op, arg);
-		return -1;
-	}
-	return 0;
-}
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-static const char *
-ether_sprintf(const u8 *addr)
-{
-	static char buf[sizeof(MACSTR)];
-
-	if (addr != NULL)
-		snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
-	else
-		snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
-	return buf;
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-/*
- * Configure WPA parameters.
- */
-static int
-madwifi_configure_wpa(struct madwifi_driver_data *drv,
-		      struct wpa_bss_params *params)
-{
-	int v;
-
-	switch (params->wpa_group) {
-	case WPA_CIPHER_CCMP:
-		v = IEEE80211_CIPHER_AES_CCM;
-		break;
-	case WPA_CIPHER_TKIP:
-		v = IEEE80211_CIPHER_TKIP;
-		break;
-	case WPA_CIPHER_WEP104:
-		v = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_CIPHER_WEP40:
-		v = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_CIPHER_NONE:
-		v = IEEE80211_CIPHER_NONE;
-		break;
-	default:
-		wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
-			   params->wpa_group);
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
-	if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
-		printf("Unable to set group key cipher to %u\n", v);
-		return -1;
-	}
-	if (v == IEEE80211_CIPHER_WEP) {
-		/* key length is done only for specific ciphers */
-		v = (params->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
-		if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
-			printf("Unable to set group key length to %u\n", v);
-			return -1;
-		}
-	}
-
-	v = 0;
-	if (params->wpa_pairwise & WPA_CIPHER_CCMP)
-		v |= 1<<IEEE80211_CIPHER_AES_CCM;
-	if (params->wpa_pairwise & WPA_CIPHER_TKIP)
-		v |= 1<<IEEE80211_CIPHER_TKIP;
-	if (params->wpa_pairwise & WPA_CIPHER_NONE)
-		v |= 1<<IEEE80211_CIPHER_NONE;
-	wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
-	if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
-		printf("Unable to set pairwise key ciphers to 0x%x\n", v);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
-		   __func__, params->wpa_key_mgmt);
-	if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS,
-			  params->wpa_key_mgmt)) {
-		printf("Unable to set key management algorithms to 0x%x\n",
-			params->wpa_key_mgmt);
-		return -1;
-	}
-
-	v = 0;
-	if (params->rsn_preauth)
-		v |= BIT(0);
-	wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
-		   __func__, params->rsn_preauth);
-	if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
-		printf("Unable to set RSN capabilities to 0x%x\n", v);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, params->wpa);
-	if (set80211param(drv, IEEE80211_PARAM_WPA, params->wpa)) {
-		printf("Unable to set WPA to %u\n", params->wpa);
-		return -1;
-	}
-	return 0;
-}
-
-static int
-madwifi_set_ieee8021x(void *priv, struct wpa_bss_params *params)
-{
-	struct madwifi_driver_data *drv = priv;
-
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, params->enabled);
-
-	if (!params->enabled) {
-		/* XXX restore state */
-		return set80211param(priv, IEEE80211_PARAM_AUTHMODE,
-			IEEE80211_AUTH_AUTO);
-	}
-	if (!params->wpa && !params->ieee802_1x) {
-		wpa_printf(MSG_WARNING, "No 802.1X or WPA enabled!");
-		return -1;
-	}
-	if (params->wpa && madwifi_configure_wpa(drv, params) != 0) {
-		wpa_printf(MSG_WARNING, "Error configuring WPA state!");
-		return -1;
-	}
-	if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
-		(params->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
-		wpa_printf(MSG_WARNING, "Error enabling WPA/802.1X!");
-		return -1;
-	}
-
-	return 0;
-}
-
-static int
-madwifi_set_privacy(void *priv, int enabled)
-{
-	struct madwifi_driver_data *drv = priv;
-
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
-
-	return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
-}
-
-static int
-madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
-		   __func__, ether_sprintf(addr), authorized);
-
-	if (authorized)
-		mlme.im_op = IEEE80211_MLME_AUTHORIZE;
-	else
-		mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
-	mlme.im_reason = 0;
-	memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-	ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR,
-			   __func__, authorized ? "" : "un", MAC2STR(addr));
-	}
-
-	return ret;
-}
-
-static int
-madwifi_sta_set_flags(void *priv, const u8 *addr,
-		      int total_flags, int flags_or, int flags_and)
-{
-	/* For now, only support setting Authorized flag */
-	if (flags_or & WPA_STA_AUTHORIZED)
-		return madwifi_set_sta_authorized(priv, addr, 1);
-	if (!(flags_and & WPA_STA_AUTHORIZED))
-		return madwifi_set_sta_authorized(priv, addr, 0);
-	return 0;
-}
-
-static int
-madwifi_del_key(void *priv, const u8 *addr, int key_idx)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_del_key wk;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
-		   __func__, ether_sprintf(addr), key_idx);
-
-	memset(&wk, 0, sizeof(wk));
-	if (addr != NULL) {
-		memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
-		wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
-	} else {
-		wk.idk_keyix = key_idx;
-	}
-
-	ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
-			   " key_idx %d)", __func__, ether_sprintf(addr),
-			   key_idx);
-	}
-
-	return ret;
-}
-
-static int
-wpa_driver_madwifi_set_key(const char *ifname, void *priv, enum wpa_alg alg,
-			   const u8 *addr, int key_idx, int set_tx,
-			   const u8 *seq, size_t seq_len,
-			   const u8 *key, size_t key_len)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_key wk;
-	u_int8_t cipher;
-	int ret;
-
-	if (alg == WPA_ALG_NONE)
-		return madwifi_del_key(drv, addr, key_idx);
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%s key_idx=%d",
-		   __func__, alg, ether_sprintf(addr), key_idx);
-
-	if (alg == WPA_ALG_WEP)
-		cipher = IEEE80211_CIPHER_WEP;
-	else if (alg == WPA_ALG_TKIP)
-		cipher = IEEE80211_CIPHER_TKIP;
-	else if (alg == WPA_ALG_CCMP)
-		cipher = IEEE80211_CIPHER_AES_CCM;
-	else {
-		printf("%s: unknown/unsupported algorithm %d\n",
-			__func__, alg);
-		return -1;
-	}
-
-	if (key_len > sizeof(wk.ik_keydata)) {
-		printf("%s: key length %lu too big\n", __func__,
-		       (unsigned long) key_len);
-		return -3;
-	}
-
-	memset(&wk, 0, sizeof(wk));
-	wk.ik_type = cipher;
-	wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
-	if (addr == NULL || is_broadcast_ether_addr(addr)) {
-		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
-		wk.ik_keyix = key_idx;
-		wk.ik_flags |= IEEE80211_KEY_DEFAULT;
-	} else {
-		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
-		wk.ik_keyix = IEEE80211_KEYIX_NONE;
-	}
-	wk.ik_keylen = key_len;
-	memcpy(wk.ik_keydata, key, key_len);
-
-	ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
-			   " key_idx %d alg %d key_len %lu set_tx %d)",
-			   __func__, ether_sprintf(wk.ik_macaddr), key_idx,
-			   alg, (unsigned long) key_len, set_tx);
-	}
-
-	return ret;
-}
-
-
-static int
-madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
-		   u8 *seq)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_key wk;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
-		   __func__, ether_sprintf(addr), idx);
-
-	memset(&wk, 0, sizeof(wk));
-	if (addr == NULL)
-		memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
-	else
-		memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
-	wk.ik_keyix = idx;
-
-	if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
-			   "(addr " MACSTR " key_idx %d)",
-			   __func__, MAC2STR(wk.ik_macaddr), idx);
-		return -1;
-	}
-
-#ifdef WORDS_BIGENDIAN
-	{
-		/*
-		 * wk.ik_keytsc is in host byte order (big endian), need to
-		 * swap it to match with the byte order used in WPA.
-		 */
-		int i;
-		u8 tmp[WPA_KEY_RSC_LEN];
-		memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
-		for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
-			seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
-		}
-	}
-#else /* WORDS_BIGENDIAN */
-	memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
-#endif /* WORDS_BIGENDIAN */
-	return 0;
-}
-
-
-static int 
-madwifi_flush(void *priv)
-{
-#ifdef MADWIFI_BSD
-	u8 allsta[IEEE80211_ADDR_LEN];
-	memset(allsta, 0xff, IEEE80211_ADDR_LEN);
-	return madwifi_sta_deauth(priv, NULL, allsta,
-				  IEEE80211_REASON_AUTH_LEAVE);
-#else /* MADWIFI_BSD */
-	return 0;		/* XXX */
-#endif /* MADWIFI_BSD */
-}
-
-
-static int
-madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
-			     const u8 *addr)
-{
-	struct madwifi_driver_data *drv = priv;
-
-#ifdef MADWIFI_BSD
-	struct ieee80211req_sta_stats stats;
-
-	memset(data, 0, sizeof(*data));
-
-	/*
-	 * Fetch statistics for station from the system.
-	 */
-	memset(&stats, 0, sizeof(stats));
-	memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
-	if (set80211priv(drv,
-#ifdef MADWIFI_NG
-			 IEEE80211_IOCTL_STA_STATS,
-#else /* MADWIFI_NG */
-			 IEEE80211_IOCTL_GETSTASTATS,
-#endif /* MADWIFI_NG */
-			 &stats, sizeof(stats))) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr "
-			   MACSTR ")", __func__, MAC2STR(addr));
-		if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
-			memcpy(data, &drv->acct_data, sizeof(*data));
-			return 0;
-		}
-
-		printf("Failed to get station stats information element.\n");
-		return -1;
-	}
-
-	data->rx_packets = stats.is_stats.ns_rx_data;
-	data->rx_bytes = stats.is_stats.ns_rx_bytes;
-	data->tx_packets = stats.is_stats.ns_tx_data;
-	data->tx_bytes = stats.is_stats.ns_tx_bytes;
-	return 0;
-
-#else /* MADWIFI_BSD */
-
-	char buf[1024], line[128], *pos;
-	FILE *f;
-	unsigned long val;
-
-	memset(data, 0, sizeof(*data));
-	snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR,
-		 drv->iface, MAC2STR(addr));
-
-	f = fopen(buf, "r");
-	if (!f) {
-		if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0)
-			return -1;
-		memcpy(data, &drv->acct_data, sizeof(*data));
-		return 0;
-	}
-	/* Need to read proc file with in one piece, so use large enough
-	 * buffer. */
-	setbuffer(f, buf, sizeof(buf));
-
-	while (fgets(line, sizeof(line), f)) {
-		pos = strchr(line, '=');
-		if (!pos)
-			continue;
-		*pos++ = '\0';
-		val = strtoul(pos, NULL, 10);
-		if (strcmp(line, "rx_packets") == 0)
-			data->rx_packets = val;
-		else if (strcmp(line, "tx_packets") == 0)
-			data->tx_packets = val;
-		else if (strcmp(line, "rx_bytes") == 0)
-			data->rx_bytes = val;
-		else if (strcmp(line, "tx_bytes") == 0)
-			data->tx_bytes = val;
-	}
-
-	fclose(f);
-
-	return 0;
-#endif /* MADWIFI_BSD */
-}
-
-
-static int
-madwifi_sta_clear_stats(void *priv, const u8 *addr)
-{
-#if defined(MADWIFI_BSD) && defined(IEEE80211_MLME_CLEAR_STATS)
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr));
-
-	mlme.im_op = IEEE80211_MLME_CLEAR_STATS;
-	memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-	ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
-			   sizeof(mlme));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
-			   MACSTR ")", __func__, MAC2STR(addr));
-	}
-
-	return ret;
-#else /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
-	return 0; /* FIX */
-#endif /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
-}
-
-
-static int
-madwifi_set_opt_ie(void *priv, const u8 *ie, size_t ie_len)
-{
-	/*
-	 * Do nothing; we setup parameters at startup that define the
-	 * contents of the beacon information element.
-	 */
-	return 0;
-}
-
-static int
-madwifi_sta_deauth(void *priv, const u8 *own_addr, const u8 *addr,
-		   int reason_code)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
-		   __func__, ether_sprintf(addr), reason_code);
-
-	mlme.im_op = IEEE80211_MLME_DEAUTH;
-	mlme.im_reason = reason_code;
-	memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-	ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR
-			   " reason %d)",
-			   __func__, MAC2STR(addr), reason_code);
-	}
-
-	return ret;
-}
-
-static int
-madwifi_sta_disassoc(void *priv, const u8 *own_addr, const u8 *addr,
-		     int reason_code)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret;
-
-	wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
-		   __func__, ether_sprintf(addr), reason_code);
-
-	mlme.im_op = IEEE80211_MLME_DISASSOC;
-	mlme.im_reason = reason_code;
-	memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-	ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
-	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr "
-			   MACSTR " reason %d)",
-			   __func__, MAC2STR(addr), reason_code);
-	}
-
-	return ret;
-}
-
-#ifdef CONFIG_WPS
-#ifdef IEEE80211_IOCTL_FILTERFRAME
-static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
-				size_t len)
-{
-	struct madwifi_driver_data *drv = ctx;
-	const struct ieee80211_mgmt *mgmt;
-	u16 fc;
-	union wpa_event_data event;
-
-	/* Send Probe Request information to WPS processing */
-
-	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
-		return;
-	mgmt = (const struct ieee80211_mgmt *) buf;
-
-	fc = le_to_host16(mgmt->frame_control);
-	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
-	    WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
-		return;
-
-	os_memset(&event, 0, sizeof(event));
-	event.rx_probe_req.sa = mgmt->sa;
-	event.rx_probe_req.da = mgmt->da;
-	event.rx_probe_req.bssid = mgmt->bssid;
-	event.rx_probe_req.ie = mgmt->u.probe_req.variable;
-	event.rx_probe_req.ie_len =
-		len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
-	wpa_supplicant_event(drv->hapd, EVENT_RX_PROBE_REQ, &event);
-}
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
-#endif /* CONFIG_WPS */
-
-static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
-{
-	int ret = 0;
-#ifdef CONFIG_WPS
-#ifdef IEEE80211_IOCTL_FILTERFRAME
-	struct ieee80211req_set_filter filt;
-
-	wpa_printf(MSG_DEBUG, "%s Enter", __func__);
-	filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ;
-
-	ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
-			   sizeof(struct ieee80211req_set_filter));
-	if (ret)
-		return ret;
-
-	drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
-				       madwifi_raw_receive, drv, 1);
-	if (drv->sock_raw == NULL)
-		return -1;
-#endif /* IEEE80211_IOCTL_FILTERFRAME */
-#endif /* CONFIG_WPS */
-	return ret;
-}
-
-#ifdef CONFIG_WPS
-static int
-madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
-{
-	struct madwifi_driver_data *drv = priv;
-	u8 buf[256];
-	struct ieee80211req_getset_appiebuf *beac_ie;
-
-	wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
-		   (unsigned long) len);
-
-	beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
-	beac_ie->app_frmtype = frametype;
-	beac_ie->app_buflen = len;
-	memcpy(&(beac_ie->app_buf[0]), ie, len);
-
-	return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
-			    sizeof(struct ieee80211req_getset_appiebuf) + len);
-}
-
-static int
-madwifi_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
-		      const struct wpabuf *proberesp,
-		      const struct wpabuf *assocresp)
-{
-	if (madwifi_set_wps_ie(priv, beacon ? wpabuf_head(beacon) : NULL,
-			       beacon ? wpabuf_len(beacon) : 0,
-			       IEEE80211_APPIE_FRAME_BEACON) < 0)
-		return -1;
-	return madwifi_set_wps_ie(priv,
-				  proberesp ? wpabuf_head(proberesp) : NULL,
-				  proberesp ? wpabuf_len(proberesp) : 0,
-				  IEEE80211_APPIE_FRAME_PROBE_RESP);
-}
-#else /* CONFIG_WPS */
-#define madwifi_set_ap_wps_ie NULL
-#endif /* CONFIG_WPS */
-
-static int madwifi_set_freq(void *priv, struct hostapd_freq_params *freq)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-	iwr.u.freq.m = freq->channel;
-	iwr.u.freq.e = 0;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
-		perror("ioctl[SIOCSIWFREQ]");
-		return -1;
-	}
-
-	return 0;
-}
-
-static void
-madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
-{
-	struct hostapd_data *hapd = drv->hapd;
-	struct ieee80211req_wpaie ie;
-	int ielen = 0;
-	u8 *iebuf = NULL;
-
-	/*
-	 * Fetch negotiated WPA/RSN parameters from the system.
-	 */
-	memset(&ie, 0, sizeof(ie));
-	memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
-	if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE",
-			   __func__);
-		goto no_ie;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE",
-		    ie.wpa_ie, IEEE80211_MAX_OPT_IE);
-	iebuf = ie.wpa_ie;
-	/* madwifi seems to return some random data if WPA/RSN IE is not set.
-	 * Assume the IE was not included if the IE type is unknown. */
-	if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
-		iebuf[1] = 0;
-#ifdef MADWIFI_NG
-	wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE",
-		    ie.rsn_ie, IEEE80211_MAX_OPT_IE);
-	if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
-		/* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
-		 * set. This is needed for WPA2. */
-		iebuf = ie.rsn_ie;
-		if (iebuf[0] != WLAN_EID_RSN)
-			iebuf[1] = 0;
-	}
-#endif /* MADWIFI_NG */
-
-	ielen = iebuf[1];
-	if (ielen == 0)
-		iebuf = NULL;
-	else
-		ielen += 2;
-
-no_ie:
-	drv_event_assoc(hapd, addr, iebuf, ielen, 0);
-
-	if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
-		/* Cached accounting data is not valid anymore. */
-		memset(drv->acct_mac, 0, ETH_ALEN);
-		memset(&drv->acct_data, 0, sizeof(drv->acct_data));
-	}
-}
-
-static void
-madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
-				       char *custom)
-{
-	wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
-
-	if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
-		char *pos;
-		u8 addr[ETH_ALEN];
-		pos = strstr(custom, "addr=");
-		if (pos == NULL) {
-			wpa_printf(MSG_DEBUG,
-				   "MLME-MICHAELMICFAILURE.indication "
-				   "without sender address ignored");
-			return;
-		}
-		pos += 5;
-		if (hwaddr_aton(pos, addr) == 0) {
-			union wpa_event_data data;
-			os_memset(&data, 0, sizeof(data));
-			data.michael_mic_failure.unicast = 1;
-			data.michael_mic_failure.src = addr;
-			wpa_supplicant_event(drv->hapd,
-					     EVENT_MICHAEL_MIC_FAILURE, &data);
-		} else {
-			wpa_printf(MSG_DEBUG,
-				   "MLME-MICHAELMICFAILURE.indication "
-				   "with invalid MAC address");
-		}
-	} else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
-		char *key, *value;
-		u32 val;
-		key = custom;
-		while ((key = strchr(key, '\n')) != NULL) {
-			key++;
-			value = strchr(key, '=');
-			if (value == NULL)
-				continue;
-			*value++ = '\0';
-			val = strtoul(value, NULL, 10);
-			if (strcmp(key, "mac") == 0)
-				hwaddr_aton(value, drv->acct_mac);
-			else if (strcmp(key, "rx_packets") == 0)
-				drv->acct_data.rx_packets = val;
-			else if (strcmp(key, "tx_packets") == 0)
-				drv->acct_data.tx_packets = val;
-			else if (strcmp(key, "rx_bytes") == 0)
-				drv->acct_data.rx_bytes = val;
-			else if (strcmp(key, "tx_bytes") == 0)
-				drv->acct_data.tx_bytes = val;
-			key = value;
-		}
-	}
-}
-
-static void
-madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
-					    char *data, int len)
-{
-	struct iw_event iwe_buf, *iwe = &iwe_buf;
-	char *pos, *end, *custom, *buf;
-
-	pos = data;
-	end = data + len;
-
-	while (pos + IW_EV_LCP_LEN <= end) {
-		/* Event data may be unaligned, so make a local, aligned copy
-		 * before processing. */
-		memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
-		wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d",
-			   iwe->cmd, iwe->len);
-		if (iwe->len <= IW_EV_LCP_LEN)
-			return;
-
-		custom = pos + IW_EV_POINT_LEN;
-		if (drv->we_version > 18 &&
-		    (iwe->cmd == IWEVMICHAELMICFAILURE ||
-		     iwe->cmd == IWEVCUSTOM)) {
-			/* WE-19 removed the pointer from struct iw_point */
-			char *dpos = (char *) &iwe_buf.u.data.length;
-			int dlen = dpos - (char *) &iwe_buf;
-			memcpy(dpos, pos + IW_EV_LCP_LEN,
-			       sizeof(struct iw_event) - dlen);
-		} else {
-			memcpy(&iwe_buf, pos, sizeof(struct iw_event));
-			custom += IW_EV_POINT_OFF;
-		}
-
-		switch (iwe->cmd) {
-		case IWEVEXPIRED:
-			drv_event_disassoc(drv->hapd,
-					   (u8 *) iwe->u.addr.sa_data);
-			break;
-		case IWEVREGISTERED:
-			madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
-			break;
-		case IWEVCUSTOM:
-			if (custom + iwe->u.data.length > end)
-				return;
-			buf = malloc(iwe->u.data.length + 1);
-			if (buf == NULL)
-				return;		/* XXX */
-			memcpy(buf, custom, iwe->u.data.length);
-			buf[iwe->u.data.length] = '\0';
-			madwifi_wireless_event_wireless_custom(drv, buf);
-			free(buf);
-			break;
-		}
-
-		pos += iwe->len;
-	}
-}
-
-
-static void
-madwifi_wireless_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi,
-				   u8 *buf, size_t len)
-{
-	struct madwifi_driver_data *drv = ctx;
-	int attrlen, rta_len;
-	struct rtattr *attr;
-
-	if (ifi->ifi_index != drv->ifindex)
-		return;
-
-	attrlen = len;
-	attr = (struct rtattr *) buf;
-
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	while (RTA_OK(attr, attrlen)) {
-		if (attr->rta_type == IFLA_WIRELESS) {
-			madwifi_wireless_event_wireless(
-				drv, ((char *) attr) + rta_len,
-				attr->rta_len - rta_len);
-		}
-		attr = RTA_NEXT(attr, attrlen);
-	}
-}
-
-
-static int
-madwifi_get_we_version(struct madwifi_driver_data *drv)
-{
-	struct iw_range *range;
-	struct iwreq iwr;
-	int minlen;
-	size_t buflen;
-
-	drv->we_version = 0;
-
-	/*
-	 * Use larger buffer than struct iw_range in order to allow the
-	 * structure to grow in the future.
-	 */
-	buflen = sizeof(struct iw_range) + 500;
-	range = os_zalloc(buflen);
-	if (range == NULL)
-		return -1;
-
-	memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) range;
-	iwr.u.data.length = buflen;
-
-	minlen = ((char *) &range->enc_capa) - (char *) range +
-		sizeof(range->enc_capa);
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWRANGE]");
-		free(range);
-		return -1;
-	} else if (iwr.u.data.length >= minlen &&
-		   range->we_version_compiled >= 18) {
-		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
-			   "WE(source)=%d enc_capa=0x%x",
-			   range->we_version_compiled,
-			   range->we_version_source,
-			   range->enc_capa);
-		drv->we_version = range->we_version_compiled;
-	}
-
-	free(range);
-	return 0;
-}
-
-
-static int
-madwifi_wireless_event_init(struct madwifi_driver_data *drv)
-{
-	struct netlink_config *cfg;
-
-	madwifi_get_we_version(drv);
-
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL)
-		return -1;
-	cfg->ctx = drv;
-	cfg->newlink_cb = madwifi_wireless_event_rtm_newlink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static int
-madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
-		   int encrypt, const u8 *own_addr, u32 flags)
-{
-	struct madwifi_driver_data *drv = priv;
-	unsigned char buf[3000];
-	unsigned char *bp = buf;
-	struct l2_ethhdr *eth;
-	size_t len;
-	int status;
-
-	/*
-	 * Prepend the Ethernet header.  If the caller left us
-	 * space at the front we could just insert it but since
-	 * we don't know we copy to a local buffer.  Given the frequency
-	 * and size of frames this probably doesn't matter.
-	 */
-	len = data_len + sizeof(struct l2_ethhdr);
-	if (len > sizeof(buf)) {
-		bp = malloc(len);
-		if (bp == NULL) {
-			printf("EAPOL frame discarded, cannot malloc temp "
-			       "buffer of size %lu!\n", (unsigned long) len);
-			return -1;
-		}
-	}
-	eth = (struct l2_ethhdr *) bp;
-	memcpy(eth->h_dest, addr, ETH_ALEN);
-	memcpy(eth->h_source, own_addr, ETH_ALEN);
-	eth->h_proto = host_to_be16(ETH_P_EAPOL);
-	memcpy(eth+1, data, data_len);
-
-	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
-
-	status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
-
-	if (bp != buf)
-		free(bp);
-	return status;
-}
-
-static void
-handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
-{
-	struct madwifi_driver_data *drv = ctx;
-	drv_event_eapol_rx(drv->hapd, src_addr, buf + sizeof(struct l2_ethhdr),
-			   len - sizeof(struct l2_ethhdr));
-}
-
-static void *
-madwifi_init(struct hostapd_data *hapd, struct wpa_init_params *params)
-{
-	struct madwifi_driver_data *drv;
-	struct ifreq ifr;
-	struct iwreq iwr;
-	char brname[IFNAMSIZ];
-
-	drv = os_zalloc(sizeof(struct madwifi_driver_data));
-	if (drv == NULL) {
-		printf("Could not allocate memory for madwifi driver data\n");
-		return NULL;
-	}
-
-	drv->hapd = hapd;
-	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->ioctl_sock < 0) {
-		perror("socket[PF_INET,SOCK_DGRAM]");
-		goto bad;
-	}
-	memcpy(drv->iface, params->ifname, sizeof(drv->iface));
-
-	memset(&ifr, 0, sizeof(ifr));
-	os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
-	if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
-		goto bad;
-	}
-	drv->ifindex = ifr.ifr_ifindex;
-
-	drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
-					handle_read, drv, 1);
-	if (drv->sock_xmit == NULL)
-		goto bad;
-	if (l2_packet_get_own_addr(drv->sock_xmit, params->own_addr))
-		goto bad;
-	if (params->bridge[0]) {
-		wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
-			   params->bridge[0]);
-		drv->sock_recv = l2_packet_init(params->bridge[0], NULL,
-						ETH_P_EAPOL, handle_read, drv,
-						1);
-		if (drv->sock_recv == NULL)
-			goto bad;
-	} else if (linux_br_get(brname, drv->iface) == 0) {
-		wpa_printf(MSG_DEBUG, "Interface in bridge %s; configure for "
-			   "EAPOL receive", brname);
-		drv->sock_recv = l2_packet_init(brname, NULL, ETH_P_EAPOL,
-						handle_read, drv, 1);
-		if (drv->sock_recv == NULL)
-			goto bad;
-	} else
-		drv->sock_recv = drv->sock_xmit;
-
-	memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-
-	iwr.u.mode = IW_MODE_MASTER;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWMODE]");
-		printf("Could not set interface to master mode!\n");
-		goto bad;
-	}
-
-	/* mark down during setup */
-	linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
-	madwifi_set_privacy(drv, 0); /* default to no privacy */
-
-	madwifi_receive_probe_req(drv);
-
-	if (madwifi_wireless_event_init(drv))
-		goto bad;
-
-	return drv;
-bad:
-	if (drv->sock_xmit != NULL)
-		l2_packet_deinit(drv->sock_xmit);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-	if (drv != NULL)
-		free(drv);
-	return NULL;
-}
-
-
-static void
-madwifi_deinit(void *priv)
-{
-	struct madwifi_driver_data *drv = priv;
-
-	netlink_deinit(drv->netlink);
-	(void) linux_set_iface_flags(drv->ioctl_sock, drv->iface, 0);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-	if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
-		l2_packet_deinit(drv->sock_recv);
-	if (drv->sock_xmit != NULL)
-		l2_packet_deinit(drv->sock_xmit);
-	if (drv->sock_raw)
-		l2_packet_deinit(drv->sock_raw);
-	free(drv);
-}
-
-static int
-madwifi_set_ssid(void *priv, const u8 *buf, int len)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct iwreq iwr;
-
-	memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-	iwr.u.essid.flags = 1; /* SSID active */
-	iwr.u.essid.pointer = (caddr_t) buf;
-	iwr.u.essid.length = len + 1;
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCSIWESSID]");
-		printf("len=%d\n", len);
-		return -1;
-	}
-	return 0;
-}
-
-static int
-madwifi_get_ssid(void *priv, u8 *buf, int len)
-{
-	struct madwifi_driver_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
-	iwr.u.essid.pointer = (caddr_t) buf;
-	iwr.u.essid.length = len;
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCGIWESSID]");
-		ret = -1;
-	} else
-		ret = iwr.u.essid.length;
-
-	return ret;
-}
-
-static int
-madwifi_set_countermeasures(void *priv, int enabled)
-{
-	struct madwifi_driver_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
-}
-
-static int
-madwifi_commit(void *priv)
-{
-	struct madwifi_driver_data *drv = priv;
-	return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
-}
-
-
-const struct wpa_driver_ops wpa_driver_madwifi_ops = {
-	.name			= "madwifi",
-	.desc			= "MADWIFI 802.11 support (Atheros, etc.)",
-	.set_key		= wpa_driver_madwifi_set_key,
-	.hapd_init		= madwifi_init,
-	.hapd_deinit		= madwifi_deinit,
-	.set_ieee8021x		= madwifi_set_ieee8021x,
-	.set_privacy		= madwifi_set_privacy,
-	.get_seqnum		= madwifi_get_seqnum,
-	.flush			= madwifi_flush,
-	.set_generic_elem	= madwifi_set_opt_ie,
-	.sta_set_flags		= madwifi_sta_set_flags,
-	.read_sta_data		= madwifi_read_sta_driver_data,
-	.hapd_send_eapol	= madwifi_send_eapol,
-	.sta_disassoc		= madwifi_sta_disassoc,
-	.sta_deauth		= madwifi_sta_deauth,
-	.hapd_set_ssid		= madwifi_set_ssid,
-	.hapd_get_ssid		= madwifi_get_ssid,
-	.hapd_set_countermeasures	= madwifi_set_countermeasures,
-	.sta_clear_stats        = madwifi_sta_clear_stats,
-	.commit			= madwifi_commit,
-	.set_ap_wps_ie		= madwifi_set_ap_wps_ie,
-	.set_freq		= madwifi_set_freq,
-};
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index 4c8f29f..8527e90 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -11,67 +11,35 @@
  */
 
 #include "includes.h"
-#include <sys/ioctl.h>
 #include <sys/types.h>
-#include <sys/stat.h>
 #include <fcntl.h>
 #include <net/if.h>
 #include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
 #include <netlink/genl/ctrl.h>
 #ifdef CONFIG_LIBNL3_ROUTE
 #include <netlink/route/neighbour.h>
 #endif /* CONFIG_LIBNL3_ROUTE */
 #include <linux/rtnetlink.h>
 #include <netpacket/packet.h>
-#include <linux/filter.h>
 #include <linux/errqueue.h>
-#include "nl80211_copy.h"
 
 #include "common.h"
 #include "eloop.h"
-#include "utils/list.h"
 #include "common/qca-vendor.h"
 #include "common/qca-vendor-attr.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "l2_packet/l2_packet.h"
 #include "netlink.h"
+#include "linux_defines.h"
 #include "linux_ioctl.h"
 #include "radiotap.h"
 #include "radiotap_iter.h"
 #include "rfkill.h"
-#include "driver.h"
+#include "driver_nl80211.h"
 
-#ifndef SO_WIFI_STATUS
-# if defined(__sparc__)
-#  define SO_WIFI_STATUS	0x0025
-# elif defined(__parisc__)
-#  define SO_WIFI_STATUS	0x4022
-# else
-#  define SO_WIFI_STATUS	41
-# endif
 
-# define SCM_WIFI_STATUS	SO_WIFI_STATUS
-#endif
-
-#ifndef SO_EE_ORIGIN_TXSTATUS
-#define SO_EE_ORIGIN_TXSTATUS	4
-#endif
-
-#ifndef PACKET_TX_TIMESTAMP
-#define PACKET_TX_TIMESTAMP	16
-#endif
-
-#ifdef ANDROID
-#include "android_drv.h"
-#endif /* ANDROID */
-#ifdef CONFIG_LIBNL20
-/* libnl 2.0 compatibility code */
-#define nl_handle nl_sock
-#define nl80211_handle_alloc nl_socket_alloc_cb
-#define nl80211_handle_destroy nl_socket_free
-#else
+#ifndef CONFIG_LIBNL20
 /*
  * libnl 1.1 has a bug, it tries to allocate socket numbers densely
  * but when you free a socket again it will mess up its bitmap and
@@ -116,12 +84,10 @@
 
 #ifdef ANDROID
 /* system/core/libnl_2 does not include nl_socket_set_nonblocking() */
-static int android_nl_socket_set_nonblocking(struct nl_handle *handle)
-{
-	return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
-}
 #undef nl_socket_set_nonblocking
 #define nl_socket_set_nonblocking(h) android_nl_socket_set_nonblocking(h)
+
+#define genl_ctrl_resolve android_genl_ctrl_resolve
 #endif /* ANDROID */
 
 
@@ -181,374 +147,41 @@
 }
 
 
-#ifndef IFF_LOWER_UP
-#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
-#endif
-#ifndef IFF_DORMANT
-#define IFF_DORMANT    0x20000         /* driver signals dormant       */
-#endif
-
-#ifndef IF_OPER_DORMANT
-#define IF_OPER_DORMANT 5
-#endif
-#ifndef IF_OPER_UP
-#define IF_OPER_UP 6
-#endif
-
-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;
-	int nl80211_id;
-	int ioctl_sock; /* socket for ioctl() use */
-
-	struct nl_handle *nl_event;
-};
-
-struct nl80211_wiphy_data {
-	struct dl_list list;
-	struct dl_list bsss;
-	struct dl_list drvs;
-
-	struct nl_handle *nl_beacons;
-	struct nl_cb *nl_cb;
-
-	int wiphy_idx;
-};
-
 static void nl80211_global_deinit(void *priv);
 
-struct i802_bss {
-	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;
-	unsigned int added_if:1;
-	unsigned int static_ap:1;
-
-	u8 addr[ETH_ALEN];
-
-	int freq;
-	int bandwidth;
-	int if_dynamic;
-
-	void *ctx;
-	struct nl_handle *nl_preq, *nl_mgmt;
-	struct nl_cb *nl_cb;
-
-	struct nl80211_wiphy_data *wiphy_data;
-	struct dl_list wiphy_list;
-};
-
-struct wpa_driver_nl80211_data {
-	struct nl80211_global *global;
-	struct dl_list list;
-	struct dl_list wiphy_list;
-	char phyname[32];
-	u8 perm_addr[ETH_ALEN];
-	void *ctx;
-	int ifindex;
-	int if_removed;
-	int if_disabled;
-	int ignore_if_down_event;
-	struct rfkill_data *rfkill;
-	struct wpa_driver_capa capa;
-	u8 *extended_capa, *extended_capa_mask;
-	unsigned int extended_capa_len;
-	int has_capability;
-
-	int operstate;
-
-	int scan_complete_events;
-	enum scan_states {
-		NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED,
-		SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED,
-		SCHED_SCAN_RESULTS
-	} scan_state;
-
-	struct nl_cb *nl_cb;
-
-	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;
-	enum nl80211_iftype nlmode;
-	enum nl80211_iftype ap_scan_as_station;
-	unsigned int assoc_freq;
-
-	int monitor_sock;
-	int monitor_ifidx;
-	int monitor_refcount;
-
-	unsigned int disabled_11b_rates:1;
-	unsigned int pending_remain_on_chan:1;
-	unsigned int in_interface_list:1;
-	unsigned int device_ap_sme:1;
-	unsigned int poll_command_supported:1;
-	unsigned int data_tx_status:1;
-	unsigned int scan_for_auth:1;
-	unsigned int retry_auth:1;
-	unsigned int use_monitor:1;
-	unsigned int ignore_next_local_disconnect:1;
-	unsigned int ignore_next_local_deauth:1;
-	unsigned int allow_p2p_device:1;
-	unsigned int hostapd:1;
-	unsigned int start_mode_ap:1;
-	unsigned int start_iface_up:1;
-	unsigned int test_use_roc_tx:1;
-	unsigned int ignore_deauth_event:1;
-	unsigned int roaming_vendor_cmd_avail:1;
-	unsigned int dfs_vendor_cmd_avail:1;
-	unsigned int have_low_prio_scan:1;
-	unsigned int force_connect_cmd:1;
-	unsigned int addr_changed:1;
-
-	u64 remain_on_chan_cookie;
-	u64 send_action_cookie;
-
-	unsigned int last_mgmt_freq;
-
-	struct wpa_driver_scan_filter *filter_ssids;
-	size_t num_filter_ssids;
-
-	struct i802_bss *first_bss;
-
-	int eapol_tx_sock;
-
-	int eapol_sock; /* socket for EAPOL frames */
-
-	struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
-
-	int default_if_indices[16];
-	int *if_indices;
-	int num_if_indices;
-
-	/* From failed authentication command */
-	int auth_freq;
-	u8 auth_bssid_[ETH_ALEN];
-	u8 auth_ssid[32];
-	size_t auth_ssid_len;
-	int auth_alg;
-	u8 *auth_ie;
-	size_t auth_ie_len;
-	u8 auth_wep_key[4][16];
-	size_t auth_wep_key_len[4];
-	int auth_wep_tx_keyidx;
-	int auth_local_state_change;
-	int auth_p2p;
-};
-
-
 static void wpa_driver_nl80211_deinit(struct i802_bss *bss);
-static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
-					    void *timeout_ctx);
-static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
-				       enum nl80211_iftype nlmode);
 static int wpa_driver_nl80211_set_mode_ibss(struct i802_bss *bss,
 					    struct hostapd_freq_params *freq);
 
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
-				   const u8 *set_addr, int first);
-static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
-				   const u8 *addr, int cmd, u16 reason_code,
-				   int local_state_change);
-static void nl80211_remove_monitor_interface(
-	struct wpa_driver_nl80211_data *drv);
+				   const u8 *set_addr, int first,
+				   const char *driver_params);
 static int nl80211_send_frame_cmd(struct i802_bss *bss,
 				  unsigned int freq, unsigned int wait,
 				  const u8 *buf, size_t buf_len, u64 *cookie,
 				  int no_cck, int no_ack, int offchanok);
-static int nl80211_register_frame(struct i802_bss *bss,
-				  struct nl_handle *hl_handle,
-				  u16 type, const u8 *match, size_t match_len);
 static int wpa_driver_nl80211_probe_req_report(struct i802_bss *bss,
 					       int report);
-#ifdef ANDROID
-static int android_pno_start(struct i802_bss *bss,
-			     struct wpa_driver_scan_params *params);
-static int android_pno_stop(struct i802_bss *bss);
-extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
-					 size_t buf_len);
-#endif /* ANDROID */
-#ifdef ANDROID_P2P
-#ifdef ANDROID_P2P_STUB
-int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration) {
-	return 0;
-}
-int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len) {
-	return 0;
-}
-int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow) {
-	return -1;
-}
-int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
-				 const struct wpabuf *proberesp,
-				 const struct wpabuf *assocresp) {
-	return 0;
-}
-#else /* ANDROID_P2P_STUB */
-int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
-int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
-int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
-int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
-				 const struct wpabuf *proberesp,
-				 const struct wpabuf *assocresp);
-#endif /* ANDROID_P2P_STUB */
-#endif /* ANDROID_P2P */
 
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
-static int wpa_driver_nl80211_if_remove(struct i802_bss *bss,
-					enum wpa_driver_if_type type,
-					const char *ifname);
 
 static int nl80211_set_channel(struct i802_bss *bss,
 			       struct hostapd_freq_params *freq, int set_chan);
 static int nl80211_disable_11b_rates(struct wpa_driver_nl80211_data *drv,
 				     int ifindex, int disabled);
 
-static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv);
-static int wpa_driver_nl80211_authenticate_retry(
-	struct wpa_driver_nl80211_data *drv);
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+			      int reset_mode);
 
-static int i802_set_freq(void *priv, struct hostapd_freq_params *freq);
 static int i802_set_iface_flags(struct i802_bss *bss, int up);
-
-
-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)
-	C2S(NL80211_CMD_GET_COALESCE)
-	C2S(NL80211_CMD_SET_COALESCE)
-	C2S(NL80211_CMD_CHANNEL_SWITCH)
-	C2S(NL80211_CMD_VENDOR)
-	C2S(NL80211_CMD_SET_QOS_MAP)
-	default:
-		return "NL80211_CMD_UNKNOWN";
-	}
-#undef C2S
-}
+static int nl80211_set_param(void *priv, const char *param);
 
 
 /* Converts nl80211_chan_width to a common format */
-static enum chan_width convert2width(int width)
+enum chan_width convert2width(int width)
 {
 	switch (width) {
 	case NL80211_CHAN_WIDTH_20_NOHT:
@@ -568,14 +201,14 @@
 }
 
 
-static int is_ap_interface(enum nl80211_iftype nlmode)
+int is_ap_interface(enum nl80211_iftype nlmode)
 {
 	return nlmode == NL80211_IFTYPE_AP ||
 		nlmode == NL80211_IFTYPE_P2P_GO;
 }
 
 
-static int is_sta_interface(enum nl80211_iftype nlmode)
+int is_sta_interface(enum nl80211_iftype nlmode)
 {
 	return nlmode == NL80211_IFTYPE_STATION ||
 		nlmode == NL80211_IFTYPE_P2P_CLIENT;
@@ -589,8 +222,8 @@
 }
 
 
-static struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
-					 int ifindex)
+struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
+				  int ifindex)
 {
 	struct i802_bss *bss;
 
@@ -603,7 +236,13 @@
 }
 
 
-static void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
+static int is_mesh_interface(enum nl80211_iftype nlmode)
+{
+	return nlmode == NL80211_IFTYPE_MESH_POINT;
+}
+
+
+void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
 {
 	if (drv->associated)
 		os_memcpy(drv->prev_bssid, drv->bssid, ETH_ALEN);
@@ -612,17 +251,6 @@
 }
 
 
-struct nl80211_bss_info_arg {
-	struct wpa_driver_nl80211_data *drv;
-	struct wpa_scan_results *res;
-	unsigned int assoc_freq;
-	unsigned int ibss_freq;
-	u8 assoc_bssid[ETH_ALEN];
-};
-
-static int bss_info_handler(struct nl_msg *msg, void *arg);
-
-
 /* nl80211 code */
 static int ack_handler(struct nl_msg *msg, void *arg)
 {
@@ -653,6 +281,28 @@
 }
 
 
+static void nl80211_nlmsg_clear(struct nl_msg *msg)
+{
+	/*
+	 * Clear nlmsg data, e.g., to make sure key material is not left in
+	 * heap memory for unnecessarily long time.
+	 */
+	if (msg) {
+		struct nlmsghdr *hdr = nlmsg_hdr(msg);
+		void *data = nlmsg_data(hdr);
+		/*
+		 * This would use nlmsg_datalen() or the older nlmsg_len() if
+		 * only libnl were to maintain a stable API.. Neither will work
+		 * with all released versions, so just calculate the length
+		 * here.
+		 */
+		int len = hdr->nlmsg_len - NLMSG_HDRLEN;
+
+		os_memset(data, 0, len);
+	}
+}
+
+
 static int send_and_recv(struct nl80211_global *global,
 			 struct nl_handle *nl_handle, struct nl_msg *msg,
 			 int (*valid_handler)(struct nl_msg *, void *),
@@ -661,6 +311,9 @@
 	struct nl_cb *cb;
 	int err = -ENOMEM;
 
+	if (!msg)
+		return -ENOMEM;
+
 	cb = nl_cb_clone(global->nl_cb);
 	if (!cb)
 		goto out;
@@ -689,25 +342,17 @@
 	}
  out:
 	nl_cb_put(cb);
+	if (!valid_handler && valid_data == (void *) -1)
+		nl80211_nlmsg_clear(msg);
 	nlmsg_free(msg);
 	return err;
 }
 
 
-static int send_and_recv_msgs_global(struct nl80211_global *global,
-				     struct nl_msg *msg,
-				     int (*valid_handler)(struct nl_msg *, void *),
-				     void *valid_data)
-{
-	return send_and_recv(global, global->nl, msg, valid_handler,
-			     valid_data);
-}
-
-
-static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
-			      struct nl_msg *msg,
-			      int (*valid_handler)(struct nl_msg *, void *),
-			      void *valid_data)
+int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
+		       struct nl_msg *msg,
+		       int (*valid_handler)(struct nl_msg *, void *),
+		       void *valid_data)
 {
 	return send_and_recv(drv->global, drv->global->nl, msg,
 			     valid_handler, valid_data);
@@ -720,19 +365,6 @@
 };
 
 
-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;
@@ -768,35 +400,93 @@
 			       const char *family, const char *group)
 {
 	struct nl_msg *msg;
-	int ret = -1;
+	int ret;
 	struct family_data res = { group, -ENOENT };
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
-	genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
-		    0, 0, CTRL_CMD_GETFAMILY, 0);
-	NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
+	if (!genlmsg_put(msg, 0, 0, genl_ctrl_resolve(global->nl, "nlctrl"),
+			 0, 0, CTRL_CMD_GETFAMILY, 0) ||
+	    nla_put_string(msg, CTRL_ATTR_FAMILY_NAME, family)) {
+		nlmsg_free(msg);
+		return -1;
+	}
 
-	ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
-	msg = NULL;
+	ret = send_and_recv(global, global->nl, msg, family_handler, &res);
 	if (ret == 0)
 		ret = res.id;
-
-nla_put_failure:
-	nlmsg_free(msg);
 	return ret;
 }
 
 
-static void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
-			  struct nl_msg *msg, int flags, uint8_t cmd)
+void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+		   struct nl_msg *msg, int flags, uint8_t cmd)
 {
 	return genlmsg_put(msg, 0, 0, drv->global->nl80211_id,
 			   0, flags, cmd, 0);
 }
 
 
+static int nl80211_set_iface_id(struct nl_msg *msg, struct i802_bss *bss)
+{
+	if (bss->wdev_id_set)
+		return nla_put_u64(msg, NL80211_ATTR_WDEV, bss->wdev_id);
+	return nla_put_u32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+}
+
+
+struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return NULL;
+
+	if (!nl80211_cmd(bss->drv, msg, flags, cmd) ||
+	    nl80211_set_iface_id(msg, bss) < 0) {
+		nlmsg_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+static struct nl_msg *
+nl80211_ifindex_msg(struct wpa_driver_nl80211_data *drv, int ifindex,
+		    int flags, uint8_t cmd)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return NULL;
+
+	if (!nl80211_cmd(drv, msg, flags, cmd) ||
+	    nla_put_u32(msg, NL80211_ATTR_IFINDEX, ifindex)) {
+		nlmsg_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
+				uint8_t cmd)
+{
+	return nl80211_ifindex_msg(drv, drv->ifindex, flags, cmd);
+}
+
+
+struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd)
+{
+	return nl80211_ifindex_msg(bss->drv, bss->ifindex, flags, cmd);
+}
+
+
 struct wiphy_idx_data {
 	int wiphy_idx;
 	enum nl80211_iftype nlmode;
@@ -827,7 +517,7 @@
 }
 
 
-static int nl80211_get_wiphy_index(struct i802_bss *bss)
+int nl80211_get_wiphy_index(struct i802_bss *bss)
 {
 	struct nl_msg *msg;
 	struct wiphy_idx_data data = {
@@ -835,20 +525,11 @@
 		.macaddr = NULL,
 	};
 
-	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;
+	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+		return -1;
 
 	if (send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data) == 0)
 		return data.wiphy_idx;
-	msg = NULL;
-nla_put_failure:
-	nlmsg_free(msg);
 	return -1;
 }
 
@@ -861,20 +542,11 @@
 		.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 (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+		return NL80211_IFTYPE_UNSPECIFIED;
 
 	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;
 }
 
@@ -886,19 +558,10 @@
 		.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;
+	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_GET_INTERFACE)))
+		return -1;
 
 	return send_and_recv_msgs(bss->drv, msg, netdev_info_handler, &data);
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return NL80211_IFTYPE_UNSPECIFIED;
 }
 
 
@@ -906,27 +569,24 @@
 				    struct nl80211_wiphy_data *w)
 {
 	struct nl_msg *msg;
-	int ret = -1;
+	int ret;
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -1;
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx);
+	if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_BEACONS) ||
+	    nla_put_u32(msg, NL80211_ATTR_WIPHY, w->wiphy_idx)) {
+		nlmsg_free(msg);
+		return -1;
+	}
 
 	ret = send_and_recv(drv->global, w->nl_beacons, msg, NULL, NULL);
-	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Register beacons command "
 			   "failed: ret=%d (%s)",
 			   ret, strerror(-ret));
-		goto nla_put_failure;
 	}
-	ret = 0;
-nla_put_failure:
-	nlmsg_free(msg);
 	return ret;
 }
 
@@ -1104,7 +764,7 @@
 
 
 static void wpa_driver_nl80211_event_newlink(
-	struct wpa_driver_nl80211_data *drv, char *ifname)
+	struct wpa_driver_nl80211_data *drv, const char *ifname)
 {
 	union wpa_event_data event;
 
@@ -1130,7 +790,7 @@
 
 
 static void wpa_driver_nl80211_event_dellink(
-	struct wpa_driver_nl80211_data *drv, char *ifname)
+	struct wpa_driver_nl80211_data *drv, const char *ifname)
 {
 	union wpa_event_data event;
 
@@ -1190,7 +850,7 @@
 	if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, buf, len)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
 			   "interface");
-		wpa_driver_nl80211_finish_drv_init(drv, NULL, 0);
+		wpa_driver_nl80211_finish_drv_init(drv, NULL, 0, NULL);
 		return 1;
 	}
 
@@ -1281,6 +941,7 @@
 				   drv->first_bss->ifname) > 0) {
 			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
 				   "event since interface %s is up", namebuf);
+			drv->ignore_if_down_event = 0;
 			return;
 		}
 		wpa_printf(MSG_DEBUG, "nl80211: Interface down");
@@ -1368,11 +1029,25 @@
 		wpa_driver_nl80211_event_newlink(drv, ifname);
 
 	if (ifi->ifi_family == AF_BRIDGE && brid) {
+		struct i802_bss *bss;
+
 		/* device has been added to bridge */
-		if_indextoname(brid, namebuf);
+		if (!if_indextoname(brid, namebuf)) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Could not find bridge ifname for ifindex %u",
+				   brid);
+			return;
+		}
 		wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
 			   brid, namebuf);
 		add_ifidx(drv, brid);
+
+		for (bss = drv->first_bss; bss; bss = bss->next) {
+			if (os_strcmp(ifname, bss->ifname) == 0) {
+				os_strlcpy(bss->brname, namebuf, IFNAMSIZ);
+				break;
+			}
+		}
 	}
 }
 
@@ -1442,73 +1117,31 @@
 	if (ifi->ifi_family == AF_BRIDGE && brid) {
 		/* device has been removed from bridge */
 		char namebuf[IFNAMSIZ];
-		if_indextoname(brid, namebuf);
-		wpa_printf(MSG_DEBUG, "nl80211: Remove ifindex %u for bridge "
-			   "%s", brid, namebuf);
+
+		if (!if_indextoname(brid, namebuf)) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Could not find bridge ifname for ifindex %u",
+				   brid);
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Remove ifindex %u for bridge %s",
+				   brid, namebuf);
+		}
 		del_ifidx(drv, brid);
 	}
 }
 
 
-static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
-			    const u8 *frame, size_t len)
-{
-	const struct ieee80211_mgmt *mgmt;
-	union wpa_event_data event;
-
-	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
-	    drv->force_connect_cmd) {
-		/*
-		 * Avoid reporting two association events that would confuse
-		 * the core code.
-		 */
-		wpa_printf(MSG_DEBUG,
-			   "nl80211: Ignore auth event when using driver SME");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
-	mgmt = (const struct ieee80211_mgmt *) frame;
-	if (len < 24 + sizeof(mgmt->u.auth)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
-			   "frame");
-		return;
-	}
-
-	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);
-	event.auth.auth_transaction =
-		le_to_host16(mgmt->u.auth.auth_transaction);
-	event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
-	if (len > 24 + sizeof(mgmt->u.auth)) {
-		event.auth.ies = mgmt->u.auth.variable;
-		event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
-}
-
-
-static unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
+unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv)
 {
 	struct nl_msg *msg;
 	int ret;
 	struct nl80211_bss_info_arg arg;
 
+	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
 	os_memset(&arg, 0, sizeof(arg));
-	msg = nlmsg_alloc();
-	if (!msg)
-		goto nla_put_failure;
-
-	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
 	arg.drv = drv;
 	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
-	msg = NULL;
 	if (ret == 0) {
 		unsigned int freq = drv->nlmode == NL80211_IFTYPE_ADHOC ?
 			arg.ibss_freq : arg.assoc_freq;
@@ -1520,804 +1153,10 @@
 	}
 	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
 		   "(%s)", ret, strerror(-ret));
-nla_put_failure:
-	nlmsg_free(msg);
 	return drv->assoc_freq;
 }
 
 
-static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
-			    const u8 *frame, size_t len)
-{
-	const struct ieee80211_mgmt *mgmt;
-	union wpa_event_data event;
-	u16 status;
-
-	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
-	    drv->force_connect_cmd) {
-		/*
-		 * Avoid reporting two association events that would confuse
-		 * the core code.
-		 */
-		wpa_printf(MSG_DEBUG,
-			   "nl80211: Ignore assoc event when using driver SME");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: Associate event");
-	mgmt = (const struct ieee80211_mgmt *) frame;
-	if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
-			   "frame");
-		return;
-	}
-
-	status = le_to_host16(mgmt->u.assoc_resp.status_code);
-	if (status != WLAN_STATUS_SUCCESS) {
-		os_memset(&event, 0, sizeof(event));
-		event.assoc_reject.bssid = mgmt->bssid;
-		if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
-			event.assoc_reject.resp_ies =
-				(u8 *) mgmt->u.assoc_resp.variable;
-			event.assoc_reject.resp_ies_len =
-				len - 24 - sizeof(mgmt->u.assoc_resp);
-		}
-		event.assoc_reject.status_code = status;
-
-		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
-		return;
-	}
-
-	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)) {
-		event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
-		event.assoc_info.resp_ies_len =
-			len - 24 - sizeof(mgmt->u.assoc_resp);
-	}
-
-	event.assoc_info.freq = drv->assoc_freq;
-
-	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
-}
-
-
-static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
-			       enum nl80211_commands cmd, struct nlattr *status,
-			       struct nlattr *addr, struct nlattr *req_ie,
-			       struct nlattr *resp_ie)
-{
-	union wpa_event_data event;
-	u16 status_code;
-
-	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
-		/*
-		 * Avoid reporting two association events that would confuse
-		 * the core code.
-		 */
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
-			   "when using userspace SME", cmd);
-		return;
-	}
-
-	status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
-
-	if (cmd == NL80211_CMD_CONNECT) {
-		wpa_printf(MSG_DEBUG,
-			   "nl80211: Connect event (status=%u ignore_next_local_disconnect=%d)",
-			   status_code, drv->ignore_next_local_disconnect);
-	} else if (cmd == NL80211_CMD_ROAM) {
-		wpa_printf(MSG_DEBUG, "nl80211: Roam event");
-	}
-
-	os_memset(&event, 0, sizeof(event));
-	if (cmd == NL80211_CMD_CONNECT && status_code != WLAN_STATUS_SUCCESS) {
-		if (addr)
-			event.assoc_reject.bssid = nla_data(addr);
-		if (drv->ignore_next_local_disconnect) {
-			drv->ignore_next_local_disconnect = 0;
-			if (!event.assoc_reject.bssid ||
-			    (os_memcmp(event.assoc_reject.bssid,
-				       drv->auth_attempt_bssid,
-				       ETH_ALEN) != 0)) {
-				/*
-				 * Ignore the event that came without a BSSID or
-				 * for the old connection since this is likely
-				 * not relevant to the new Connect command.
-				 */
-				wpa_printf(MSG_DEBUG,
-					   "nl80211: Ignore connection failure event triggered during reassociation");
-				return;
-			}
-		}
-		if (resp_ie) {
-			event.assoc_reject.resp_ies = nla_data(resp_ie);
-			event.assoc_reject.resp_ies_len = nla_len(resp_ie);
-		}
-		event.assoc_reject.status_code = status_code;
-		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
-		return;
-	}
-
-	drv->associated = 1;
-	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);
-		event.assoc_info.req_ies_len = nla_len(req_ie);
-	}
-	if (resp_ie) {
-		event.assoc_info.resp_ies = nla_data(resp_ie);
-		event.assoc_info.resp_ies_len = nla_len(resp_ie);
-	}
-
-	event.assoc_info.freq = nl80211_get_assoc_freq(drv);
-
-	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
-}
-
-
-static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
-				  struct nlattr *reason, struct nlattr *addr,
-				  struct nlattr *by_ap)
-{
-	union wpa_event_data data;
-	unsigned int locally_generated = by_ap == NULL;
-
-	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
-		/*
-		 * Avoid reporting two disassociation events that could
-		 * confuse the core code.
-		 */
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
-			   "event when using userspace SME");
-		return;
-	}
-
-	if (drv->ignore_next_local_disconnect) {
-		drv->ignore_next_local_disconnect = 0;
-		if (locally_generated) {
-			wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
-				   "event triggered during reassociation");
-			return;
-		}
-		wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
-			   "disconnect but got another disconnect "
-			   "event first");
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
-	nl80211_mark_disconnected(drv);
-	os_memset(&data, 0, sizeof(data));
-	if (reason)
-		data.deauth_info.reason_code = nla_get_u16(reason);
-	data.deauth_info.locally_generated = by_ap == NULL;
-	wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
-}
-
-
-static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
-{
-	int freq1 = 0;
-
-	switch (convert2width(width)) {
-	case CHAN_WIDTH_20_NOHT:
-	case CHAN_WIDTH_20:
-		return 0;
-	case CHAN_WIDTH_40:
-		freq1 = cf1 - 10;
-		break;
-	case CHAN_WIDTH_80:
-		freq1 = cf1 - 30;
-		break;
-	case CHAN_WIDTH_160:
-		freq1 = cf1 - 70;
-		break;
-	case CHAN_WIDTH_UNKNOWN:
-	case CHAN_WIDTH_80P80:
-		/* FIXME: implement this */
-		return 0;
-	}
-
-	return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1;
-}
-
-
-static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
-				 struct nlattr *ifindex, struct nlattr *freq,
-				 struct nlattr *type, struct nlattr *bw,
-				 struct nlattr *cf1, struct nlattr *cf2)
-{
-	struct i802_bss *bss;
-	union wpa_event_data data;
-	int ht_enabled = 1;
-	int chan_offset = 0;
-	int ifidx;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
-
-	if (!freq)
-		return;
-
-	ifidx = nla_get_u32(ifindex);
-	bss = get_bss_ifindex(drv, ifidx);
-	if (bss == NULL) {
-		wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
-			   ifidx);
-		return;
-	}
-
-	if (type) {
-		switch (nla_get_u32(type)) {
-		case NL80211_CHAN_NO_HT:
-			ht_enabled = 0;
-			break;
-		case NL80211_CHAN_HT20:
-			break;
-		case NL80211_CHAN_HT40PLUS:
-			chan_offset = 1;
-			break;
-		case NL80211_CHAN_HT40MINUS:
-			chan_offset = -1;
-			break;
-		}
-	} else if (bw && cf1) {
-		/* This can happen for example with VHT80 ch switch */
-		chan_offset = calculate_chan_offset(nla_get_u32(bw),
-						    nla_get_u32(freq),
-						    nla_get_u32(cf1),
-						    cf2 ? nla_get_u32(cf2) : 0);
-	} else {
-		wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
-	}
-
-	os_memset(&data, 0, sizeof(data));
-	data.ch_switch.freq = nla_get_u32(freq);
-	data.ch_switch.ht_enabled = ht_enabled;
-	data.ch_switch.ch_offset = chan_offset;
-	if (bw)
-		data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
-	if (cf1)
-		data.ch_switch.cf1 = nla_get_u32(cf1);
-	if (cf2)
-		data.ch_switch.cf2 = nla_get_u32(cf2);
-
-	bss->freq = data.ch_switch.freq;
-
-	wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
-}
-
-
-static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
-			       enum nl80211_commands cmd, struct nlattr *addr)
-{
-	union wpa_event_data event;
-	enum wpa_event_type ev;
-
-	if (nla_len(addr) != ETH_ALEN)
-		return;
-
-	wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
-		   cmd, MAC2STR((u8 *) nla_data(addr)));
-
-	if (cmd == NL80211_CMD_AUTHENTICATE)
-		ev = EVENT_AUTH_TIMED_OUT;
-	else if (cmd == NL80211_CMD_ASSOCIATE)
-		ev = EVENT_ASSOC_TIMED_OUT;
-	else
-		return;
-
-	os_memset(&event, 0, sizeof(event));
-	os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
-	wpa_supplicant_event(drv->ctx, ev, &event);
-}
-
-
-static void mlme_event_mgmt(struct i802_bss *bss,
-			    struct nlattr *freq, struct nlattr *sig,
-			    const u8 *frame, size_t len)
-{
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	const struct ieee80211_mgmt *mgmt;
-	union wpa_event_data event;
-	u16 fc, stype;
-	int ssi_signal = 0;
-	int rx_freq = 0;
-
-	wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
-	mgmt = (const struct ieee80211_mgmt *) frame;
-	if (len < 24) {
-		wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
-		return;
-	}
-
-	fc = le_to_host16(mgmt->frame_control);
-	stype = WLAN_FC_GET_STYPE(fc);
-
-	if (sig)
-		ssi_signal = (s32) nla_get_u32(sig);
-
-	os_memset(&event, 0, sizeof(event));
-	if (freq) {
-		event.rx_mgmt.freq = nla_get_u32(freq);
-		rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
-	}
-	wpa_printf(MSG_DEBUG,
-		   "nl80211: RX frame sa=" MACSTR
-		   " freq=%d ssi_signal=%d stype=%u (%s) len=%u",
-		   MAC2STR(mgmt->sa), rx_freq, ssi_signal, stype, fc2str(fc),
-		   (unsigned int) len);
-	event.rx_mgmt.frame = frame;
-	event.rx_mgmt.frame_len = len;
-	event.rx_mgmt.ssi_signal = ssi_signal;
-	event.rx_mgmt.drv_priv = bss;
-	wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
-}
-
-
-static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
-				      struct nlattr *cookie, const u8 *frame,
-				      size_t len, struct nlattr *ack)
-{
-	union wpa_event_data event;
-	const struct ieee80211_hdr *hdr;
-	u16 fc;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
-	if (!is_ap_interface(drv->nlmode)) {
-		u64 cookie_val;
-
-		if (!cookie)
-			return;
-
-		cookie_val = nla_get_u64(cookie);
-		wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
-			   " cookie=0%llx%s (ack=%d)",
-			   (long long unsigned int) cookie_val,
-			   cookie_val == drv->send_action_cookie ?
-			   " (match)" : " (unknown)", ack != NULL);
-		if (cookie_val != drv->send_action_cookie)
-			return;
-	}
-
-	hdr = (const struct ieee80211_hdr *) frame;
-	fc = le_to_host16(hdr->frame_control);
-
-	os_memset(&event, 0, sizeof(event));
-	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
-	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
-	event.tx_status.dst = hdr->addr1;
-	event.tx_status.data = frame;
-	event.tx_status.data_len = len;
-	event.tx_status.ack = ack != NULL;
-	wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
-}
-
-
-static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
-				       enum wpa_event_type type,
-				       const u8 *frame, size_t len)
-{
-	const struct ieee80211_mgmt *mgmt;
-	union wpa_event_data event;
-	const u8 *bssid = NULL;
-	u16 reason_code = 0;
-
-	if (type == EVENT_DEAUTH)
-		wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
-	else
-		wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
-
-	mgmt = (const struct ieee80211_mgmt *) frame;
-	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) {
-			/*
-			 * We have presumably received this deauth as a
-			 * response to a clear_state_mismatch() outgoing
-			 * deauth.  Don't let it take us offline!
-			 */
-			wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
-				   "from Unknown BSSID " MACSTR " -- ignoring",
-				   MAC2STR(bssid));
-			return;
-		}
-	}
-
-	nl80211_mark_disconnected(drv);
-	os_memset(&event, 0, sizeof(event));
-
-	/* Note: Same offset for Reason Code in both frame subtypes */
-	if (len >= 24 + sizeof(mgmt->u.deauth))
-		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
-
-	if (type == EVENT_DISASSOC) {
-		event.disassoc_info.locally_generated =
-			!os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
-		event.disassoc_info.addr = bssid;
-		event.disassoc_info.reason_code = reason_code;
-		if (frame + len > mgmt->u.disassoc.variable) {
-			event.disassoc_info.ie = mgmt->u.disassoc.variable;
-			event.disassoc_info.ie_len = frame + len -
-				mgmt->u.disassoc.variable;
-		}
-	} else {
-		if (drv->ignore_deauth_event) {
-			wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth");
-			drv->ignore_deauth_event = 0;
-			return;
-		}
-		event.deauth_info.locally_generated =
-			!os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
-		if (drv->ignore_next_local_deauth) {
-			drv->ignore_next_local_deauth = 0;
-			if (event.deauth_info.locally_generated) {
-				wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event triggered due to own deauth request");
-				return;
-			}
-			wpa_printf(MSG_WARNING, "nl80211: Was expecting local deauth but got another disconnect event first");
-		}
-		event.deauth_info.addr = bssid;
-		event.deauth_info.reason_code = reason_code;
-		if (frame + len > mgmt->u.deauth.variable) {
-			event.deauth_info.ie = mgmt->u.deauth.variable;
-			event.deauth_info.ie_len = frame + len -
-				mgmt->u.deauth.variable;
-		}
-	}
-
-	wpa_supplicant_event(drv->ctx, type, &event);
-}
-
-
-static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
-					 enum wpa_event_type type,
-					 const u8 *frame, size_t len)
-{
-	const struct ieee80211_mgmt *mgmt;
-	union wpa_event_data event;
-	u16 reason_code = 0;
-
-	if (type == EVENT_UNPROT_DEAUTH)
-		wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
-	else
-		wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
-
-	if (len < 24)
-		return;
-
-	mgmt = (const struct ieee80211_mgmt *) frame;
-
-	os_memset(&event, 0, sizeof(event));
-	/* Note: Same offset for Reason Code in both frame subtypes */
-	if (len >= 24 + sizeof(mgmt->u.deauth))
-		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
-
-	if (type == EVENT_UNPROT_DISASSOC) {
-		event.unprot_disassoc.sa = mgmt->sa;
-		event.unprot_disassoc.da = mgmt->da;
-		event.unprot_disassoc.reason_code = reason_code;
-	} else {
-		event.unprot_deauth.sa = mgmt->sa;
-		event.unprot_deauth.da = mgmt->da;
-		event.unprot_deauth.reason_code = reason_code;
-	}
-
-	wpa_supplicant_event(drv->ctx, type, &event);
-}
-
-
-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 (%s) without frame data",
-			   cmd, nl80211_command_to_string(cmd));
-		return;
-	}
-
-	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));
-
-	switch (cmd) {
-	case NL80211_CMD_AUTHENTICATE:
-		mlme_event_auth(drv, nla_data(frame), nla_len(frame));
-		break;
-	case NL80211_CMD_ASSOCIATE:
-		mlme_event_assoc(drv, nla_data(frame), nla_len(frame));
-		break;
-	case NL80211_CMD_DEAUTHENTICATE:
-		mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
-					   nla_data(frame), nla_len(frame));
-		break;
-	case NL80211_CMD_DISASSOCIATE:
-		mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
-					   nla_data(frame), nla_len(frame));
-		break;
-	case NL80211_CMD_FRAME:
-		mlme_event_mgmt(bss, freq, sig, nla_data(frame),
-				nla_len(frame));
-		break;
-	case NL80211_CMD_FRAME_TX_STATUS:
-		mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
-					  nla_len(frame), ack);
-		break;
-	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
-		mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
-					     nla_data(frame), nla_len(frame));
-		break;
-	case NL80211_CMD_UNPROT_DISASSOCIATE:
-		mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
-					     nla_data(frame), nla_len(frame));
-		break;
-	default:
-		break;
-	}
-}
-
-
-static void mlme_event_michael_mic_failure(struct i802_bss *bss,
-					   struct nlattr *tb[])
-{
-	union wpa_event_data data;
-
-	wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
-	os_memset(&data, 0, sizeof(data));
-	if (tb[NL80211_ATTR_MAC]) {
-		wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
-			    nla_data(tb[NL80211_ATTR_MAC]),
-			    nla_len(tb[NL80211_ATTR_MAC]));
-		data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
-	}
-	if (tb[NL80211_ATTR_KEY_SEQ]) {
-		wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
-			    nla_data(tb[NL80211_ATTR_KEY_SEQ]),
-			    nla_len(tb[NL80211_ATTR_KEY_SEQ]));
-	}
-	if (tb[NL80211_ATTR_KEY_TYPE]) {
-		enum nl80211_key_type key_type =
-			nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
-		wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
-		if (key_type == NL80211_KEYTYPE_PAIRWISE)
-			data.michael_mic_failure.unicast = 1;
-	} else
-		data.michael_mic_failure.unicast = 1;
-
-	if (tb[NL80211_ATTR_KEY_IDX]) {
-		u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
-		wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
-	}
-
-	wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-}
-
-
-static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
-				 struct nlattr *tb[])
-{
-	unsigned int freq;
-
-	if (tb[NL80211_ATTR_MAC] == NULL) {
-		wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
-			   "event");
-		return;
-	}
-	os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
-	drv->associated = 1;
-	wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
-		   MAC2STR(drv->bssid));
-
-	freq = nl80211_get_assoc_freq(drv);
-	if (freq) {
-		wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz",
-			   freq);
-		drv->first_bss->freq = freq;
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-}
-
-
-static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
-					 int cancel_event, struct nlattr *tb[])
-{
-	unsigned int freq, chan_type, duration;
-	union wpa_event_data data;
-	u64 cookie;
-
-	if (tb[NL80211_ATTR_WIPHY_FREQ])
-		freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
-	else
-		freq = 0;
-
-	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
-		chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
-	else
-		chan_type = 0;
-
-	if (tb[NL80211_ATTR_DURATION])
-		duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
-	else
-		duration = 0;
-
-	if (tb[NL80211_ATTR_COOKIE])
-		cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
-	else
-		cookie = 0;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
-		   "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
-		   cancel_event, freq, chan_type, duration,
-		   (long long unsigned int) cookie,
-		   cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
-
-	if (cookie != drv->remain_on_chan_cookie)
-		return; /* not for us */
-
-	if (cancel_event)
-		drv->pending_remain_on_chan = 0;
-
-	os_memset(&data, 0, sizeof(data));
-	data.remain_on_channel.freq = freq;
-	data.remain_on_channel.duration = duration;
-	wpa_supplicant_event(drv->ctx, cancel_event ?
-			     EVENT_CANCEL_REMAIN_ON_CHANNEL :
-			     EVENT_REMAIN_ON_CHANNEL, &data);
-}
-
-
-static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
-				struct nlattr *tb[])
-{
-	union wpa_event_data data;
-
-	os_memset(&data, 0, sizeof(data));
-
-	if (tb[NL80211_ATTR_IE]) {
-		data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]);
-		data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]);
-	}
-
-	if (tb[NL80211_ATTR_IE_RIC]) {
-		data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]);
-		data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]);
-	}
-
-	if (tb[NL80211_ATTR_MAC])
-		os_memcpy(data.ft_ies.target_ap,
-			  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
-	wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR,
-		   MAC2STR(data.ft_ies.target_ap));
-
-	wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data);
-}
-
-
-static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
-			    struct nlattr *tb[])
-{
-	union wpa_event_data event;
-	struct nlattr *nl;
-	int rem;
-	struct scan_info *info;
-#define MAX_REPORT_FREQS 50
-	int freqs[MAX_REPORT_FREQS];
-	int num_freqs = 0;
-
-	if (drv->scan_for_auth) {
-		drv->scan_for_auth = 0;
-		wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
-			   "cfg80211 BSS entry");
-		wpa_driver_nl80211_authenticate_retry(drv);
-		return;
-	}
-
-	os_memset(&event, 0, sizeof(event));
-	info = &event.scan_info;
-	info->aborted = aborted;
-
-	if (tb[NL80211_ATTR_SCAN_SSIDS]) {
-		nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
-			struct wpa_driver_scan_ssid *s =
-				&info->ssids[info->num_ssids];
-			s->ssid = nla_data(nl);
-			s->ssid_len = nla_len(nl);
-			wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'",
-				   wpa_ssid_txt(s->ssid, s->ssid_len));
-			info->num_ssids++;
-			if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
-				break;
-		}
-	}
-	if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
-		char msg[200], *pos, *end;
-		int res;
-
-		pos = msg;
-		end = pos + sizeof(msg);
-		*pos = '\0';
-
-		nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
-		{
-			freqs[num_freqs] = nla_get_u32(nl);
-			res = os_snprintf(pos, end - pos, " %d",
-					  freqs[num_freqs]);
-			if (res > 0 && end - pos > res)
-				pos += res;
-			num_freqs++;
-			if (num_freqs == MAX_REPORT_FREQS - 1)
-				break;
-		}
-		info->freqs = freqs;
-		info->num_freqs = num_freqs;
-		wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
-			   msg);
-	}
-	wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
-}
-
-
 static int get_link_signal(struct nl_msg *msg, void *arg)
 {
 	struct nlattr *tb[NL80211_ATTR_MAX + 1];
@@ -2372,27 +1211,21 @@
 }
 
 
-static int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
-				   struct wpa_signal_info *sig)
+int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
+			    struct wpa_signal_info *sig)
 {
 	struct nl_msg *msg;
 
 	sig->current_signal = -9999;
 	sig->current_txrate = 0;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_STATION)) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	return send_and_recv_msgs(drv, msg, get_link_signal, sig);
- nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
@@ -2440,946 +1273,16 @@
 }
 
 
-static int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
-				  struct wpa_signal_info *sig_change)
+int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
+			   struct wpa_signal_info *sig_change)
 {
 	struct nl_msg *msg;
 
 	sig_change->current_noise = 9999;
 	sig_change->frequency = drv->assoc_freq;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
+	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
 	return send_and_recv_msgs(drv, msg, get_link_noise, sig_change);
- nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
-}
-
-
-static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
-	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
-		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
-		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
-	};
-	struct wpa_scan_results *scan_results = arg;
-	struct wpa_scan_res *scan_res;
-	size_t i;
-
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-
-	if (!tb[NL80211_ATTR_SURVEY_INFO]) {
-		wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
-		return NL_SKIP;
-	}
-
-	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
-			     tb[NL80211_ATTR_SURVEY_INFO],
-			     survey_policy)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
-			   "attributes");
-		return NL_SKIP;
-	}
-
-	if (!sinfo[NL80211_SURVEY_INFO_NOISE])
-		return NL_SKIP;
-
-	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
-		return NL_SKIP;
-
-	for (i = 0; i < scan_results->num; ++i) {
-		scan_res = scan_results->res[i];
-		if (!scan_res)
-			continue;
-		if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
-		    scan_res->freq)
-			continue;
-		if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
-			continue;
-		scan_res->noise = (s8)
-			nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
-		scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
-	}
-
-	return NL_SKIP;
-}
-
-
-static int nl80211_get_noise_for_scan_results(
-	struct wpa_driver_nl80211_data *drv,
-	struct wpa_scan_results *scan_res)
-{
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-	return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
-				  scan_res);
- nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
-}
-
-
-static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
-			      struct nlattr *tb[])
-{
-	static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
-		[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
-		[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
-		[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
-		[NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
-	};
-	struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
-	enum nl80211_cqm_rssi_threshold_event event;
-	union wpa_event_data ed;
-	struct wpa_signal_info sig;
-	int res;
-
-	if (tb[NL80211_ATTR_CQM] == NULL ||
-	    nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
-			     cqm_policy)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
-		return;
-	}
-
-	os_memset(&ed, 0, sizeof(ed));
-
-	if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
-		if (!tb[NL80211_ATTR_MAC])
-			return;
-		os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
-			  ETH_ALEN);
-		wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
-		return;
-	}
-
-	if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
-		return;
-	event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
-
-	if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
-		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
-			   "event: RSSI high");
-		ed.signal_change.above_threshold = 1;
-	} else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
-		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
-			   "event: RSSI low");
-		ed.signal_change.above_threshold = 0;
-	} else
-		return;
-
-	res = nl80211_get_link_signal(drv, &sig);
-	if (res == 0) {
-		ed.signal_change.current_signal = sig.current_signal;
-		ed.signal_change.current_txrate = sig.current_txrate;
-		wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm  txrate: %d",
-			   sig.current_signal, sig.current_txrate);
-	}
-
-	res = nl80211_get_link_noise(drv, &sig);
-	if (res == 0) {
-		ed.signal_change.current_noise = sig.current_noise;
-		wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
-			   sig.current_noise);
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
-}
-
-
-static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
-				      struct nlattr **tb)
-{
-	u8 *addr;
-	union wpa_event_data data;
-
-	if (tb[NL80211_ATTR_MAC] == NULL)
-		return;
-	addr = nla_data(tb[NL80211_ATTR_MAC]);
-	wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
-
-	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
-		u8 *ies = NULL;
-		size_t ies_len = 0;
-		if (tb[NL80211_ATTR_IE]) {
-			ies = nla_data(tb[NL80211_ATTR_IE]);
-			ies_len = nla_len(tb[NL80211_ATTR_IE]);
-		}
-		wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
-		drv_event_assoc(drv->ctx, addr, ies, ies_len, 0);
-		return;
-	}
-
-	if (drv->nlmode != NL80211_IFTYPE_ADHOC)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
-	wpa_supplicant_event(drv->ctx, EVENT_IBSS_RSN_START, &data);
-}
-
-
-static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
-				      struct nlattr **tb)
-{
-	u8 *addr;
-	union wpa_event_data data;
-
-	if (tb[NL80211_ATTR_MAC] == NULL)
-		return;
-	addr = nla_data(tb[NL80211_ATTR_MAC]);
-	wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
-		   MAC2STR(addr));
-
-	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
-		drv_event_disassoc(drv->ctx, addr);
-		return;
-	}
-
-	if (drv->nlmode != NL80211_IFTYPE_ADHOC)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
-	wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
-}
-
-
-static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
-					struct nlattr **tb)
-{
-	struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
-	static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
-		[NL80211_REKEY_DATA_KEK] = {
-			.minlen = NL80211_KEK_LEN,
-			.maxlen = NL80211_KEK_LEN,
-		},
-		[NL80211_REKEY_DATA_KCK] = {
-			.minlen = NL80211_KCK_LEN,
-			.maxlen = NL80211_KCK_LEN,
-		},
-		[NL80211_REKEY_DATA_REPLAY_CTR] = {
-			.minlen = NL80211_REPLAY_CTR_LEN,
-			.maxlen = NL80211_REPLAY_CTR_LEN,
-		},
-	};
-	union wpa_event_data data;
-
-	if (!tb[NL80211_ATTR_MAC])
-		return;
-	if (!tb[NL80211_ATTR_REKEY_DATA])
-		return;
-	if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
-			     tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
-		return;
-	if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
-	wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
-		   MAC2STR(data.driver_gtk_rekey.bssid));
-	data.driver_gtk_rekey.replay_ctr =
-		nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
-	wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
-		    data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
-	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
-}
-
-
-static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
-					  struct nlattr **tb)
-{
-	struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
-	static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
-		[NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
-		[NL80211_PMKSA_CANDIDATE_BSSID] = {
-			.minlen = ETH_ALEN,
-			.maxlen = ETH_ALEN,
-		},
-		[NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
-	};
-	union wpa_event_data data;
-
-	wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
-
-	if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
-		return;
-	if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
-			     tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
-		return;
-	if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
-	    !cand[NL80211_PMKSA_CANDIDATE_BSSID])
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	os_memcpy(data.pmkid_candidate.bssid,
-		  nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
-	data.pmkid_candidate.index =
-		nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
-	data.pmkid_candidate.preauth =
-		cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
-	wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
-}
-
-
-static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
-				       struct nlattr **tb)
-{
-	union wpa_event_data data;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
-
-	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	os_memcpy(data.client_poll.addr,
-		  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
-	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
-}
-
-
-static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
-				    struct nlattr **tb)
-{
-	union wpa_event_data data;
-
-	wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
-
-	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-	switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
-	case NL80211_TDLS_SETUP:
-		wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
-			   MACSTR, MAC2STR(data.tdls.peer));
-		data.tdls.oper = TDLS_REQUEST_SETUP;
-		break;
-	case NL80211_TDLS_TEARDOWN:
-		wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
-			   MACSTR, MAC2STR(data.tdls.peer));
-		data.tdls.oper = TDLS_REQUEST_TEARDOWN;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
-			   "event");
-		return;
-	}
-	if (tb[NL80211_ATTR_REASON_CODE]) {
-		data.tdls.reason_code =
-			nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
-}
-
-
-static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
-			    struct nlattr **tb)
-{
-	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
-}
-
-
-static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
-					 struct nlattr **tb)
-{
-	union wpa_event_data data;
-	u32 reason;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
-
-	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	os_memcpy(data.connect_failed_reason.addr,
-		  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
-
-	reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
-	switch (reason) {
-	case NL80211_CONN_FAIL_MAX_CLIENTS:
-		wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
-		data.connect_failed_reason.code = MAX_CLIENT_REACHED;
-		break;
-	case NL80211_CONN_FAIL_BLOCKED_CLIENT:
-		wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
-			   " tried to connect",
-			   MAC2STR(data.connect_failed_reason.addr));
-		data.connect_failed_reason.code = BLOCKED_CLIENT;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
-			   "%u", reason);
-		return;
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
-}
-
-
-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_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
-	event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
-
-	/* Check HT params */
-	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
-		data.dfs_event.ht_enabled = 1;
-		data.dfs_event.chan_offset = 0;
-
-		switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
-		case NL80211_CHAN_NO_HT:
-			data.dfs_event.ht_enabled = 0;
-			break;
-		case NL80211_CHAN_HT20:
-			break;
-		case NL80211_CHAN_HT40PLUS:
-			data.dfs_event.chan_offset = 1;
-			break;
-		case NL80211_CHAN_HT40MINUS:
-			data.dfs_event.chan_offset = -1;
-			break;
-		}
-	}
-
-	/* Get VHT params */
-	if (tb[NL80211_ATTR_CHANNEL_WIDTH])
-		data.dfs_event.chan_width =
-			convert2width(nla_get_u32(
-					      tb[NL80211_ATTR_CHANNEL_WIDTH]));
-	if (tb[NL80211_ATTR_CENTER_FREQ1])
-		data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
-	if (tb[NL80211_ATTR_CENTER_FREQ2])
-		data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
-
-	wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
-		   data.dfs_event.freq, data.dfs_event.ht_enabled,
-		   data.dfs_event.chan_offset, data.dfs_event.chan_width,
-		   data.dfs_event.cf1, data.dfs_event.cf2);
-
-	switch (event_type) {
-	case NL80211_RADAR_DETECTED:
-		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)
-{
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	union wpa_event_data event;
-
-	if (!tb[NL80211_ATTR_MAC])
-		return;
-
-	os_memset(&event, 0, sizeof(event));
-	event.rx_from_unknown.bssid = bss->addr;
-	event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
-	event.rx_from_unknown.wds = wds;
-
-	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
-}
-
-
-static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
-				   const u8 *data, size_t len)
-{
-	u32 i, count;
-	union wpa_event_data event;
-	struct wpa_freq_range *range = NULL;
-	const struct qca_avoid_freq_list *freq_range;
-
-	freq_range = (const struct qca_avoid_freq_list *) data;
-	if (len < sizeof(freq_range->count))
-		return;
-
-	count = freq_range->count;
-	if (len < sizeof(freq_range->count) +
-	    count * sizeof(struct qca_avoid_freq_range)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)",
-			   (unsigned int) len);
-		return;
-	}
-
-	if (count > 0) {
-		range = os_calloc(count, sizeof(struct wpa_freq_range));
-		if (range == NULL)
-			return;
-	}
-
-	os_memset(&event, 0, sizeof(event));
-	for (i = 0; i < count; i++) {
-		unsigned int idx = event.freq_range.num;
-		range[idx].min = freq_range->range[i].start_freq;
-		range[idx].max = freq_range->range[i].end_freq;
-		wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u",
-			   range[idx].min, range[idx].max);
-		if (range[idx].min > range[idx].max) {
-			wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range");
-			continue;
-		}
-		event.freq_range.num++;
-	}
-	event.freq_range.range = range;
-
-	wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event);
-
-	os_free(range);
-}
-
-
-static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
-				     u32 subcmd, u8 *data, size_t len)
-{
-	switch (subcmd) {
-	case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
-		qca_nl80211_avoid_freq(drv, data, len);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG,
-			   "nl80211: Ignore unsupported QCA vendor event %u",
-			   subcmd);
-		break;
-	}
-}
-
-
-static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
-				 struct nlattr **tb)
-{
-	u32 vendor_id, subcmd, wiphy = 0;
-	int wiphy_idx;
-	u8 *data = NULL;
-	size_t len = 0;
-
-	if (!tb[NL80211_ATTR_VENDOR_ID] ||
-	    !tb[NL80211_ATTR_VENDOR_SUBCMD])
-		return;
-
-	vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]);
-	subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]);
-
-	if (tb[NL80211_ATTR_WIPHY])
-		wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
-
-	wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u",
-		   wiphy, vendor_id, subcmd);
-
-	if (tb[NL80211_ATTR_VENDOR_DATA]) {
-		data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]);
-		len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]);
-		wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len);
-	}
-
-	wiphy_idx = nl80211_get_wiphy_index(drv->first_bss);
-	if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) {
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)",
-			   wiphy, wiphy_idx);
-		return;
-	}
-
-	switch (vendor_id) {
-	case OUI_QCA:
-		nl80211_vendor_event_qca(drv, subcmd, data, len);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
-		break;
-	}
-}
-
-
-static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv,
-				     struct nlattr *tb[])
-{
-	union wpa_event_data data;
-	enum nl80211_reg_initiator init;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
-
-	if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-	init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]);
-	wpa_printf(MSG_DEBUG, " * initiator=%d", init);
-	switch (init) {
-	case NL80211_REGDOM_SET_BY_CORE:
-		data.channel_list_changed.initiator = REGDOM_SET_BY_CORE;
-		break;
-	case NL80211_REGDOM_SET_BY_USER:
-		data.channel_list_changed.initiator = REGDOM_SET_BY_USER;
-		break;
-	case NL80211_REGDOM_SET_BY_DRIVER:
-		data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER;
-		break;
-	case NL80211_REGDOM_SET_BY_COUNTRY_IE:
-		data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE;
-		break;
-	}
-
-	if (tb[NL80211_ATTR_REG_TYPE]) {
-		enum nl80211_reg_type type;
-		type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
-		wpa_printf(MSG_DEBUG, " * type=%d", type);
-		switch (type) {
-		case NL80211_REGDOM_TYPE_COUNTRY:
-			data.channel_list_changed.type = REGDOM_TYPE_COUNTRY;
-			break;
-		case NL80211_REGDOM_TYPE_WORLD:
-			data.channel_list_changed.type = REGDOM_TYPE_WORLD;
-			break;
-		case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
-			data.channel_list_changed.type =
-				REGDOM_TYPE_CUSTOM_WORLD;
-			break;
-		case NL80211_REGDOM_TYPE_INTERSECTION:
-			data.channel_list_changed.type =
-				REGDOM_TYPE_INTERSECTION;
-			break;
-		}
-	}
-
-	if (tb[NL80211_ATTR_REG_ALPHA2]) {
-		os_strlcpy(data.channel_list_changed.alpha2,
-			   nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
-			   sizeof(data.channel_list_changed.alpha2));
-		wpa_printf(MSG_DEBUG, " * alpha2=%s",
-			   data.channel_list_changed.alpha2);
-	}
-
-	wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
-}
-
-
-static void do_process_drv_event(struct i802_bss *bss, int cmd,
-				 struct nlattr **tb)
-{
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	union wpa_event_data data;
-
-	wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
-		   cmd, nl80211_command_to_string(cmd), bss->ifname);
-
-	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
-	    (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
-	     cmd == NL80211_CMD_SCAN_ABORTED)) {
-		wpa_driver_nl80211_set_mode(drv->first_bss,
-					    drv->ap_scan_as_station);
-		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
-	}
-
-	switch (cmd) {
-	case NL80211_CMD_TRIGGER_SCAN:
-		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
-		drv->scan_state = SCAN_STARTED;
-		if (drv->scan_for_auth) {
-			/*
-			 * Cannot indicate EVENT_SCAN_STARTED here since we skip
-			 * EVENT_SCAN_RESULTS in scan_for_auth case and the
-			 * upper layer implementation could get confused about
-			 * scanning state.
-			 */
-			wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth");
-			break;
-		}
-		wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
-		break;
-	case NL80211_CMD_START_SCHED_SCAN:
-		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
-		drv->scan_state = SCHED_SCAN_STARTED;
-		break;
-	case NL80211_CMD_SCHED_SCAN_STOPPED:
-		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
-		drv->scan_state = SCHED_SCAN_STOPPED;
-		wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
-		break;
-	case NL80211_CMD_NEW_SCAN_RESULTS:
-		wpa_dbg(drv->ctx, MSG_DEBUG,
-			"nl80211: New scan results available");
-		drv->scan_state = SCAN_COMPLETED;
-		drv->scan_complete_events = 1;
-		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
-				     drv->ctx);
-		send_scan_event(drv, 0, tb);
-		break;
-	case NL80211_CMD_SCHED_SCAN_RESULTS:
-		wpa_dbg(drv->ctx, MSG_DEBUG,
-			"nl80211: New sched scan results available");
-		drv->scan_state = SCHED_SCAN_RESULTS;
-		send_scan_event(drv, 0, tb);
-		break;
-	case NL80211_CMD_SCAN_ABORTED:
-		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
-		drv->scan_state = SCAN_ABORTED;
-		/*
-		 * Need to indicate that scan results are available in order
-		 * not to make wpa_supplicant stop its scanning.
-		 */
-		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
-				     drv->ctx);
-		send_scan_event(drv, 1, tb);
-		break;
-	case NL80211_CMD_AUTHENTICATE:
-	case NL80211_CMD_ASSOCIATE:
-	case NL80211_CMD_DEAUTHENTICATE:
-	case NL80211_CMD_DISASSOCIATE:
-	case NL80211_CMD_FRAME_TX_STATUS:
-	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
-	case NL80211_CMD_UNPROT_DISASSOCIATE:
-		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],
-			   tb[NL80211_ATTR_RX_SIGNAL_DBM]);
-		break;
-	case NL80211_CMD_CONNECT:
-	case NL80211_CMD_ROAM:
-		mlme_event_connect(drv, cmd,
-				   tb[NL80211_ATTR_STATUS_CODE],
-				   tb[NL80211_ATTR_MAC],
-				   tb[NL80211_ATTR_REQ_IE],
-				   tb[NL80211_ATTR_RESP_IE]);
-		break;
-	case NL80211_CMD_CH_SWITCH_NOTIFY:
-		mlme_event_ch_switch(drv,
-				     tb[NL80211_ATTR_IFINDEX],
-				     tb[NL80211_ATTR_WIPHY_FREQ],
-				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
-				     tb[NL80211_ATTR_CHANNEL_WIDTH],
-				     tb[NL80211_ATTR_CENTER_FREQ1],
-				     tb[NL80211_ATTR_CENTER_FREQ2]);
-		break;
-	case NL80211_CMD_DISCONNECT:
-		mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
-				      tb[NL80211_ATTR_MAC],
-				      tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
-		break;
-	case NL80211_CMD_MICHAEL_MIC_FAILURE:
-		mlme_event_michael_mic_failure(bss, tb);
-		break;
-	case NL80211_CMD_JOIN_IBSS:
-		mlme_event_join_ibss(drv, tb);
-		break;
-	case NL80211_CMD_REMAIN_ON_CHANNEL:
-		mlme_event_remain_on_channel(drv, 0, tb);
-		break;
-	case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
-		mlme_event_remain_on_channel(drv, 1, tb);
-		break;
-	case NL80211_CMD_NOTIFY_CQM:
-		nl80211_cqm_event(drv, tb);
-		break;
-	case NL80211_CMD_REG_CHANGE:
-		nl80211_reg_change_event(drv, tb);
-		break;
-	case NL80211_CMD_REG_BEACON_HINT:
-		wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
-		os_memset(&data, 0, sizeof(data));
-		data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
-		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
-				     &data);
-		break;
-	case NL80211_CMD_NEW_STATION:
-		nl80211_new_station_event(drv, tb);
-		break;
-	case NL80211_CMD_DEL_STATION:
-		nl80211_del_station_event(drv, tb);
-		break;
-	case NL80211_CMD_SET_REKEY_OFFLOAD:
-		nl80211_rekey_offload_event(drv, tb);
-		break;
-	case NL80211_CMD_PMKSA_CANDIDATE:
-		nl80211_pmksa_candidate_event(drv, tb);
-		break;
-	case NL80211_CMD_PROBE_CLIENT:
-		nl80211_client_probe_event(drv, tb);
-		break;
-	case NL80211_CMD_TDLS_OPER:
-		nl80211_tdls_oper_event(drv, tb);
-		break;
-	case NL80211_CMD_CONN_FAILED:
-		nl80211_connect_failed_event(drv, tb);
-		break;
-	case NL80211_CMD_FT_EVENT:
-		mlme_event_ft_event(drv, tb);
-		break;
-	case NL80211_CMD_RADAR_DETECT:
-		nl80211_radar_event(drv, tb);
-		break;
-	case NL80211_CMD_STOP_AP:
-		nl80211_stop_ap(drv, tb);
-		break;
-	case NL80211_CMD_VENDOR:
-		nl80211_vendor_event(drv, tb);
-		break;
-	default:
-		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
-			"(cmd=%d)", cmd);
-		break;
-	}
-}
-
-
-static int process_drv_event(struct nl_msg *msg, void *arg)
-{
-	struct wpa_driver_nl80211_data *drv = arg;
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct i802_bss *bss;
-	int ifidx = -1;
-
-	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]);
-
-		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);
-	}
-
-	return NL_SKIP;
-}
-
-
-static int process_global_event(struct nl_msg *msg, void *arg)
-{
-	struct nl80211_global *global = arg;
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	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 && !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;
-			}
-		}
-	}
-
-	return NL_SKIP;
-}
-
-
-static int process_bss_event(struct nl_msg *msg, void *arg)
-{
-	struct i802_bss *bss = arg;
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-
-	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, 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],
-			   tb[NL80211_ATTR_RX_SIGNAL_DBM]);
-		break;
-	case NL80211_CMD_UNEXPECTED_FRAME:
-		nl80211_spurious_frame(bss, tb, 0);
-		break;
-	case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
-		nl80211_spurious_frame(bss, tb, 1);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
-			   "(cmd=%d)", gnlh->cmd);
-		break;
-	}
-
-	return NL_SKIP;
 }
 
 
@@ -3423,15 +1326,14 @@
 	alpha2[1] = alpha2_arg[1];
 	alpha2[2] = '\0';
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
-
-	NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
+	if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG) ||
+	    nla_put_string(msg, NL80211_ATTR_REG_ALPHA2, alpha2)) {
+		nlmsg_free(msg);
+		return -EINVAL;
+	}
 	if (send_and_recv_msgs(drv, msg, NULL, NULL))
 		return -EINVAL;
 	return 0;
-nla_put_failure:
-	nlmsg_free(msg);
-	return -EINVAL;
 }
 
 
@@ -3473,709 +1375,6 @@
 }
 
 
-static int protocol_feature_handler(struct nl_msg *msg, void *arg)
-{
-	u32 *feat = arg;
-	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-
-	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-
-	if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
-		*feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
-
-	return NL_SKIP;
-}
-
-
-static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
-{
-	u32 feat = 0;
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		goto nla_put_failure;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES);
-	if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
-		return feat;
-
-	msg = NULL;
-nla_put_failure:
-	nlmsg_free(msg);
-	return 0;
-}
-
-
-struct wiphy_info_data {
-	struct wpa_driver_nl80211_data *drv;
-	struct wpa_driver_capa *capa;
-
-	unsigned int num_multichan_concurrent;
-
-	unsigned int error:1;
-	unsigned int device_ap_sme:1;
-	unsigned int poll_command_supported:1;
-	unsigned int data_tx_status:1;
-	unsigned int monitor_supported:1;
-	unsigned int auth_supported:1;
-	unsigned int connect_supported:1;
-	unsigned int p2p_go_supported:1;
-	unsigned int p2p_client_supported:1;
-	unsigned int p2p_concurrent:1;
-	unsigned int channel_switch_supported:1;
-	unsigned int set_qos_map_supported:1;
-	unsigned int have_low_prio_scan:1;
-};
-
-
-static unsigned int probe_resp_offload_support(int supp_protocols)
-{
-	unsigned int prot = 0;
-
-	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
-		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
-	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
-		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
-	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
-		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
-	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
-		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
-
-	return prot;
-}
-
-
-static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
-					 struct nlattr *tb)
-{
-	struct nlattr *nl_mode;
-	int i;
-
-	if (tb == NULL)
-		return;
-
-	nla_for_each_nested(nl_mode, tb, i) {
-		switch (nla_type(nl_mode)) {
-		case NL80211_IFTYPE_AP:
-			info->capa->flags |= WPA_DRIVER_FLAGS_AP;
-			break;
-		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;
-		case NL80211_IFTYPE_P2P_CLIENT:
-			info->p2p_client_supported = 1;
-			break;
-		case NL80211_IFTYPE_MONITOR:
-			info->monitor_supported = 1;
-			break;
-		}
-	}
-}
-
-
-static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
-					 struct nlattr *nl_combi)
-{
-	struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
-	struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
-	struct nlattr *nl_limit, *nl_mode;
-	int err, rem_limit, rem_mode;
-	int combination_has_p2p = 0, combination_has_mgd = 0;
-	static struct nla_policy
-	iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
-		[NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
-		[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 },
-		[NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
-	};
-
-	err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
-			       nl_combi, iface_combination_policy);
-	if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
-	    !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
-	    !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,
-				       nl_limit, iface_limit_policy);
-		if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
-			return 0; /* broken combination */
-
-		nla_for_each_nested(nl_mode,
-				    tb_limit[NL80211_IFACE_LIMIT_TYPES],
-				    rem_mode) {
-			int ift = nla_type(nl_mode);
-			if (ift == NL80211_IFTYPE_P2P_GO ||
-			    ift == NL80211_IFTYPE_P2P_CLIENT)
-				combination_has_p2p = 1;
-			if (ift == NL80211_IFTYPE_STATION)
-				combination_has_mgd = 1;
-		}
-		if (combination_has_p2p && combination_has_mgd)
-			break;
-	}
-
-	if (combination_has_p2p && combination_has_mgd) {
-		unsigned int num_channels =
-			nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
-
-		info->p2p_concurrent = 1;
-		if (info->num_multichan_concurrent < num_channels)
-			info->num_multichan_concurrent = num_channels;
-	}
-
-	return 0;
-}
-
-
-static void wiphy_info_iface_comb(struct wiphy_info_data *info,
-				  struct nlattr *tb)
-{
-	struct nlattr *nl_combi;
-	int rem_combi;
-
-	if (tb == NULL)
-		return;
-
-	nla_for_each_nested(nl_combi, tb, rem_combi) {
-		if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
-			break;
-	}
-}
-
-
-static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
-				 struct nlattr *tb)
-{
-	struct nlattr *nl_cmd;
-	int i;
-
-	if (tb == NULL)
-		return;
-
-	nla_for_each_nested(nl_cmd, tb, i) {
-		switch (nla_get_u32(nl_cmd)) {
-		case NL80211_CMD_AUTHENTICATE:
-			info->auth_supported = 1;
-			break;
-		case NL80211_CMD_CONNECT:
-			info->connect_supported = 1;
-			break;
-		case NL80211_CMD_START_SCHED_SCAN:
-			info->capa->sched_scan_supported = 1;
-			break;
-		case NL80211_CMD_PROBE_CLIENT:
-			info->poll_command_supported = 1;
-			break;
-		case NL80211_CMD_CHANNEL_SWITCH:
-			info->channel_switch_supported = 1;
-			break;
-		case NL80211_CMD_SET_QOS_MAP:
-			info->set_qos_map_supported = 1;
-			break;
-		}
-	}
-}
-
-
-static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
-				     struct nlattr *tb)
-{
-	int i, num;
-	u32 *ciphers;
-
-	if (tb == NULL)
-		return;
-
-	num = nla_len(tb) / sizeof(u32);
-	ciphers = nla_data(tb);
-	for (i = 0; i < num; i++) {
-		u32 c = ciphers[i];
-
-		wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
-			   c >> 24, (c >> 16) & 0xff,
-			   (c >> 8) & 0xff, c & 0xff);
-		switch (c) {
-		case WLAN_CIPHER_SUITE_CCMP_256:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
-			break;
-		case WLAN_CIPHER_SUITE_GCMP_256:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
-			break;
-		case WLAN_CIPHER_SUITE_CCMP:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
-			break;
-		case WLAN_CIPHER_SUITE_GCMP:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
-			break;
-		case WLAN_CIPHER_SUITE_TKIP:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
-			break;
-		case WLAN_CIPHER_SUITE_WEP104:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
-			break;
-		case WLAN_CIPHER_SUITE_WEP40:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
-			break;
-		case WLAN_CIPHER_SUITE_AES_CMAC:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
-			break;
-		case WLAN_CIPHER_SUITE_BIP_GMAC_128:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
-			break;
-		case WLAN_CIPHER_SUITE_BIP_GMAC_256:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
-			break;
-		case WLAN_CIPHER_SUITE_BIP_CMAC_256:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
-			break;
-		case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
-			info->capa->enc |= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED;
-			break;
-		}
-	}
-}
-
-
-static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
-			       struct nlattr *tb)
-{
-	if (tb)
-		capa->max_remain_on_chan = nla_get_u32(tb);
-}
-
-
-static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
-			    struct nlattr *ext_setup)
-{
-	if (tdls == NULL)
-		return;
-
-	wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
-	capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
-
-	if (ext_setup) {
-		wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
-		capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
-	}
-}
-
-
-static void wiphy_info_feature_flags(struct wiphy_info_data *info,
-				     struct nlattr *tb)
-{
-	u32 flags;
-	struct wpa_driver_capa *capa = info->capa;
-
-	if (tb == NULL)
-		return;
-
-	flags = nla_get_u32(tb);
-
-	if (flags & NL80211_FEATURE_SK_TX_STATUS)
-		info->data_tx_status = 1;
-
-	if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
-		capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
-
-	if (flags & NL80211_FEATURE_SAE)
-		capa->flags |= WPA_DRIVER_FLAGS_SAE;
-
-	if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
-		capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
-
-	if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
-		capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
-
-	if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN)
-		info->have_low_prio_scan = 1;
-}
-
-
-static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
-					  struct nlattr *tb)
-{
-	u32 protocols;
-
-	if (tb == NULL)
-		return;
-
-	protocols = nla_get_u32(tb);
-	wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
-		   "mode");
-	capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
-	capa->probe_resp_offloads = probe_resp_offload_support(protocols);
-}
-
-
-static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
-				       struct nlattr *tb)
-{
-	struct nlattr *triggers[MAX_NL80211_WOWLAN_TRIG + 1];
-
-	if (tb == NULL)
-		return;
-
-	if (nla_parse_nested(triggers, MAX_NL80211_WOWLAN_TRIG,
-			     tb, NULL))
-		return;
-
-	if (triggers[NL80211_WOWLAN_TRIG_ANY])
-		capa->wowlan_triggers.any = 1;
-	if (triggers[NL80211_WOWLAN_TRIG_DISCONNECT])
-		capa->wowlan_triggers.disconnect = 1;
-	if (triggers[NL80211_WOWLAN_TRIG_MAGIC_PKT])
-		capa->wowlan_triggers.magic_pkt = 1;
-	if (triggers[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
-		capa->wowlan_triggers.gtk_rekey_failure = 1;
-	if (triggers[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
-		capa->wowlan_triggers.eap_identity_req = 1;
-	if (triggers[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
-		capa->wowlan_triggers.four_way_handshake = 1;
-	if (triggers[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
-		capa->wowlan_triggers.rfkill_release = 1;
-}
-
-
-static int wiphy_info_handler(struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct wiphy_info_data *info = arg;
-	struct wpa_driver_capa *capa = info->capa;
-	struct wpa_driver_nl80211_data *drv = info->drv;
-
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-
-	if (tb[NL80211_ATTR_WIPHY_NAME])
-		os_strlcpy(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]);
-
-	if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
-		capa->max_sched_scan_ssids =
-			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
-
-	if (tb[NL80211_ATTR_MAX_MATCH_SETS])
-		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]);
-	wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
-
-	if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
-		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
-			   "off-channel TX");
-		capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
-	}
-
-	if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
-		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
-		capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
-	}
-
-	wiphy_info_max_roc(capa,
-			   tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
-
-	if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
-		capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
-
-	wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
-			tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
-
-	if (tb[NL80211_ATTR_DEVICE_AP_SME])
-		info->device_ap_sme = 1;
-
-	wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
-	wiphy_info_probe_resp_offload(capa,
-				      tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
-
-	if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
-	    drv->extended_capa == NULL) {
-		drv->extended_capa =
-			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
-		if (drv->extended_capa) {
-			os_memcpy(drv->extended_capa,
-				  nla_data(tb[NL80211_ATTR_EXT_CAPA]),
-				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
-			drv->extended_capa_len =
-				nla_len(tb[NL80211_ATTR_EXT_CAPA]);
-		}
-		drv->extended_capa_mask =
-			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
-		if (drv->extended_capa_mask) {
-			os_memcpy(drv->extended_capa_mask,
-				  nla_data(tb[NL80211_ATTR_EXT_CAPA]),
-				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
-		} else {
-			os_free(drv->extended_capa);
-			drv->extended_capa = NULL;
-			drv->extended_capa_len = 0;
-		}
-	}
-
-	if (tb[NL80211_ATTR_VENDOR_DATA]) {
-		struct nlattr *nl;
-		int rem;
-
-		nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) {
-			struct nl80211_vendor_cmd_info *vinfo;
-			if (nla_len(nl) != sizeof(*vinfo)) {
-				wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
-				continue;
-			}
-			vinfo = nla_data(nl);
-			switch (vinfo->subcmd) {
-			case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
-				drv->roaming_vendor_cmd_avail = 1;
-				break;
-			case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
-				drv->dfs_vendor_cmd_avail = 1;
-				break;
-			}
-
-			wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
-				   vinfo->vendor_id, vinfo->subcmd);
-		}
-	}
-
-	if (tb[NL80211_ATTR_VENDOR_EVENTS]) {
-		struct nlattr *nl;
-		int rem;
-
-		nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) {
-			struct nl80211_vendor_cmd_info *vinfo;
-			if (nla_len(nl) != sizeof(*vinfo)) {
-				wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
-				continue;
-			}
-			vinfo = nla_data(nl);
-			wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
-				   vinfo->vendor_id, vinfo->subcmd);
-		}
-	}
-
-	wiphy_info_wowlan_triggers(capa,
-				   tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]);
-
-	if (tb[NL80211_ATTR_MAX_AP_ASSOC_STA])
-		capa->max_stations =
-			nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]);
-
-	return NL_SKIP;
-}
-
-
-static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
-				       struct wiphy_info_data *info)
-{
-	u32 feat;
-	struct nl_msg *msg;
-
-	os_memset(info, 0, sizeof(*info));
-	info->capa = &drv->capa;
-	info->drv = drv;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	feat = get_nl80211_protocol_features(drv);
-	if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
-		nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
-	else
-		nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
-
-	NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
-	if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
-		goto nla_put_failure;
-
-	if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
-		return -1;
-
-	if (info->auth_supported)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
-	else if (!info->connect_supported) {
-		wpa_printf(MSG_INFO, "nl80211: Driver does not support "
-			   "authentication/association or connect commands");
-		info->error = 1;
-	}
-
-	if (info->p2p_go_supported && info->p2p_client_supported)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
-	if (info->p2p_concurrent) {
-		wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
-			   "interface (driver advertised support)");
-		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
-		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
-	}
-	if (info->num_multichan_concurrent > 1) {
-		wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
-			   "concurrent (driver advertised support)");
-		drv->capa.num_multichan_concurrent =
-			info->num_multichan_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;
-
-	if (info->channel_switch_supported)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
-
-	return 0;
-nla_put_failure:
-	nlmsg_free(msg);
-	return -1;
-}
-
-
-static int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
-{
-	struct wiphy_info_data info;
-	if (wpa_driver_nl80211_get_info(drv, &info))
-		return -1;
-
-	if (info.error)
-		return -1;
-
-	drv->has_capability = 1;
-	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
-	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
-		WPA_DRIVER_AUTH_SHARED |
-		WPA_DRIVER_AUTH_LEAP;
-
-	drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
-	drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
-	drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
-
-	/*
-	 * As all cfg80211 drivers must support cases where the AP interface is
-	 * removed without the knowledge of wpa_supplicant/hostapd, e.g., in
-	 * case that the user space daemon has crashed, they must be able to
-	 * cleanup all stations and key entries in the AP tear down flow. Thus,
-	 * this flag can/should always be set for cfg80211 drivers.
-	 */
-	drv->capa.flags |= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT;
-
-	if (!info.device_ap_sme) {
-		drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
-
-		/*
-		 * No AP SME is currently assumed to also indicate no AP MLME
-		 * in the driver/firmware.
-		 */
-		drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
-	}
-
-	drv->device_ap_sme = info.device_ap_sme;
-	drv->poll_command_supported = info.poll_command_supported;
-	drv->data_tx_status = info.data_tx_status;
-	if (info.set_qos_map_supported)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
-	drv->have_low_prio_scan = info.have_low_prio_scan;
-
-	/*
-	 * If poll command and tx status are supported, mac80211 is new enough
-	 * to have everything we need to not need monitor interfaces.
-	 */
-	drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
-
-	if (drv->device_ap_sme && drv->use_monitor) {
-		/*
-		 * Non-mac80211 drivers may not support monitor interface.
-		 * Make sure we do not get stuck with incorrect capability here
-		 * by explicitly testing this.
-		 */
-		if (!info.monitor_supported) {
-			wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
-				   "with device_ap_sme since no monitor mode "
-				   "support detected");
-			drv->use_monitor = 0;
-		}
-	}
-
-	/*
-	 * If we aren't going to use monitor interfaces, but the
-	 * driver doesn't support data TX status, we won't get TX
-	 * status for EAPOL frames.
-	 */
-	if (!drv->use_monitor && !info.data_tx_status)
-		drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
-
-	return 0;
-}
-
-
-#ifdef ANDROID
-static int android_genl_ctrl_resolve(struct nl_handle *handle,
-				     const char *name)
-{
-	/*
-	 * Android ICS has very minimal genl_ctrl_resolve() implementation, so
-	 * need to work around that.
-	 */
-	struct nl_cache *cache = NULL;
-	struct genl_family *nl80211 = NULL;
-	int id = -1;
-
-	if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache");
-		goto fail;
-	}
-
-	nl80211 = genl_ctrl_search_by_name(cache, name);
-	if (nl80211 == NULL)
-		goto fail;
-
-	id = genl_family_get_id(nl80211);
-
-fail:
-	if (nl80211)
-		genl_family_put(nl80211);
-	if (cache)
-		nl_cache_free(cache);
-
-	return id;
-}
-#define genl_ctrl_resolve android_genl_ctrl_resolve
-#endif /* ANDROID */
-
-
 static int wpa_driver_nl80211_init_nl_global(struct nl80211_global *global)
 {
 	int ret;
@@ -4262,23 +1461,6 @@
 }
 
 
-static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
-{
-	drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
-	if (!drv->nl_cb) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to alloc cb struct");
-		return -1;
-	}
-
-	nl_cb_set(drv->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
-		  no_seq_check, NULL);
-	nl_cb_set(drv->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
-		  process_drv_event, drv);
-
-	return 0;
-}
-
-
 static void wpa_driver_nl80211_rfkill_blocked(void *ctx)
 {
 	wpa_printf(MSG_DEBUG, "nl80211: RFKILL blocked");
@@ -4385,7 +1567,8 @@
 
 static void * wpa_driver_nl80211_drv_init(void *ctx, const char *ifname,
 					  void *global_priv, int hostapd,
-					  const u8 *set_addr)
+					  const u8 *set_addr,
+					  const char *driver_params)
 {
 	struct wpa_driver_nl80211_data *drv;
 	struct rfkill_config *rcfg;
@@ -4418,11 +1601,6 @@
 	drv->eapol_tx_sock = -1;
 	drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 
-	if (wpa_driver_nl80211_init_nl(drv)) {
-		os_free(drv);
-		return NULL;
-	}
-
 	if (nl80211_init_bss(bss))
 		goto failed;
 
@@ -4442,7 +1620,7 @@
 	if (linux_iface_up(drv->global->ioctl_sock, ifname) > 0)
 		drv->start_iface_up = 1;
 
-	if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1))
+	if (wpa_driver_nl80211_finish_drv_init(drv, set_addr, 1, driver_params))
 		goto failed;
 
 	drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
@@ -4491,7 +1669,8 @@
 static void * wpa_driver_nl80211_init(void *ctx, const char *ifname,
 				      void *global_priv)
 {
-	return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL);
+	return wpa_driver_nl80211_drv_init(ctx, ifname, global_priv, 0, NULL,
+					   NULL);
 }
 
 
@@ -4501,54 +1680,42 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
-	int ret = -1;
+	int ret;
 	char buf[30];
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
 	buf[0] = '\0';
 	wpa_snprintf_hex(buf, sizeof(buf), match, match_len);
 	wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x (%s) nl_handle=%p match=%s",
 		   type, fc2str(type), nl_handle, buf);
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
-
-	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);
+	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REGISTER_ACTION)) ||
+	    nla_put_u16(msg, NL80211_ATTR_FRAME_TYPE, type) ||
+	    nla_put(msg, NL80211_ATTR_FRAME_MATCH, match_len, match)) {
+		nlmsg_free(msg);
+		return -1;
+	}
 
 	ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
-	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
 			   "failed (type=%u): ret=%d (%s)",
 			   type, ret, strerror(-ret));
 		wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
 			    match, match_len);
-		goto nla_put_failure;
 	}
-	ret = 0;
-nla_put_failure:
-	nlmsg_free(msg);
 	return ret;
 }
 
 
 static int nl80211_alloc_mgmt_handle(struct i802_bss *bss)
 {
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-
 	if (bss->nl_mgmt) {
 		wpa_printf(MSG_DEBUG, "nl80211: Mgmt reporting "
 			   "already on! (nl_mgmt=%p)", bss->nl_mgmt);
 		return -1;
 	}
 
-	bss->nl_mgmt = nl_create_handle(drv->nl_cb, "mgmt");
+	bss->nl_mgmt = nl_create_handle(bss->nl_cb, "mgmt");
 	if (bss->nl_mgmt == NULL)
 		return -1;
 
@@ -4667,6 +1834,57 @@
 		ret = -1;
 #endif /* CONFIG_HS20 */
 
+	/* WMM-AC ADDTS Response */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x11\x01", 2) < 0)
+		ret = -1;
+
+	/* WMM-AC DELTS */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x11\x02", 2) < 0)
+		ret = -1;
+
+	/* Radio Measurement - Neighbor Report Response */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x05\x05", 2) < 0)
+		ret = -1;
+
+	/* Radio Measurement - Link Measurement Request */
+	if ((drv->capa.rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION) &&
+	    (nl80211_register_action_frame(bss, (u8 *) "\x05\x02", 2) < 0))
+		ret = -1;
+
+	nl80211_mgmt_handle_register_eloop(bss);
+
+	return ret;
+}
+
+
+static int nl80211_mgmt_subscribe_mesh(struct i802_bss *bss)
+{
+	int ret = 0;
+
+	if (nl80211_alloc_mgmt_handle(bss))
+		return -1;
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: Subscribe to mgmt frames with mesh handle %p",
+		   bss->nl_mgmt);
+
+	/* Auth frames for mesh SAE */
+	if (nl80211_register_frame(bss, bss->nl_mgmt,
+				   (WLAN_FC_TYPE_MGMT << 2) |
+				   (WLAN_FC_STYPE_AUTH << 4),
+				   NULL, 0) < 0)
+		ret = -1;
+
+	/* Mesh peering open */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x01", 2) < 0)
+		ret = -1;
+	/* Mesh peering confirm */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x02", 2) < 0)
+		ret = -1;
+	/* Mesh peering close */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x0f\x03", 2) < 0)
+		ret = -1;
+
 	nl80211_mgmt_handle_register_eloop(bss);
 
 	return ret;
@@ -4675,29 +1893,16 @@
 
 static int nl80211_register_spurious_class3(struct i802_bss *bss)
 {
-	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
-	int ret = -1;
+	int ret;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_UNEXPECTED_FRAME);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-
-	ret = send_and_recv(drv->global, bss->nl_mgmt, msg, NULL, NULL);
-	msg = NULL;
+	msg = nl80211_bss_msg(bss, 0, NL80211_CMD_UNEXPECTED_FRAME);
+	ret = send_and_recv(bss->drv->global, bss->nl_mgmt, msg, NULL, NULL);
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Register spurious class3 "
 			   "failed: ret=%d (%s)",
 			   ret, strerror(-ret));
-		goto nla_put_failure;
 	}
-	ret = 0;
-nla_put_failure:
-	nlmsg_free(msg);
 	return ret;
 }
 
@@ -4792,56 +1997,31 @@
 
 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;
+	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_INTERFACE);
+	ret = send_and_recv_msgs(bss->drv, msg, NULL, 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;
+	int ret;
 
-	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;
+	msg = nl80211_cmd_msg(bss, 0, start ? NL80211_CMD_START_P2P_DEVICE :
+			      NL80211_CMD_STOP_P2P_DEVICE);
+	ret = send_and_recv_msgs(bss->drv, msg, NULL, 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;
 }
 
@@ -4863,7 +2043,8 @@
 
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv,
-				   const u8 *set_addr, int first)
+				   const u8 *set_addr, int first,
+				   const char *driver_params)
 {
 	struct i802_bss *bss = drv->first_bss;
 	int send_rfkill_event = 0;
@@ -4884,6 +2065,9 @@
 	if (wpa_driver_nl80211_capa(drv))
 		return -1;
 
+	if (driver_params && nl80211_set_param(bss, driver_params) < 0)
+		return -1;
+
 	wpa_printf(MSG_DEBUG, "nl80211: interface %s in phy %s",
 		   bss->ifname, drv->phyname);
 
@@ -4951,19 +2135,10 @@
 {
 	struct nl_msg *msg;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
 	wpa_printf(MSG_DEBUG, "nl80211: Remove beacon (ifindex=%d)",
 		   drv->ifindex);
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_DEL_BEACON);
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
@@ -4978,6 +2153,9 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
+	wpa_printf(MSG_INFO, "nl80211: deinit ifname=%s disabled_11b_rates=%d",
+		   bss->ifname, drv->disabled_11b_rates);
+
 	bss->in_deinit = 1;
 	if (drv->data_tx_status)
 		eloop_unregister_read_sock(drv->eapol_tx_sock);
@@ -4996,6 +2174,11 @@
 			nl80211_handle_destroy(drv->rtnl_sk);
 	}
 	if (bss->added_bridge) {
+		if (linux_set_iface_flags(drv->global->ioctl_sock, bss->brname,
+					  0) < 0)
+			wpa_printf(MSG_INFO,
+				   "nl80211: Could not set bridge %s down",
+				   bss->brname);
 		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
 			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
 				   "bridge %s: %s",
@@ -5029,7 +2212,11 @@
 		(void) i802_set_iface_flags(bss, 0);
 
 	if (drv->addr_changed) {
-		linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
+		if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname,
+					  0) < 0) {
+			wpa_printf(MSG_DEBUG,
+				   "nl80211: Could not set interface down to restore permanent MAC address");
+		}
 		if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
 				       drv->perm_addr) < 0) {
 			wpa_printf(MSG_DEBUG,
@@ -5046,7 +2233,6 @@
 		nl80211_mgmt_unsubscribe(bss, "deinit");
 		nl80211_del_p2pdev(bss);
 	}
-	nl_cb_put(drv->nl_cb);
 
 	nl80211_destroy_bss(drv->first_bss);
 
@@ -5064,720 +2250,6 @@
 }
 
 
-/**
- * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
- * @eloop_ctx: Driver private data
- * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
- *
- * This function can be used as registered timeout when starting a scan to
- * generate a scan completed event if the driver does not report this.
- */
-static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
-	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
-		wpa_driver_nl80211_set_mode(drv->first_bss,
-					    drv->ap_scan_as_station);
-		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
-	}
-	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static struct nl_msg *
-nl80211_scan_common(struct wpa_driver_nl80211_data *drv, u8 cmd,
-		    struct wpa_driver_scan_params *params, u64 *wdev_id)
-{
-	struct nl_msg *msg;
-	size_t i;
-	u32 scan_flags = 0;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return NULL;
-
-	nl80211_cmd(drv, msg, 0, cmd);
-
-	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 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(msg, i + 1, params->ssids[i].ssid_len,
-				    params->ssids[i].ssid) < 0)
-				goto fail;
-		}
-		nla_nest_end(msg, ssids);
-	}
-
-	if (params->extra_ies) {
-		wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
-			    params->extra_ies, params->extra_ies_len);
-		if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
-			    params->extra_ies) < 0)
-			goto fail;
-	}
-
-	if (params->freqs) {
-		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(msg, i + 1, params->freqs[i]) < 0)
-				goto fail;
-		}
-		nla_nest_end(msg, freqs);
-	}
-
-	os_free(drv->filter_ssids);
-	drv->filter_ssids = params->filter_ssids;
-	params->filter_ssids = NULL;
-	drv->num_filter_ssids = params->num_filter_ssids;
-
-	if (params->only_new_results) {
-		wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
-		scan_flags |= NL80211_SCAN_FLAG_FLUSH;
-	}
-
-	if (params->low_priority && drv->have_low_prio_scan) {
-		wpa_printf(MSG_DEBUG,
-			   "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
-		scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
-	}
-
-	if (scan_flags)
-		NLA_PUT_U32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags);
-
-	return msg;
-
-fail:
-nla_put_failure:
-	nlmsg_free(msg);
-	return NULL;
-}
-
-
-/**
- * wpa_driver_nl80211_scan - Request the driver to initiate scan
- * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
- * @params: Scan parameters
- * Returns: 0 on success, -1 on failure
- */
-static int wpa_driver_nl80211_scan(struct i802_bss *bss,
-				   struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret = -1, timeout;
-	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,
-				  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 = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
-		if (rates == NULL)
-			goto nla_put_failure;
-
-		/*
-		 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
-		 * by masking out everything else apart from the OFDM rates 6,
-		 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
-		 * rates are left enabled.
-		 */
-		NLA_PUT(msg, NL80211_BAND_2GHZ, 8,
-			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
-		nla_nest_end(msg, rates);
-
-		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
-	}
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
-		if (drv->hostapd && is_ap_interface(drv->nlmode)) {
-			enum nl80211_iftype old_mode = drv->nlmode;
-
-			/*
-			 * mac80211 does not allow scan requests in AP mode, so
-			 * try to do this in station mode.
-			 */
-			if (wpa_driver_nl80211_set_mode(
-				    bss, NL80211_IFTYPE_STATION))
-				goto nla_put_failure;
-
-			if (wpa_driver_nl80211_scan(bss, params)) {
-				wpa_driver_nl80211_set_mode(bss, drv->nlmode);
-				goto nla_put_failure;
-			}
-
-			/* Restore AP mode when processing scan results */
-			drv->ap_scan_as_station = old_mode;
-			ret = 0;
-		} else
-			goto nla_put_failure;
-	}
-
-	drv->scan_state = SCAN_REQUESTED;
-	/* Not all drivers generate "scan completed" wireless event, so try to
-	 * read results after a timeout. */
-	timeout = 10;
-	if (drv->scan_complete_events) {
-		/*
-		 * The driver seems to deliver events to notify when scan is
-		 * complete, so use longer timeout to avoid race conditions
-		 * with scanning and following association request.
-		 */
-		timeout = 30;
-	}
-	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
-		   "seconds", ret, timeout);
-	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
-			       drv, drv->ctx);
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return ret;
-}
-
-
-/**
- * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
- * @params: Scan parameters
- * @interval: Interval between scan cycles in milliseconds
- * Returns: 0 on success, -1 on failure or if not supported
- */
-static int wpa_driver_nl80211_sched_scan(void *priv,
-					 struct wpa_driver_scan_params *params,
-					 u32 interval)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret = -1;
-	struct nl_msg *msg;
-	size_t i;
-
-	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
-
-#ifdef ANDROID
-	if (!drv->capa.sched_scan_supported)
-		return android_pno_start(bss, params);
-#endif /* ANDROID */
-
-	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;
-
-	NLA_PUT_U32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval);
-
-	if ((drv->num_filter_ssids &&
-	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
-	    params->filter_rssi) {
-		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 = nla_nest_start(msg, i + 1);
-			if (match_set_ssid == NULL)
-				goto nla_put_failure;
-			NLA_PUT(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
-				drv->filter_ssids[i].ssid_len,
-				drv->filter_ssids[i].ssid);
-			if (params->filter_rssi)
-				NLA_PUT_U32(msg,
-					    NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
-					    params->filter_rssi);
-
-			nla_nest_end(msg, match_set_ssid);
-		}
-
-		/*
-		 * Due to backward compatibility code, newer kernels treat this
-		 * matchset (with only an RSSI filter) as the default for all
-		 * other matchsets, unless it's the only one, in which case the
-		 * matchset will actually allow all SSIDs above the RSSI.
-		 */
-		if (params->filter_rssi) {
-			struct nlattr *match_set_rssi;
-			match_set_rssi = nla_nest_start(msg, 0);
-			if (match_set_rssi == NULL)
-				goto nla_put_failure;
-			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);
-			nla_nest_end(msg, match_set_rssi);
-		}
-
-		nla_nest_end(msg, match_sets);
-	}
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-
-	/* TODO: if we get an error here, we should fall back to normal scan */
-
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
-			   "ret=%d (%s)", ret, strerror(-ret));
-		goto nla_put_failure;
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
-		   "scan interval %d msec", ret, interval);
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return ret;
-}
-
-
-/**
- * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
- * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
- * Returns: 0 on success, -1 on failure or if not supported
- */
-static int wpa_driver_nl80211_stop_sched_scan(void *priv)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret = 0;
-	struct nl_msg *msg;
-
-#ifdef ANDROID
-	if (!drv->capa.sched_scan_supported)
-		return android_pno_stop(bss);
-#endif /* ANDROID */
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_STOP_SCHED_SCAN);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop failed: "
-			   "ret=%d (%s)", ret, strerror(-ret));
-		goto nla_put_failure;
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: Sched scan stop sent (ret=%d)", ret);
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return ret;
-}
-
-
-static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
-{
-	const u8 *end, *pos;
-
-	if (ies == NULL)
-		return NULL;
-
-	pos = ies;
-	end = ies + ies_len;
-
-	while (pos + 1 < end) {
-		if (pos + 2 + pos[1] > end)
-			break;
-		if (pos[0] == ie)
-			return pos;
-		pos += 2 + pos[1];
-	}
-
-	return NULL;
-}
-
-
-static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
-				 const u8 *ie, size_t ie_len)
-{
-	const u8 *ssid;
-	size_t i;
-
-	if (drv->filter_ssids == NULL)
-		return 0;
-
-	ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
-	if (ssid == NULL)
-		return 1;
-
-	for (i = 0; i < drv->num_filter_ssids; i++) {
-		if (ssid[1] == drv->filter_ssids[i].ssid_len &&
-		    os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
-		    0)
-			return 0;
-	}
-
-	return 1;
-}
-
-
-static int bss_info_handler(struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *bss[NL80211_BSS_MAX + 1];
-	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
-		[NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
-		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
-		[NL80211_BSS_TSF] = { .type = NLA_U64 },
-		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
-		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
-		[NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
-		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
-		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
-		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
-		[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
-		[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
-	};
-	struct nl80211_bss_info_arg *_arg = arg;
-	struct wpa_scan_results *res = _arg->res;
-	struct wpa_scan_res **tmp;
-	struct wpa_scan_res *r;
-	const u8 *ie, *beacon_ie;
-	size_t ie_len, beacon_ie_len;
-	u8 *pos;
-	size_t i;
-
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-	if (!tb[NL80211_ATTR_BSS])
-		return NL_SKIP;
-	if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
-			     bss_policy))
-		return NL_SKIP;
-	if (bss[NL80211_BSS_STATUS]) {
-		enum nl80211_bss_status status;
-		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
-		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
-		    bss[NL80211_BSS_FREQUENCY]) {
-			_arg->assoc_freq =
-				nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
-			wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
-				   _arg->assoc_freq);
-		}
-		if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
-		    bss[NL80211_BSS_FREQUENCY]) {
-			_arg->ibss_freq =
-				nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
-			wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
-				   _arg->ibss_freq);
-		}
-		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
-		    bss[NL80211_BSS_BSSID]) {
-			os_memcpy(_arg->assoc_bssid,
-				  nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
-			wpa_printf(MSG_DEBUG, "nl80211: Associated with "
-				   MACSTR, MAC2STR(_arg->assoc_bssid));
-		}
-	}
-	if (!res)
-		return NL_SKIP;
-	if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
-		ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
-		ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
-	} else {
-		ie = NULL;
-		ie_len = 0;
-	}
-	if (bss[NL80211_BSS_BEACON_IES]) {
-		beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
-		beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
-	} else {
-		beacon_ie = NULL;
-		beacon_ie_len = 0;
-	}
-
-	if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
-				  ie ? ie_len : beacon_ie_len))
-		return NL_SKIP;
-
-	r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
-	if (r == NULL)
-		return NL_SKIP;
-	if (bss[NL80211_BSS_BSSID])
-		os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
-			  ETH_ALEN);
-	if (bss[NL80211_BSS_FREQUENCY])
-		r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
-	if (bss[NL80211_BSS_BEACON_INTERVAL])
-		r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
-	if (bss[NL80211_BSS_CAPABILITY])
-		r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
-	r->flags |= WPA_SCAN_NOISE_INVALID;
-	if (bss[NL80211_BSS_SIGNAL_MBM]) {
-		r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
-		r->level /= 100; /* mBm to dBm */
-		r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
-	} else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
-		r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
-		r->flags |= WPA_SCAN_QUAL_INVALID;
-	} else
-		r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
-	if (bss[NL80211_BSS_TSF])
-		r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
-	if (bss[NL80211_BSS_SEEN_MS_AGO])
-		r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
-	r->ie_len = ie_len;
-	pos = (u8 *) (r + 1);
-	if (ie) {
-		os_memcpy(pos, ie, ie_len);
-		pos += ie_len;
-	}
-	r->beacon_ie_len = beacon_ie_len;
-	if (beacon_ie)
-		os_memcpy(pos, beacon_ie, beacon_ie_len);
-
-	if (bss[NL80211_BSS_STATUS]) {
-		enum nl80211_bss_status status;
-		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
-		switch (status) {
-		case NL80211_BSS_STATUS_AUTHENTICATED:
-			r->flags |= WPA_SCAN_AUTHENTICATED;
-			break;
-		case NL80211_BSS_STATUS_ASSOCIATED:
-			r->flags |= WPA_SCAN_ASSOCIATED;
-			break;
-		default:
-			break;
-		}
-	}
-
-	/*
-	 * cfg80211 maintains separate BSS table entries for APs if the same
-	 * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
-	 * not use frequency as a separate key in the BSS table, so filter out
-	 * duplicated entries. Prefer associated BSS entry in such a case in
-	 * order to get the correct frequency into the BSS table. Similarly,
-	 * prefer newer entries over older.
-	 */
-	for (i = 0; i < res->num; i++) {
-		const u8 *s1, *s2;
-		if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
-			continue;
-
-		s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
-				    res->res[i]->ie_len, WLAN_EID_SSID);
-		s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
-		if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
-		    os_memcmp(s1, s2, 2 + s1[1]) != 0)
-			continue;
-
-		/* Same BSSID,SSID was already included in scan results */
-		wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
-			   "for " MACSTR, MAC2STR(r->bssid));
-
-		if (((r->flags & WPA_SCAN_ASSOCIATED) &&
-		     !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
-		    r->age < res->res[i]->age) {
-			os_free(res->res[i]);
-			res->res[i] = r;
-		} else
-			os_free(r);
-		return NL_SKIP;
-	}
-
-	tmp = os_realloc_array(res->res, res->num + 1,
-			       sizeof(struct wpa_scan_res *));
-	if (tmp == NULL) {
-		os_free(r);
-		return NL_SKIP;
-	}
-	tmp[res->num++] = r;
-	res->res = tmp;
-
-	return NL_SKIP;
-}
-
-
-static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
-				 const u8 *addr)
-{
-	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
-		wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
-			   "mismatch (" MACSTR ")", MAC2STR(addr));
-		wpa_driver_nl80211_mlme(drv, addr,
-					NL80211_CMD_DEAUTHENTICATE,
-					WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
-	}
-}
-
-
-static void wpa_driver_nl80211_check_bss_status(
-	struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
-{
-	size_t i;
-
-	for (i = 0; i < res->num; i++) {
-		struct wpa_scan_res *r = res->res[i];
-		if (r->flags & WPA_SCAN_AUTHENTICATED) {
-			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
-				   "indicates BSS status with " MACSTR
-				   " as authenticated",
-				   MAC2STR(r->bssid));
-			if (is_sta_interface(drv->nlmode) &&
-			    os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
-			    os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
-			    0) {
-				wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
-					   " in local state (auth=" MACSTR
-					   " assoc=" MACSTR ")",
-					   MAC2STR(drv->auth_bssid),
-					   MAC2STR(drv->bssid));
-				clear_state_mismatch(drv, r->bssid);
-			}
-		}
-
-		if (r->flags & WPA_SCAN_ASSOCIATED) {
-			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
-				   "indicate BSS status with " MACSTR
-				   " as associated",
-				   MAC2STR(r->bssid));
-			if (is_sta_interface(drv->nlmode) &&
-			    !drv->associated) {
-				wpa_printf(MSG_DEBUG, "nl80211: Local state "
-					   "(not associated) does not match "
-					   "with BSS state");
-				clear_state_mismatch(drv, r->bssid);
-			} else if (is_sta_interface(drv->nlmode) &&
-				   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
-				   0) {
-				wpa_printf(MSG_DEBUG, "nl80211: Local state "
-					   "(associated with " MACSTR ") does "
-					   "not match with BSS state",
-					   MAC2STR(drv->bssid));
-				clear_state_mismatch(drv, r->bssid);
-				clear_state_mismatch(drv, drv->bssid);
-			}
-		}
-	}
-}
-
-
-static struct wpa_scan_results *
-nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
-{
-	struct nl_msg *msg;
-	struct wpa_scan_results *res;
-	int ret;
-	struct nl80211_bss_info_arg arg;
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL)
-		return NULL;
-	msg = nlmsg_alloc();
-	if (!msg)
-		goto nla_put_failure;
-
-	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
-	if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
-		goto nla_put_failure;
-
-	arg.drv = drv;
-	arg.res = res;
-	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
-	msg = NULL;
-	if (ret == 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
-			   "BSSes)", (unsigned long) res->num);
-		nl80211_get_noise_for_scan_results(drv, res);
-		return res;
-	}
-	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
-		   "(%s)", ret, strerror(-ret));
-nla_put_failure:
-	nlmsg_free(msg);
-	wpa_scan_results_free(res);
-	return NULL;
-}
-
-
-/**
- * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
- * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
- * Returns: Scan results on success, -1 on failure
- */
-static struct wpa_scan_results *
-wpa_driver_nl80211_get_scan_results(void *priv)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct wpa_scan_results *res;
-
-	res = nl80211_get_scan_results(drv);
-	if (res)
-		wpa_driver_nl80211_check_bss_status(drv, res);
-	return res;
-}
-
-
-static void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
-{
-	struct wpa_scan_results *res;
-	size_t i;
-
-	res = nl80211_get_scan_results(drv);
-	if (res == NULL) {
-		wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
-	for (i = 0; i < res->num; i++) {
-		struct wpa_scan_res *r = res->res[i];
-		wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
-			   (int) i, (int) res->num, MAC2STR(r->bssid),
-			   r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
-			   r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
-	}
-
-	wpa_scan_results_free(res);
-}
-
-
 static u32 wpa_alg_to_cipher_suite(enum wpa_alg alg, size_t key_len)
 {
 	switch (alg) {
@@ -5869,6 +2341,35 @@
 }
 
 
+static int issue_key_mgmt_set_key(struct wpa_driver_nl80211_data *drv,
+				  const u8 *key, size_t key_len)
+{
+	struct nl_msg *msg;
+	int ret;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD))
+		return 0;
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY) ||
+	    nla_put(msg, NL80211_ATTR_VENDOR_DATA, key_len, key)) {
+		nl80211_nlmsg_clear(msg);
+		nlmsg_free(msg);
+		return -1;
+	}
+	ret = send_and_recv_msgs(drv, msg, NULL, (void *) -1);
+	if (ret) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Key management set key failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+	}
+
+	return ret;
+}
+
+
 static int wpa_driver_nl80211_set_key(const char *ifname, struct i802_bss *bss,
 				      enum wpa_alg alg, const u8 *addr,
 				      int key_idx, int set_tx,
@@ -5897,33 +2398,44 @@
 	}
 #endif /* CONFIG_TDLS */
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
+	if (alg == WPA_ALG_PMK &&
+	    (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+		wpa_printf(MSG_DEBUG, "%s: calling issue_key_mgmt_set_key",
+			   __func__);
+		ret = issue_key_mgmt_set_key(drv, key, key_len);
+		return ret;
+	}
 
 	if (alg == WPA_ALG_NONE) {
-		nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
+		msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_DEL_KEY);
+		if (!msg)
+			return -ENOBUFS;
 	} else {
-		nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
-		NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
+		msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_NEW_KEY);
+		if (!msg ||
+		    nla_put(msg, NL80211_ATTR_KEY_DATA, key_len, key) ||
+		    nla_put_u32(msg, NL80211_ATTR_KEY_CIPHER,
+				wpa_alg_to_cipher_suite(alg, key_len)))
+			goto fail;
 		wpa_hexdump_key(MSG_DEBUG, "nl80211: KEY_DATA", key, key_len);
-		NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
-			    wpa_alg_to_cipher_suite(alg, key_len));
 	}
 
 	if (seq && seq_len) {
-		NLA_PUT(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq);
+		if (nla_put(msg, NL80211_ATTR_KEY_SEQ, seq_len, seq))
+			goto fail;
 		wpa_hexdump(MSG_DEBUG, "nl80211: KEY_SEQ", seq, seq_len);
 	}
 
 	if (addr && !is_broadcast_ether_addr(addr)) {
 		wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+		if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+			goto fail;
 
 		if (alg != WPA_ALG_WEP && key_idx && !set_tx) {
 			wpa_printf(MSG_DEBUG, "   RSN IBSS RX GTK");
-			NLA_PUT_U32(msg, NL80211_ATTR_KEY_TYPE,
-				    NL80211_KEYTYPE_GROUP);
+			if (nla_put_u32(msg, NL80211_ATTR_KEY_TYPE,
+					NL80211_KEYTYPE_GROUP))
+				goto fail;
 		}
 	} else if (addr && is_broadcast_ether_addr(addr)) {
 		struct nlattr *types;
@@ -5931,15 +2443,15 @@
 		wpa_printf(MSG_DEBUG, "   broadcast key");
 
 		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
-		if (!types)
-			goto nla_put_failure;
-		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+		if (!types ||
+		    nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+			goto fail;
 		nla_nest_end(msg, types);
 	}
-	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+	if (nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx))
+		goto fail;
 
-	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	ret = send_and_recv_msgs(drv, msg, NULL, key ? (void *) -1 : NULL);
 	if ((ret == -ENOENT || ret == -ENOLINK) && alg == WPA_ALG_NONE)
 		ret = 0;
 	if (ret)
@@ -5956,32 +2468,28 @@
 	    !is_broadcast_ether_addr(addr))
 		return ret;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_KEY);
-	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
-	if (alg == WPA_ALG_IGTK)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
-	else
-		NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+	msg = nl80211_ifindex_msg(drv, ifindex, 0, NL80211_CMD_SET_KEY);
+	if (!msg ||
+	    nla_put_u8(msg, NL80211_ATTR_KEY_IDX, key_idx) ||
+	    nla_put_flag(msg, alg == WPA_ALG_IGTK ?
+			 NL80211_ATTR_KEY_DEFAULT_MGMT :
+			 NL80211_ATTR_KEY_DEFAULT))
+		goto fail;
 	if (addr && is_broadcast_ether_addr(addr)) {
 		struct nlattr *types;
 
 		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
-		if (!types)
-			goto nla_put_failure;
-		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST);
+		if (!types ||
+		    nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_MULTICAST))
+			goto fail;
 		nla_nest_end(msg, types);
 	} else if (addr) {
 		struct nlattr *types;
 
 		types = nla_nest_start(msg, NL80211_ATTR_KEY_DEFAULT_TYPES);
-		if (!types)
-			goto nla_put_failure;
-		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST);
+		if (!types ||
+		    nla_put_flag(msg, NL80211_KEY_DEFAULT_TYPE_UNICAST))
+			goto fail;
 		nla_nest_end(msg, types);
 	}
 
@@ -5993,7 +2501,8 @@
 			   "err=%d %s)", ret, strerror(-ret));
 	return ret;
 
-nla_put_failure:
+fail:
+	nl80211_nlmsg_clear(msg);
 	nlmsg_free(msg);
 	return -ENOBUFS;
 }
@@ -6008,26 +2517,25 @@
 	if (!key_attr)
 		return -1;
 
-	if (defkey && alg == WPA_ALG_IGTK)
-		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT_MGMT);
-	else if (defkey)
-		NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
+	if (defkey && alg == WPA_ALG_IGTK) {
+		if (nla_put_flag(msg, NL80211_KEY_DEFAULT_MGMT))
+			return -1;
+	} else if (defkey) {
+		if (nla_put_flag(msg, NL80211_KEY_DEFAULT))
+			return -1;
+	}
 
-	NLA_PUT_U8(msg, NL80211_KEY_IDX, key_idx);
-
-	NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
-		    wpa_alg_to_cipher_suite(alg, key_len));
-
-	if (seq && seq_len)
-		NLA_PUT(msg, NL80211_KEY_SEQ, seq_len, seq);
-
-	NLA_PUT(msg, NL80211_KEY_DATA, key_len, key);
+	if (nla_put_u8(msg, NL80211_KEY_IDX, key_idx) ||
+	    nla_put_u32(msg, NL80211_KEY_CIPHER,
+			wpa_alg_to_cipher_suite(alg, key_len)) ||
+	    (seq && seq_len &&
+	     nla_put(msg, NL80211_KEY_SEQ, seq_len, seq)) ||
+	    nla_put(msg, NL80211_KEY_DATA, key_len, key))
+		return -1;
 
 	nla_nest_end(msg, key_attr);
 
 	return 0;
- nla_put_failure:
-	return -1;
 }
 
 
@@ -6052,77 +2560,60 @@
 	if (!privacy)
 		return 0;
 
-	NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+	if (nla_put_flag(msg, NL80211_ATTR_PRIVACY))
+		return -ENOBUFS;
 
 	nl_keys = nla_nest_start(msg, NL80211_ATTR_KEYS);
 	if (!nl_keys)
-		goto nla_put_failure;
+		return -ENOBUFS;
 
 	for (i = 0; i < 4; i++) {
 		if (!params->wep_key[i])
 			continue;
 
 		nl_key = nla_nest_start(msg, i);
-		if (!nl_key)
-			goto nla_put_failure;
-
-		NLA_PUT(msg, NL80211_KEY_DATA, params->wep_key_len[i],
-			params->wep_key[i]);
-		if (params->wep_key_len[i] == 5)
-			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_WEP40);
-		else
-			NLA_PUT_U32(msg, NL80211_KEY_CIPHER,
-				    WLAN_CIPHER_SUITE_WEP104);
-
-		NLA_PUT_U8(msg, NL80211_KEY_IDX, i);
-
-		if (i == params->wep_tx_keyidx)
-			NLA_PUT_FLAG(msg, NL80211_KEY_DEFAULT);
+		if (!nl_key ||
+		    nla_put(msg, NL80211_KEY_DATA, params->wep_key_len[i],
+			    params->wep_key[i]) ||
+		    nla_put_u32(msg, NL80211_KEY_CIPHER,
+				params->wep_key_len[i] == 5 ?
+				WLAN_CIPHER_SUITE_WEP40 :
+				WLAN_CIPHER_SUITE_WEP104) ||
+		    nla_put_u8(msg, NL80211_KEY_IDX, i) ||
+		    (i == params->wep_tx_keyidx &&
+		     nla_put_flag(msg, NL80211_KEY_DEFAULT)))
+			return -ENOBUFS;
 
 		nla_nest_end(msg, nl_key);
 	}
 	nla_nest_end(msg, nl_keys);
 
 	return 0;
-
-nla_put_failure:
-	return -ENOBUFS;
 }
 
 
-static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
-				   const u8 *addr, int cmd, u16 reason_code,
-				   int local_state_change)
+int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+			    const u8 *addr, int cmd, u16 reason_code,
+			    int local_state_change)
 {
-	int ret = -1;
+	int ret;
 	struct nl_msg *msg;
 
-	msg = nlmsg_alloc();
-	if (!msg)
+	if (!(msg = nl80211_drv_msg(drv, 0, cmd)) ||
+	    nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code) ||
+	    (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
+	    (local_state_change &&
+	     nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))) {
+		nlmsg_free(msg);
 		return -1;
-
-	nl80211_cmd(drv, msg, 0, cmd);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U16(msg, NL80211_ATTR_REASON_CODE, reason_code);
-	if (addr)
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-	if (local_state_change)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
 	if (ret) {
 		wpa_dbg(drv->ctx, MSG_DEBUG,
 			"nl80211: MLME command failed: reason=%u ret=%d (%s)",
 			reason_code, ret, strerror(-ret));
-		goto nla_put_failure;
 	}
-	ret = 0;
-
-nla_put_failure:
-	nlmsg_free(msg);
 	return ret;
 }
 
@@ -6155,7 +2646,7 @@
 
 	if (drv->nlmode == NL80211_IFTYPE_ADHOC) {
 		nl80211_mark_disconnected(drv);
-		return nl80211_leave_ibss(drv);
+		return nl80211_leave_ibss(drv, 1);
 	}
 	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME))
 		return wpa_driver_nl80211_disconnect(drv, reason_code);
@@ -6219,6 +2710,25 @@
 }
 
 
+static void nl80211_unmask_11b_rates(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (is_p2p_net_interface(drv->nlmode) || !drv->disabled_11b_rates)
+		return;
+
+	/*
+	 * Looks like we failed to unmask 11b rates previously. This could
+	 * happen, e.g., if the interface was down at the point in time when a
+	 * P2P group was terminated.
+	 */
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: Interface %s mode is for non-P2P, but 11b rates were disabled - re-enable them",
+		   bss->ifname);
+	nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+}
+
+
 static int wpa_driver_nl80211_authenticate(
 	struct i802_bss *bss, struct wpa_driver_auth_params *params)
 {
@@ -6230,6 +2740,8 @@
 	int count = 0;
 	int is_retry;
 
+	nl80211_unmask_11b_rates(bss);
+
 	is_retry = drv->retry_auth;
 	drv->retry_auth = 0;
 	drv->ignore_deauth_event = 0;
@@ -6248,14 +2760,12 @@
 		return -1;
 
 retry:
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
 	wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
 		   drv->ifindex);
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_AUTHENTICATE);
+	if (!msg)
+		goto fail;
 
 	for (i = 0; i < 4; i++) {
 		if (!params->wep_key[i])
@@ -6268,36 +2778,38 @@
 		if (params->wep_tx_keyidx != i)
 			continue;
 		if (nl_add_key(msg, WPA_ALG_WEP, i, 1, NULL, 0,
-			       params->wep_key[i], params->wep_key_len[i])) {
-			nlmsg_free(msg);
-			return -1;
-		}
+			       params->wep_key[i], params->wep_key_len[i]))
+			goto fail;
 	}
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	if (params->bssid) {
 		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
 			   MAC2STR(params->bssid));
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+		if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+			goto fail;
 	}
 	if (params->freq) {
 		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
-		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq);
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
+			goto fail;
 	}
 	if (params->ssid) {
 		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
 				  params->ssid, params->ssid_len);
-		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
-			params->ssid);
+		if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
+			    params->ssid))
+			goto fail;
 	}
 	wpa_hexdump(MSG_DEBUG, "  * IEs", params->ie, params->ie_len);
-	if (params->ie)
-		NLA_PUT(msg, NL80211_ATTR_IE, params->ie_len, params->ie);
+	if (params->ie &&
+	    nla_put(msg, NL80211_ATTR_IE, params->ie_len, params->ie))
+		goto fail;
 	if (params->sae_data) {
 		wpa_hexdump(MSG_DEBUG, "  * SAE data", params->sae_data,
 			    params->sae_data_len);
-		NLA_PUT(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
-			params->sae_data);
+		if (nla_put(msg, NL80211_ATTR_SAE_DATA, params->sae_data_len,
+			    params->sae_data))
+			goto fail;
 	}
 	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
 		type = NL80211_AUTHTYPE_OPEN_SYSTEM;
@@ -6310,12 +2822,14 @@
 	else if (params->auth_alg & WPA_AUTH_ALG_SAE)
 		type = NL80211_AUTHTYPE_SAE;
 	else
-		goto nla_put_failure;
+		goto fail;
 	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
-	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+	if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+		goto fail;
 	if (params->local_state_change) {
 		wpa_printf(MSG_DEBUG, "  * Local state change only");
-		NLA_PUT_FLAG(msg, NL80211_ATTR_LOCAL_STATE_CHANGE);
+		if (nla_put_flag(msg, NL80211_ATTR_LOCAL_STATE_CHANGE))
+			goto fail;
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -6383,21 +2897,18 @@
 			wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
 					     &event);
 		}
-
-		goto nla_put_failure;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Authentication request send successfully");
 	}
-	ret = 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Authentication request send "
-		   "successfully");
 
-nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return ret;
 }
 
 
-static int wpa_driver_nl80211_authenticate_retry(
-	struct wpa_driver_nl80211_data *drv)
+int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv)
 {
 	struct wpa_driver_auth_params params;
 	struct i802_bss *bss = drv->first_bss;
@@ -6435,726 +2946,6 @@
 }
 
 
-struct phy_info_arg {
-	u16 *num_modes;
-	struct hostapd_hw_modes *modes;
-	int last_mode, last_chan_idx;
-};
-
-static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
-			     struct nlattr *ampdu_factor,
-			     struct nlattr *ampdu_density,
-			     struct nlattr *mcs_set)
-{
-	if (capa)
-		mode->ht_capab = nla_get_u16(capa);
-
-	if (ampdu_factor)
-		mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
-
-	if (ampdu_density)
-		mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
-
-	if (mcs_set && nla_len(mcs_set) >= 16) {
-		u8 *mcs;
-		mcs = nla_data(mcs_set);
-		os_memcpy(mode->mcs_set, mcs, 16);
-	}
-}
-
-
-static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
-			      struct nlattr *capa,
-			      struct nlattr *mcs_set)
-{
-	if (capa)
-		mode->vht_capab = nla_get_u32(capa);
-
-	if (mcs_set && nla_len(mcs_set) >= 8) {
-		u8 *mcs;
-		mcs = nla_data(mcs_set);
-		os_memcpy(mode->vht_mcs_set, mcs, 8);
-	}
-}
-
-
-static void phy_info_freq(struct hostapd_hw_modes *mode,
-			  struct hostapd_channel_data *chan,
-			  struct nlattr *tb_freq[])
-{
-	u8 channel;
-	chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
-	chan->flag = 0;
-	chan->dfs_cac_ms = 0;
-	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;
-	if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
-		chan->flag |= HOSTAPD_CHAN_PASSIVE_SCAN | HOSTAPD_CHAN_NO_IBSS;
-	if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
-		chan->flag |= HOSTAPD_CHAN_RADAR;
-
-	if (tb_freq[NL80211_FREQUENCY_ATTR_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;
-		}
-	}
-
-	if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) {
-		chan->dfs_cac_ms = nla_get_u32(
-			tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]);
-	}
-}
-
-
-static int phy_info_freqs(struct phy_info_arg *phy_info,
-			  struct hostapd_hw_modes *mode, struct nlattr *tb)
-{
-	static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
-		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
-		[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
-		[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
-		[NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
-	};
-	int new_channels = 0;
-	struct hostapd_channel_data *channel;
-	struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
-	struct nlattr *nl_freq;
-	int rem_freq, idx;
-
-	if (tb == NULL)
-		return NL_OK;
-
-	nla_for_each_nested(nl_freq, tb, rem_freq) {
-		nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
-			  nla_data(nl_freq), nla_len(nl_freq), freq_policy);
-		if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
-			continue;
-		new_channels++;
-	}
-
-	channel = os_realloc_array(mode->channels,
-				   mode->num_channels + new_channels,
-				   sizeof(struct hostapd_channel_data));
-	if (!channel)
-		return NL_SKIP;
-
-	mode->channels = channel;
-	mode->num_channels += new_channels;
-
-	idx = phy_info->last_chan_idx;
-
-	nla_for_each_nested(nl_freq, tb, rem_freq) {
-		nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
-			  nla_data(nl_freq), nla_len(nl_freq), freq_policy);
-		if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
-			continue;
-		phy_info_freq(mode, &mode->channels[idx], tb_freq);
-		idx++;
-	}
-	phy_info->last_chan_idx = idx;
-
-	return NL_OK;
-}
-
-
-static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
-{
-	static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
-		[NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
-		[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
-		{ .type = NLA_FLAG },
-	};
-	struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
-	struct nlattr *nl_rate;
-	int rem_rate, idx;
-
-	if (tb == NULL)
-		return NL_OK;
-
-	nla_for_each_nested(nl_rate, tb, rem_rate) {
-		nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
-			  nla_data(nl_rate), nla_len(nl_rate),
-			  rate_policy);
-		if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
-			continue;
-		mode->num_rates++;
-	}
-
-	mode->rates = os_calloc(mode->num_rates, sizeof(int));
-	if (!mode->rates)
-		return NL_SKIP;
-
-	idx = 0;
-
-	nla_for_each_nested(nl_rate, tb, rem_rate) {
-		nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
-			  nla_data(nl_rate), nla_len(nl_rate),
-			  rate_policy);
-		if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
-			continue;
-		mode->rates[idx] = nla_get_u32(
-			tb_rate[NL80211_BITRATE_ATTR_RATE]);
-		idx++;
-	}
-
-	return NL_OK;
-}
-
-
-static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
-{
-	struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
-	struct hostapd_hw_modes *mode;
-	int ret;
-
-	if (phy_info->last_mode != nl_band->nla_type) {
-		mode = os_realloc_array(phy_info->modes,
-					*phy_info->num_modes + 1,
-					sizeof(*mode));
-		if (!mode)
-			return NL_SKIP;
-		phy_info->modes = mode;
-
-		mode = &phy_info->modes[*(phy_info->num_modes)];
-		os_memset(mode, 0, sizeof(*mode));
-		mode->mode = NUM_HOSTAPD_MODES;
-		mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
-			HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
-
-		/*
-		 * Unsupported VHT MCS stream is defined as value 3, so the VHT
-		 * MCS RX/TX map must be initialized with 0xffff to mark all 8
-		 * possible streams as unsupported. This will be overridden if
-		 * driver advertises VHT support.
-		 */
-		mode->vht_mcs_set[0] = 0xff;
-		mode->vht_mcs_set[1] = 0xff;
-		mode->vht_mcs_set[4] = 0xff;
-		mode->vht_mcs_set[5] = 0xff;
-
-		*(phy_info->num_modes) += 1;
-		phy_info->last_mode = nl_band->nla_type;
-		phy_info->last_chan_idx = 0;
-	} else
-		mode = &phy_info->modes[*(phy_info->num_modes) - 1];
-
-	nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
-		  nla_len(nl_band), NULL);
-
-	phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
-			 tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
-			 tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
-			 tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
-	phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
-			  tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
-	ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
-	if (ret != NL_OK)
-		return ret;
-	ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
-	if (ret != NL_OK)
-		return ret;
-
-	return NL_OK;
-}
-
-
-static int phy_info_handler(struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct phy_info_arg *phy_info = arg;
-	struct nlattr *nl_band;
-	int rem_band;
-
-	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-
-	if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
-		return NL_SKIP;
-
-	nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
-	{
-		int res = phy_info_band(phy_info, nl_band);
-		if (res != NL_OK)
-			return res;
-	}
-
-	return NL_SKIP;
-}
-
-
-static struct hostapd_hw_modes *
-wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
-				     u16 *num_modes)
-{
-	u16 m;
-	struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
-	int i, mode11g_idx = -1;
-
-	/* heuristic to set up modes */
-	for (m = 0; m < *num_modes; m++) {
-		if (!modes[m].num_channels)
-			continue;
-		if (modes[m].channels[0].freq < 4000) {
-			modes[m].mode = HOSTAPD_MODE_IEEE80211B;
-			for (i = 0; i < modes[m].num_rates; i++) {
-				if (modes[m].rates[i] > 200) {
-					modes[m].mode = HOSTAPD_MODE_IEEE80211G;
-					break;
-				}
-			}
-		} else if (modes[m].channels[0].freq > 50000)
-			modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
-		else
-			modes[m].mode = HOSTAPD_MODE_IEEE80211A;
-	}
-
-	/* If only 802.11g mode is included, use it to construct matching
-	 * 802.11b mode data. */
-
-	for (m = 0; m < *num_modes; m++) {
-		if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
-			return modes; /* 802.11b already included */
-		if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
-			mode11g_idx = m;
-	}
-
-	if (mode11g_idx < 0)
-		return modes; /* 2.4 GHz band not supported at all */
-
-	nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
-	if (nmodes == NULL)
-		return modes; /* Could not add 802.11b mode */
-
-	mode = &nmodes[*num_modes];
-	os_memset(mode, 0, sizeof(*mode));
-	(*num_modes)++;
-	modes = nmodes;
-
-	mode->mode = HOSTAPD_MODE_IEEE80211B;
-
-	mode11g = &modes[mode11g_idx];
-	mode->num_channels = mode11g->num_channels;
-	mode->channels = os_malloc(mode11g->num_channels *
-				   sizeof(struct hostapd_channel_data));
-	if (mode->channels == NULL) {
-		(*num_modes)--;
-		return modes; /* Could not add 802.11b mode */
-	}
-	os_memcpy(mode->channels, mode11g->channels,
-		  mode11g->num_channels * sizeof(struct hostapd_channel_data));
-
-	mode->num_rates = 0;
-	mode->rates = os_malloc(4 * sizeof(int));
-	if (mode->rates == NULL) {
-		os_free(mode->channels);
-		(*num_modes)--;
-		return modes; /* Could not add 802.11b mode */
-	}
-
-	for (i = 0; i < mode11g->num_rates; i++) {
-		if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
-		    mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
-			continue;
-		mode->rates[mode->num_rates] = mode11g->rates[i];
-		mode->num_rates++;
-		if (mode->num_rates == 4)
-			break;
-	}
-
-	if (mode->num_rates == 0) {
-		os_free(mode->channels);
-		os_free(mode->rates);
-		(*num_modes)--;
-		return modes; /* No 802.11b rates */
-	}
-
-	wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
-		   "information");
-
-	return modes;
-}
-
-
-static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
-				  int end)
-{
-	int c;
-
-	for (c = 0; c < mode->num_channels; c++) {
-		struct hostapd_channel_data *chan = &mode->channels[c];
-		if (chan->freq - 10 >= start && chan->freq + 10 <= end)
-			chan->flag |= HOSTAPD_CHAN_HT40;
-	}
-}
-
-
-static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
-				      int end)
-{
-	int c;
-
-	for (c = 0; c < mode->num_channels; c++) {
-		struct hostapd_channel_data *chan = &mode->channels[c];
-		if (!(chan->flag & HOSTAPD_CHAN_HT40))
-			continue;
-		if (chan->freq - 30 >= start && chan->freq - 10 <= end)
-			chan->flag |= HOSTAPD_CHAN_HT40MINUS;
-		if (chan->freq + 10 >= start && chan->freq + 30 <= end)
-			chan->flag |= HOSTAPD_CHAN_HT40PLUS;
-	}
-}
-
-
-static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp,
-				      struct phy_info_arg *results)
-{
-	u16 m;
-
-	for (m = 0; m < *results->num_modes; m++) {
-		int c;
-		struct hostapd_hw_modes *mode = &results->modes[m];
-
-		for (c = 0; c < mode->num_channels; c++) {
-			struct hostapd_channel_data *chan = &mode->channels[c];
-			if ((u32) chan->freq - 10 >= start &&
-			    (u32) chan->freq + 10 <= end)
-				chan->max_tx_power = max_eirp;
-		}
-	}
-}
-
-
-static void nl80211_reg_rule_ht40(u32 start, u32 end,
-				  struct phy_info_arg *results)
-{
-	u16 m;
-
-	for (m = 0; m < *results->num_modes; m++) {
-		if (!(results->modes[m].ht_capab &
-		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
-			continue;
-		nl80211_set_ht40_mode(&results->modes[m], start, end);
-	}
-}
-
-
-static void nl80211_reg_rule_sec(struct nlattr *tb[],
-				 struct phy_info_arg *results)
-{
-	u32 start, end, max_bw;
-	u16 m;
-
-	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
-	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
-	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
-		return;
-
-	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
-	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
-	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
-
-	if (max_bw < 20)
-		return;
-
-	for (m = 0; m < *results->num_modes; m++) {
-		if (!(results->modes[m].ht_capab &
-		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
-			continue;
-		nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
-	}
-}
-
-
-static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
-				 int end)
-{
-	int c;
-
-	for (c = 0; c < mode->num_channels; c++) {
-		struct hostapd_channel_data *chan = &mode->channels[c];
-		if (chan->freq - 10 >= start && chan->freq + 70 <= end)
-			chan->flag |= HOSTAPD_CHAN_VHT_10_70;
-
-		if (chan->freq - 30 >= start && chan->freq + 50 <= end)
-			chan->flag |= HOSTAPD_CHAN_VHT_30_50;
-
-		if (chan->freq - 50 >= start && chan->freq + 30 <= end)
-			chan->flag |= HOSTAPD_CHAN_VHT_50_30;
-
-		if (chan->freq - 70 >= start && chan->freq + 10 <= end)
-			chan->flag |= HOSTAPD_CHAN_VHT_70_10;
-	}
-}
-
-
-static void nl80211_reg_rule_vht(struct nlattr *tb[],
-				 struct phy_info_arg *results)
-{
-	u32 start, end, max_bw;
-	u16 m;
-
-	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
-	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
-	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
-		return;
-
-	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
-	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
-	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
-
-	if (max_bw < 80)
-		return;
-
-	for (m = 0; m < *results->num_modes; m++) {
-		if (!(results->modes[m].ht_capab &
-		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
-			continue;
-		/* TODO: use a real VHT support indication */
-		if (!results->modes[m].vht_capab)
-			continue;
-
-		nl80211_set_vht_mode(&results->modes[m], start, end);
-	}
-}
-
-
-static const char * dfs_domain_name(enum nl80211_dfs_regions region)
-{
-	switch (region) {
-	case NL80211_DFS_UNSET:
-		return "DFS-UNSET";
-	case NL80211_DFS_FCC:
-		return "DFS-FCC";
-	case NL80211_DFS_ETSI:
-		return "DFS-ETSI";
-	case NL80211_DFS_JP:
-		return "DFS-JP";
-	default:
-		return "DFS-invalid";
-	}
-}
-
-
-static int nl80211_get_reg(struct nl_msg *msg, void *arg)
-{
-	struct phy_info_arg *results = arg;
-	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *nl_rule;
-	struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
-	int rem_rule;
-	static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
-		[NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
-		[NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
-		[NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
-		[NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
-		[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
-		[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
-	};
-
-	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-	if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
-	    !tb_msg[NL80211_ATTR_REG_RULES]) {
-		wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
-			   "available");
-		return NL_SKIP;
-	}
-
-	if (tb_msg[NL80211_ATTR_DFS_REGION]) {
-		enum nl80211_dfs_regions dfs_domain;
-		dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]);
-		wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)",
-			   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]),
-			   dfs_domain_name(dfs_domain));
-	} else {
-		wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
-			   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
-	}
-
-	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
-	{
-		u32 start, end, max_eirp = 0, max_bw = 0, flags = 0;
-		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
-			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
-		if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
-		    tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL)
-			continue;
-		start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
-		end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
-		if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
-			max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
-		if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW])
-			max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
-		if (tb_rule[NL80211_ATTR_REG_RULE_FLAGS])
-			flags = nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS]);
-
-		wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm%s%s%s%s%s%s%s%s",
-			   start, end, max_bw, max_eirp,
-			   flags & NL80211_RRF_NO_OFDM ? " (no OFDM)" : "",
-			   flags & NL80211_RRF_NO_CCK ? " (no CCK)" : "",
-			   flags & NL80211_RRF_NO_INDOOR ? " (no indoor)" : "",
-			   flags & NL80211_RRF_NO_OUTDOOR ? " (no outdoor)" :
-			   "",
-			   flags & NL80211_RRF_DFS ? " (DFS)" : "",
-			   flags & NL80211_RRF_PTP_ONLY ? " (PTP only)" : "",
-			   flags & NL80211_RRF_PTMP_ONLY ? " (PTMP only)" : "",
-			   flags & NL80211_RRF_NO_IR ? " (no IR)" : "");
-		if (max_bw >= 40)
-			nl80211_reg_rule_ht40(start, end, results);
-		if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
-			nl80211_reg_rule_max_eirp(start, end, max_eirp,
-						  results);
-	}
-
-	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
-	{
-		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
-			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
-		nl80211_reg_rule_sec(tb_rule, results);
-	}
-
-	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
-	{
-		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
-			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
-		nl80211_reg_rule_vht(tb_rule, results);
-	}
-
-	return NL_SKIP;
-}
-
-
-static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
-					struct phy_info_arg *results)
-{
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
-	return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
-}
-
-
-static struct hostapd_hw_modes *
-wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
-{
-	u32 feat;
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	struct phy_info_arg result = {
-		.num_modes = num_modes,
-		.modes = NULL,
-		.last_mode = -1,
-	};
-
-	*num_modes = 0;
-	*flags = 0;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return NULL;
-
-	feat = get_nl80211_protocol_features(drv);
-	if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
-		nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_WIPHY);
-	else
-		nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
-
-	NLA_PUT_FLAG(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP);
-	if (nl80211_set_iface_id(msg, bss) < 0)
-		goto nla_put_failure;
-
-	if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
-		nl80211_set_regulatory_flags(drv, &result);
-		return wpa_driver_nl80211_postprocess_modes(result.modes,
-							    num_modes);
-	}
-	msg = NULL;
- nla_put_failure:
-	nlmsg_free(msg);
-	return NULL;
-}
-
-
-static int wpa_driver_nl80211_send_mntr(struct wpa_driver_nl80211_data *drv,
-					const void *data, size_t len,
-					int encrypt, int noack)
-{
-	__u8 rtap_hdr[] = {
-		0x00, 0x00, /* radiotap version */
-		0x0e, 0x00, /* radiotap length */
-		0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
-		IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
-		0x00,       /* padding */
-		0x00, 0x00, /* RX and TX flags to indicate that */
-		0x00, 0x00, /* this is the injected frame directly */
-	};
-	struct iovec iov[2] = {
-		{
-			.iov_base = &rtap_hdr,
-			.iov_len = sizeof(rtap_hdr),
-		},
-		{
-			.iov_base = (void *) data,
-			.iov_len = len,
-		}
-	};
-	struct msghdr msg = {
-		.msg_name = NULL,
-		.msg_namelen = 0,
-		.msg_iov = iov,
-		.msg_iovlen = 2,
-		.msg_control = NULL,
-		.msg_controllen = 0,
-		.msg_flags = 0,
-	};
-	int res;
-	u16 txflags = 0;
-
-	if (encrypt)
-		rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
-
-	if (drv->monitor_sock < 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
-			   "for %s", __func__);
-		return -1;
-	}
-
-	if (noack)
-		txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
-	WPA_PUT_LE16(&rtap_hdr[12], txflags);
-
-	res = sendmsg(drv->monitor_sock, &msg, 0);
-	if (res < 0) {
-		wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
-		return -1;
-	}
-	return 0;
-}
-
-
 static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
 					 const void *data, size_t len,
 					 int encrypt, int noack,
@@ -7178,10 +2969,9 @@
 	}
 
 	if (drv->use_monitor) {
-		wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_mntr",
+		wpa_printf(MSG_DEBUG, "nl80211: send_frame(freq=%u bss->freq=%u) -> send_monitor",
 			   freq, bss->freq);
-		return wpa_driver_nl80211_send_mntr(drv, data, len,
-						    encrypt, noack);
+		return nl80211_send_monitor(drv, data, len, encrypt, noack);
 	}
 
 	wpa_printf(MSG_DEBUG, "nl80211: send_frame -> send_frame_cmd");
@@ -7287,22 +3077,18 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_BSS);
-
-	if (cts >= 0)
-		NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
-	if (preamble >= 0)
-		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
-	if (slot >= 0)
-		NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
-	if (ht_opmode >= 0)
-		NLA_PUT_U16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode);
-	if (ap_isolate >= 0)
-		NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate);
+	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_BSS)) ||
+	    (cts >= 0 &&
+	     nla_put_u8(msg, NL80211_ATTR_BSS_CTS_PROT, cts)) ||
+	    (preamble >= 0 &&
+	     nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble)) ||
+	    (slot >= 0 &&
+	     nla_put_u8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot)) ||
+	    (ht_opmode >= 0 &&
+	     nla_put_u16(msg, NL80211_ATTR_BSS_HT_OPMODE, ht_opmode)) ||
+	    (ap_isolate >= 0 &&
+	     nla_put_u8(msg, NL80211_ATTR_AP_ISOLATE, ap_isolate)))
+		goto fail;
 
 	if (basic_rates) {
 		u8 rates[NL80211_MAX_SUPP_RATES];
@@ -7313,13 +3099,13 @@
 		     i++)
 			rates[rates_len++] = basic_rates[i] / 5;
 
-		NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+		if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
+			    rates))
+			goto fail;
 	}
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return -ENOBUFS;
 }
@@ -7333,7 +3119,7 @@
 	struct nl_msg *msg;
 	struct nlattr *acl;
 	unsigned int i;
-	int ret = 0;
+	int ret;
 
 	if (!(drv->capa.max_acl_mac_addrs))
 		return -ENOTSUP;
@@ -7341,40 +3127,33 @@
 	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);
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_MAC_ACL)) ||
+	    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)) == NULL) {
+		nlmsg_free(msg);
+		return -ENOMEM;
+	}
 
-	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);
+	for (i = 0; i < params->num_mac_acl; i++) {
+		if (nla_put(msg, i + 1, ETH_ALEN, params->mac_acl[i].addr)) {
+			nlmsg_free(msg);
+			return -ENOMEM;
+		}
+	}
 
 	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;
 }
 
@@ -7388,75 +3167,81 @@
 	u8 cmd = NL80211_CMD_NEW_BEACON;
 	int ret;
 	int beacon_set;
-	int ifindex = if_nametoindex(bss->ifname);
 	int num_suites;
+	int smps_mode;
 	u32 suites[10], suite;
 	u32 ver;
 
 	beacon_set = bss->beacon_set;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
 	wpa_printf(MSG_DEBUG, "nl80211: Set beacon (beacon_set=%d)",
 		   beacon_set);
 	if (beacon_set)
 		cmd = NL80211_CMD_SET_BEACON;
 
-	nl80211_cmd(drv, msg, 0, cmd);
 	wpa_hexdump(MSG_DEBUG, "nl80211: Beacon head",
 		    params->head, params->head_len);
-	NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, params->head_len, params->head);
 	wpa_hexdump(MSG_DEBUG, "nl80211: Beacon tail",
 		    params->tail, params->tail_len);
-	NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len, params->tail);
-	wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+	wpa_printf(MSG_DEBUG, "nl80211: ifindex=%d", bss->ifindex);
 	wpa_printf(MSG_DEBUG, "nl80211: beacon_int=%d", params->beacon_int);
-	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, params->beacon_int);
 	wpa_printf(MSG_DEBUG, "nl80211: dtim_period=%d", params->dtim_period);
-	NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period);
 	wpa_hexdump_ascii(MSG_DEBUG, "nl80211: ssid",
 			  params->ssid, params->ssid_len);
-	NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
-		params->ssid);
+	if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
+	    nla_put(msg, NL80211_ATTR_BEACON_HEAD, params->head_len,
+		    params->head) ||
+	    nla_put(msg, NL80211_ATTR_BEACON_TAIL, params->tail_len,
+		    params->tail) ||
+	    nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+			params->beacon_int) ||
+	    nla_put_u32(msg, NL80211_ATTR_DTIM_PERIOD, params->dtim_period) ||
+	    nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
+		goto fail;
 	if (params->proberesp && params->proberesp_len) {
 		wpa_hexdump(MSG_DEBUG, "nl80211: proberesp (offload)",
 			    params->proberesp, params->proberesp_len);
-		NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
-			params->proberesp);
+		if (nla_put(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
+			    params->proberesp))
+			goto fail;
 	}
 	switch (params->hide_ssid) {
 	case NO_SSID_HIDING:
 		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID not in use");
-		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
-			    NL80211_HIDDEN_SSID_NOT_IN_USE);
+		if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+				NL80211_HIDDEN_SSID_NOT_IN_USE))
+			goto fail;
 		break;
 	case HIDDEN_SSID_ZERO_LEN:
 		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero len");
-		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
-			    NL80211_HIDDEN_SSID_ZERO_LEN);
+		if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+				NL80211_HIDDEN_SSID_ZERO_LEN))
+			goto fail;
 		break;
 	case HIDDEN_SSID_ZERO_CONTENTS:
 		wpa_printf(MSG_DEBUG, "nl80211: hidden SSID zero contents");
-		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
-			    NL80211_HIDDEN_SSID_ZERO_CONTENTS);
+		if (nla_put_u32(msg, NL80211_ATTR_HIDDEN_SSID,
+				NL80211_HIDDEN_SSID_ZERO_CONTENTS))
+			goto fail;
 		break;
 	}
 	wpa_printf(MSG_DEBUG, "nl80211: privacy=%d", params->privacy);
-	if (params->privacy)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+	if (params->privacy &&
+	    nla_put_flag(msg, NL80211_ATTR_PRIVACY))
+		goto fail;
 	wpa_printf(MSG_DEBUG, "nl80211: auth_algs=0x%x", params->auth_algs);
 	if ((params->auth_algs & (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) ==
 	    (WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED)) {
 		/* Leave out the attribute */
-	} else if (params->auth_algs & WPA_AUTH_ALG_SHARED)
-		NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
-			    NL80211_AUTHTYPE_SHARED_KEY);
-	else
-		NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE,
-			    NL80211_AUTHTYPE_OPEN_SYSTEM);
+	} else if (params->auth_algs & WPA_AUTH_ALG_SHARED) {
+		if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
+				NL80211_AUTHTYPE_SHARED_KEY))
+			goto fail;
+	} else {
+		if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE,
+				NL80211_AUTHTYPE_OPEN_SYSTEM))
+			goto fail;
+	}
 
 	wpa_printf(MSG_DEBUG, "nl80211: wpa_version=0x%x", params->wpa_version);
 	ver = 0;
@@ -7464,8 +3249,9 @@
 		ver |= NL80211_WPA_VERSION_1;
 	if (params->wpa_version & WPA_PROTO_RSN)
 		ver |= NL80211_WPA_VERSION_2;
-	if (ver)
-		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+	if (ver &&
+	    nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
+		goto fail;
 
 	wpa_printf(MSG_DEBUG, "nl80211: key_mgmt_suites=0x%x",
 		   params->key_mgmt_suites);
@@ -7474,56 +3260,82 @@
 		suites[num_suites++] = WLAN_AKM_SUITE_8021X;
 	if (params->key_mgmt_suites & WPA_KEY_MGMT_PSK)
 		suites[num_suites++] = WLAN_AKM_SUITE_PSK;
-	if (num_suites) {
-		NLA_PUT(msg, NL80211_ATTR_AKM_SUITES,
-			num_suites * sizeof(u32), suites);
-	}
+	if (num_suites &&
+	    nla_put(msg, NL80211_ATTR_AKM_SUITES, num_suites * sizeof(u32),
+		    suites))
+		goto fail;
 
-	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X &&
-	    params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40))
-		NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT);
+	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+	    params->pairwise_ciphers & (WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40) &&
+	    nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT))
+		goto fail;
 
 	wpa_printf(MSG_DEBUG, "nl80211: pairwise_ciphers=0x%x",
 		   params->pairwise_ciphers);
 	num_suites = wpa_cipher_to_cipher_suites(params->pairwise_ciphers,
 						 suites, ARRAY_SIZE(suites));
-	if (num_suites) {
-		NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
-			num_suites * sizeof(u32), suites);
-	}
+	if (num_suites &&
+	    nla_put(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+		    num_suites * sizeof(u32), suites))
+		goto fail;
 
 	wpa_printf(MSG_DEBUG, "nl80211: group_cipher=0x%x",
 		   params->group_cipher);
 	suite = wpa_cipher_to_cipher_suite(params->group_cipher);
-	if (suite)
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite);
+	if (suite &&
+	    nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, suite))
+		goto fail;
+
+	switch (params->smps_mode) {
+	case HT_CAP_INFO_SMPS_DYNAMIC:
+		wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - dynamic");
+		smps_mode = NL80211_SMPS_DYNAMIC;
+		break;
+	case HT_CAP_INFO_SMPS_STATIC:
+		wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - static");
+		smps_mode = NL80211_SMPS_STATIC;
+		break;
+	default:
+		/* invalid - fallback to smps off */
+	case HT_CAP_INFO_SMPS_DISABLED:
+		wpa_printf(MSG_DEBUG, "nl80211: SMPS mode - off");
+		smps_mode = NL80211_SMPS_OFF;
+		break;
+	}
+	if (nla_put_u32(msg, NL80211_ATTR_SMPS_MODE, smps_mode))
+		goto fail;
 
 	if (params->beacon_ies) {
 		wpa_hexdump_buf(MSG_DEBUG, "nl80211: beacon_ies",
 				params->beacon_ies);
-		NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
-			wpabuf_head(params->beacon_ies));
+		if (nla_put(msg, NL80211_ATTR_IE,
+			    wpabuf_len(params->beacon_ies),
+			    wpabuf_head(params->beacon_ies)))
+			goto fail;
 	}
 	if (params->proberesp_ies) {
 		wpa_hexdump_buf(MSG_DEBUG, "nl80211: proberesp_ies",
 				params->proberesp_ies);
-		NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
-			wpabuf_len(params->proberesp_ies),
-			wpabuf_head(params->proberesp_ies));
+		if (nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
+			    wpabuf_len(params->proberesp_ies),
+			    wpabuf_head(params->proberesp_ies)))
+			goto fail;
 	}
 	if (params->assocresp_ies) {
 		wpa_hexdump_buf(MSG_DEBUG, "nl80211: assocresp_ies",
 				params->assocresp_ies);
-		NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
-			wpabuf_len(params->assocresp_ies),
-			wpabuf_head(params->assocresp_ies));
+		if (nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
+			    wpabuf_len(params->assocresp_ies),
+			    wpabuf_head(params->assocresp_ies)))
+			goto fail;
 	}
 
 	if (drv->capa.flags & WPA_DRIVER_FLAGS_INACTIVITY_TIMER)  {
 		wpa_printf(MSG_DEBUG, "nl80211: ap_max_inactivity=%d",
 			   params->ap_max_inactivity);
-		NLA_PUT_U16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
-			    params->ap_max_inactivity);
+		if (nla_put_u16(msg, NL80211_ATTR_INACTIVITY_TIMEOUT,
+				params->ap_max_inactivity))
+			goto fail;
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -7561,65 +3373,67 @@
 		}
 	}
 	return ret;
- nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
 
 static int nl80211_put_freq_params(struct nl_msg *msg,
-				   struct hostapd_freq_params *freq)
+				   const struct hostapd_freq_params *freq)
 {
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
+	if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq))
+		return -ENOBUFS;
+
 	if (freq->vht_enabled) {
+		enum nl80211_chan_width cw;
+
 		switch (freq->bandwidth) {
 		case 20:
-			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
-				    NL80211_CHAN_WIDTH_20);
+			cw = NL80211_CHAN_WIDTH_20;
 			break;
 		case 40:
-			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
-				    NL80211_CHAN_WIDTH_40);
+			cw = NL80211_CHAN_WIDTH_40;
 			break;
 		case 80:
 			if (freq->center_freq2)
-				NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
-					    NL80211_CHAN_WIDTH_80P80);
+				cw = NL80211_CHAN_WIDTH_80P80;
 			else
-				NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
-					    NL80211_CHAN_WIDTH_80);
+				cw = NL80211_CHAN_WIDTH_80;
 			break;
 		case 160:
-			NLA_PUT_U32(msg, NL80211_ATTR_CHANNEL_WIDTH,
-				    NL80211_CHAN_WIDTH_160);
+			cw = NL80211_CHAN_WIDTH_160;
 			break;
 		default:
 			return -EINVAL;
 		}
-		NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ1, freq->center_freq1);
-		if (freq->center_freq2)
-			NLA_PUT_U32(msg, NL80211_ATTR_CENTER_FREQ2,
-				    freq->center_freq2);
+
+		if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, cw) ||
+		    nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1,
+				freq->center_freq1) ||
+		    (freq->center_freq2 &&
+		     nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2,
+				 freq->center_freq2)))
+			return -ENOBUFS;
 	} else if (freq->ht_enabled) {
+		enum nl80211_channel_type ct;
+
 		switch (freq->sec_channel_offset) {
 		case -1:
-			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-				    NL80211_CHAN_HT40MINUS);
+			ct = NL80211_CHAN_HT40MINUS;
 			break;
 		case 1:
-			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-				    NL80211_CHAN_HT40PLUS);
+			ct = NL80211_CHAN_HT40PLUS;
 			break;
 		default:
-			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-				    NL80211_CHAN_HT20);
+			ct = NL80211_CHAN_HT20;
 			break;
 		}
+
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ct))
+			return -ENOBUFS;
 	}
 	return 0;
-
-nla_put_failure:
-	return -ENOBUFS;
 }
 
 
@@ -7634,27 +3448,21 @@
 		   "nl80211: Set freq %d (ht_enabled=%d, vht_enabled=%d, bandwidth=%d MHz, cf1=%d MHz, cf2=%d MHz)",
 		   freq->freq, freq->ht_enabled, freq->vht_enabled,
 		   freq->bandwidth, freq->center_freq1, freq->center_freq2);
-	msg = nlmsg_alloc();
-	if (!msg)
+
+	msg = nl80211_drv_msg(drv, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
+			      NL80211_CMD_SET_WIPHY);
+	if (!msg || nl80211_put_freq_params(msg, freq) < 0) {
+		nlmsg_free(msg);
 		return -1;
-
-	nl80211_cmd(drv, msg, 0, set_chan ? NL80211_CMD_SET_CHANNEL :
-		    NL80211_CMD_SET_WIPHY);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	if (nl80211_put_freq_params(msg, freq) < 0)
-		goto nla_put_failure;
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
 	if (ret == 0) {
 		bss->freq = freq->freq;
 		return 0;
 	}
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
 		   "%d (%s)", freq->freq, ret, strerror(-ret));
-nla_put_failure:
-	nlmsg_free(msg);
 	return -1;
 }
 
@@ -7673,11 +3481,40 @@
 		f |= BIT(NL80211_STA_FLAG_MFP);
 	if (flags & WPA_STA_TDLS_PEER)
 		f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+	if (flags & WPA_STA_AUTHENTICATED)
+		f |= BIT(NL80211_STA_FLAG_AUTHENTICATED);
 
 	return f;
 }
 
 
+#ifdef CONFIG_MESH
+static u32 sta_plink_state_nl80211(enum mesh_plink_state state)
+{
+	switch (state) {
+	case PLINK_LISTEN:
+		return NL80211_PLINK_LISTEN;
+	case PLINK_OPEN_SENT:
+		return NL80211_PLINK_OPN_SNT;
+	case PLINK_OPEN_RCVD:
+		return NL80211_PLINK_OPN_RCVD;
+	case PLINK_CNF_RCVD:
+		return NL80211_PLINK_CNF_RCVD;
+	case PLINK_ESTAB:
+		return NL80211_PLINK_ESTAB;
+	case PLINK_HOLDING:
+		return NL80211_PLINK_HOLDING;
+	case PLINK_BLOCKED:
+		return NL80211_PLINK_BLOCKED;
+	default:
+		wpa_printf(MSG_ERROR, "nl80211: Invalid mesh plink state %d",
+			   state);
+	}
+	return -1;
+}
+#endif /* CONFIG_MESH */
+
+
 static int wpa_driver_nl80211_sta_add(void *priv,
 				      struct hostapd_sta_add_params *params)
 {
@@ -7691,25 +3528,57 @@
 	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
 		return -EOPNOTSUPP;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
 	wpa_printf(MSG_DEBUG, "nl80211: %s STA " MACSTR,
 		   params->set ? "Set" : "Add", MAC2STR(params->addr));
-	nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
-		    NL80211_CMD_NEW_STATION);
+	msg = nl80211_bss_msg(bss, 0, params->set ? NL80211_CMD_SET_STATION :
+			      NL80211_CMD_NEW_STATION);
+	if (!msg || nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr))
+		goto fail;
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
-	NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
-		params->supp_rates);
-	wpa_hexdump(MSG_DEBUG, "  * supported rates", params->supp_rates,
-		    params->supp_rates_len);
+	if (!params->set || (params->flags & WPA_STA_TDLS_PEER)) {
+		wpa_hexdump(MSG_DEBUG, "  * supported rates",
+			    params->supp_rates, params->supp_rates_len);
+		wpa_printf(MSG_DEBUG, "  * capability=0x%x",
+			   params->capability);
+		if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_RATES,
+			    params->supp_rates_len, params->supp_rates) ||
+		    nla_put_u16(msg, NL80211_ATTR_STA_CAPABILITY,
+				params->capability))
+			goto fail;
+
+		if (params->ht_capabilities) {
+			wpa_hexdump(MSG_DEBUG, "  * ht_capabilities",
+				    (u8 *) params->ht_capabilities,
+				    sizeof(*params->ht_capabilities));
+			if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY,
+				    sizeof(*params->ht_capabilities),
+				    params->ht_capabilities))
+				goto fail;
+		}
+
+		if (params->vht_capabilities) {
+			wpa_hexdump(MSG_DEBUG, "  * vht_capabilities",
+				    (u8 *) params->vht_capabilities,
+				    sizeof(*params->vht_capabilities));
+			if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY,
+				    sizeof(*params->vht_capabilities),
+				    params->vht_capabilities))
+				goto fail;
+		}
+
+		if (params->ext_capab) {
+			wpa_hexdump(MSG_DEBUG, "  * ext_capab",
+				    params->ext_capab, params->ext_capab_len);
+			if (nla_put(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
+				    params->ext_capab_len, params->ext_capab))
+				goto fail;
+		}
+	}
 	if (!params->set) {
 		if (params->aid) {
 			wpa_printf(MSG_DEBUG, "  * aid=%u", params->aid);
-			NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+			if (nla_put_u16(msg, NL80211_ATTR_STA_AID, params->aid))
+				goto fail;
 		} else {
 			/*
 			 * cfg80211 validates that AID is non-zero, so we have
@@ -7717,85 +3586,71 @@
 			 * 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);
+			if (nla_put_u16(msg, NL80211_ATTR_STA_AID, 1))
+				goto fail;
 		}
 		wpa_printf(MSG_DEBUG, "  * listen_interval=%u",
 			   params->listen_interval);
-		NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
-			    params->listen_interval);
+		if (nla_put_u16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+				params->listen_interval))
+			goto fail;
 	} 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",
-			    (u8 *) params->ht_capabilities,
-			    sizeof(*params->ht_capabilities));
-		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
-			sizeof(*params->ht_capabilities),
-			params->ht_capabilities);
-	}
-
-	if (params->vht_capabilities) {
-		wpa_hexdump(MSG_DEBUG, "  * vht_capabilities",
-			    (u8 *) params->vht_capabilities,
-			    sizeof(*params->vht_capabilities));
-		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY,
-			sizeof(*params->vht_capabilities),
-			params->vht_capabilities);
+		if (nla_put_u16(msg, NL80211_ATTR_PEER_AID, params->aid))
+			goto fail;
 	}
 
 	if (params->vht_opmode_enabled) {
 		wpa_printf(MSG_DEBUG, "  * opmode=%u", params->vht_opmode);
-		NLA_PUT_U8(msg, NL80211_ATTR_OPMODE_NOTIF,
-			   params->vht_opmode);
-	}
-
-	wpa_printf(MSG_DEBUG, "  * capability=0x%x", params->capability);
-	NLA_PUT_U16(msg, NL80211_ATTR_STA_CAPABILITY, params->capability);
-
-	if (params->ext_capab) {
-		wpa_hexdump(MSG_DEBUG, "  * ext_capab",
-			    params->ext_capab, params->ext_capab_len);
-		NLA_PUT(msg, NL80211_ATTR_STA_EXT_CAPABILITY,
-			params->ext_capab_len, params->ext_capab);
+		if (nla_put_u8(msg, NL80211_ATTR_OPMODE_NOTIF,
+			       params->vht_opmode))
+			goto fail;
 	}
 
 	if (params->supp_channels) {
 		wpa_hexdump(MSG_DEBUG, "  * supported channels",
 			    params->supp_channels, params->supp_channels_len);
-		NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
-			params->supp_channels_len, params->supp_channels);
+		if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_CHANNELS,
+			    params->supp_channels_len, params->supp_channels))
+			goto fail;
 	}
 
 	if (params->supp_oper_classes) {
 		wpa_hexdump(MSG_DEBUG, "  * supported operating classes",
 			    params->supp_oper_classes,
 			    params->supp_oper_classes_len);
-		NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
-			params->supp_oper_classes_len,
-			params->supp_oper_classes);
+		if (nla_put(msg, NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES,
+			    params->supp_oper_classes_len,
+			    params->supp_oper_classes))
+			goto fail;
 	}
 
 	os_memset(&upd, 0, sizeof(upd));
-	upd.mask = sta_flags_nl80211(params->flags);
-	upd.set = upd.mask;
+	upd.set = sta_flags_nl80211(params->flags);
+	upd.mask = upd.set | sta_flags_nl80211(params->flags_mask);
 	wpa_printf(MSG_DEBUG, "  * flags set=0x%x mask=0x%x",
 		   upd.set, upd.mask);
-	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+	if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
+		goto fail;
+
+#ifdef CONFIG_MESH
+	if (params->plink_state &&
+	    nla_put_u8(msg, NL80211_ATTR_STA_PLINK_STATE,
+		       sta_plink_state_nl80211(params->plink_state)))
+		goto fail;
+#endif /* CONFIG_MESH */
 
 	if (params->flags & WPA_STA_WMM) {
 		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(msg, NL80211_STA_WME_UAPSD_QUEUES,
-				params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
-		NLA_PUT_U8(msg, NL80211_STA_WME_MAX_SP,
-				(params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
-				WMM_QOSINFO_STA_SP_MASK);
+		if (!wme ||
+		    nla_put_u8(msg, NL80211_STA_WME_UAPSD_QUEUES,
+			       params->qosinfo & WMM_QOSINFO_STA_AC_MASK) ||
+		    nla_put_u8(msg, NL80211_STA_WME_MAX_SP,
+			       (params->qosinfo >> WMM_QOSINFO_STA_SP_SHIFT) &
+			       WMM_QOSINFO_STA_SP_MASK))
+			goto fail;
 		nla_nest_end(msg, wme);
 	}
 
@@ -7807,7 +3662,7 @@
 			   strerror(-ret));
 	if (ret == -EEXIST)
 		ret = 0;
- nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return ret;
 }
@@ -7850,21 +3705,26 @@
 }
 
 
-static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr)
+static int wpa_driver_nl80211_sta_remove(struct i802_bss *bss, const u8 *addr,
+					 int deauth, u16 reason_code)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	int ret;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-		    if_nametoindex(bss->ifname));
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION)) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+	    (deauth == 0 &&
+	     nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
+			WLAN_FC_STYPE_DISASSOC)) ||
+	    (deauth == 1 &&
+	     nla_put_u8(msg, NL80211_ATTR_MGMT_SUBTYPE,
+			WLAN_FC_STYPE_DEAUTH)) ||
+	    (reason_code &&
+	     nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code))) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	wpa_printf(MSG_DEBUG, "nl80211: sta_remove -> DEL_STATION %s " MACSTR
@@ -7877,14 +3737,10 @@
 	if (ret == -ENOENT)
 		return 0;
 	return ret;
- nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
-static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
-				 int ifidx)
+void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
 	struct nl_msg *msg;
 	struct wpa_driver_nl80211_data *drv2;
@@ -7896,18 +3752,9 @@
 			 struct wpa_driver_nl80211_data, list)
 		del_ifidx(drv2, ifidx);
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		goto nla_put_failure;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
-
+	msg = nl80211_ifindex_msg(drv, ifidx, 0, NL80211_CMD_DEL_INTERFACE);
 	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
 		return;
-	msg = NULL;
- nla_put_failure:
-	nlmsg_free(msg);
 	wpa_printf(MSG_ERROR, "Failed to remove interface (ifidx=%d)", ifidx);
 }
 
@@ -7955,40 +3802,37 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
 		   iftype, nl80211_iftype_str(iftype));
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
-	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);
+	msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_NEW_INTERFACE);
+	if (!msg ||
+	    nla_put_string(msg, NL80211_ATTR_IFNAME, ifname) ||
+	    nla_put_u32(msg, NL80211_ATTR_IFTYPE, iftype))
+		goto fail;
 
 	if (iftype == NL80211_IFTYPE_MONITOR) {
 		struct nlattr *flags;
 
 		flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
-		if (!flags)
-			goto nla_put_failure;
-
-		NLA_PUT_FLAG(msg, NL80211_MNTR_FLAG_COOK_FRAMES);
+		if (!flags ||
+		    nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
+			goto fail;
 
 		nla_nest_end(msg, flags);
 	} else if (wds) {
-		NLA_PUT_U8(msg, NL80211_ATTR_4ADDR, wds);
+		if (nla_put_u8(msg, NL80211_ATTR_4ADDR, wds))
+			goto fail;
 	}
 
 	/*
 	 * Tell cfg80211 that the interface belongs to the socket that created
 	 * it, and the interface should be deleted when the socket is closed.
 	 */
-	NLA_PUT_FLAG(msg, NL80211_ATTR_IFACE_SOCKET_OWNER);
+	if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
+		goto fail;
 
 	ret = send_and_recv_msgs(drv, msg, handler, arg);
 	msg = NULL;
 	if (ret) {
- nla_put_failure:
+	fail:
 		nlmsg_free(msg);
 		wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
 			   ifname, ret, strerror(-ret));
@@ -8027,11 +3871,11 @@
 }
 
 
-static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
-				const char *ifname, enum nl80211_iftype iftype,
-				const u8 *addr, int wds,
-				int (*handler)(struct nl_msg *, void *),
-				void *arg, int use_existing)
+int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+			 const char *ifname, enum nl80211_iftype iftype,
+			 const u8 *addr, int wds,
+			 int (*handler)(struct nl_msg *, void *),
+			 void *arg, int use_existing)
 {
 	int ret;
 
@@ -8065,426 +3909,17 @@
 						wds, handler, arg);
 	}
 
-	if (ret >= 0 && is_p2p_net_interface(iftype))
+	if (ret >= 0 && is_p2p_net_interface(iftype)) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Interface %s created for P2P - disable 11b rates",
+			   ifname);
 		nl80211_disable_11b_rates(drv, ret, 1);
+	}
 
 	return ret;
 }
 
 
-static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
-{
-	struct ieee80211_hdr *hdr;
-	u16 fc;
-	union wpa_event_data event;
-
-	hdr = (struct ieee80211_hdr *) buf;
-	fc = le_to_host16(hdr->frame_control);
-
-	os_memset(&event, 0, sizeof(event));
-	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
-	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
-	event.tx_status.dst = hdr->addr1;
-	event.tx_status.data = buf;
-	event.tx_status.data_len = len;
-	event.tx_status.ack = ok;
-	wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
-}
-
-
-static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
-			     u8 *buf, size_t len)
-{
-	struct ieee80211_hdr *hdr = (void *)buf;
-	u16 fc;
-	union wpa_event_data event;
-
-	if (len < sizeof(*hdr))
-		return;
-
-	fc = le_to_host16(hdr->frame_control);
-
-	os_memset(&event, 0, sizeof(event));
-	event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
-	event.rx_from_unknown.addr = hdr->addr2;
-	event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
-		(WLAN_FC_FROMDS | WLAN_FC_TODS);
-	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
-}
-
-
-static void handle_frame(struct wpa_driver_nl80211_data *drv,
-			 u8 *buf, size_t len, int datarate, int ssi_signal)
-{
-	struct ieee80211_hdr *hdr;
-	u16 fc;
-	union wpa_event_data event;
-
-	hdr = (struct ieee80211_hdr *) buf;
-	fc = le_to_host16(hdr->frame_control);
-
-	switch (WLAN_FC_GET_TYPE(fc)) {
-	case WLAN_FC_TYPE_MGMT:
-		os_memset(&event, 0, sizeof(event));
-		event.rx_mgmt.frame = buf;
-		event.rx_mgmt.frame_len = len;
-		event.rx_mgmt.datarate = datarate;
-		event.rx_mgmt.ssi_signal = ssi_signal;
-		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
-		break;
-	case WLAN_FC_TYPE_CTRL:
-		/* can only get here with PS-Poll frames */
-		wpa_printf(MSG_DEBUG, "CTRL");
-		from_unknown_sta(drv, buf, len);
-		break;
-	case WLAN_FC_TYPE_DATA:
-		from_unknown_sta(drv, buf, len);
-		break;
-	}
-}
-
-
-static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
-	int len;
-	unsigned char buf[3000];
-	struct ieee80211_radiotap_iterator iter;
-	int ret;
-	int datarate = 0, ssi_signal = 0;
-	int injected = 0, failed = 0, rxflags = 0;
-
-	len = recv(sock, buf, sizeof(buf), 0);
-	if (len < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
-			   strerror(errno));
-		return;
-	}
-
-	if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) {
-		wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
-		return;
-	}
-
-	while (1) {
-		ret = ieee80211_radiotap_iterator_next(&iter);
-		if (ret == -ENOENT)
-			break;
-		if (ret) {
-			wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
-				   ret);
-			return;
-		}
-		switch (iter.this_arg_index) {
-		case IEEE80211_RADIOTAP_FLAGS:
-			if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
-				len -= 4;
-			break;
-		case IEEE80211_RADIOTAP_RX_FLAGS:
-			rxflags = 1;
-			break;
-		case IEEE80211_RADIOTAP_TX_FLAGS:
-			injected = 1;
-			failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
-					IEEE80211_RADIOTAP_F_TX_FAIL;
-			break;
-		case IEEE80211_RADIOTAP_DATA_RETRIES:
-			break;
-		case IEEE80211_RADIOTAP_CHANNEL:
-			/* TODO: convert from freq/flags to channel number */
-			break;
-		case IEEE80211_RADIOTAP_RATE:
-			datarate = *iter.this_arg * 5;
-			break;
-		case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
-			ssi_signal = (s8) *iter.this_arg;
-			break;
-		}
-	}
-
-	if (rxflags && injected)
-		return;
-
-	if (!injected)
-		handle_frame(drv, buf + iter._max_length,
-			     len - iter._max_length, datarate, ssi_signal);
-	else
-		handle_tx_callback(drv->ctx, buf + iter._max_length,
-				   len - iter._max_length, !failed);
-}
-
-
-/*
- * we post-process the filter code later and rewrite
- * this to the offset to the last instruction
- */
-#define PASS	0xFF
-#define FAIL	0xFE
-
-static struct sock_filter msock_filter_insns[] = {
-	/*
-	 * do a little-endian load of the radiotap length field
-	 */
-	/* load lower byte into A */
-	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 2),
-	/* put it into X (== index register) */
-	BPF_STMT(BPF_MISC| BPF_TAX, 0),
-	/* load upper byte into A */
-	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 3),
-	/* left-shift it by 8 */
-	BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
-	/* or with X */
-	BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
-	/* put result into X */
-	BPF_STMT(BPF_MISC| BPF_TAX, 0),
-
-	/*
-	 * Allow management frames through, this also gives us those
-	 * management frames that we sent ourselves with status
-	 */
-	/* load the lower byte of the IEEE 802.11 frame control field */
-	BPF_STMT(BPF_LD  | BPF_B | BPF_IND, 0),
-	/* mask off frame type and version */
-	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
-	/* accept frame if it's both 0, fall through otherwise */
-	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
-
-	/*
-	 * TODO: add a bit to radiotap RX flags that indicates
-	 * that the sending station is not associated, then
-	 * add a filter here that filters on our DA and that flag
-	 * to allow us to deauth frames to that bad station.
-	 *
-	 * For now allow all To DS data frames through.
-	 */
-	/* load the IEEE 802.11 frame control field */
-	BPF_STMT(BPF_LD  | BPF_H | BPF_IND, 0),
-	/* mask off frame type, version and DS status */
-	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
-	/* accept frame if version 0, type 2 and To DS, fall through otherwise
-	 */
-	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
-
-#if 0
-	/*
-	 * drop non-data frames
-	 */
-	/* load the lower byte of the frame control field */
-	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
-	/* mask off QoS bit */
-	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x0c),
-	/* drop non-data frames */
-	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 8, 0, FAIL),
-#endif
-	/* load the upper byte of the frame control field */
-	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 1),
-	/* mask off toDS/fromDS */
-	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x03),
-	/* accept WDS frames */
-	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 3, PASS, 0),
-
-	/*
-	 * add header length to index
-	 */
-	/* load the lower byte of the frame control field */
-	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
-	/* mask off QoS bit */
-	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x80),
-	/* right shift it by 6 to give 0 or 2 */
-	BPF_STMT(BPF_ALU  | BPF_RSH | BPF_K, 6),
-	/* add data frame header length */
-	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_K, 24),
-	/* add index, was start of 802.11 header */
-	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_X, 0),
-	/* move to index, now start of LL header */
-	BPF_STMT(BPF_MISC | BPF_TAX, 0),
-
-	/*
-	 * Accept empty data frames, we use those for
-	 * polling activity.
-	 */
-	BPF_STMT(BPF_LD  | BPF_W | BPF_LEN, 0),
-	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
-
-	/*
-	 * Accept EAPOL frames
-	 */
-	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 0),
-	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
-	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 4),
-	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
-
-	/* keep these last two statements or change the code below */
-	/* return 0 == "DROP" */
-	BPF_STMT(BPF_RET | BPF_K, 0),
-	/* return ~0 == "keep all" */
-	BPF_STMT(BPF_RET | BPF_K, ~0),
-};
-
-static struct sock_fprog msock_filter = {
-	.len = ARRAY_SIZE(msock_filter_insns),
-	.filter = msock_filter_insns,
-};
-
-
-static int add_monitor_filter(int s)
-{
-	int idx;
-
-	/* rewrite all PASS/FAIL jump offsets */
-	for (idx = 0; idx < msock_filter.len; idx++) {
-		struct sock_filter *insn = &msock_filter_insns[idx];
-
-		if (BPF_CLASS(insn->code) == BPF_JMP) {
-			if (insn->code == (BPF_JMP|BPF_JA)) {
-				if (insn->k == PASS)
-					insn->k = msock_filter.len - idx - 2;
-				else if (insn->k == FAIL)
-					insn->k = msock_filter.len - idx - 3;
-			}
-
-			if (insn->jt == PASS)
-				insn->jt = msock_filter.len - idx - 2;
-			else if (insn->jt == FAIL)
-				insn->jt = msock_filter.len - idx - 3;
-
-			if (insn->jf == PASS)
-				insn->jf = msock_filter.len - idx - 2;
-			else if (insn->jf == FAIL)
-				insn->jf = msock_filter.len - idx - 3;
-		}
-	}
-
-	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
-		       &msock_filter, sizeof(msock_filter))) {
-		wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
-			   strerror(errno));
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static void nl80211_remove_monitor_interface(
-	struct wpa_driver_nl80211_data *drv)
-{
-	if (drv->monitor_refcount > 0)
-		drv->monitor_refcount--;
-	wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
-		   drv->monitor_refcount);
-	if (drv->monitor_refcount > 0)
-		return;
-
-	if (drv->monitor_ifidx >= 0) {
-		nl80211_remove_iface(drv, drv->monitor_ifidx);
-		drv->monitor_ifidx = -1;
-	}
-	if (drv->monitor_sock >= 0) {
-		eloop_unregister_read_sock(drv->monitor_sock);
-		close(drv->monitor_sock);
-		drv->monitor_sock = -1;
-	}
-}
-
-
-static int
-nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
-{
-	char buf[IFNAMSIZ];
-	struct sockaddr_ll ll;
-	int optval;
-	socklen_t optlen;
-
-	if (drv->monitor_ifidx >= 0) {
-		drv->monitor_refcount++;
-		wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
-			   drv->monitor_refcount);
-		return 0;
-	}
-
-	if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
-		/*
-		 * P2P interface name is of the format p2p-%s-%d. For monitor
-		 * interface name corresponding to P2P GO, replace "p2p-" with
-		 * "mon-" to retain the same interface name length and to
-		 * indicate that it is a monitor interface.
-		 */
-		snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
-	} else {
-		/* Non-P2P interface with AP functionality. */
-		snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
-	}
-
-	buf[IFNAMSIZ - 1] = '\0';
-
-	drv->monitor_ifidx =
-		nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
-				     0, NULL, NULL, 0);
-
-	if (drv->monitor_ifidx == -EOPNOTSUPP) {
-		/*
-		 * This is backward compatibility for a few versions of
-		 * the kernel only that didn't advertise the right
-		 * attributes for the only driver that then supported
-		 * AP mode w/o monitor -- ath6kl.
-		 */
-		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
-			   "monitor interface type - try to run without it");
-		drv->device_ap_sme = 1;
-	}
-
-	if (drv->monitor_ifidx < 0)
-		return -1;
-
-	if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
-		goto error;
-
-	memset(&ll, 0, sizeof(ll));
-	ll.sll_family = AF_PACKET;
-	ll.sll_ifindex = drv->monitor_ifidx;
-	drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
-	if (drv->monitor_sock < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
-			   strerror(errno));
-		goto error;
-	}
-
-	if (add_monitor_filter(drv->monitor_sock)) {
-		wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
-			   "interface; do filtering in user space");
-		/* This works, but will cost in performance. */
-	}
-
-	if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
-			   strerror(errno));
-		goto error;
-	}
-
-	optlen = sizeof(optval);
-	optval = 20;
-	if (setsockopt
-	    (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
-			   strerror(errno));
-		goto error;
-	}
-
-	if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
-				     drv, NULL)) {
-		wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
-		goto error;
-	}
-
-	drv->monitor_refcount++;
-	return 0;
- error:
-	nl80211_remove_monitor_interface(drv);
-	return -1;
-}
-
-
 static int nl80211_setup_ap(struct i802_bss *bss)
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -8643,7 +4078,6 @@
 					    int flags_or, int flags_and)
 {
 	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	struct nlattr *flags;
 	struct nl80211_sta_flag_update upd;
@@ -8653,47 +4087,38 @@
 		   bss->ifname, MAC2STR(addr), total_flags, flags_or, flags_and,
 		   !!(total_flags & WPA_STA_AUTHORIZED));
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-		    if_nametoindex(bss->ifname));
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr))
+		goto fail;
 
 	/*
 	 * 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(msg, NL80211_STA_FLAG_AUTHORIZED);
-
-	if (total_flags & WPA_STA_WMM)
-		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_WME);
-
-	if (total_flags & WPA_STA_SHORT_PREAMBLE)
-		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_SHORT_PREAMBLE);
-
-	if (total_flags & WPA_STA_MFP)
-		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_MFP);
-
-	if (total_flags & WPA_STA_TDLS_PEER)
-		NLA_PUT_FLAG(msg, NL80211_STA_FLAG_TDLS_PEER);
+	if (!flags ||
+	    ((total_flags & WPA_STA_AUTHORIZED) &&
+	     nla_put_flag(msg, NL80211_STA_FLAG_AUTHORIZED)) ||
+	    ((total_flags & WPA_STA_WMM) &&
+	     nla_put_flag(msg, NL80211_STA_FLAG_WME)) ||
+	    ((total_flags & WPA_STA_SHORT_PREAMBLE) &&
+	     nla_put_flag(msg, NL80211_STA_FLAG_SHORT_PREAMBLE)) ||
+	    ((total_flags & WPA_STA_MFP) &&
+	     nla_put_flag(msg, NL80211_STA_FLAG_MFP)) ||
+	    ((total_flags & WPA_STA_TDLS_PEER) &&
+	     nla_put_flag(msg, NL80211_STA_FLAG_TDLS_PEER)))
+		goto fail;
 
 	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);
+	if (nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd))
+		goto fail;
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
+	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+fail:
 	nlmsg_free(msg);
 	return -ENOBUFS;
 }
@@ -8728,36 +4153,29 @@
 }
 
 
-static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv)
+static int nl80211_leave_ibss(struct wpa_driver_nl80211_data *drv,
+			      int reset_mode)
 {
 	struct nl_msg *msg;
-	int ret = -1;
+	int ret;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_IBSS);
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
-		goto nla_put_failure;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Leave IBSS request sent successfully");
 	}
 
-	ret = 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Leave IBSS request sent successfully");
-
-nla_put_failure:
-	if (wpa_driver_nl80211_set_mode(drv->first_bss,
+	if (reset_mode &&
+	    wpa_driver_nl80211_set_mode(drv->first_bss,
 					NL80211_IFTYPE_STATION)) {
 		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
 			   "station mode");
 	}
 
-	nlmsg_free(msg);
 	return ret;
 }
 
@@ -8778,20 +4196,14 @@
 	}
 
 retry:
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_JOIN_IBSS);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-	if (params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
-		goto nla_put_failure;
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_IBSS)) ||
+	    params->ssid == NULL || params->ssid_len > sizeof(drv->ssid))
+		goto fail;
 
 	wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
 			  params->ssid, params->ssid_len);
-	NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
-		params->ssid);
+	if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len, params->ssid))
+		goto fail;
 	os_memcpy(drv->ssid, params->ssid, params->ssid_len);
 	drv->ssid_len = params->ssid_len;
 
@@ -8804,22 +4216,24 @@
 	wpa_printf(MSG_DEBUG, "  * center_freq2=%d", params->freq.center_freq2);
 	wpa_printf(MSG_DEBUG, "  * bandwidth=%d", params->freq.bandwidth);
 	if (nl80211_put_freq_params(msg, &params->freq) < 0)
-		goto nla_put_failure;
+		goto fail;
 
 	if (params->beacon_int > 0) {
 		wpa_printf(MSG_DEBUG, "  * beacon_int=%d", params->beacon_int);
-		NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL,
-			    params->beacon_int);
+		if (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+				params->beacon_int))
+			goto fail;
 	}
 
 	ret = nl80211_set_conn_keys(params, msg);
 	if (ret)
-		goto nla_put_failure;
+		goto fail;
 
 	if (params->bssid && params->fixed_bssid) {
 		wpa_printf(MSG_DEBUG, "  * BSSID=" MACSTR,
 			   MAC2STR(params->bssid));
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+		if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+			goto fail;
 	}
 
 	if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
@@ -8827,15 +4241,17 @@
 	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
 	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
 		wpa_printf(MSG_DEBUG, "  * control port");
-		NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+		if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
+			goto fail;
 	}
 
 	if (params->wpa_ie) {
 		wpa_hexdump(MSG_DEBUG,
 			    "  * Extra IEs for Beacon/Probe Response frames",
 			    params->wpa_ie, params->wpa_ie_len);
-		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
-			params->wpa_ie);
+		if (nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len,
+			    params->wpa_ie))
+			goto fail;
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -8847,17 +4263,16 @@
 		if (ret == -EALREADY && count == 1) {
 			wpa_printf(MSG_DEBUG, "nl80211: Retry IBSS join after "
 				   "forced leave");
-			nl80211_leave_ibss(drv);
+			nl80211_leave_ibss(drv, 0);
 			nlmsg_free(msg);
 			goto retry;
 		}
-
-		goto nla_put_failure;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Join IBSS request sent successfully");
 	}
-	ret = 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS request sent successfully");
 
-nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return ret;
 }
@@ -8867,56 +4282,61 @@
 				  struct wpa_driver_associate_params *params,
 				  struct nl_msg *msg)
 {
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
 	if (params->bssid) {
 		wpa_printf(MSG_DEBUG, "  * bssid=" MACSTR,
 			   MAC2STR(params->bssid));
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid);
+		if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, params->bssid))
+			return -1;
 	}
 
 	if (params->bssid_hint) {
 		wpa_printf(MSG_DEBUG, "  * bssid_hint=" MACSTR,
 			   MAC2STR(params->bssid_hint));
-		NLA_PUT(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
-			params->bssid_hint);
+		if (nla_put(msg, NL80211_ATTR_MAC_HINT, ETH_ALEN,
+			    params->bssid_hint))
+			return -1;
 	}
 
 	if (params->freq.freq) {
 		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq.freq);
-		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq.freq);
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+				params->freq.freq))
+			return -1;
 		drv->assoc_freq = params->freq.freq;
 	} else
 		drv->assoc_freq = 0;
 
 	if (params->freq_hint) {
 		wpa_printf(MSG_DEBUG, "  * freq_hint=%d", params->freq_hint);
-		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
-			    params->freq_hint);
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ_HINT,
+				params->freq_hint))
+			return -1;
 	}
 
 	if (params->bg_scan_period >= 0) {
 		wpa_printf(MSG_DEBUG, "  * bg scan period=%d",
 			   params->bg_scan_period);
-		NLA_PUT_U16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
-			    params->bg_scan_period);
+		if (nla_put_u16(msg, NL80211_ATTR_BG_SCAN_PERIOD,
+				params->bg_scan_period))
+			return -1;
 	}
 
 	if (params->ssid) {
 		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
 				  params->ssid, params->ssid_len);
-		NLA_PUT(msg, NL80211_ATTR_SSID, params->ssid_len,
-			params->ssid);
+		if (nla_put(msg, NL80211_ATTR_SSID, params->ssid_len,
+			    params->ssid))
+			return -1;
 		if (params->ssid_len > sizeof(drv->ssid))
-			goto nla_put_failure;
+			return -1;
 		os_memcpy(drv->ssid, params->ssid, params->ssid_len);
 		drv->ssid_len = params->ssid_len;
 	}
 
 	wpa_hexdump(MSG_DEBUG, "  * IEs", params->wpa_ie, params->wpa_ie_len);
-	if (params->wpa_ie)
-		NLA_PUT(msg, NL80211_ATTR_IE, params->wpa_ie_len,
-			params->wpa_ie);
+	if (params->wpa_ie &&
+	    nla_put(msg, NL80211_ATTR_IE, params->wpa_ie_len, params->wpa_ie))
+		return -1;
 
 	if (params->wpa_proto) {
 		enum nl80211_wpa_versions ver = 0;
@@ -8927,13 +4347,16 @@
 			ver |= NL80211_WPA_VERSION_2;
 
 		wpa_printf(MSG_DEBUG, "  * WPA Versions 0x%x", ver);
-		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
+		if (nla_put_u32(msg, NL80211_ATTR_WPA_VERSIONS, ver))
+			return -1;
 	}
 
 	if (params->pairwise_suite != WPA_CIPHER_NONE) {
 		u32 cipher = wpa_cipher_to_cipher_suite(params->pairwise_suite);
 		wpa_printf(MSG_DEBUG, "  * pairwise=0x%x", cipher);
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE, cipher);
+		if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+				cipher))
+			return -1;
 	}
 
 	if (params->group_suite == WPA_CIPHER_GTK_NOT_USED &&
@@ -8946,7 +4369,8 @@
 	} else if (params->group_suite != WPA_CIPHER_NONE) {
 		u32 cipher = wpa_cipher_to_cipher_suite(params->group_suite);
 		wpa_printf(MSG_DEBUG, "  * group=0x%x", cipher);
-		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher);
+		if (nla_put_u32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP, cipher))
+			return -1;
 	}
 
 	if (params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
@@ -8956,7 +4380,8 @@
 	    params->key_mgmt_suite == WPA_KEY_MGMT_CCKM ||
 	    params->key_mgmt_suite == WPA_KEY_MGMT_OSEN ||
 	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
-	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256) {
+	    params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+	    params->key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
 		int mgmt = WLAN_AKM_SUITE_PSK;
 
 		switch (params->key_mgmt_suite) {
@@ -8981,47 +4406,67 @@
 		case WPA_KEY_MGMT_OSEN:
 			mgmt = WLAN_AKM_SUITE_OSEN;
 			break;
+		case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+			mgmt = WLAN_AKM_SUITE_8021X_SUITE_B;
+			break;
 		case WPA_KEY_MGMT_PSK:
 		default:
 			mgmt = WLAN_AKM_SUITE_PSK;
 			break;
 		}
 		wpa_printf(MSG_DEBUG, "  * akm=0x%x", mgmt);
-		NLA_PUT_U32(msg, NL80211_ATTR_AKM_SUITES, mgmt);
+		if (nla_put_u32(msg, NL80211_ATTR_AKM_SUITES, mgmt))
+			return -1;
 	}
 
-	NLA_PUT_FLAG(msg, NL80211_ATTR_CONTROL_PORT);
+	if (nla_put_flag(msg, NL80211_ATTR_CONTROL_PORT))
+		return -1;
 
-	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED)
-		NLA_PUT_U32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED);
+	if (params->mgmt_frame_protection == MGMT_FRAME_PROTECTION_REQUIRED &&
+	    nla_put_u32(msg, NL80211_ATTR_USE_MFP, NL80211_MFP_REQUIRED))
+		return -1;
 
-	if (params->disable_ht)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_HT);
+	if (params->rrm_used) {
+		u32 drv_rrm_flags = drv->capa.rrm_flags;
+		if (!(drv_rrm_flags &
+		      WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
+		    !(drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET) ||
+		    nla_put_flag(msg, NL80211_ATTR_USE_RRM))
+			return -1;
+	}
+
+	if (params->disable_ht && nla_put_flag(msg, NL80211_ATTR_DISABLE_HT))
+		return -1;
 
 	if (params->htcaps && params->htcaps_mask) {
 		int sz = sizeof(struct ieee80211_ht_capabilities);
 		wpa_hexdump(MSG_DEBUG, "  * htcaps", params->htcaps, sz);
-		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY, sz, params->htcaps);
 		wpa_hexdump(MSG_DEBUG, "  * htcaps_mask",
 			    params->htcaps_mask, sz);
-		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
-			params->htcaps_mask);
+		if (nla_put(msg, NL80211_ATTR_HT_CAPABILITY, sz,
+			    params->htcaps) ||
+		    nla_put(msg, NL80211_ATTR_HT_CAPABILITY_MASK, sz,
+			    params->htcaps_mask))
+			return -1;
 	}
 
 #ifdef CONFIG_VHT_OVERRIDES
 	if (params->disable_vht) {
 		wpa_printf(MSG_DEBUG, "  * VHT disabled");
-		NLA_PUT_FLAG(msg, NL80211_ATTR_DISABLE_VHT);
+		if (nla_put_flag(msg, NL80211_ATTR_DISABLE_VHT))
+			return -1;
 	}
 
 	if (params->vhtcaps && params->vhtcaps_mask) {
 		int sz = sizeof(struct ieee80211_vht_capabilities);
 		wpa_hexdump(MSG_DEBUG, "  * vhtcaps", params->vhtcaps, sz);
-		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY, sz, params->vhtcaps);
 		wpa_hexdump(MSG_DEBUG, "  * vhtcaps_mask",
 			    params->vhtcaps_mask, sz);
-		NLA_PUT(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
-			params->vhtcaps_mask);
+		if (nla_put(msg, NL80211_ATTR_VHT_CAPABILITY, sz,
+			    params->vhtcaps) ||
+		    nla_put(msg, NL80211_ATTR_VHT_CAPABILITY_MASK, sz,
+			    params->vhtcaps_mask))
+			return -1;
 	}
 #endif /* CONFIG_VHT_OVERRIDES */
 
@@ -9029,8 +4474,6 @@
 		wpa_printf(MSG_DEBUG, "  * P2P group");
 
 	return 0;
-nla_put_failure:
-	return -1;
 }
 
 
@@ -9043,16 +4486,24 @@
 	int ret;
 	int algs;
 
-	msg = nlmsg_alloc();
+	if (params->req_key_mgmt_offload && params->psk &&
+	    (params->key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+	     params->key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+	     params->key_mgmt_suite == WPA_KEY_MGMT_FT_PSK)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Key management set PSK");
+		ret = issue_key_mgmt_set_key(drv, params->psk, 32);
+		if (ret)
+			return ret;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_CONNECT);
 	if (!msg)
 		return -1;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
-
 	ret = nl80211_connect_common(drv, params, msg);
 	if (ret)
-		goto nla_put_failure;
+		goto fail;
 
 	algs = 0;
 	if (params->auth_alg & WPA_AUTH_ALG_OPEN)
@@ -9076,27 +4527,28 @@
 	else if (params->auth_alg & WPA_AUTH_ALG_FT)
 		type = NL80211_AUTHTYPE_FT;
 	else
-		goto nla_put_failure;
+		goto fail;
 
 	wpa_printf(MSG_DEBUG, "  * Auth Type %d", type);
-	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
+	if (nla_put_u32(msg, NL80211_ATTR_AUTH_TYPE, type))
+		goto fail;
 
 skip_auth_type:
 	ret = nl80211_set_conn_keys(params, msg);
 	if (ret)
-		goto nla_put_failure;
+		goto fail;
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
-		goto nla_put_failure;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Connect request send successfully");
 	}
-	ret = 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Connect request send successfully");
 
-nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return ret;
 
@@ -9139,9 +4591,11 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret;
+	int ret = -1;
 	struct nl_msg *msg;
 
+	nl80211_unmask_11b_rates(bss);
+
 	if (params->mode == IEEE80211_MODE_AP)
 		return wpa_driver_nl80211_ap(drv, params);
 
@@ -9159,23 +4613,22 @@
 
 	nl80211_mark_disconnected(drv);
 
-	msg = nlmsg_alloc();
+	wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
+		   drv->ifindex);
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_ASSOCIATE);
 	if (!msg)
 		return -1;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
-		   drv->ifindex);
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
-
 	ret = nl80211_connect_common(drv, params, msg);
 	if (ret)
-		goto nla_put_failure;
+		goto fail;
 
 	if (params->prev_bssid) {
 		wpa_printf(MSG_DEBUG, "  * prev_bssid=" MACSTR,
 			   MAC2STR(params->prev_bssid));
-		NLA_PUT(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
-			params->prev_bssid);
+		if (nla_put(msg, NL80211_ATTR_PREV_BSSID, ETH_ALEN,
+			    params->prev_bssid))
+			goto fail;
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -9185,13 +4638,12 @@
 			"nl80211: MLME command failed (assoc): ret=%d (%s)",
 			ret, strerror(-ret));
 		nl80211_dump_scan(drv);
-		goto nla_put_failure;
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Association request send successfully");
 	}
-	ret = 0;
-	wpa_printf(MSG_DEBUG, "nl80211: Association request send "
-		   "successfully");
 
-nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return ret;
 }
@@ -9206,20 +4658,15 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Set mode ifindex %d iftype %d (%s)",
 		   ifindex, mode, nl80211_iftype_str(mode));
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
-	if (nl80211_set_iface_id(msg, drv->first_bss) < 0)
-		goto nla_put_failure;
-	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
+	msg = nl80211_cmd_msg(drv->first_bss, 0, NL80211_CMD_SET_INTERFACE);
+	if (!msg || nla_put_u32(msg, NL80211_ATTR_IFTYPE, mode))
+		goto fail;
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (!ret)
 		return 0;
-nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface %d to mode %d:"
 		   " %d (%s)", ifindex, mode, ret, strerror(-ret));
@@ -9281,7 +4728,7 @@
 		 * on a frequency that the mode is disallowed in.
 		 */
 		if (desired_freq_params) {
-			res = i802_set_freq(bss, desired_freq_params);
+			res = nl80211_set_channel(bss, desired_freq_params, 0);
 			if (res) {
 				wpa_printf(MSG_DEBUG,
 					   "nl80211: Failed to set frequency on interface");
@@ -9322,10 +4769,17 @@
 		return ret;
 	}
 
-	if (is_p2p_net_interface(nlmode))
+	if (is_p2p_net_interface(nlmode)) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Interface %s mode change to P2P - disable 11b rates",
+			   bss->ifname);
 		nl80211_disable_11b_rates(drv, drv->ifindex, 1);
-	else if (drv->disabled_11b_rates)
+	} else if (drv->disabled_11b_rates) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Interface %s mode changed to non-P2P - re-enable 11b rates",
+			   bss->ifname);
 		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
+	}
 
 	if (is_ap_interface(nlmode)) {
 		nl80211_mgmt_unsubscribe(bss, "start AP");
@@ -9339,7 +4793,12 @@
 		nl80211_mgmt_unsubscribe(bss, "mode change");
 	}
 
+	if (is_mesh_interface(nlmode) &&
+	    nl80211_mgmt_subscribe_mesh(bss))
+		return -1;
+
 	if (!bss->in_deinit && !is_ap_interface(nlmode) &&
+	    !is_mesh_interface(nlmode) &&
 	    nl80211_mgmt_subscribe_non_ap(bss) < 0)
 		wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
 			   "frame processing - ignore for now");
@@ -9348,37 +4807,8 @@
 }
 
 
-static int dfs_info_handler(struct nl_msg *msg, void *arg)
-{
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	int *dfs_capability_ptr = arg;
-
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
-
-	if (tb[NL80211_ATTR_VENDOR_DATA]) {
-		struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
-		struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
-
-		nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
-			  nla_data(nl_vend), nla_len(nl_vend), NULL);
-
-		if (tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]) {
-			u32 val;
-			val = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]);
-			wpa_printf(MSG_DEBUG, "nl80211: DFS offload capability: %u",
-				   val);
-			*dfs_capability_ptr = val;
-		}
-	}
-
-	return NL_SKIP;
-}
-
-
-static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
-				       enum nl80211_iftype nlmode)
+int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+				enum nl80211_iftype nlmode)
 {
 	return wpa_driver_nl80211_set_mode_impl(bss, nlmode, NULL);
 }
@@ -9397,9 +4827,6 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	int dfs_capability = 0;
-	int ret = 0;
 
 	if (!drv->has_capability)
 		return -1;
@@ -9410,37 +4837,7 @@
 		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;
-	}
-
-	if (drv->dfs_vendor_cmd_avail == 1) {
-		msg = nlmsg_alloc();
-		if (!msg)
-			return -ENOMEM;
-
-		nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
-
-		NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-		NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
-		NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD,
-			    QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY);
-
-		ret = send_and_recv_msgs(drv, msg, dfs_info_handler,
-					 &dfs_capability);
-		if (!ret) {
-			if (dfs_capability)
-				capa->flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
-		}
-	}
-
-	return ret;
-
- nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
+	return 0;
 }
 
 
@@ -9464,7 +4861,7 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	struct nl80211_sta_flag_update upd;
-	int ret = -ENOBUFS;
+	int ret;
 
 	if (!drv->associated && is_zero_ether_addr(drv->bssid) && !authorized) {
 		wpa_printf(MSG_DEBUG, "nl80211: Skip set_supp_port(unauthorized) while not associated");
@@ -9474,28 +4871,21 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Set supplicant port %sauthorized for "
 		   MACSTR, authorized ? "" : "un", MAC2STR(drv->bssid));
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-		    if_nametoindex(bss->ifname));
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid);
-
 	os_memset(&upd, 0, sizeof(upd));
 	upd.mask = BIT(NL80211_STA_FLAG_AUTHORIZED);
 	if (authorized)
 		upd.set = BIT(NL80211_STA_FLAG_AUTHORIZED);
-	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, drv->bssid) ||
+	    nla_put(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
 	if (!ret)
 		return 0;
- nla_put_failure:
-	nlmsg_free(msg);
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set STA flag: %d (%s)",
 		   ret, strerror(-ret));
 	return ret;
@@ -9546,23 +4936,18 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
-
-	if (addr)
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-	NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+	msg = nl80211_ifindex_msg(drv, if_nametoindex(iface), 0,
+				  NL80211_CMD_GET_KEY);
+	if (!msg ||
+	    (addr && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) ||
+	    nla_put_u8(msg, NL80211_ATTR_KEY_IDX, idx)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	memset(seq, 0, 6);
 
 	return send_and_recv_msgs(drv, msg, get_key_handler, seq);
- nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
@@ -9571,28 +4956,23 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
-	int ret = -ENOBUFS;
+	int ret;
 	u32 val;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
 	if (rts >= 2347)
 		val = (u32) -1;
 	else
 		val = rts;
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val);
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
+	    nla_put_u32(msg, NL80211_ATTR_WIPHY_RTS_THRESHOLD, val)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
 	if (!ret)
 		return 0;
-nla_put_failure:
-	nlmsg_free(msg);
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set RTS threshold %d: "
 		   "%d (%s)", rts, ret, strerror(-ret));
 	return ret;
@@ -9604,28 +4984,23 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
-	int ret = -ENOBUFS;
+	int ret;
 	u32 val;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
 	if (frag >= 2346)
 		val = (u32) -1;
 	else
 		val = frag;
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val);
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WIPHY)) ||
+	    nla_put_u32(msg, NL80211_ATTR_WIPHY_FRAG_THRESHOLD, val)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
 	if (!ret)
 		return 0;
-nla_put_failure:
-	nlmsg_free(msg);
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set fragmentation threshold "
 		   "%d: %d (%s)", frag, ret, strerror(-ret));
 	return ret;
@@ -9635,33 +5010,22 @@
 static int i802_flush(void *priv)
 {
 	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	int res;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
 	wpa_printf(MSG_DEBUG, "nl80211: flush -> DEL_STATION %s (all)",
 		   bss->ifname);
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
 
 	/*
 	 * XXX: FIX! this needs to flush all VLANs too
 	 */
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-		    if_nametoindex(bss->ifname));
-
-	res = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = nl80211_bss_msg(bss, 0, NL80211_CMD_DEL_STATION);
+	res = send_and_recv_msgs(bss->drv, msg, NULL, NULL);
 	if (res) {
 		wpa_printf(MSG_DEBUG, "nl80211: Station flush failed: ret=%d "
 			   "(%s)", res, strerror(-res));
 	}
 	return res;
- nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
@@ -9724,23 +5088,17 @@
 			      struct hostap_sta_driver_data *data,
 			      const u8 *addr)
 {
-	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 
 	os_memset(data, 0, sizeof(*data));
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
+	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_GET_STATION)) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-	return send_and_recv_msgs(drv, msg, get_sta_handler, data);
- nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
+	return send_and_recv_msgs(bss->drv, msg, get_sta_handler, data);
 }
 
 
@@ -9752,43 +5110,45 @@
 	struct nl_msg *msg;
 	struct nlattr *txq, *params;
 
-	msg = nlmsg_alloc();
+	msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_WIPHY);
 	if (!msg)
 		return -1;
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
 	txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
 	if (!txq)
-		goto nla_put_failure;
+		goto fail;
 
 	/* We are only sending parameters for a single TXQ at a time */
 	params = nla_nest_start(msg, 1);
 	if (!params)
-		goto nla_put_failure;
+		goto fail;
 
 	switch (queue) {
 	case 0:
-		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO);
+		if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VO))
+			goto fail;
 		break;
 	case 1:
-		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI);
+		if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_VI))
+			goto fail;
 		break;
 	case 2:
-		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE);
+		if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BE))
+			goto fail;
 		break;
 	case 3:
-		NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK);
+		if (nla_put_u8(msg, NL80211_TXQ_ATTR_QUEUE, NL80211_TXQ_Q_BK))
+			goto fail;
 		break;
 	}
 	/* Burst time is configured in units of 0.1 msec and TXOP parameter in
 	 * 32 usec, so need to convert the value here. */
-	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
-	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min);
-	NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max);
-	NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs);
+	if (nla_put_u16(msg, NL80211_TXQ_ATTR_TXOP,
+			(burst_time * 100 + 16) / 32) ||
+	    nla_put_u16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min) ||
+	    nla_put_u16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max) ||
+	    nla_put_u8(msg, NL80211_TXQ_ATTR_AIFS, aifs))
+		goto fail;
 
 	nla_nest_end(msg, params);
 
@@ -9797,7 +5157,7 @@
 	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
 		return 0;
 	msg = NULL;
- nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return -1;
 }
@@ -9808,34 +5168,26 @@
 {
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
-	int ret = -ENOBUFS;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
+	int ret;
 
 	wpa_printf(MSG_DEBUG, "nl80211: %s[%d]: set_sta_vlan(" MACSTR
 		   ", ifname=%s[%d], vlan_id=%d)",
 		   bss->ifname, if_nametoindex(bss->ifname),
 		   MAC2STR(addr), ifname, if_nametoindex(ifname), vlan_id);
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
-		    if_nametoindex(bss->ifname));
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
-	NLA_PUT_U32(msg, NL80211_ATTR_STA_VLAN,
-		    if_nametoindex(ifname));
+	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_STATION)) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+	    nla_put_u32(msg, NL80211_ATTR_STA_VLAN, if_nametoindex(ifname))) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
 	if (ret < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: NL80211_ATTR_STA_VLAN (addr="
 			   MACSTR " ifname=%s vlan_id=%d) failed: %d (%s)",
 			   MAC2STR(addr), ifname, vlan_id, ret,
 			   strerror(-ret));
 	}
- nla_put_failure:
-	nlmsg_free(msg);
 	return ret;
 }
 
@@ -9869,8 +5221,11 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct ieee80211_mgmt mgmt;
 
+	if (is_mesh_interface(drv->nlmode))
+		return -1;
+
 	if (drv->device_ap_sme)
-		return wpa_driver_nl80211_sta_remove(bss, addr);
+		return wpa_driver_nl80211_sta_remove(bss, addr, 1, reason);
 
 	memset(&mgmt, 0, sizeof(mgmt));
 	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -9893,8 +5248,11 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct ieee80211_mgmt mgmt;
 
+	if (is_mesh_interface(drv->nlmode))
+		return -1;
+
 	if (drv->device_ap_sme)
-		return wpa_driver_nl80211_sta_remove(bss, addr);
+		return wpa_driver_nl80211_sta_remove(bss, addr, 0, reason);
 
 	memset(&mgmt, 0, sizeof(mgmt));
 	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
@@ -9922,7 +5280,7 @@
 		if (!drv->if_indices[i])
 			continue;
 		res = os_snprintf(pos, end - pos, " %d", drv->if_indices[i]);
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			break;
 		pos += res;
 	}
@@ -10071,12 +5429,12 @@
 			     struct i802_bss *bss,
 			     const char *brname, const char *ifname)
 {
-	int ifindex;
+	int br_ifindex;
 	char in_br[IFNAMSIZ];
 
 	os_strlcpy(bss->brname, brname, IFNAMSIZ);
-	ifindex = if_nametoindex(brname);
-	if (ifindex == 0) {
+	br_ifindex = if_nametoindex(brname);
+	if (br_ifindex == 0) {
 		/*
 		 * Bridge was configured, but the bridge device does
 		 * not exist. Try to add it now.
@@ -10088,8 +5446,10 @@
 			return -1;
 		}
 		bss->added_bridge = 1;
-		add_ifidx(drv, if_nametoindex(brname));
+		br_ifindex = if_nametoindex(brname);
+		add_ifidx(drv, br_ifindex);
 	}
+	bss->br_ifindex = br_ifindex;
 
 	if (linux_br_get(in_br, ifname) == 0) {
 		if (os_strcmp(in_br, brname) == 0)
@@ -10133,7 +5493,7 @@
 
 	bss = wpa_driver_nl80211_drv_init(hapd, params->ifname,
 					  params->global_priv, 1,
-					  params->bssid);
+					  params->bssid, params->driver_params);
 	if (bss == NULL)
 		return NULL;
 
@@ -10143,10 +5503,12 @@
 		wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
 			   params->ifname, brname);
 		br_ifindex = if_nametoindex(brname);
+		os_strlcpy(bss->brname, brname, IFNAMSIZ);
 	} else {
 		brname[0] = '\0';
 		br_ifindex = 0;
 	}
+	bss->br_ifindex = br_ifindex;
 
 	for (i = 0; i < params->num_bridge; i++) {
 		if (params->bridge[i]) {
@@ -10157,16 +5519,21 @@
 				br_added = 1;
 		}
 	}
-	if (!br_added && br_ifindex &&
-	    (params->num_bridge == 0 || !params->bridge[0]))
-		add_ifidx(drv, br_ifindex);
 
 	/* start listening for EAPOL on the default AP interface */
 	add_ifidx(drv, drv->ifindex);
 
-	if (params->num_bridge && params->bridge[0] &&
-	    i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
-		goto failed;
+	if (params->num_bridge && params->bridge[0]) {
+		if (i802_check_bridge(drv, bss, params->bridge[0],
+				      params->ifname) < 0)
+			goto failed;
+		if (os_strcmp(params->bridge[0], brname) != 0)
+			br_added = 1;
+	}
+
+	if (!br_added && br_ifindex &&
+	    (params->num_bridge == 0 || !params->bridge[0]))
+		add_ifidx(drv, br_ifindex);
 
 #ifdef CONFIG_LIBNL3_ROUTE
 	if (bss->added_if_into_bridge) {
@@ -10236,12 +5603,14 @@
 		return NL80211_IFTYPE_P2P_GO;
 	case WPA_IF_P2P_DEVICE:
 		return NL80211_IFTYPE_P2P_DEVICE;
+	case WPA_IF_MESH:
+		return NL80211_IFTYPE_MESH_POINT;
 	}
 	return -1;
 }
 
 
-#ifdef CONFIG_P2P
+#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
 
 static int nl80211_addr_in_use(struct nl80211_global *global, const u8 *addr)
 {
@@ -10255,8 +5624,7 @@
 }
 
 
-static int nl80211_p2p_interface_addr(struct wpa_driver_nl80211_data *drv,
-				      u8 *new_addr)
+static int nl80211_vif_addr(struct wpa_driver_nl80211_data *drv, u8 *new_addr)
 {
 	unsigned int idx;
 
@@ -10273,13 +5641,13 @@
 	if (idx == 64)
 		return -1;
 
-	wpa_printf(MSG_DEBUG, "nl80211: Assigned new P2P Interface Address "
+	wpa_printf(MSG_DEBUG, "nl80211: Assigned new virtual interface address "
 		   MACSTR, MAC2STR(new_addr));
 
 	return 0;
 }
 
-#endif /* CONFIG_P2P */
+#endif /* CONFIG_P2P || CONFIG_MESH */
 
 
 struct wdev_info {
@@ -10366,10 +5734,10 @@
 		}
 	}
 
-#ifdef CONFIG_P2P
+#if defined(CONFIG_P2P) || defined(CONFIG_MESH)
 	if (!addr &&
 	    (type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP ||
-	     type == WPA_IF_P2P_GO)) {
+	     type == WPA_IF_P2P_GO || type == WPA_IF_MESH)) {
 		/* Enforce unique P2P Interface Address */
 		u8 new_addr[ETH_ALEN];
 
@@ -10381,8 +5749,9 @@
 		}
 		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) {
+				   "for %s interface", type == WPA_IF_MESH ?
+				   "mesh" : "P2P group");
+			if (nl80211_vif_addr(drv, new_addr) < 0) {
 				if (added)
 					nl80211_remove_iface(drv, ifidx);
 				return -1;
@@ -10396,7 +5765,7 @@
 		}
 		os_memcpy(if_addr, new_addr, ETH_ALEN);
 	}
-#endif /* CONFIG_P2P */
+#endif /* CONFIG_P2P || CONFIG_MESH */
 
 	if (type == WPA_IF_AP_BSS) {
 		struct i802_bss *new_bss = os_zalloc(sizeof(*new_bss));
@@ -10560,31 +5929,21 @@
 	u64 cookie;
 	int ret = -1;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -1;
-
 	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);
 	wpa_hexdump(MSG_MSGDUMP, "CMD_FRAME", buf, buf_len);
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-	if (nl80211_set_iface_id(msg, bss) < 0)
-		goto nla_put_failure;
-	if (freq)
-		NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-	if (wait)
-		NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
-	if (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
-			  drv->test_use_roc_tx))
-		NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
-	if (no_cck)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_TX_NO_CCK_RATE);
-	if (no_ack)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK);
-
-	NLA_PUT(msg, NL80211_ATTR_FRAME, buf_len, buf);
+	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME)) ||
+	    (freq && nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
+	    (wait && nla_put_u32(msg, NL80211_ATTR_DURATION, wait)) ||
+	    (offchanok && ((drv->capa.flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) ||
+			   drv->test_use_roc_tx) &&
+	     nla_put_flag(msg, NL80211_ATTR_OFFCHANNEL_TX_OK)) ||
+	    (no_cck && nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE)) ||
+	    (no_ack && nla_put_flag(msg, NL80211_ATTR_DONT_WAIT_FOR_ACK)) ||
+	    nla_put(msg, NL80211_ATTR_FRAME, buf_len, buf))
+		goto fail;
 
 	cookie = 0;
 	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
@@ -10593,16 +5952,16 @@
 		wpa_printf(MSG_DEBUG, "nl80211: Frame command failed: ret=%d "
 			   "(%s) (freq=%u wait=%u)", ret, strerror(-ret),
 			   freq, wait);
-		goto nla_put_failure;
+	} else {
+		wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
+			   "cookie 0x%llx", no_ack ? " (no ACK)" : "",
+			   (long long unsigned int) cookie);
+
+		if (cookie_out)
+			*cookie_out = no_ack ? (u64) -1 : cookie;
 	}
-	wpa_printf(MSG_MSGDUMP, "nl80211: Frame TX command accepted%s; "
-		   "cookie 0x%llx", no_ack ? " (no ACK)" : "",
-		   (long long unsigned int) cookie);
 
-	if (cookie_out)
-		*cookie_out = no_ack ? (u64) -1 : cookie;
-
-nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return ret;
 }
@@ -10661,26 +6020,18 @@
 	struct nl_msg *msg;
 	int ret;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return;
-
 	wpa_printf(MSG_DEBUG, "nl80211: Cancel TX frame wait: cookie=0x%llx",
 		   (long long unsigned int) drv->send_action_cookie);
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
-
-	if (nl80211_set_iface_id(msg, bss) < 0)
-		goto nla_put_failure;
-	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
+	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_FRAME_WAIT_CANCEL)) ||
+	    nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie)) {
+		nlmsg_free(msg);
+		return;
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
 	if (ret)
 		wpa_printf(MSG_DEBUG, "nl80211: wait cancel failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
-
- nla_put_failure:
-	nlmsg_free(msg);
 }
 
 
@@ -10693,21 +6044,15 @@
 	int ret;
 	u64 cookie;
 
-	msg = nlmsg_alloc();
-	if (!msg)
+	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_REMAIN_ON_CHANNEL)) ||
+	    nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
+	    nla_put_u32(msg, NL80211_ATTR_DURATION, duration)) {
+		nlmsg_free(msg);
 		return -1;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
-
-	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);
+	}
 
 	cookie = 0;
 	ret = send_and_recv_msgs(drv, msg, cookie_handler, &cookie);
-	msg = NULL;
 	if (ret == 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel cookie "
 			   "0x%llx for freq=%u MHz duration=%u",
@@ -10719,8 +6064,6 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to request remain-on-channel "
 		   "(freq=%d duration=%u): %d (%s)",
 		   freq, duration, ret, strerror(-ret));
-nla_put_failure:
-	nlmsg_free(msg);
 	return -1;
 }
 
@@ -10742,25 +6085,18 @@
 		   "0x%llx",
 		   (long long unsigned int) drv->remain_on_chan_cookie);
 
-	msg = nlmsg_alloc();
-	if (!msg)
+	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
+	if (!msg ||
+	    nla_put_u64(msg, NL80211_ATTR_COOKIE, drv->remain_on_chan_cookie)) {
+		nlmsg_free(msg);
 		return -1;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
-
-	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);
-	msg = NULL;
 	if (ret == 0)
 		return 0;
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to cancel remain-on-channel: "
 		   "%d (%s)", ret, strerror(-ret));
-nla_put_failure:
-	nlmsg_free(msg);
 	return -1;
 }
 
@@ -10825,16 +6161,19 @@
 	struct nlattr *bands, *band;
 	int ret;
 
-	msg = nlmsg_alloc();
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: NL80211_CMD_SET_TX_BITRATE_MASK (ifindex=%d %s)",
+		   ifindex, disabled ? "NL80211_TXRATE_LEGACY=OFDM-only" :
+		   "no NL80211_TXRATE_LEGACY constraint");
+
+	msg = nl80211_ifindex_msg(drv, ifindex, 0,
+				  NL80211_CMD_SET_TX_BITRATE_MASK);
 	if (!msg)
 		return -1;
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_TX_BITRATE_MASK);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
-
 	bands = nla_nest_start(msg, NL80211_ATTR_TX_RATES);
 	if (!bands)
-		goto nla_put_failure;
+		goto fail;
 
 	/*
 	 * Disable 2 GHz rates 1, 2, 5.5, 11 Mbps by masking out everything
@@ -10842,18 +6181,15 @@
 	 * rates. All 5 GHz rates are left enabled.
 	 */
 	band = nla_nest_start(msg, NL80211_BAND_2GHZ);
-	if (!band)
-		goto nla_put_failure;
-	if (disabled) {
-		NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
-			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
-	}
+	if (!band ||
+	    (disabled && nla_put(msg, NL80211_TXRATE_LEGACY, 8,
+				 "\x0c\x12\x18\x24\x30\x48\x60\x6c")))
+		goto fail;
 	nla_nest_end(msg, band);
 
 	nla_nest_end(msg, bands);
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Set TX rates failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
@@ -10862,7 +6198,7 @@
 
 	return ret;
 
-nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return -1;
 }
@@ -10875,6 +6211,7 @@
 	if (!is_ap_interface(drv->nlmode))
 		return -1;
 	wpa_driver_nl80211_del_beacon(drv);
+	bss->beacon_set = 0;
 
 	/*
 	 * If the P2P GO interface was dynamically added, then it is
@@ -10926,86 +6263,26 @@
 }
 
 
-static int nl80211_send_ft_action(void *priv, u8 action, const u8 *target_ap,
-				  const u8 *ies, size_t ies_len)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	int ret;
-	u8 *data, *pos;
-	size_t data_len;
-	const u8 *own_addr = bss->addr;
-
-	if (action != 1) {
-		wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
-			   "action %d", action);
-		return -1;
-	}
-
-	/*
-	 * Action frame payload:
-	 * Category[1] = 6 (Fast BSS Transition)
-	 * Action[1] = 1 (Fast BSS Transition Request)
-	 * STA Address
-	 * Target AP Address
-	 * FT IEs
-	 */
-
-	data_len = 2 + 2 * ETH_ALEN + ies_len;
-	data = os_malloc(data_len);
-	if (data == NULL)
-		return -1;
-	pos = data;
-	*pos++ = 0x06; /* FT Action category */
-	*pos++ = action;
-	os_memcpy(pos, own_addr, ETH_ALEN);
-	pos += ETH_ALEN;
-	os_memcpy(pos, target_ap, ETH_ALEN);
-	pos += ETH_ALEN;
-	os_memcpy(pos, ies, ies_len);
-
-	ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
-					     drv->bssid, own_addr, drv->bssid,
-					     data, data_len, 0);
-	os_free(data);
-
-	return ret;
-}
-
-
 static int nl80211_signal_monitor(void *priv, int threshold, int hysteresis)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	struct nlattr *cqm;
-	int ret = -1;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Signal monitor threshold=%d "
 		   "hysteresis=%d", threshold, hysteresis);
 
-	msg = nlmsg_alloc();
-	if (!msg)
+	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_CQM)) ||
+	    !(cqm = nla_nest_start(msg, NL80211_ATTR_CQM)) ||
+	    nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_THOLD, threshold) ||
+	    nla_put_u32(msg, NL80211_ATTR_CQM_RSSI_HYST, hysteresis)) {
+		nlmsg_free(msg);
 		return -1;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-
-	cqm = nla_nest_start(msg, NL80211_ATTR_CQM);
-	if (cqm == NULL)
-		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(msg);
-	return ret;
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
 }
 
 
@@ -11042,18 +6319,8 @@
 {
 	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);
-
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_GET_INTERFACE);
 	return send_and_recv_msgs(drv, msg, get_channel_width, sig);
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
@@ -11142,12 +6409,6 @@
 		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;
-	}
 #endif /* CONFIG_P2P */
 
 	if (os_strstr(param, "use_monitor=1")) {
@@ -11258,22 +6519,14 @@
 {
 	struct nl_msg *msg;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(bss->drv, msg, 0, cmd);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-	if (pmkid)
-		NLA_PUT(msg, NL80211_ATTR_PMKID, 16, pmkid);
-	if (bssid)
-		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid);
+	if (!(msg = nl80211_bss_msg(bss, 0, cmd)) ||
+	    (pmkid && nla_put(msg, NL80211_ATTR_PMKID, 16, pmkid)) ||
+	    (bssid && nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, bssid))) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
- nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
@@ -11444,7 +6697,7 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
-	int err = -ENOBUFS;
+	int err;
 	union wpa_event_data data;
 	struct survey_results *survey_results;
 
@@ -11453,13 +6706,9 @@
 
 	dl_list_init(&survey_results->survey_list);
 
-	msg = nlmsg_alloc();
+	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
 	if (!msg)
-		goto nla_put_failure;
-
-	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+		return -ENOBUFS;
 
 	if (freq)
 		data.survey_results.freq_filter = freq;
@@ -11470,16 +6719,12 @@
 					 survey_results);
 	} while (err > 0);
 
-	if (err) {
+	if (err)
 		wpa_printf(MSG_ERROR, "nl80211: Failed to process survey data");
-		goto out_clean;
-	}
+	else
+		wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
 
-	wpa_supplicant_event(drv->ctx, EVENT_SURVEY, &data);
-
-out_clean:
 	clean_survey_results(survey_results);
-nla_put_failure:
 	return err;
 }
 
@@ -11492,29 +6737,20 @@
 	struct nlattr *replay_nested;
 	struct nl_msg *msg;
 
-	msg = nlmsg_alloc();
-	if (!msg)
+	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_REKEY_OFFLOAD)) ||
+	    !(replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA)) ||
+	    nla_put(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek) ||
+	    nla_put(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck) ||
+	    nla_put(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
+		    replay_ctr)) {
+		nl80211_nlmsg_clear(msg);
+		nlmsg_free(msg);
 		return;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_REKEY_OFFLOAD);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-
-	replay_nested = nla_nest_start(msg, NL80211_ATTR_REKEY_DATA);
-	if (!replay_nested)
-		goto nla_put_failure;
-
-	NLA_PUT(msg, NL80211_REKEY_DATA_KEK, NL80211_KEK_LEN, kek);
-	NLA_PUT(msg, NL80211_REKEY_DATA_KCK, NL80211_KCK_LEN, kck);
-	NLA_PUT(msg, NL80211_REKEY_DATA_REPLAY_CTR, NL80211_REPLAY_CTR_LEN,
-		replay_ctr);
+	}
 
 	nla_nest_end(msg, replay_nested);
 
-	send_and_recv_msgs(drv, msg, NULL, NULL);
-	return;
- nla_put_failure:
-	nlmsg_free(msg);
+	send_and_recv_msgs(drv, msg, NULL, (void *) -1);
 }
 
 
@@ -11568,19 +6804,13 @@
 		return;
 	}
 
-	msg = nlmsg_alloc();
-	if (!msg)
+	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_PROBE_CLIENT)) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+		nlmsg_free(msg);
 		return;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_PROBE_CLIENT);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+	}
 
 	send_and_recv_msgs(drv, msg, NULL, NULL);
-	return;
- nla_put_failure:
-	nlmsg_free(msg);
 }
 
 
@@ -11588,18 +6818,13 @@
 {
 	struct nl_msg *msg;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_SET_POWER_SAVE);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_PS_STATE,
-		    enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED);
+	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_SET_POWER_SAVE)) ||
+	    nla_put_u32(msg, NL80211_ATTR_PS_STATE,
+			enabled ? NL80211_PS_ENABLED : NL80211_PS_DISABLED)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
-nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
@@ -11646,24 +6871,17 @@
 		return -1;
 	}
 
-	msg = nlmsg_alloc();
-	if (!msg)
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_RADAR_DETECT)) ||
+	    nl80211_put_freq_params(msg, freq) < 0) {
+		nlmsg_free(msg);
 		return -1;
-
-	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_RADAR_DETECT);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-	if (nl80211_put_freq_params(msg, freq) < 0)
-		goto nla_put_failure;
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	msg = NULL;
 	if (ret == 0)
 		return 0;
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to start radar detection: "
 		   "%d (%s)", ret, strerror(-ret));
-nla_put_failure:
-	nlmsg_free(msg);
 	return -1;
 }
 
@@ -11684,16 +6902,12 @@
 	if (!dst)
 		return -EINVAL;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_MGMT);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, dst);
-	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_ACTION, action_code);
-	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token);
-	NLA_PUT_U16(msg, NL80211_ATTR_STATUS_CODE, status_code);
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_MGMT)) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, dst) ||
+	    nla_put_u8(msg, NL80211_ATTR_TDLS_ACTION, action_code) ||
+	    nla_put_u8(msg, NL80211_ATTR_TDLS_DIALOG_TOKEN, dialog_token) ||
+	    nla_put_u16(msg, NL80211_ATTR_STATUS_CODE, status_code))
+		goto fail;
 	if (peer_capab) {
 		/*
 		 * The internal enum tdls_peer_capability definition is
@@ -11701,15 +6915,18 @@
 		 * nl80211_tdls_peer_capability, so no conversion is needed
 		 * here.
 		 */
-		NLA_PUT_U32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY, peer_capab);
+		if (nla_put_u32(msg, NL80211_ATTR_TDLS_PEER_CAPABILITY,
+				peer_capab))
+			goto fail;
 	}
-	if (initiator)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_TDLS_INITIATOR);
-	NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
+	if ((initiator &&
+	     nla_put_flag(msg, NL80211_ATTR_TDLS_INITIATOR)) ||
+	    nla_put(msg, NL80211_ATTR_IE, len, buf))
+		goto fail;
 
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
 
-nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return -ENOBUFS;
 }
@@ -11749,158 +6966,75 @@
 		return -EINVAL;
 	}
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_TDLS_OPER);
-	NLA_PUT_U8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, peer);
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_TDLS_OPER)) ||
+	    nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, nl80211_oper) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
 
-nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
+
+static int
+nl80211_tdls_enable_channel_switch(void *priv, const u8 *addr, u8 oper_class,
+				   const struct hostapd_freq_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret = -ENOBUFS;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+		return -EOPNOTSUPP;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Enable TDLS channel switch " MACSTR
+		   " oper_class=%u freq=%u",
+		   MAC2STR(addr), oper_class, params->freq);
+	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CHANNEL_SWITCH);
+	if (!msg ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+	    nla_put_u8(msg, NL80211_ATTR_OPER_CLASS, oper_class) ||
+	    (ret = nl80211_put_freq_params(msg, params))) {
+		nlmsg_free(msg);
+		wpa_printf(MSG_DEBUG, "nl80211: Could not build TDLS chan switch");
+		return ret;
+	}
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+}
+
+
+static int
+nl80211_tdls_disable_channel_switch(void *priv, const u8 *addr)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT) ||
+	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH))
+		return -EOPNOTSUPP;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Disable TDLS channel switch " MACSTR,
+		   MAC2STR(addr));
+	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH);
+	if (!msg ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+		nlmsg_free(msg);
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Could not build TDLS cancel chan switch");
+		return -ENOBUFS;
+	}
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
 }
 
 #endif /* CONFIG TDLS */
 
 
-#ifdef ANDROID
-
-typedef struct android_wifi_priv_cmd {
-	char *buf;
-	int used_len;
-	int total_len;
-} android_wifi_priv_cmd;
-
-static int drv_errors = 0;
-
-static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
-{
-	drv_errors++;
-	if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
-		drv_errors = 0;
-		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
-	}
-}
-
-
-static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
-{
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct ifreq ifr;
-	android_wifi_priv_cmd priv_cmd;
-	char buf[MAX_DRV_CMD_SIZE];
-	int ret;
-
-	os_memset(&ifr, 0, sizeof(ifr));
-	os_memset(&priv_cmd, 0, sizeof(priv_cmd));
-	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
-
-	os_memset(buf, 0, sizeof(buf));
-	os_strlcpy(buf, cmd, sizeof(buf));
-
-	priv_cmd.buf = buf;
-	priv_cmd.used_len = sizeof(buf);
-	priv_cmd.total_len = sizeof(buf);
-	ifr.ifr_data = &priv_cmd;
-
-	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
-	if (ret < 0) {
-		wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
-			   __func__);
-		wpa_driver_send_hang_msg(drv);
-		return ret;
-	}
-
-	drv_errors = 0;
-	return 0;
-}
-
-
-static int android_pno_start(struct i802_bss *bss,
-			     struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct ifreq ifr;
-	android_wifi_priv_cmd priv_cmd;
-	int ret = 0, i = 0, bp;
-	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
-
-	bp = WEXT_PNOSETUP_HEADER_SIZE;
-	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
-	buf[bp++] = WEXT_PNO_TLV_PREFIX;
-	buf[bp++] = WEXT_PNO_TLV_VERSION;
-	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
-	buf[bp++] = WEXT_PNO_TLV_RESERVED;
-
-	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
-		/* Check that there is enough space needed for 1 more SSID, the
-		 * other sections and null termination */
-		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
-		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
-			break;
-		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
-				  params->ssids[i].ssid,
-				  params->ssids[i].ssid_len);
-		buf[bp++] = WEXT_PNO_SSID_SECTION;
-		buf[bp++] = params->ssids[i].ssid_len;
-		os_memcpy(&buf[bp], params->ssids[i].ssid,
-			  params->ssids[i].ssid_len);
-		bp += params->ssids[i].ssid_len;
-		i++;
-	}
-
-	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
-	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
-		    WEXT_PNO_SCAN_INTERVAL);
-	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
-
-	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
-	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
-		    WEXT_PNO_REPEAT);
-	bp += WEXT_PNO_REPEAT_LENGTH;
-
-	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
-	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
-		    WEXT_PNO_MAX_REPEAT);
-	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
-
-	memset(&ifr, 0, sizeof(ifr));
-	memset(&priv_cmd, 0, sizeof(priv_cmd));
-	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
-
-	priv_cmd.buf = buf;
-	priv_cmd.used_len = bp;
-	priv_cmd.total_len = bp;
-	ifr.ifr_data = &priv_cmd;
-
-	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
-
-	if (ret < 0) {
-		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
-			   ret);
-		wpa_driver_send_hang_msg(drv);
-		return ret;
-	}
-
-	drv_errors = 0;
-
-	return android_priv_cmd(bss, "PNOFORCE 1");
-}
-
-
-static int android_pno_stop(struct i802_bss *bss)
-{
-	return android_priv_cmd(bss, "PNOFORCE 0");
-}
-
-#endif /* ANDROID */
-
-
 static int driver_nl80211_set_key(const char *ifname, void *priv,
 				  enum wpa_alg alg, const u8 *addr,
 				  int key_idx, int set_tx,
@@ -11964,7 +7098,7 @@
 static int driver_nl80211_sta_remove(void *priv, const u8 *addr)
 {
 	struct i802_bss *bss = priv;
-	return wpa_driver_nl80211_sta_remove(bss, addr);
+	return wpa_driver_nl80211_sta_remove(bss, addr, -1, 0);
 }
 
 
@@ -12014,15 +7148,13 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	u16 mdid = WPA_GET_LE16(md);
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
 	wpa_printf(MSG_DEBUG, "nl80211: Updating FT IEs");
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_UPDATE_FT_IES);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies);
-	NLA_PUT_U16(msg, NL80211_ATTR_MDID, mdid);
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_UPDATE_FT_IES)) ||
+	    nla_put(msg, NL80211_ATTR_IE, ies_len, ies) ||
+	    nla_put_u16(msg, NL80211_ATTR_MDID, mdid)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (ret) {
@@ -12031,10 +7163,6 @@
 	}
 
 	return ret;
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
@@ -12103,14 +7231,14 @@
 			  bss->added_bridge ? "added_bridge=1\n" : "",
 			  bss->in_deinit ? "in_deinit=1\n" : "",
 			  bss->if_dynamic ? "if_dynamic=1\n" : "");
-	if (res < 0 || res >= end - pos)
+	if (os_snprintf_error(end - pos, res))
 		return pos - buf;
 	pos += res;
 
 	if (bss->wdev_id_set) {
 		res = os_snprintf(pos, end - pos, "wdev_id=%llu\n",
 				  (unsigned long long) bss->wdev_id);
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
 	}
@@ -12132,7 +7260,7 @@
 			  "monitor_refcount=%d\n"
 			  "last_mgmt_freq=%u\n"
 			  "eapol_tx_sock=%d\n"
-			  "%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+			  "%s%s%s%s%s%s%s%s%s%s%s%s%s",
 			  drv->phyname,
 			  MAC2STR(drv->perm_addr),
 			  drv->ifindex,
@@ -12168,9 +7296,8 @@
 			  drv->ignore_next_local_disconnect ?
 			  "ignore_next_local_disconnect=1\n" : "",
 			  drv->ignore_next_local_deauth ?
-			  "ignore_next_local_deauth=1\n" : "",
-			  drv->allow_p2p_device ? "allow_p2p_device=1\n" : "");
-	if (res < 0 || res >= end - pos)
+			  "ignore_next_local_deauth=1\n" : "");
+	if (os_snprintf_error(end - pos, res))
 		return pos - buf;
 	pos += res;
 
@@ -12179,7 +7306,8 @@
 				  "capa.key_mgmt=0x%x\n"
 				  "capa.enc=0x%x\n"
 				  "capa.auth=0x%x\n"
-				  "capa.flags=0x%x\n"
+				  "capa.flags=0x%llx\n"
+				  "capa.rrm_flags=0x%x\n"
 				  "capa.max_scan_ssids=%d\n"
 				  "capa.max_sched_scan_ssids=%d\n"
 				  "capa.sched_scan_supported=%d\n"
@@ -12188,11 +7316,14 @@
 				  "capa.max_stations=%u\n"
 				  "capa.probe_resp_offloads=0x%x\n"
 				  "capa.max_acl_mac_addrs=%u\n"
-				  "capa.num_multichan_concurrent=%u\n",
+				  "capa.num_multichan_concurrent=%u\n"
+				  "capa.mac_addr_rand_sched_scan_supported=%d\n"
+				  "capa.mac_addr_rand_scan_supported=%d\n",
 				  drv->capa.key_mgmt,
 				  drv->capa.enc,
 				  drv->capa.auth,
-				  drv->capa.flags,
+				  (unsigned long long) drv->capa.flags,
+				  drv->capa.rrm_flags,
 				  drv->capa.max_scan_ssids,
 				  drv->capa.max_sched_scan_ssids,
 				  drv->capa.sched_scan_supported,
@@ -12201,8 +7332,10 @@
 				  drv->capa.max_stations,
 				  drv->capa.probe_resp_offloads,
 				  drv->capa.max_acl_mac_addrs,
-				  drv->capa.num_multichan_concurrent);
-		if (res < 0 || res >= end - pos)
+				  drv->capa.num_multichan_concurrent,
+				  drv->capa.mac_addr_rand_sched_scan_supported,
+				  drv->capa.mac_addr_rand_scan_supported);
+		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
 	}
@@ -12213,35 +7346,27 @@
 
 static int set_beacon_data(struct nl_msg *msg, struct beacon_data *settings)
 {
-	if (settings->head)
-		NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD,
-			settings->head_len, settings->head);
-
-	if (settings->tail)
-		NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL,
-			settings->tail_len, settings->tail);
-
-	if (settings->beacon_ies)
-		NLA_PUT(msg, NL80211_ATTR_IE,
-			settings->beacon_ies_len, settings->beacon_ies);
-
-	if (settings->proberesp_ies)
-		NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
-			settings->proberesp_ies_len, settings->proberesp_ies);
-
-	if (settings->assocresp_ies)
-		NLA_PUT(msg,
-			NL80211_ATTR_IE_ASSOC_RESP,
-			settings->assocresp_ies_len, settings->assocresp_ies);
-
-	if (settings->probe_resp)
-		NLA_PUT(msg, NL80211_ATTR_PROBE_RESP,
-			settings->probe_resp_len, settings->probe_resp);
+	if ((settings->head &&
+	     nla_put(msg, NL80211_ATTR_BEACON_HEAD,
+		     settings->head_len, settings->head)) ||
+	    (settings->tail &&
+	     nla_put(msg, NL80211_ATTR_BEACON_TAIL,
+		     settings->tail_len, settings->tail)) ||
+	    (settings->beacon_ies &&
+	     nla_put(msg, NL80211_ATTR_IE,
+		     settings->beacon_ies_len, settings->beacon_ies)) ||
+	    (settings->proberesp_ies &&
+	     nla_put(msg, NL80211_ATTR_IE_PROBE_RESP,
+		     settings->proberesp_ies_len, settings->proberesp_ies)) ||
+	    (settings->assocresp_ies &&
+	     nla_put(msg, NL80211_ATTR_IE_ASSOC_RESP,
+		     settings->assocresp_ies_len, settings->assocresp_ies)) ||
+	    (settings->probe_resp &&
+	     nla_put(msg, NL80211_ATTR_PROBE_RESP,
+		     settings->probe_resp_len, settings->probe_resp)))
+		return -ENOBUFS;
 
 	return 0;
-
-nla_put_failure:
-	return -ENOBUFS;
 }
 
 
@@ -12283,20 +7408,14 @@
 	      settings->cs_count)))
 		return -EINVAL;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_CHANNEL_SWITCH);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_CH_SWITCH_COUNT, settings->cs_count);
-	ret = nl80211_put_freq_params(msg, &settings->freq_params);
-	if (ret)
+	if (!(msg = nl80211_bss_msg(bss, 0, NL80211_CMD_CHANNEL_SWITCH)) ||
+	    nla_put_u32(msg, NL80211_ATTR_CH_SWITCH_COUNT,
+			settings->cs_count) ||
+	    (ret = nl80211_put_freq_params(msg, &settings->freq_params)) ||
+	    (settings->block_tx &&
+	     nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX)))
 		goto error;
 
-	if (settings->block_tx)
-		NLA_PUT_FLAG(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX);
-
 	/* beacon_after params */
 	ret = set_beacon_data(msg, &settings->beacon_after);
 	if (ret)
@@ -12305,18 +7424,18 @@
 	/* beacon_csa params */
 	beacon_csa = nla_nest_start(msg, NL80211_ATTR_CSA_IES);
 	if (!beacon_csa)
-		goto nla_put_failure;
+		goto fail;
 
 	ret = set_beacon_data(msg, &settings->beacon_csa);
 	if (ret)
 		goto error;
 
-	NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
-		    settings->counter_offset_beacon);
-
-	if (settings->beacon_csa.probe_resp)
-		NLA_PUT_U16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
-			    settings->counter_offset_presp);
+	if (nla_put_u16(msg, NL80211_ATTR_CSA_C_OFF_BEACON,
+			settings->counter_offset_beacon) ||
+	    (settings->beacon_csa.probe_resp &&
+	     nla_put_u16(msg, NL80211_ATTR_CSA_C_OFF_PRESP,
+			 settings->counter_offset_presp)))
+		goto fail;
 
 	nla_nest_end(msg, beacon_csa);
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
@@ -12326,7 +7445,7 @@
 	}
 	return ret;
 
-nla_put_failure:
+fail:
 	ret = -ENOBUFS;
 error:
 	nlmsg_free(msg);
@@ -12335,6 +7454,66 @@
 }
 
 
+static int nl80211_add_ts(void *priv, u8 tsid, const u8 *addr,
+			  u8 user_priority, u16 admitted_time)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: add_ts request: tsid=%u admitted_time=%u up=%d",
+		   tsid, admitted_time, user_priority);
+
+	if (!is_sta_interface(drv->nlmode))
+		return -ENOTSUP;
+
+	msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_ADD_TX_TS);
+	if (!msg ||
+	    nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr) ||
+	    nla_put_u8(msg, NL80211_ATTR_USER_PRIO, user_priority) ||
+	    nla_put_u16(msg, NL80211_ATTR_ADMITTED_TIME, admitted_time)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret)
+		wpa_printf(MSG_DEBUG, "nl80211: add_ts failed err=%d (%s)",
+			   ret, strerror(-ret));
+	return ret;
+}
+
+
+static int nl80211_del_ts(void *priv, u8 tsid, const u8 *addr)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "nl80211: del_ts request: tsid=%u", tsid);
+
+	if (!is_sta_interface(drv->nlmode))
+		return -ENOTSUP;
+
+	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_DEL_TX_TS)) ||
+	    nla_put_u8(msg, NL80211_ATTR_TSID, tsid) ||
+	    nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, addr)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret)
+		wpa_printf(MSG_DEBUG, "nl80211: del_ts failed err=%d (%s)",
+			   ret, strerror(-ret));
+	return ret;
+}
+
+
 #ifdef CONFIG_TESTING_OPTIONS
 static int cmd_reply_handler(struct nl_msg *msg, void *arg)
 {
@@ -12397,16 +7576,16 @@
 	struct nl_msg *msg;
 	int ret;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
 #ifdef CONFIG_TESTING_OPTIONS
 	if (vendor_id == 0xffffffff) {
+		msg = nlmsg_alloc();
+		if (!msg)
+			return -ENOMEM;
+
 		nl80211_cmd(drv, msg, 0, subcmd);
 		if (nlmsg_append(msg, (void *) data, data_len, NLMSG_ALIGNTO) <
 		    0)
-			goto nla_put_failure;
+			goto fail;
 		ret = send_and_recv_msgs(drv, msg, cmd_reply_handler, buf);
 		if (ret)
 			wpa_printf(MSG_DEBUG, "nl80211: command failed err=%d",
@@ -12415,13 +7594,12 @@
 	}
 #endif /* CONFIG_TESTING_OPTIONS */
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
-	if (nl80211_set_iface_id(msg, bss) < 0)
-		goto nla_put_failure;
-	NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, vendor_id);
-	NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd);
-	if (data)
-		NLA_PUT(msg, NL80211_ATTR_VENDOR_DATA, data_len, data);
+	if (!(msg = nl80211_cmd_msg(bss, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, vendor_id) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD, subcmd) ||
+	    (data &&
+	     nla_put(msg, NL80211_ATTR_VENDOR_DATA, data_len, data)))
+		goto fail;
 
 	ret = send_and_recv_msgs(drv, msg, vendor_reply_handler, buf);
 	if (ret)
@@ -12429,7 +7607,7 @@
 			   ret);
 	return ret;
 
-nla_put_failure:
+fail:
 	nlmsg_free(msg);
 	return -ENOBUFS;
 }
@@ -12443,26 +7621,20 @@
 	struct nl_msg *msg;
 	int ret;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
 	wpa_hexdump(MSG_DEBUG, "nl80211: Setting QoS Map",
 		    qos_map_set, qos_map_set_len);
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_QOS_MAP);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set);
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_QOS_MAP)) ||
+	    nla_put(msg, NL80211_ATTR_QOS_MAP, qos_map_set_len, qos_map_set)) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (ret)
 		wpa_printf(MSG_DEBUG, "nl80211: Setting QoS Map failed");
 
 	return ret;
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
@@ -12475,33 +7647,28 @@
 	struct nlattr *wowlan_triggers;
 	int ret;
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
 	wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan");
 
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WOWLAN);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-
-	wowlan_triggers = nla_nest_start(msg, NL80211_ATTR_WOWLAN_TRIGGERS);
-	if (!wowlan_triggers)
-		goto nla_put_failure;
-
-	if (triggers->any)
-		NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_ANY);
-	if (triggers->disconnect)
-		NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_DISCONNECT);
-	if (triggers->magic_pkt)
-		NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT);
-	if (triggers->gtk_rekey_failure)
-		NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE);
-	if (triggers->eap_identity_req)
-		NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST);
-	if (triggers->four_way_handshake)
-		NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE);
-	if (triggers->rfkill_release)
-		NLA_PUT_FLAG(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE);
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_SET_WOWLAN)) ||
+	    !(wowlan_triggers = nla_nest_start(msg,
+					       NL80211_ATTR_WOWLAN_TRIGGERS)) ||
+	    (triggers->any &&
+	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_ANY)) ||
+	    (triggers->disconnect &&
+	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_DISCONNECT)) ||
+	    (triggers->magic_pkt &&
+	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_MAGIC_PKT)) ||
+	    (triggers->gtk_rekey_failure &&
+	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE)) ||
+	    (triggers->eap_identity_req &&
+	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST)) ||
+	    (triggers->four_way_handshake &&
+	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE)) ||
+	    (triggers->rfkill_release &&
+	     nla_put_flag(msg, NL80211_WOWLAN_TRIG_RFKILL_RELEASE))) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
 
 	nla_nest_end(msg, wowlan_triggers);
 
@@ -12510,10 +7677,6 @@
 		wpa_printf(MSG_DEBUG, "nl80211: Setting wowlan failed");
 
 	return ret;
-
-nla_put_failure:
-	nlmsg_free(msg);
-	return -ENOBUFS;
 }
 
 
@@ -12532,32 +7695,22 @@
 		return -1;
 	}
 
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	nl80211_cmd(drv, msg, 0, NL80211_CMD_VENDOR);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA);
-	NLA_PUT_U32(msg, NL80211_ATTR_VENDOR_SUBCMD,
-		    QCA_NL80211_VENDOR_SUBCMD_ROAMING);
-
-	params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA);
-	if (!params)
-		goto nla_put_failure;
-	NLA_PUT_U32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
-		    allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
-		    QCA_ROAMING_NOT_ALLOWED);
-	if (bssid)
-		NLA_PUT(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid);
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			QCA_NL80211_VENDOR_SUBCMD_ROAMING) ||
+	    !(params = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+	    nla_put_u32(msg, QCA_WLAN_VENDOR_ATTR_ROAMING_POLICY,
+			allowed ? QCA_ROAMING_ALLOWED_WITHIN_ESS :
+			QCA_ROAMING_NOT_ALLOWED) ||
+	    (bssid &&
+	     nla_put(msg, QCA_WLAN_VENDOR_ATTR_MAC_ADDR, ETH_ALEN, bssid))) {
+		nlmsg_free(msg);
+		return -1;
+	}
 	nla_nest_end(msg, params);
 
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
-
- nla_put_failure:
-	nlmsg_free(msg);
-	return -1;
 }
 
 
@@ -12601,6 +7754,502 @@
 }
 
 
+#ifdef CONFIG_MESH
+
+static int wpa_driver_nl80211_init_mesh(void *priv)
+{
+	if (wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_MESH_POINT)) {
+		wpa_printf(MSG_INFO,
+			   "nl80211: Failed to set interface into mesh mode");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int
+wpa_driver_nl80211_join_mesh(void *priv,
+			     struct wpa_driver_mesh_join_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	struct nlattr *container;
+	int ret = 0;
+
+	wpa_printf(MSG_DEBUG, "nl80211: mesh join (ifindex=%d)", drv->ifindex);
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_JOIN_MESH);
+	if (!msg)
+		goto fail;
+	if (params->freq) {
+		wpa_printf(MSG_DEBUG, "  * freq=%d", params->freq);
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, params->freq))
+			goto fail;
+	}
+
+	if (params->ht_mode) {
+		unsigned int ht_value;
+		char *ht_mode = "";
+
+		switch (params->ht_mode) {
+		default:
+		case CHAN_NO_HT:
+			ht_value = NL80211_CHAN_NO_HT;
+			ht_mode = "NOHT";
+			break;
+		case CHAN_HT20:
+			ht_value = NL80211_CHAN_HT20;
+			ht_mode = "HT20";
+			break;
+		case CHAN_HT40PLUS:
+			ht_value = NL80211_CHAN_HT40PLUS;
+			ht_mode = "HT40+";
+			break;
+		case CHAN_HT40MINUS:
+			ht_value = NL80211_CHAN_HT40MINUS;
+			ht_mode = "HT40-";
+			break;
+		}
+		wpa_printf(MSG_DEBUG, "  * ht_mode=%s", ht_mode);
+		if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, ht_value))
+			goto fail;
+	}
+
+	if (params->basic_rates) {
+		u8 rates[NL80211_MAX_SUPP_RATES];
+		u8 rates_len = 0;
+		int i;
+
+		for (i = 0; i < NL80211_MAX_SUPP_RATES; i++) {
+			if (params->basic_rates[i] < 0)
+				break;
+			rates[rates_len++] = params->basic_rates[i] / 5;
+		}
+
+		if (nla_put(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len,
+			    rates))
+			goto fail;
+	}
+
+	if (params->meshid) {
+		wpa_hexdump_ascii(MSG_DEBUG, "  * SSID",
+				  params->meshid, params->meshid_len);
+		if (nla_put(msg, NL80211_ATTR_MESH_ID, params->meshid_len,
+			    params->meshid))
+			goto fail;
+	}
+
+	if (params->beacon_int > 0) {
+		wpa_printf(MSG_DEBUG, "  * beacon_int=%d", params->beacon_int);
+		if (nla_put_u32(msg, NL80211_ATTR_BEACON_INTERVAL,
+				params->beacon_int))
+			goto fail;
+	}
+
+	wpa_printf(MSG_DEBUG, "  * flags=%08X", params->flags);
+
+	container = nla_nest_start(msg, NL80211_ATTR_MESH_SETUP);
+	if (!container)
+		goto fail;
+
+	if (params->ies) {
+		wpa_hexdump(MSG_DEBUG, "  * IEs", params->ies, params->ie_len);
+		if (nla_put(msg, NL80211_MESH_SETUP_IE, params->ie_len,
+			    params->ies))
+			goto fail;
+	}
+	/* WPA_DRIVER_MESH_FLAG_OPEN_AUTH is treated as default by nl80211 */
+	if (params->flags & WPA_DRIVER_MESH_FLAG_SAE_AUTH) {
+		if (nla_put_u8(msg, NL80211_MESH_SETUP_AUTH_PROTOCOL, 0x1) ||
+		    nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AUTH))
+			goto fail;
+	}
+	if ((params->flags & WPA_DRIVER_MESH_FLAG_AMPE) &&
+	    nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_AMPE))
+		goto fail;
+	if ((params->flags & WPA_DRIVER_MESH_FLAG_USER_MPM) &&
+	    nla_put_flag(msg, NL80211_MESH_SETUP_USERSPACE_MPM))
+		goto fail;
+	nla_nest_end(msg, container);
+
+	container = nla_nest_start(msg, NL80211_ATTR_MESH_CONFIG);
+	if (!container)
+		goto fail;
+
+	if (!(params->conf.flags & WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS) &&
+	    nla_put_u32(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, 0))
+		goto fail;
+	if ((params->conf.flags & WPA_DRIVER_MESH_FLAG_DRIVER_MPM) &&
+	    nla_put_u16(msg, NL80211_MESHCONF_MAX_PEER_LINKS,
+			params->max_peer_links))
+		goto fail;
+	nla_nest_end(msg, container);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: mesh join failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+		goto fail;
+	}
+	ret = 0;
+	bss->freq = params->freq;
+	wpa_printf(MSG_DEBUG, "nl80211: mesh join request send successfully");
+
+fail:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+static int wpa_driver_nl80211_leave_mesh(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "nl80211: mesh leave (ifindex=%d)", drv->ifindex);
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_LEAVE_MESH);
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: mesh leave failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: mesh leave request send successfully");
+	}
+
+	if (wpa_driver_nl80211_set_mode(drv->first_bss,
+					NL80211_IFTYPE_STATION)) {
+		wpa_printf(MSG_INFO,
+			   "nl80211: Failed to set interface into station mode");
+	}
+	return ret;
+}
+
+#endif /* CONFIG_MESH */
+
+
+static int wpa_driver_br_add_ip_neigh(void *priv, u8 version,
+				      const u8 *ipaddr, int prefixlen,
+				      const u8 *addr)
+{
+#ifdef CONFIG_LIBNL3_ROUTE
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct rtnl_neigh *rn;
+	struct nl_addr *nl_ipaddr = NULL;
+	struct nl_addr *nl_lladdr = NULL;
+	int family, addrsize;
+	int res;
+
+	if (!ipaddr || prefixlen == 0 || !addr)
+		return -EINVAL;
+
+	if (bss->br_ifindex == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: bridge must be set before adding an ip neigh to it");
+		return -1;
+	}
+
+	if (!drv->rtnl_sk) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
+		return -1;
+	}
+
+	if (version == 4) {
+		family = AF_INET;
+		addrsize = 4;
+	} else if (version == 6) {
+		family = AF_INET6;
+		addrsize = 16;
+	} else {
+		return -EINVAL;
+	}
+
+	rn = rtnl_neigh_alloc();
+	if (rn == NULL)
+		return -ENOMEM;
+
+	/* set the destination ip address for neigh */
+	nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
+	if (nl_ipaddr == NULL) {
+		wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
+		res = -ENOMEM;
+		goto errout;
+	}
+	nl_addr_set_prefixlen(nl_ipaddr, prefixlen);
+	res = rtnl_neigh_set_dst(rn, nl_ipaddr);
+	if (res) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: neigh set destination addr failed");
+		goto errout;
+	}
+
+	/* set the corresponding lladdr for neigh */
+	nl_lladdr = nl_addr_build(AF_BRIDGE, (u8 *) addr, ETH_ALEN);
+	if (nl_lladdr == NULL) {
+		wpa_printf(MSG_DEBUG, "nl80211: neigh set lladdr failed");
+		res = -ENOMEM;
+		goto errout;
+	}
+	rtnl_neigh_set_lladdr(rn, nl_lladdr);
+
+	rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
+	rtnl_neigh_set_state(rn, NUD_PERMANENT);
+
+	res = rtnl_neigh_add(drv->rtnl_sk, rn, NLM_F_CREATE);
+	if (res) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Adding bridge ip neigh failed: %s",
+			   strerror(errno));
+	}
+errout:
+	if (nl_lladdr)
+		nl_addr_put(nl_lladdr);
+	if (nl_ipaddr)
+		nl_addr_put(nl_ipaddr);
+	if (rn)
+		rtnl_neigh_put(rn);
+	return res;
+#else /* CONFIG_LIBNL3_ROUTE */
+	return -1;
+#endif /* CONFIG_LIBNL3_ROUTE */
+}
+
+
+static int wpa_driver_br_delete_ip_neigh(void *priv, u8 version,
+					 const u8 *ipaddr)
+{
+#ifdef CONFIG_LIBNL3_ROUTE
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct rtnl_neigh *rn;
+	struct nl_addr *nl_ipaddr;
+	int family, addrsize;
+	int res;
+
+	if (!ipaddr)
+		return -EINVAL;
+
+	if (version == 4) {
+		family = AF_INET;
+		addrsize = 4;
+	} else if (version == 6) {
+		family = AF_INET6;
+		addrsize = 16;
+	} else {
+		return -EINVAL;
+	}
+
+	if (bss->br_ifindex == 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: bridge must be set to delete an ip neigh");
+		return -1;
+	}
+
+	if (!drv->rtnl_sk) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: nl_sock for NETLINK_ROUTE is not initialized");
+		return -1;
+	}
+
+	rn = rtnl_neigh_alloc();
+	if (rn == NULL)
+		return -ENOMEM;
+
+	/* set the destination ip address for neigh */
+	nl_ipaddr = nl_addr_build(family, (void *) ipaddr, addrsize);
+	if (nl_ipaddr == NULL) {
+		wpa_printf(MSG_DEBUG, "nl80211: nl_ipaddr build failed");
+		res = -ENOMEM;
+		goto errout;
+	}
+	res = rtnl_neigh_set_dst(rn, nl_ipaddr);
+	if (res) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: neigh set destination addr failed");
+		goto errout;
+	}
+
+	rtnl_neigh_set_ifindex(rn, bss->br_ifindex);
+
+	res = rtnl_neigh_delete(drv->rtnl_sk, rn, 0);
+	if (res) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Deleting bridge ip neigh failed: %s",
+			   strerror(errno));
+	}
+errout:
+	if (nl_ipaddr)
+		nl_addr_put(nl_ipaddr);
+	if (rn)
+		rtnl_neigh_put(rn);
+	return res;
+#else /* CONFIG_LIBNL3_ROUTE */
+	return -1;
+#endif /* CONFIG_LIBNL3_ROUTE */
+}
+
+
+static int linux_write_system_file(const char *path, unsigned int val)
+{
+	char buf[50];
+	int fd, len;
+
+	len = os_snprintf(buf, sizeof(buf), "%u\n", val);
+	if (os_snprintf_error(sizeof(buf), len))
+		return -1;
+
+	fd = open(path, O_WRONLY);
+	if (fd < 0)
+		return -1;
+
+	if (write(fd, buf, len) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Failed to write Linux system file: %s with the value of %d",
+			   path, val);
+		close(fd);
+		return -1;
+	}
+	close(fd);
+
+	return 0;
+}
+
+
+static const char * drv_br_port_attr_str(enum drv_br_port_attr attr)
+{
+	switch (attr) {
+	case DRV_BR_PORT_ATTR_PROXYARP:
+		return "proxyarp";
+	case DRV_BR_PORT_ATTR_HAIRPIN_MODE:
+		return "hairpin_mode";
+	}
+
+	return NULL;
+}
+
+
+static int wpa_driver_br_port_set_attr(void *priv, enum drv_br_port_attr attr,
+				       unsigned int val)
+{
+	struct i802_bss *bss = priv;
+	char path[128];
+	const char *attr_txt;
+
+	attr_txt = drv_br_port_attr_str(attr);
+	if (attr_txt == NULL)
+		return -EINVAL;
+
+	os_snprintf(path, sizeof(path), "/sys/class/net/%s/brport/%s",
+		    bss->ifname, attr_txt);
+
+	if (linux_write_system_file(path, val))
+		return -1;
+
+	return 0;
+}
+
+
+static const char * drv_br_net_param_str(enum drv_br_net_param param)
+{
+	switch (param) {
+	case DRV_BR_NET_PARAM_GARP_ACCEPT:
+		return "arp_accept";
+	}
+
+	return NULL;
+}
+
+
+static int wpa_driver_br_set_net_param(void *priv, enum drv_br_net_param param,
+				       unsigned int val)
+{
+	struct i802_bss *bss = priv;
+	char path[128];
+	const char *param_txt;
+	int ip_version = 4;
+
+	param_txt = drv_br_net_param_str(param);
+	if (param_txt == NULL)
+		return -EINVAL;
+
+	switch (param) {
+		case DRV_BR_NET_PARAM_GARP_ACCEPT:
+			ip_version = 4;
+			break;
+		default:
+			return -EINVAL;
+	}
+
+	os_snprintf(path, sizeof(path), "/proc/sys/net/ipv%d/conf/%s/%s",
+		    ip_version, bss->brname, param_txt);
+
+	if (linux_write_system_file(path, val))
+		return -1;
+
+	return 0;
+}
+
+
+static int hw_mode_to_qca_acs(enum hostapd_hw_mode hw_mode)
+{
+	switch (hw_mode) {
+	case HOSTAPD_MODE_IEEE80211B:
+		return QCA_ACS_MODE_IEEE80211B;
+	case HOSTAPD_MODE_IEEE80211G:
+		return QCA_ACS_MODE_IEEE80211G;
+	case HOSTAPD_MODE_IEEE80211A:
+		return QCA_ACS_MODE_IEEE80211A;
+	case HOSTAPD_MODE_IEEE80211AD:
+		return QCA_ACS_MODE_IEEE80211AD;
+	default:
+		return -1;
+	}
+}
+
+
+static int wpa_driver_do_acs(void *priv, struct drv_acs_params *params)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	struct nlattr *data;
+	int ret;
+	int mode;
+
+	mode = hw_mode_to_qca_acs(params->hw_mode);
+	if (mode < 0)
+		return -1;
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			QCA_NL80211_VENDOR_SUBCMD_DO_ACS) ||
+	    !(data = nla_nest_start(msg, NL80211_ATTR_VENDOR_DATA)) ||
+	    nla_put_u8(msg, QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE, mode) ||
+	    (params->ht_enabled &&
+	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED)) ||
+	    (params->ht40_enabled &&
+	     nla_put_flag(msg, QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED))) {
+		nlmsg_free(msg);
+		return -ENOBUFS;
+	}
+	nla_nest_end(msg, data);
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Failed to invoke driver ACS function: %s",
+			   strerror(errno));
+	}
+	return ret;
+}
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -12628,7 +8277,7 @@
 	.if_add = wpa_driver_nl80211_if_add,
 	.if_remove = driver_nl80211_if_remove,
 	.send_mlme = driver_nl80211_send_mlme,
-	.get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
+	.get_hw_feature_data = nl80211_get_hw_feature_data,
 	.sta_add = wpa_driver_nl80211_sta_add,
 	.sta_remove = driver_nl80211_sta_remove,
 	.hapd_send_eapol = wpa_driver_nl80211_hapd_send_eapol,
@@ -12657,7 +8306,6 @@
 	.deinit_ap = wpa_driver_nl80211_deinit_ap,
 	.deinit_p2p_cli = wpa_driver_nl80211_deinit_p2p_cli,
 	.resume = wpa_driver_nl80211_resume,
-	.send_ft_action = nl80211_send_ft_action,
 	.signal_monitor = nl80211_signal_monitor,
 	.signal_poll = nl80211_signal_poll,
 	.send_frame = nl80211_send_frame,
@@ -12675,6 +8323,8 @@
 #ifdef CONFIG_TDLS
 	.send_tdls_mgmt = nl80211_send_tdls_mgmt,
 	.tdls_oper = nl80211_tdls_oper,
+	.tdls_enable_channel_switch = nl80211_tdls_enable_channel_switch,
+	.tdls_disable_channel_switch = nl80211_tdls_disable_channel_switch,
 #endif /* CONFIG_TDLS */
 	.update_ft_ies = wpa_driver_nl80211_update_ft_ies,
 	.get_mac_addr = wpa_driver_nl80211_get_macaddr,
@@ -12694,4 +8344,16 @@
 	.set_wowlan = nl80211_set_wowlan,
 	.roaming = nl80211_roaming,
 	.set_mac_addr = nl80211_set_mac_addr,
+#ifdef CONFIG_MESH
+	.init_mesh = wpa_driver_nl80211_init_mesh,
+	.join_mesh = wpa_driver_nl80211_join_mesh,
+	.leave_mesh = wpa_driver_nl80211_leave_mesh,
+#endif /* CONFIG_MESH */
+	.br_add_ip_neigh = wpa_driver_br_add_ip_neigh,
+	.br_delete_ip_neigh = wpa_driver_br_delete_ip_neigh,
+	.br_port_set_attr = wpa_driver_br_port_set_attr,
+	.br_set_net_param = wpa_driver_br_set_net_param,
+	.add_tx_ts = nl80211_add_ts,
+	.del_tx_ts = nl80211_del_ts,
+	.do_acs = wpa_driver_do_acs,
 };
diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h
new file mode 100644
index 0000000..6892b31
--- /dev/null
+++ b/src/drivers/driver_nl80211.h
@@ -0,0 +1,271 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - definitions
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_NL80211_H
+#define DRIVER_NL80211_H
+
+#include "nl80211_copy.h"
+#include "utils/list.h"
+#include "driver.h"
+
+#ifdef CONFIG_LIBNL20
+/* libnl 2.0 compatibility code */
+#define nl_handle nl_sock
+#define nl80211_handle_alloc nl_socket_alloc_cb
+#define nl80211_handle_destroy nl_socket_free
+#endif /* CONFIG_LIBNL20 */
+
+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;
+	int nl80211_id;
+	int ioctl_sock; /* socket for ioctl() use */
+
+	struct nl_handle *nl_event;
+};
+
+struct nl80211_wiphy_data {
+	struct dl_list list;
+	struct dl_list bsss;
+	struct dl_list drvs;
+
+	struct nl_handle *nl_beacons;
+	struct nl_cb *nl_cb;
+
+	int wiphy_idx;
+};
+
+struct i802_bss {
+	struct wpa_driver_nl80211_data *drv;
+	struct i802_bss *next;
+	int ifindex;
+	int br_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;
+	unsigned int added_if:1;
+	unsigned int static_ap:1;
+
+	u8 addr[ETH_ALEN];
+
+	int freq;
+	int bandwidth;
+	int if_dynamic;
+
+	void *ctx;
+	struct nl_handle *nl_preq, *nl_mgmt;
+	struct nl_cb *nl_cb;
+
+	struct nl80211_wiphy_data *wiphy_data;
+	struct dl_list wiphy_list;
+};
+
+struct wpa_driver_nl80211_data {
+	struct nl80211_global *global;
+	struct dl_list list;
+	struct dl_list wiphy_list;
+	char phyname[32];
+	u8 perm_addr[ETH_ALEN];
+	void *ctx;
+	int ifindex;
+	int if_removed;
+	int if_disabled;
+	int ignore_if_down_event;
+	struct rfkill_data *rfkill;
+	struct wpa_driver_capa capa;
+	u8 *extended_capa, *extended_capa_mask;
+	unsigned int extended_capa_len;
+	int has_capability;
+
+	int operstate;
+
+	int scan_complete_events;
+	enum scan_states {
+		NO_SCAN, SCAN_REQUESTED, SCAN_STARTED, SCAN_COMPLETED,
+		SCAN_ABORTED, SCHED_SCAN_STARTED, SCHED_SCAN_STOPPED,
+		SCHED_SCAN_RESULTS
+	} scan_state;
+
+	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;
+	enum nl80211_iftype nlmode;
+	enum nl80211_iftype ap_scan_as_station;
+	unsigned int assoc_freq;
+
+	int monitor_sock;
+	int monitor_ifidx;
+	int monitor_refcount;
+
+	unsigned int disabled_11b_rates:1;
+	unsigned int pending_remain_on_chan:1;
+	unsigned int in_interface_list:1;
+	unsigned int device_ap_sme:1;
+	unsigned int poll_command_supported:1;
+	unsigned int data_tx_status:1;
+	unsigned int scan_for_auth:1;
+	unsigned int retry_auth:1;
+	unsigned int use_monitor:1;
+	unsigned int ignore_next_local_disconnect:1;
+	unsigned int ignore_next_local_deauth:1;
+	unsigned int hostapd:1;
+	unsigned int start_mode_ap:1;
+	unsigned int start_iface_up:1;
+	unsigned int test_use_roc_tx:1;
+	unsigned int ignore_deauth_event:1;
+	unsigned int roaming_vendor_cmd_avail:1;
+	unsigned int dfs_vendor_cmd_avail:1;
+	unsigned int have_low_prio_scan:1;
+	unsigned int force_connect_cmd:1;
+	unsigned int addr_changed:1;
+	unsigned int get_features_vendor_cmd_avail:1;
+
+	u64 remain_on_chan_cookie;
+	u64 send_action_cookie;
+
+	unsigned int last_mgmt_freq;
+
+	struct wpa_driver_scan_filter *filter_ssids;
+	size_t num_filter_ssids;
+
+	struct i802_bss *first_bss;
+
+	int eapol_tx_sock;
+
+	int eapol_sock; /* socket for EAPOL frames */
+
+	struct nl_handle *rtnl_sk; /* nl_sock for NETLINK_ROUTE */
+
+	int default_if_indices[16];
+	int *if_indices;
+	int num_if_indices;
+
+	/* From failed authentication command */
+	int auth_freq;
+	u8 auth_bssid_[ETH_ALEN];
+	u8 auth_ssid[32];
+	size_t auth_ssid_len;
+	int auth_alg;
+	u8 *auth_ie;
+	size_t auth_ie_len;
+	u8 auth_wep_key[4][16];
+	size_t auth_wep_key_len[4];
+	int auth_wep_tx_keyidx;
+	int auth_local_state_change;
+	int auth_p2p;
+};
+
+struct nl_msg;
+
+void * nl80211_cmd(struct wpa_driver_nl80211_data *drv,
+		   struct nl_msg *msg, int flags, uint8_t cmd);
+struct nl_msg * nl80211_cmd_msg(struct i802_bss *bss, int flags, uint8_t cmd);
+struct nl_msg * nl80211_drv_msg(struct wpa_driver_nl80211_data *drv, int flags,
+				uint8_t cmd);
+struct nl_msg * nl80211_bss_msg(struct i802_bss *bss, int flags, uint8_t cmd);
+int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv, struct nl_msg *msg,
+		       int (*valid_handler)(struct nl_msg *, void *),
+		       void *valid_data);
+int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+			 const char *ifname, enum nl80211_iftype iftype,
+			 const u8 *addr, int wds,
+			 int (*handler)(struct nl_msg *, void *),
+			 void *arg, int use_existing);
+void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv, int ifidx);
+unsigned int nl80211_get_assoc_freq(struct wpa_driver_nl80211_data *drv);
+enum chan_width convert2width(int width);
+void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv);
+struct i802_bss * get_bss_ifindex(struct wpa_driver_nl80211_data *drv,
+				  int ifindex);
+int is_ap_interface(enum nl80211_iftype nlmode);
+int is_sta_interface(enum nl80211_iftype nlmode);
+int wpa_driver_nl80211_authenticate_retry(struct wpa_driver_nl80211_data *drv);
+int nl80211_get_link_signal(struct wpa_driver_nl80211_data *drv,
+			    struct wpa_signal_info *sig);
+int nl80211_get_link_noise(struct wpa_driver_nl80211_data *drv,
+			   struct wpa_signal_info *sig_change);
+int nl80211_get_wiphy_index(struct i802_bss *bss);
+int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+				enum nl80211_iftype nlmode);
+int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+			    const u8 *addr, int cmd, u16 reason_code,
+			    int local_state_change);
+
+int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv);
+void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv);
+int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
+			 const void *data, size_t len,
+			 int encrypt, int noack);
+
+int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv);
+struct hostapd_hw_modes *
+nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags);
+
+int process_global_event(struct nl_msg *msg, void *arg);
+int process_bss_event(struct nl_msg *msg, void *arg);
+
+#ifdef ANDROID
+int android_nl_socket_set_nonblocking(struct nl_handle *handle);
+int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name);
+int android_pno_start(struct i802_bss *bss,
+		      struct wpa_driver_scan_params *params);
+int android_pno_stop(struct i802_bss *bss);
+extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
+					 size_t buf_len);
+
+#ifdef ANDROID_P2P
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration);
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow);
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+				 const struct wpabuf *proberesp,
+				 const struct wpabuf *assocresp);
+#endif /* ANDROID_P2P */
+#endif /* ANDROID */
+
+
+/* driver_nl80211_scan.c */
+
+struct nl80211_bss_info_arg {
+	struct wpa_driver_nl80211_data *drv;
+	struct wpa_scan_results *res;
+	unsigned int assoc_freq;
+	unsigned int ibss_freq;
+	u8 assoc_bssid[ETH_ALEN];
+};
+
+int bss_info_handler(struct nl_msg *msg, void *arg);
+void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+int wpa_driver_nl80211_scan(struct i802_bss *bss,
+			    struct wpa_driver_scan_params *params);
+int wpa_driver_nl80211_sched_scan(void *priv,
+				  struct wpa_driver_scan_params *params,
+				  u32 interval);
+int wpa_driver_nl80211_stop_sched_scan(void *priv);
+struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv);
+void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv);
+
+#endif /* DRIVER_NL80211_H */
diff --git a/src/drivers/driver_nl80211_android.c b/src/drivers/driver_nl80211_android.c
new file mode 100644
index 0000000..3cc9a65
--- /dev/null
+++ b/src/drivers/driver_nl80211_android.c
@@ -0,0 +1,220 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Android specific
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <fcntl.h>
+
+#include "utils/common.h"
+#include "driver_nl80211.h"
+#include "android_drv.h"
+
+
+typedef struct android_wifi_priv_cmd {
+	char *buf;
+	int used_len;
+	int total_len;
+} android_wifi_priv_cmd;
+
+static int drv_errors = 0;
+
+static void wpa_driver_send_hang_msg(struct wpa_driver_nl80211_data *drv)
+{
+	drv_errors++;
+	if (drv_errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+		drv_errors = 0;
+		wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE "HANGED");
+	}
+}
+
+
+static int android_priv_cmd(struct i802_bss *bss, const char *cmd)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct ifreq ifr;
+	android_wifi_priv_cmd priv_cmd;
+	char buf[MAX_DRV_CMD_SIZE];
+	int ret;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_memset(&priv_cmd, 0, sizeof(priv_cmd));
+	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+	os_memset(buf, 0, sizeof(buf));
+	os_strlcpy(buf, cmd, sizeof(buf));
+
+	priv_cmd.buf = buf;
+	priv_cmd.used_len = sizeof(buf);
+	priv_cmd.total_len = sizeof(buf);
+	ifr.ifr_data = &priv_cmd;
+
+	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "%s: failed to issue private commands",
+			   __func__);
+		wpa_driver_send_hang_msg(drv);
+		return ret;
+	}
+
+	drv_errors = 0;
+	return 0;
+}
+
+
+int android_pno_start(struct i802_bss *bss,
+		      struct wpa_driver_scan_params *params)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct ifreq ifr;
+	android_wifi_priv_cmd priv_cmd;
+	int ret = 0, i = 0, bp;
+	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+	bp = WEXT_PNOSETUP_HEADER_SIZE;
+	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+	buf[bp++] = WEXT_PNO_TLV_PREFIX;
+	buf[bp++] = WEXT_PNO_TLV_VERSION;
+	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+	buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+		/* Check that there is enough space needed for 1 more SSID, the
+		 * other sections and null termination */
+		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN +
+		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+			break;
+		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+				  params->ssids[i].ssid,
+				  params->ssids[i].ssid_len);
+		buf[bp++] = WEXT_PNO_SSID_SECTION;
+		buf[bp++] = params->ssids[i].ssid_len;
+		os_memcpy(&buf[bp], params->ssids[i].ssid,
+			  params->ssids[i].ssid_len);
+		bp += params->ssids[i].ssid_len;
+		i++;
+	}
+
+	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+		    WEXT_PNO_SCAN_INTERVAL);
+	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_REPEAT);
+	bp += WEXT_PNO_REPEAT_LENGTH;
+
+	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_MAX_REPEAT);
+	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+	memset(&ifr, 0, sizeof(ifr));
+	memset(&priv_cmd, 0, sizeof(priv_cmd));
+	os_strlcpy(ifr.ifr_name, bss->ifname, IFNAMSIZ);
+
+	priv_cmd.buf = buf;
+	priv_cmd.used_len = bp;
+	priv_cmd.total_len = bp;
+	ifr.ifr_data = &priv_cmd;
+
+	ret = ioctl(drv->global->ioctl_sock, SIOCDEVPRIVATE + 1, &ifr);
+
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+			   ret);
+		wpa_driver_send_hang_msg(drv);
+		return ret;
+	}
+
+	drv_errors = 0;
+
+	return android_priv_cmd(bss, "PNOFORCE 1");
+}
+
+
+int android_pno_stop(struct i802_bss *bss)
+{
+	return android_priv_cmd(bss, "PNOFORCE 0");
+}
+
+
+#ifdef ANDROID_P2P
+#ifdef ANDROID_P2P_STUB
+
+int wpa_driver_set_p2p_noa(void *priv, u8 count, int start, int duration)
+{
+	return 0;
+}
+
+
+int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len)
+{
+	return 0;
+}
+
+
+int wpa_driver_set_p2p_ps(void *priv, int legacy_ps, int opp_ps, int ctwindow)
+{
+	return -1;
+}
+
+
+int wpa_driver_set_ap_wps_p2p_ie(void *priv, const struct wpabuf *beacon,
+				 const struct wpabuf *proberesp,
+				 const struct wpabuf *assocresp)
+{
+	return 0;
+}
+
+#endif /* ANDROID_P2P_STUB */
+#endif /* ANDROID_P2P */
+
+
+int android_nl_socket_set_nonblocking(struct nl_handle *handle)
+{
+	return fcntl(nl_socket_get_fd(handle), F_SETFL, O_NONBLOCK);
+}
+
+
+int android_genl_ctrl_resolve(struct nl_handle *handle, const char *name)
+{
+	/*
+	 * Android ICS has very minimal genl_ctrl_resolve() implementation, so
+	 * need to work around that.
+	 */
+	struct nl_cache *cache = NULL;
+	struct genl_family *nl80211 = NULL;
+	int id = -1;
+
+	if (genl_ctrl_alloc_cache(handle, &cache) < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+			   "netlink cache");
+		goto fail;
+	}
+
+	nl80211 = genl_ctrl_search_by_name(cache, name);
+	if (nl80211 == NULL)
+		goto fail;
+
+	id = genl_family_get_id(nl80211);
+
+fail:
+	if (nl80211)
+		genl_family_put(nl80211);
+	if (cache)
+		nl_cache_free(cache);
+
+	return id;
+}
diff --git a/src/drivers/driver_nl80211_capa.c b/src/drivers/driver_nl80211_capa.c
new file mode 100644
index 0000000..6661a89
--- /dev/null
+++ b/src/drivers/driver_nl80211_capa.c
@@ -0,0 +1,1519 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Capabilities
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/qca-vendor.h"
+#include "common/qca-vendor-attr.h"
+#include "driver_nl80211.h"
+
+
+static int protocol_feature_handler(struct nl_msg *msg, void *arg)
+{
+	u32 *feat = arg;
+	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb_msg[NL80211_ATTR_PROTOCOL_FEATURES])
+		*feat = nla_get_u32(tb_msg[NL80211_ATTR_PROTOCOL_FEATURES]);
+
+	return NL_SKIP;
+}
+
+
+static u32 get_nl80211_protocol_features(struct wpa_driver_nl80211_data *drv)
+{
+	u32 feat = 0;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return 0;
+
+	if (!nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_PROTOCOL_FEATURES)) {
+		nlmsg_free(msg);
+		return 0;
+	}
+
+	if (send_and_recv_msgs(drv, msg, protocol_feature_handler, &feat) == 0)
+		return feat;
+
+	return 0;
+}
+
+
+struct wiphy_info_data {
+	struct wpa_driver_nl80211_data *drv;
+	struct wpa_driver_capa *capa;
+
+	unsigned int num_multichan_concurrent;
+
+	unsigned int error:1;
+	unsigned int device_ap_sme:1;
+	unsigned int poll_command_supported:1;
+	unsigned int data_tx_status:1;
+	unsigned int monitor_supported:1;
+	unsigned int auth_supported:1;
+	unsigned int connect_supported:1;
+	unsigned int p2p_go_supported:1;
+	unsigned int p2p_client_supported:1;
+	unsigned int p2p_concurrent:1;
+	unsigned int channel_switch_supported:1;
+	unsigned int set_qos_map_supported:1;
+	unsigned int have_low_prio_scan:1;
+	unsigned int wmm_ac_supported:1;
+	unsigned int mac_addr_rand_scan_supported:1;
+	unsigned int mac_addr_rand_sched_scan_supported:1;
+};
+
+
+static unsigned int probe_resp_offload_support(int supp_protocols)
+{
+	unsigned int prot = 0;
+
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS;
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2;
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P;
+	if (supp_protocols & NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U)
+		prot |= WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING;
+
+	return prot;
+}
+
+
+static void wiphy_info_supported_iftypes(struct wiphy_info_data *info,
+					 struct nlattr *tb)
+{
+	struct nlattr *nl_mode;
+	int i;
+
+	if (tb == NULL)
+		return;
+
+	nla_for_each_nested(nl_mode, tb, i) {
+		switch (nla_type(nl_mode)) {
+		case NL80211_IFTYPE_AP:
+			info->capa->flags |= WPA_DRIVER_FLAGS_AP;
+			break;
+		case NL80211_IFTYPE_MESH_POINT:
+			info->capa->flags |= WPA_DRIVER_FLAGS_MESH;
+			break;
+		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;
+		case NL80211_IFTYPE_P2P_CLIENT:
+			info->p2p_client_supported = 1;
+			break;
+		case NL80211_IFTYPE_MONITOR:
+			info->monitor_supported = 1;
+			break;
+		}
+	}
+}
+
+
+static int wiphy_info_iface_comb_process(struct wiphy_info_data *info,
+					 struct nlattr *nl_combi)
+{
+	struct nlattr *tb_comb[NUM_NL80211_IFACE_COMB];
+	struct nlattr *tb_limit[NUM_NL80211_IFACE_LIMIT];
+	struct nlattr *nl_limit, *nl_mode;
+	int err, rem_limit, rem_mode;
+	int combination_has_p2p = 0, combination_has_mgd = 0;
+	static struct nla_policy
+	iface_combination_policy[NUM_NL80211_IFACE_COMB] = {
+		[NL80211_IFACE_COMB_LIMITS] = { .type = NLA_NESTED },
+		[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 },
+		[NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
+	};
+
+	err = nla_parse_nested(tb_comb, MAX_NL80211_IFACE_COMB,
+			       nl_combi, iface_combination_policy);
+	if (err || !tb_comb[NL80211_IFACE_COMB_LIMITS] ||
+	    !tb_comb[NL80211_IFACE_COMB_MAXNUM] ||
+	    !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,
+				       nl_limit, iface_limit_policy);
+		if (err || !tb_limit[NL80211_IFACE_LIMIT_TYPES])
+			return 0; /* broken combination */
+
+		nla_for_each_nested(nl_mode,
+				    tb_limit[NL80211_IFACE_LIMIT_TYPES],
+				    rem_mode) {
+			int ift = nla_type(nl_mode);
+			if (ift == NL80211_IFTYPE_P2P_GO ||
+			    ift == NL80211_IFTYPE_P2P_CLIENT)
+				combination_has_p2p = 1;
+			if (ift == NL80211_IFTYPE_STATION)
+				combination_has_mgd = 1;
+		}
+		if (combination_has_p2p && combination_has_mgd)
+			break;
+	}
+
+	if (combination_has_p2p && combination_has_mgd) {
+		unsigned int num_channels =
+			nla_get_u32(tb_comb[NL80211_IFACE_COMB_NUM_CHANNELS]);
+
+		info->p2p_concurrent = 1;
+		if (info->num_multichan_concurrent < num_channels)
+			info->num_multichan_concurrent = num_channels;
+	}
+
+	return 0;
+}
+
+
+static void wiphy_info_iface_comb(struct wiphy_info_data *info,
+				  struct nlattr *tb)
+{
+	struct nlattr *nl_combi;
+	int rem_combi;
+
+	if (tb == NULL)
+		return;
+
+	nla_for_each_nested(nl_combi, tb, rem_combi) {
+		if (wiphy_info_iface_comb_process(info, nl_combi) > 0)
+			break;
+	}
+}
+
+
+static void wiphy_info_supp_cmds(struct wiphy_info_data *info,
+				 struct nlattr *tb)
+{
+	struct nlattr *nl_cmd;
+	int i;
+
+	if (tb == NULL)
+		return;
+
+	nla_for_each_nested(nl_cmd, tb, i) {
+		switch (nla_get_u32(nl_cmd)) {
+		case NL80211_CMD_AUTHENTICATE:
+			info->auth_supported = 1;
+			break;
+		case NL80211_CMD_CONNECT:
+			info->connect_supported = 1;
+			break;
+		case NL80211_CMD_START_SCHED_SCAN:
+			info->capa->sched_scan_supported = 1;
+			break;
+		case NL80211_CMD_PROBE_CLIENT:
+			info->poll_command_supported = 1;
+			break;
+		case NL80211_CMD_CHANNEL_SWITCH:
+			info->channel_switch_supported = 1;
+			break;
+		case NL80211_CMD_SET_QOS_MAP:
+			info->set_qos_map_supported = 1;
+			break;
+		}
+	}
+}
+
+
+static void wiphy_info_cipher_suites(struct wiphy_info_data *info,
+				     struct nlattr *tb)
+{
+	int i, num;
+	u32 *ciphers;
+
+	if (tb == NULL)
+		return;
+
+	num = nla_len(tb) / sizeof(u32);
+	ciphers = nla_data(tb);
+	for (i = 0; i < num; i++) {
+		u32 c = ciphers[i];
+
+		wpa_printf(MSG_DEBUG, "nl80211: Supported cipher %02x-%02x-%02x:%d",
+			   c >> 24, (c >> 16) & 0xff,
+			   (c >> 8) & 0xff, c & 0xff);
+		switch (c) {
+		case WLAN_CIPHER_SUITE_CCMP_256:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP_256;
+			break;
+		case WLAN_CIPHER_SUITE_GCMP_256:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP_256;
+			break;
+		case WLAN_CIPHER_SUITE_CCMP:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+			break;
+		case WLAN_CIPHER_SUITE_GCMP:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_GCMP;
+			break;
+		case WLAN_CIPHER_SUITE_TKIP:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+			break;
+		case WLAN_CIPHER_SUITE_WEP104:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP104;
+			break;
+		case WLAN_CIPHER_SUITE_WEP40:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_WEP40;
+			break;
+		case WLAN_CIPHER_SUITE_AES_CMAC:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP;
+			break;
+		case WLAN_CIPHER_SUITE_BIP_GMAC_128:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_128;
+			break;
+		case WLAN_CIPHER_SUITE_BIP_GMAC_256:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_GMAC_256;
+			break;
+		case WLAN_CIPHER_SUITE_BIP_CMAC_256:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_BIP_CMAC_256;
+			break;
+		case WLAN_CIPHER_SUITE_NO_GROUP_ADDR:
+			info->capa->enc |= WPA_DRIVER_CAPA_ENC_GTK_NOT_USED;
+			break;
+		}
+	}
+}
+
+
+static void wiphy_info_max_roc(struct wpa_driver_capa *capa,
+			       struct nlattr *tb)
+{
+	if (tb)
+		capa->max_remain_on_chan = nla_get_u32(tb);
+}
+
+
+static void wiphy_info_tdls(struct wpa_driver_capa *capa, struct nlattr *tdls,
+			    struct nlattr *ext_setup)
+{
+	if (tdls == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+	capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+	if (ext_setup) {
+		wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+		capa->flags |= WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+	}
+}
+
+
+static void wiphy_info_feature_flags(struct wiphy_info_data *info,
+				     struct nlattr *tb)
+{
+	u32 flags;
+	struct wpa_driver_capa *capa = info->capa;
+
+	if (tb == NULL)
+		return;
+
+	flags = nla_get_u32(tb);
+
+	if (flags & NL80211_FEATURE_SK_TX_STATUS)
+		info->data_tx_status = 1;
+
+	if (flags & NL80211_FEATURE_INACTIVITY_TIMER)
+		capa->flags |= WPA_DRIVER_FLAGS_INACTIVITY_TIMER;
+
+	if (flags & NL80211_FEATURE_SAE)
+		capa->flags |= WPA_DRIVER_FLAGS_SAE;
+
+	if (flags & NL80211_FEATURE_NEED_OBSS_SCAN)
+		capa->flags |= WPA_DRIVER_FLAGS_OBSS_SCAN;
+
+	if (flags & NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE)
+		capa->flags |= WPA_DRIVER_FLAGS_HT_2040_COEX;
+
+	if (flags & NL80211_FEATURE_TDLS_CHANNEL_SWITCH) {
+		wpa_printf(MSG_DEBUG, "nl80211: TDLS channel switch");
+		capa->flags |= WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH;
+	}
+
+	if (flags & NL80211_FEATURE_LOW_PRIORITY_SCAN)
+		info->have_low_prio_scan = 1;
+
+	if (flags & NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR)
+		info->mac_addr_rand_scan_supported = 1;
+
+	if (flags & NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR)
+		info->mac_addr_rand_sched_scan_supported = 1;
+
+	if (flags & NL80211_FEATURE_STATIC_SMPS)
+		capa->smps_modes |= WPA_DRIVER_SMPS_MODE_STATIC;
+
+	if (flags & NL80211_FEATURE_DYNAMIC_SMPS)
+		capa->smps_modes |= WPA_DRIVER_SMPS_MODE_DYNAMIC;
+
+	if (flags & NL80211_FEATURE_SUPPORTS_WMM_ADMISSION)
+		info->wmm_ac_supported = 1;
+
+	if (flags & NL80211_FEATURE_DS_PARAM_SET_IE_IN_PROBES)
+		capa->rrm_flags |= WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES;
+
+	if (flags & NL80211_FEATURE_WFA_TPC_IE_IN_PROBES)
+		capa->rrm_flags |= WPA_DRIVER_FLAGS_WFA_TPC_IE_IN_PROBES;
+
+	if (flags & NL80211_FEATURE_QUIET)
+		capa->rrm_flags |= WPA_DRIVER_FLAGS_QUIET;
+
+	if (flags & NL80211_FEATURE_TX_POWER_INSERTION)
+		capa->rrm_flags |= WPA_DRIVER_FLAGS_TX_POWER_INSERTION;
+}
+
+
+static void wiphy_info_probe_resp_offload(struct wpa_driver_capa *capa,
+					  struct nlattr *tb)
+{
+	u32 protocols;
+
+	if (tb == NULL)
+		return;
+
+	protocols = nla_get_u32(tb);
+	wpa_printf(MSG_DEBUG, "nl80211: Supports Probe Response offload in AP "
+		   "mode");
+	capa->flags |= WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD;
+	capa->probe_resp_offloads = probe_resp_offload_support(protocols);
+}
+
+
+static void wiphy_info_wowlan_triggers(struct wpa_driver_capa *capa,
+				       struct nlattr *tb)
+{
+	struct nlattr *triggers[MAX_NL80211_WOWLAN_TRIG + 1];
+
+	if (tb == NULL)
+		return;
+
+	if (nla_parse_nested(triggers, MAX_NL80211_WOWLAN_TRIG,
+			     tb, NULL))
+		return;
+
+	if (triggers[NL80211_WOWLAN_TRIG_ANY])
+		capa->wowlan_triggers.any = 1;
+	if (triggers[NL80211_WOWLAN_TRIG_DISCONNECT])
+		capa->wowlan_triggers.disconnect = 1;
+	if (triggers[NL80211_WOWLAN_TRIG_MAGIC_PKT])
+		capa->wowlan_triggers.magic_pkt = 1;
+	if (triggers[NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE])
+		capa->wowlan_triggers.gtk_rekey_failure = 1;
+	if (triggers[NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST])
+		capa->wowlan_triggers.eap_identity_req = 1;
+	if (triggers[NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE])
+		capa->wowlan_triggers.four_way_handshake = 1;
+	if (triggers[NL80211_WOWLAN_TRIG_RFKILL_RELEASE])
+		capa->wowlan_triggers.rfkill_release = 1;
+}
+
+
+static int wiphy_info_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct wiphy_info_data *info = arg;
+	struct wpa_driver_capa *capa = info->capa;
+	struct wpa_driver_nl80211_data *drv = info->drv;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_WIPHY_NAME])
+		os_strlcpy(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]);
+
+	if (tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS])
+		capa->max_sched_scan_ssids =
+			nla_get_u8(tb[NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS]);
+
+	if (tb[NL80211_ATTR_MAX_MATCH_SETS])
+		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]);
+	wiphy_info_cipher_suites(info, tb[NL80211_ATTR_CIPHER_SUITES]);
+
+	if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK]) {
+		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
+			   "off-channel TX");
+		capa->flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
+	}
+
+	if (tb[NL80211_ATTR_ROAM_SUPPORT]) {
+		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based roaming");
+		capa->flags |= WPA_DRIVER_FLAGS_BSS_SELECTION;
+	}
+
+	wiphy_info_max_roc(capa,
+			   tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
+
+	if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
+		capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
+
+	wiphy_info_tdls(capa, tb[NL80211_ATTR_TDLS_SUPPORT],
+			tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]);
+
+	if (tb[NL80211_ATTR_DEVICE_AP_SME])
+		info->device_ap_sme = 1;
+
+	wiphy_info_feature_flags(info, tb[NL80211_ATTR_FEATURE_FLAGS]);
+	wiphy_info_probe_resp_offload(capa,
+				      tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+
+	if (tb[NL80211_ATTR_EXT_CAPA] && tb[NL80211_ATTR_EXT_CAPA_MASK] &&
+	    drv->extended_capa == NULL) {
+		drv->extended_capa =
+			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+		if (drv->extended_capa) {
+			os_memcpy(drv->extended_capa,
+				  nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+			drv->extended_capa_len =
+				nla_len(tb[NL80211_ATTR_EXT_CAPA]);
+		}
+		drv->extended_capa_mask =
+			os_malloc(nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+		if (drv->extended_capa_mask) {
+			os_memcpy(drv->extended_capa_mask,
+				  nla_data(tb[NL80211_ATTR_EXT_CAPA]),
+				  nla_len(tb[NL80211_ATTR_EXT_CAPA]));
+		} else {
+			os_free(drv->extended_capa);
+			drv->extended_capa = NULL;
+			drv->extended_capa_len = 0;
+		}
+	}
+
+	if (tb[NL80211_ATTR_VENDOR_DATA]) {
+		struct nlattr *nl;
+		int rem;
+
+		nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_DATA], rem) {
+			struct nl80211_vendor_cmd_info *vinfo;
+			if (nla_len(nl) != sizeof(*vinfo)) {
+				wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
+				continue;
+			}
+			vinfo = nla_data(nl);
+			switch (vinfo->subcmd) {
+			case QCA_NL80211_VENDOR_SUBCMD_ROAMING:
+				drv->roaming_vendor_cmd_avail = 1;
+				break;
+			case QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY:
+				drv->dfs_vendor_cmd_avail = 1;
+				break;
+			case QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES:
+				drv->get_features_vendor_cmd_avail = 1;
+				break;
+			case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+				drv->capa.flags |= WPA_DRIVER_FLAGS_ACS_OFFLOAD;
+				break;
+			}
+
+			wpa_printf(MSG_DEBUG, "nl80211: Supported vendor command: vendor_id=0x%x subcmd=%u",
+				   vinfo->vendor_id, vinfo->subcmd);
+		}
+	}
+
+	if (tb[NL80211_ATTR_VENDOR_EVENTS]) {
+		struct nlattr *nl;
+		int rem;
+
+		nla_for_each_nested(nl, tb[NL80211_ATTR_VENDOR_EVENTS], rem) {
+			struct nl80211_vendor_cmd_info *vinfo;
+			if (nla_len(nl) != sizeof(*vinfo)) {
+				wpa_printf(MSG_DEBUG, "nl80211: Unexpected vendor data info");
+				continue;
+			}
+			vinfo = nla_data(nl);
+			wpa_printf(MSG_DEBUG, "nl80211: Supported vendor event: vendor_id=0x%x subcmd=%u",
+				   vinfo->vendor_id, vinfo->subcmd);
+		}
+	}
+
+	wiphy_info_wowlan_triggers(capa,
+				   tb[NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED]);
+
+	if (tb[NL80211_ATTR_MAX_AP_ASSOC_STA])
+		capa->max_stations =
+			nla_get_u32(tb[NL80211_ATTR_MAX_AP_ASSOC_STA]);
+
+	return NL_SKIP;
+}
+
+
+static int wpa_driver_nl80211_get_info(struct wpa_driver_nl80211_data *drv,
+				       struct wiphy_info_data *info)
+{
+	u32 feat;
+	struct nl_msg *msg;
+	int flags = 0;
+
+	os_memset(info, 0, sizeof(*info));
+	info->capa = &drv->capa;
+	info->drv = drv;
+
+	feat = get_nl80211_protocol_features(drv);
+	if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+		flags = NLM_F_DUMP;
+	msg = nl80211_cmd_msg(drv->first_bss, flags, NL80211_CMD_GET_WIPHY);
+	if (!msg || nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
+		nlmsg_free(msg);
+		return -1;
+	}
+
+	if (send_and_recv_msgs(drv, msg, wiphy_info_handler, info))
+		return -1;
+
+	if (info->auth_supported)
+		drv->capa.flags |= WPA_DRIVER_FLAGS_SME;
+	else if (!info->connect_supported) {
+		wpa_printf(MSG_INFO, "nl80211: Driver does not support "
+			   "authentication/association or connect commands");
+		info->error = 1;
+	}
+
+	if (info->p2p_go_supported && info->p2p_client_supported)
+		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+	if (info->p2p_concurrent) {
+		wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+			   "interface (driver advertised support)");
+		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+	}
+	if (info->num_multichan_concurrent > 1) {
+		wpa_printf(MSG_DEBUG, "nl80211: Enable multi-channel "
+			   "concurrent (driver advertised support)");
+		drv->capa.num_multichan_concurrent =
+			info->num_multichan_concurrent;
+	}
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)
+		wpa_printf(MSG_DEBUG, "nl80211: use P2P_DEVICE support");
+
+	/* 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;
+
+	if (info->channel_switch_supported)
+		drv->capa.flags |= WPA_DRIVER_FLAGS_AP_CSA;
+	drv->capa.wmm_ac_supported = info->wmm_ac_supported;
+
+	drv->capa.mac_addr_rand_sched_scan_supported =
+		info->mac_addr_rand_sched_scan_supported;
+	drv->capa.mac_addr_rand_scan_supported =
+		info->mac_addr_rand_scan_supported;
+
+	return 0;
+}
+
+
+static int dfs_info_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	int *dfs_capability_ptr = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_VENDOR_DATA]) {
+		struct nlattr *nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+		struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+
+		nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+			  nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+		if (tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]) {
+			u32 val;
+			val = nla_get_u32(tb_vendor[QCA_WLAN_VENDOR_ATTR_DFS]);
+			wpa_printf(MSG_DEBUG, "nl80211: DFS offload capability: %u",
+				   val);
+			*dfs_capability_ptr = val;
+		}
+	}
+
+	return NL_SKIP;
+}
+
+
+static void qca_nl80211_check_dfs_capa(struct wpa_driver_nl80211_data *drv)
+{
+	struct nl_msg *msg;
+	int dfs_capability = 0;
+	int ret;
+
+	if (!drv->dfs_vendor_cmd_avail)
+		return;
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			QCA_NL80211_VENDOR_SUBCMD_DFS_CAPABILITY)) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	ret = send_and_recv_msgs(drv, msg, dfs_info_handler, &dfs_capability);
+	if (!ret && dfs_capability)
+		drv->capa.flags |= WPA_DRIVER_FLAGS_DFS_OFFLOAD;
+}
+
+
+struct features_info {
+	u8 *flags;
+	size_t flags_len;
+};
+
+
+static int features_info_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct features_info *info = arg;
+	struct nlattr *nl_vend, *attr;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	nl_vend = tb[NL80211_ATTR_VENDOR_DATA];
+	if (nl_vend) {
+		struct nlattr *tb_vendor[QCA_WLAN_VENDOR_ATTR_MAX + 1];
+
+		nla_parse(tb_vendor, QCA_WLAN_VENDOR_ATTR_MAX,
+			  nla_data(nl_vend), nla_len(nl_vend), NULL);
+
+		attr = tb_vendor[QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS];
+		if (attr) {
+			info->flags = nla_data(attr);
+			info->flags_len = nla_len(attr);
+		}
+	}
+
+	return NL_SKIP;
+}
+
+
+static int check_feature(enum qca_wlan_vendor_features feature,
+			 struct features_info *info)
+{
+	size_t idx = feature / 8;
+
+	return (idx < info->flags_len) &&
+		(info->flags[idx] & BIT(feature % 8));
+}
+
+
+static void qca_nl80211_get_features(struct wpa_driver_nl80211_data *drv)
+{
+	struct nl_msg *msg;
+	struct features_info info;
+	int ret;
+
+	if (!drv->get_features_vendor_cmd_avail)
+		return;
+
+	if (!(msg = nl80211_drv_msg(drv, 0, NL80211_CMD_VENDOR)) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_ID, OUI_QCA) ||
+	    nla_put_u32(msg, NL80211_ATTR_VENDOR_SUBCMD,
+			QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES)) {
+		nlmsg_free(msg);
+		return;
+	}
+
+	os_memset(&info, 0, sizeof(info));
+	ret = send_and_recv_msgs(drv, msg, features_info_handler, &info);
+	if (ret || !info.flags)
+		return;
+
+	if (check_feature(QCA_WLAN_VENDOR_FEATURE_KEY_MGMT_OFFLOAD, &info))
+		drv->capa.flags |= WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD;
+}
+
+
+int wpa_driver_nl80211_capa(struct wpa_driver_nl80211_data *drv)
+{
+	struct wiphy_info_data info;
+	if (wpa_driver_nl80211_get_info(drv, &info))
+		return -1;
+
+	if (info.error)
+		return -1;
+
+	drv->has_capability = 1;
+	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+	drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+		WPA_DRIVER_AUTH_SHARED |
+		WPA_DRIVER_AUTH_LEAP;
+
+	drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
+	drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
+	drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+
+	/*
+	 * As all cfg80211 drivers must support cases where the AP interface is
+	 * removed without the knowledge of wpa_supplicant/hostapd, e.g., in
+	 * case that the user space daemon has crashed, they must be able to
+	 * cleanup all stations and key entries in the AP tear down flow. Thus,
+	 * this flag can/should always be set for cfg80211 drivers.
+	 */
+	drv->capa.flags |= WPA_DRIVER_FLAGS_AP_TEARDOWN_SUPPORT;
+
+	if (!info.device_ap_sme) {
+		drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+
+		/*
+		 * No AP SME is currently assumed to also indicate no AP MLME
+		 * in the driver/firmware.
+		 */
+		drv->capa.flags |= WPA_DRIVER_FLAGS_AP_MLME;
+	}
+
+	drv->device_ap_sme = info.device_ap_sme;
+	drv->poll_command_supported = info.poll_command_supported;
+	drv->data_tx_status = info.data_tx_status;
+	if (info.set_qos_map_supported)
+		drv->capa.flags |= WPA_DRIVER_FLAGS_QOS_MAPPING;
+	drv->have_low_prio_scan = info.have_low_prio_scan;
+
+	/*
+	 * If poll command and tx status are supported, mac80211 is new enough
+	 * to have everything we need to not need monitor interfaces.
+	 */
+	drv->use_monitor = !info.poll_command_supported || !info.data_tx_status;
+
+	if (drv->device_ap_sme && drv->use_monitor) {
+		/*
+		 * Non-mac80211 drivers may not support monitor interface.
+		 * Make sure we do not get stuck with incorrect capability here
+		 * by explicitly testing this.
+		 */
+		if (!info.monitor_supported) {
+			wpa_printf(MSG_DEBUG, "nl80211: Disable use_monitor "
+				   "with device_ap_sme since no monitor mode "
+				   "support detected");
+			drv->use_monitor = 0;
+		}
+	}
+
+	/*
+	 * If we aren't going to use monitor interfaces, but the
+	 * driver doesn't support data TX status, we won't get TX
+	 * status for EAPOL frames.
+	 */
+	if (!drv->use_monitor && !info.data_tx_status)
+		drv->capa.flags &= ~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+
+	qca_nl80211_check_dfs_capa(drv);
+	qca_nl80211_get_features(drv);
+
+	return 0;
+}
+
+
+struct phy_info_arg {
+	u16 *num_modes;
+	struct hostapd_hw_modes *modes;
+	int last_mode, last_chan_idx;
+};
+
+static void phy_info_ht_capa(struct hostapd_hw_modes *mode, struct nlattr *capa,
+			     struct nlattr *ampdu_factor,
+			     struct nlattr *ampdu_density,
+			     struct nlattr *mcs_set)
+{
+	if (capa)
+		mode->ht_capab = nla_get_u16(capa);
+
+	if (ampdu_factor)
+		mode->a_mpdu_params |= nla_get_u8(ampdu_factor) & 0x03;
+
+	if (ampdu_density)
+		mode->a_mpdu_params |= nla_get_u8(ampdu_density) << 2;
+
+	if (mcs_set && nla_len(mcs_set) >= 16) {
+		u8 *mcs;
+		mcs = nla_data(mcs_set);
+		os_memcpy(mode->mcs_set, mcs, 16);
+	}
+}
+
+
+static void phy_info_vht_capa(struct hostapd_hw_modes *mode,
+			      struct nlattr *capa,
+			      struct nlattr *mcs_set)
+{
+	if (capa)
+		mode->vht_capab = nla_get_u32(capa);
+
+	if (mcs_set && nla_len(mcs_set) >= 8) {
+		u8 *mcs;
+		mcs = nla_data(mcs_set);
+		os_memcpy(mode->vht_mcs_set, mcs, 8);
+	}
+}
+
+
+static void phy_info_freq(struct hostapd_hw_modes *mode,
+			  struct hostapd_channel_data *chan,
+			  struct nlattr *tb_freq[])
+{
+	u8 channel;
+	chan->freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+	chan->flag = 0;
+	chan->dfs_cac_ms = 0;
+	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;
+	if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR])
+		chan->flag |= HOSTAPD_CHAN_NO_IR;
+	if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+		chan->flag |= HOSTAPD_CHAN_RADAR;
+	if (tb_freq[NL80211_FREQUENCY_ATTR_INDOOR_ONLY])
+		chan->flag |= HOSTAPD_CHAN_INDOOR_ONLY;
+	if (tb_freq[NL80211_FREQUENCY_ATTR_GO_CONCURRENT])
+		chan->flag |= HOSTAPD_CHAN_GO_CONCURRENT;
+
+	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;
+		}
+	}
+
+	if (tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]) {
+		chan->dfs_cac_ms = nla_get_u32(
+			tb_freq[NL80211_FREQUENCY_ATTR_DFS_CAC_TIME]);
+	}
+}
+
+
+static int phy_info_freqs(struct phy_info_arg *phy_info,
+			  struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
+	static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+		[NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+		[NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_NO_IR] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+		[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+		[NL80211_FREQUENCY_ATTR_DFS_STATE] = { .type = NLA_U32 },
+	};
+	int new_channels = 0;
+	struct hostapd_channel_data *channel;
+	struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+	struct nlattr *nl_freq;
+	int rem_freq, idx;
+
+	if (tb == NULL)
+		return NL_OK;
+
+	nla_for_each_nested(nl_freq, tb, rem_freq) {
+		nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+			  nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+		if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+			continue;
+		new_channels++;
+	}
+
+	channel = os_realloc_array(mode->channels,
+				   mode->num_channels + new_channels,
+				   sizeof(struct hostapd_channel_data));
+	if (!channel)
+		return NL_SKIP;
+
+	mode->channels = channel;
+	mode->num_channels += new_channels;
+
+	idx = phy_info->last_chan_idx;
+
+	nla_for_each_nested(nl_freq, tb, rem_freq) {
+		nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+			  nla_data(nl_freq), nla_len(nl_freq), freq_policy);
+		if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+			continue;
+		phy_info_freq(mode, &mode->channels[idx], tb_freq);
+		idx++;
+	}
+	phy_info->last_chan_idx = idx;
+
+	return NL_OK;
+}
+
+
+static int phy_info_rates(struct hostapd_hw_modes *mode, struct nlattr *tb)
+{
+	static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
+		[NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
+		[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
+		{ .type = NLA_FLAG },
+	};
+	struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+	struct nlattr *nl_rate;
+	int rem_rate, idx;
+
+	if (tb == NULL)
+		return NL_OK;
+
+	nla_for_each_nested(nl_rate, tb, rem_rate) {
+		nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+			  nla_data(nl_rate), nla_len(nl_rate),
+			  rate_policy);
+		if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+			continue;
+		mode->num_rates++;
+	}
+
+	mode->rates = os_calloc(mode->num_rates, sizeof(int));
+	if (!mode->rates)
+		return NL_SKIP;
+
+	idx = 0;
+
+	nla_for_each_nested(nl_rate, tb, rem_rate) {
+		nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+			  nla_data(nl_rate), nla_len(nl_rate),
+			  rate_policy);
+		if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+			continue;
+		mode->rates[idx] = nla_get_u32(
+			tb_rate[NL80211_BITRATE_ATTR_RATE]);
+		idx++;
+	}
+
+	return NL_OK;
+}
+
+
+static int phy_info_band(struct phy_info_arg *phy_info, struct nlattr *nl_band)
+{
+	struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+	struct hostapd_hw_modes *mode;
+	int ret;
+
+	if (phy_info->last_mode != nl_band->nla_type) {
+		mode = os_realloc_array(phy_info->modes,
+					*phy_info->num_modes + 1,
+					sizeof(*mode));
+		if (!mode)
+			return NL_SKIP;
+		phy_info->modes = mode;
+
+		mode = &phy_info->modes[*(phy_info->num_modes)];
+		os_memset(mode, 0, sizeof(*mode));
+		mode->mode = NUM_HOSTAPD_MODES;
+		mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN |
+			HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN;
+
+		/*
+		 * Unsupported VHT MCS stream is defined as value 3, so the VHT
+		 * MCS RX/TX map must be initialized with 0xffff to mark all 8
+		 * possible streams as unsupported. This will be overridden if
+		 * driver advertises VHT support.
+		 */
+		mode->vht_mcs_set[0] = 0xff;
+		mode->vht_mcs_set[1] = 0xff;
+		mode->vht_mcs_set[4] = 0xff;
+		mode->vht_mcs_set[5] = 0xff;
+
+		*(phy_info->num_modes) += 1;
+		phy_info->last_mode = nl_band->nla_type;
+		phy_info->last_chan_idx = 0;
+	} else
+		mode = &phy_info->modes[*(phy_info->num_modes) - 1];
+
+	nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+		  nla_len(nl_band), NULL);
+
+	phy_info_ht_capa(mode, tb_band[NL80211_BAND_ATTR_HT_CAPA],
+			 tb_band[NL80211_BAND_ATTR_HT_AMPDU_FACTOR],
+			 tb_band[NL80211_BAND_ATTR_HT_AMPDU_DENSITY],
+			 tb_band[NL80211_BAND_ATTR_HT_MCS_SET]);
+	phy_info_vht_capa(mode, tb_band[NL80211_BAND_ATTR_VHT_CAPA],
+			  tb_band[NL80211_BAND_ATTR_VHT_MCS_SET]);
+	ret = phy_info_freqs(phy_info, mode, tb_band[NL80211_BAND_ATTR_FREQS]);
+	if (ret != NL_OK)
+		return ret;
+	ret = phy_info_rates(mode, tb_band[NL80211_BAND_ATTR_RATES]);
+	if (ret != NL_OK)
+		return ret;
+
+	return NL_OK;
+}
+
+
+static int phy_info_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct phy_info_arg *phy_info = arg;
+	struct nlattr *nl_band;
+	int rem_band;
+
+	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+		return NL_SKIP;
+
+	nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band)
+	{
+		int res = phy_info_band(phy_info, nl_band);
+		if (res != NL_OK)
+			return res;
+	}
+
+	return NL_SKIP;
+}
+
+
+static struct hostapd_hw_modes *
+wpa_driver_nl80211_postprocess_modes(struct hostapd_hw_modes *modes,
+				     u16 *num_modes)
+{
+	u16 m;
+	struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
+	int i, mode11g_idx = -1;
+
+	/* heuristic to set up modes */
+	for (m = 0; m < *num_modes; m++) {
+		if (!modes[m].num_channels)
+			continue;
+		if (modes[m].channels[0].freq < 4000) {
+			modes[m].mode = HOSTAPD_MODE_IEEE80211B;
+			for (i = 0; i < modes[m].num_rates; i++) {
+				if (modes[m].rates[i] > 200) {
+					modes[m].mode = HOSTAPD_MODE_IEEE80211G;
+					break;
+				}
+			}
+		} else if (modes[m].channels[0].freq > 50000)
+			modes[m].mode = HOSTAPD_MODE_IEEE80211AD;
+		else
+			modes[m].mode = HOSTAPD_MODE_IEEE80211A;
+	}
+
+	/* If only 802.11g mode is included, use it to construct matching
+	 * 802.11b mode data. */
+
+	for (m = 0; m < *num_modes; m++) {
+		if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
+			return modes; /* 802.11b already included */
+		if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
+			mode11g_idx = m;
+	}
+
+	if (mode11g_idx < 0)
+		return modes; /* 2.4 GHz band not supported at all */
+
+	nmodes = os_realloc_array(modes, *num_modes + 1, sizeof(*nmodes));
+	if (nmodes == NULL)
+		return modes; /* Could not add 802.11b mode */
+
+	mode = &nmodes[*num_modes];
+	os_memset(mode, 0, sizeof(*mode));
+	(*num_modes)++;
+	modes = nmodes;
+
+	mode->mode = HOSTAPD_MODE_IEEE80211B;
+
+	mode11g = &modes[mode11g_idx];
+	mode->num_channels = mode11g->num_channels;
+	mode->channels = os_malloc(mode11g->num_channels *
+				   sizeof(struct hostapd_channel_data));
+	if (mode->channels == NULL) {
+		(*num_modes)--;
+		return modes; /* Could not add 802.11b mode */
+	}
+	os_memcpy(mode->channels, mode11g->channels,
+		  mode11g->num_channels * sizeof(struct hostapd_channel_data));
+
+	mode->num_rates = 0;
+	mode->rates = os_malloc(4 * sizeof(int));
+	if (mode->rates == NULL) {
+		os_free(mode->channels);
+		(*num_modes)--;
+		return modes; /* Could not add 802.11b mode */
+	}
+
+	for (i = 0; i < mode11g->num_rates; i++) {
+		if (mode11g->rates[i] != 10 && mode11g->rates[i] != 20 &&
+		    mode11g->rates[i] != 55 && mode11g->rates[i] != 110)
+			continue;
+		mode->rates[mode->num_rates] = mode11g->rates[i];
+		mode->num_rates++;
+		if (mode->num_rates == 4)
+			break;
+	}
+
+	if (mode->num_rates == 0) {
+		os_free(mode->channels);
+		os_free(mode->rates);
+		(*num_modes)--;
+		return modes; /* No 802.11b rates */
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
+		   "information");
+
+	return modes;
+}
+
+
+static void nl80211_set_ht40_mode(struct hostapd_hw_modes *mode, int start,
+				  int end)
+{
+	int c;
+
+	for (c = 0; c < mode->num_channels; c++) {
+		struct hostapd_channel_data *chan = &mode->channels[c];
+		if (chan->freq - 10 >= start && chan->freq + 10 <= end)
+			chan->flag |= HOSTAPD_CHAN_HT40;
+	}
+}
+
+
+static void nl80211_set_ht40_mode_sec(struct hostapd_hw_modes *mode, int start,
+				      int end)
+{
+	int c;
+
+	for (c = 0; c < mode->num_channels; c++) {
+		struct hostapd_channel_data *chan = &mode->channels[c];
+		if (!(chan->flag & HOSTAPD_CHAN_HT40))
+			continue;
+		if (chan->freq - 30 >= start && chan->freq - 10 <= end)
+			chan->flag |= HOSTAPD_CHAN_HT40MINUS;
+		if (chan->freq + 10 >= start && chan->freq + 30 <= end)
+			chan->flag |= HOSTAPD_CHAN_HT40PLUS;
+	}
+}
+
+
+static void nl80211_reg_rule_max_eirp(u32 start, u32 end, u32 max_eirp,
+				      struct phy_info_arg *results)
+{
+	u16 m;
+
+	for (m = 0; m < *results->num_modes; m++) {
+		int c;
+		struct hostapd_hw_modes *mode = &results->modes[m];
+
+		for (c = 0; c < mode->num_channels; c++) {
+			struct hostapd_channel_data *chan = &mode->channels[c];
+			if ((u32) chan->freq - 10 >= start &&
+			    (u32) chan->freq + 10 <= end)
+				chan->max_tx_power = max_eirp;
+		}
+	}
+}
+
+
+static void nl80211_reg_rule_ht40(u32 start, u32 end,
+				  struct phy_info_arg *results)
+{
+	u16 m;
+
+	for (m = 0; m < *results->num_modes; m++) {
+		if (!(results->modes[m].ht_capab &
+		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+			continue;
+		nl80211_set_ht40_mode(&results->modes[m], start, end);
+	}
+}
+
+
+static void nl80211_reg_rule_sec(struct nlattr *tb[],
+				 struct phy_info_arg *results)
+{
+	u32 start, end, max_bw;
+	u16 m;
+
+	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+		return;
+
+	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+	if (max_bw < 20)
+		return;
+
+	for (m = 0; m < *results->num_modes; m++) {
+		if (!(results->modes[m].ht_capab &
+		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+			continue;
+		nl80211_set_ht40_mode_sec(&results->modes[m], start, end);
+	}
+}
+
+
+static void nl80211_set_vht_mode(struct hostapd_hw_modes *mode, int start,
+				 int end)
+{
+	int c;
+
+	for (c = 0; c < mode->num_channels; c++) {
+		struct hostapd_channel_data *chan = &mode->channels[c];
+		if (chan->freq - 10 >= start && chan->freq + 70 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_10_70;
+
+		if (chan->freq - 30 >= start && chan->freq + 50 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_30_50;
+
+		if (chan->freq - 50 >= start && chan->freq + 30 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_50_30;
+
+		if (chan->freq - 70 >= start && chan->freq + 10 <= end)
+			chan->flag |= HOSTAPD_CHAN_VHT_70_10;
+	}
+}
+
+
+static void nl80211_reg_rule_vht(struct nlattr *tb[],
+				 struct phy_info_arg *results)
+{
+	u32 start, end, max_bw;
+	u16 m;
+
+	if (tb[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_END] == NULL ||
+	    tb[NL80211_ATTR_FREQ_RANGE_MAX_BW] == NULL)
+		return;
+
+	start = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+	end = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+	max_bw = nla_get_u32(tb[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+
+	if (max_bw < 80)
+		return;
+
+	for (m = 0; m < *results->num_modes; m++) {
+		if (!(results->modes[m].ht_capab &
+		      HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET))
+			continue;
+		/* TODO: use a real VHT support indication */
+		if (!results->modes[m].vht_capab)
+			continue;
+
+		nl80211_set_vht_mode(&results->modes[m], start, end);
+	}
+}
+
+
+static const char * dfs_domain_name(enum nl80211_dfs_regions region)
+{
+	switch (region) {
+	case NL80211_DFS_UNSET:
+		return "DFS-UNSET";
+	case NL80211_DFS_FCC:
+		return "DFS-FCC";
+	case NL80211_DFS_ETSI:
+		return "DFS-ETSI";
+	case NL80211_DFS_JP:
+		return "DFS-JP";
+	default:
+		return "DFS-invalid";
+	}
+}
+
+
+static int nl80211_get_reg(struct nl_msg *msg, void *arg)
+{
+	struct phy_info_arg *results = arg;
+	struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *nl_rule;
+	struct nlattr *tb_rule[NL80211_FREQUENCY_ATTR_MAX + 1];
+	int rem_rule;
+	static struct nla_policy reg_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+		[NL80211_ATTR_REG_RULE_FLAGS] = { .type = NLA_U32 },
+		[NL80211_ATTR_FREQ_RANGE_START] = { .type = NLA_U32 },
+		[NL80211_ATTR_FREQ_RANGE_END] = { .type = NLA_U32 },
+		[NL80211_ATTR_FREQ_RANGE_MAX_BW] = { .type = NLA_U32 },
+		[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN] = { .type = NLA_U32 },
+		[NL80211_ATTR_POWER_RULE_MAX_EIRP] = { .type = NLA_U32 },
+	};
+
+	nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (!tb_msg[NL80211_ATTR_REG_ALPHA2] ||
+	    !tb_msg[NL80211_ATTR_REG_RULES]) {
+		wpa_printf(MSG_DEBUG, "nl80211: No regulatory information "
+			   "available");
+		return NL_SKIP;
+	}
+
+	if (tb_msg[NL80211_ATTR_DFS_REGION]) {
+		enum nl80211_dfs_regions dfs_domain;
+		dfs_domain = nla_get_u8(tb_msg[NL80211_ATTR_DFS_REGION]);
+		wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s (%s)",
+			   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]),
+			   dfs_domain_name(dfs_domain));
+	} else {
+		wpa_printf(MSG_DEBUG, "nl80211: Regulatory information - country=%s",
+			   (char *) nla_data(tb_msg[NL80211_ATTR_REG_ALPHA2]));
+	}
+
+	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+	{
+		u32 start, end, max_eirp = 0, max_bw = 0, flags = 0;
+		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+		if (tb_rule[NL80211_ATTR_FREQ_RANGE_START] == NULL ||
+		    tb_rule[NL80211_ATTR_FREQ_RANGE_END] == NULL)
+			continue;
+		start = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]) / 1000;
+		end = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]) / 1000;
+		if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+			max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]) / 100;
+		if (tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW])
+			max_bw = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]) / 1000;
+		if (tb_rule[NL80211_ATTR_REG_RULE_FLAGS])
+			flags = nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS]);
+
+		wpa_printf(MSG_DEBUG, "nl80211: %u-%u @ %u MHz %u mBm%s%s%s%s%s%s%s%s",
+			   start, end, max_bw, max_eirp,
+			   flags & NL80211_RRF_NO_OFDM ? " (no OFDM)" : "",
+			   flags & NL80211_RRF_NO_CCK ? " (no CCK)" : "",
+			   flags & NL80211_RRF_NO_INDOOR ? " (no indoor)" : "",
+			   flags & NL80211_RRF_NO_OUTDOOR ? " (no outdoor)" :
+			   "",
+			   flags & NL80211_RRF_DFS ? " (DFS)" : "",
+			   flags & NL80211_RRF_PTP_ONLY ? " (PTP only)" : "",
+			   flags & NL80211_RRF_PTMP_ONLY ? " (PTMP only)" : "",
+			   flags & NL80211_RRF_NO_IR ? " (no IR)" : "");
+		if (max_bw >= 40)
+			nl80211_reg_rule_ht40(start, end, results);
+		if (tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP])
+			nl80211_reg_rule_max_eirp(start, end, max_eirp,
+						  results);
+	}
+
+	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+	{
+		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+		nl80211_reg_rule_sec(tb_rule, results);
+	}
+
+	nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rule)
+	{
+		nla_parse(tb_rule, NL80211_FREQUENCY_ATTR_MAX,
+			  nla_data(nl_rule), nla_len(nl_rule), reg_policy);
+		nl80211_reg_rule_vht(tb_rule, results);
+	}
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_set_regulatory_flags(struct wpa_driver_nl80211_data *drv,
+					struct phy_info_arg *results)
+{
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -ENOMEM;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
+	return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
+}
+
+
+struct hostapd_hw_modes *
+nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+	u32 feat;
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int nl_flags = 0;
+	struct nl_msg *msg;
+	struct phy_info_arg result = {
+		.num_modes = num_modes,
+		.modes = NULL,
+		.last_mode = -1,
+	};
+
+	*num_modes = 0;
+	*flags = 0;
+
+	feat = get_nl80211_protocol_features(drv);
+	if (feat & NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP)
+		nl_flags = NLM_F_DUMP;
+	if (!(msg = nl80211_cmd_msg(bss, nl_flags, NL80211_CMD_GET_WIPHY)) ||
+	    nla_put_flag(msg, NL80211_ATTR_SPLIT_WIPHY_DUMP)) {
+		nlmsg_free(msg);
+		return NULL;
+	}
+
+	if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0) {
+		nl80211_set_regulatory_flags(drv, &result);
+		return wpa_driver_nl80211_postprocess_modes(result.modes,
+							    num_modes);
+	}
+
+	return NULL;
+}
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
new file mode 100644
index 0000000..85769d8
--- /dev/null
+++ b/src/drivers/driver_nl80211_event.c
@@ -0,0 +1,1948 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Event processing
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/qca-vendor.h"
+#include "common/qca-vendor-attr.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "driver_nl80211.h"
+
+
+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)
+	C2S(NL80211_CMD_GET_COALESCE)
+	C2S(NL80211_CMD_SET_COALESCE)
+	C2S(NL80211_CMD_CHANNEL_SWITCH)
+	C2S(NL80211_CMD_VENDOR)
+	C2S(NL80211_CMD_SET_QOS_MAP)
+	C2S(NL80211_CMD_ADD_TX_TS)
+	C2S(NL80211_CMD_DEL_TX_TS)
+	default:
+		return "NL80211_CMD_UNKNOWN";
+	}
+#undef C2S
+}
+
+
+static void mlme_event_auth(struct wpa_driver_nl80211_data *drv,
+			    const u8 *frame, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt;
+	union wpa_event_data event;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+	    drv->force_connect_cmd) {
+		/*
+		 * Avoid reporting two association events that would confuse
+		 * the core code.
+		 */
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignore auth event when using driver SME");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Authenticate event");
+	mgmt = (const struct ieee80211_mgmt *) frame;
+	if (len < 24 + sizeof(mgmt->u.auth)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+			   "frame");
+		return;
+	}
+
+	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);
+	event.auth.auth_transaction =
+		le_to_host16(mgmt->u.auth.auth_transaction);
+	event.auth.status_code = le_to_host16(mgmt->u.auth.status_code);
+	if (len > 24 + sizeof(mgmt->u.auth)) {
+		event.auth.ies = mgmt->u.auth.variable;
+		event.auth.ies_len = len - 24 - sizeof(mgmt->u.auth);
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_AUTH, &event);
+}
+
+
+static int nl80211_parse_wmm_params(struct nlattr *wmm_attr,
+				    struct wmm_params *wmm_params)
+{
+	struct nlattr *wmm_info[NL80211_STA_WME_MAX + 1];
+	static struct nla_policy wme_policy[NL80211_STA_WME_MAX + 1] = {
+		[NL80211_STA_WME_UAPSD_QUEUES] = { .type = NLA_U8 },
+	};
+
+	if (!wmm_attr) {
+		wpa_printf(MSG_DEBUG, "nl80211: WMM data missing");
+		return -1;
+	}
+
+	if (nla_parse_nested(wmm_info, NL80211_STA_WME_MAX, wmm_attr,
+			     wme_policy)) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Failed to parse nested attributes");
+		return -1;
+	}
+
+	if (!wmm_info[NL80211_STA_WME_UAPSD_QUEUES])
+		return -1;
+
+	wmm_params->uapsd_queues =
+		nla_get_u8(wmm_info[NL80211_STA_WME_UAPSD_QUEUES]);
+	wmm_params->info_bitmap |= WMM_PARAMS_UAPSD_QUEUES_INFO;
+
+	return 0;
+}
+
+
+static void mlme_event_assoc(struct wpa_driver_nl80211_data *drv,
+			    const u8 *frame, size_t len, struct nlattr *wmm)
+{
+	const struct ieee80211_mgmt *mgmt;
+	union wpa_event_data event;
+	u16 status;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME) &&
+	    drv->force_connect_cmd) {
+		/*
+		 * Avoid reporting two association events that would confuse
+		 * the core code.
+		 */
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignore assoc event when using driver SME");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Associate event");
+	mgmt = (const struct ieee80211_mgmt *) frame;
+	if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
+			   "frame");
+		return;
+	}
+
+	status = le_to_host16(mgmt->u.assoc_resp.status_code);
+	if (status != WLAN_STATUS_SUCCESS) {
+		os_memset(&event, 0, sizeof(event));
+		event.assoc_reject.bssid = mgmt->bssid;
+		if (len > 24 + sizeof(mgmt->u.assoc_resp)) {
+			event.assoc_reject.resp_ies =
+				(u8 *) mgmt->u.assoc_resp.variable;
+			event.assoc_reject.resp_ies_len =
+				len - 24 - sizeof(mgmt->u.assoc_resp);
+		}
+		event.assoc_reject.status_code = status;
+
+		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+		return;
+	}
+
+	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)) {
+		event.assoc_info.resp_ies = (u8 *) mgmt->u.assoc_resp.variable;
+		event.assoc_info.resp_ies_len =
+			len - 24 - sizeof(mgmt->u.assoc_resp);
+	}
+
+	event.assoc_info.freq = drv->assoc_freq;
+
+	nl80211_parse_wmm_params(wmm, &event.assoc_info.wmm_params);
+
+	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
+			       enum nl80211_commands cmd, struct nlattr *status,
+			       struct nlattr *addr, struct nlattr *req_ie,
+			       struct nlattr *resp_ie,
+			       struct nlattr *authorized,
+			       struct nlattr *key_replay_ctr,
+			       struct nlattr *ptk_kck,
+			       struct nlattr *ptk_kek)
+{
+	union wpa_event_data event;
+	u16 status_code;
+
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+		/*
+		 * Avoid reporting two association events that would confuse
+		 * the core code.
+		 */
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore connect event (cmd=%d) "
+			   "when using userspace SME", cmd);
+		return;
+	}
+
+	status_code = status ? nla_get_u16(status) : WLAN_STATUS_SUCCESS;
+
+	if (cmd == NL80211_CMD_CONNECT) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Connect event (status=%u ignore_next_local_disconnect=%d)",
+			   status_code, drv->ignore_next_local_disconnect);
+	} else if (cmd == NL80211_CMD_ROAM) {
+		wpa_printf(MSG_DEBUG, "nl80211: Roam event");
+	}
+
+	os_memset(&event, 0, sizeof(event));
+	if (cmd == NL80211_CMD_CONNECT && status_code != WLAN_STATUS_SUCCESS) {
+		if (addr)
+			event.assoc_reject.bssid = nla_data(addr);
+		if (drv->ignore_next_local_disconnect) {
+			drv->ignore_next_local_disconnect = 0;
+			if (!event.assoc_reject.bssid ||
+			    (os_memcmp(event.assoc_reject.bssid,
+				       drv->auth_attempt_bssid,
+				       ETH_ALEN) != 0)) {
+				/*
+				 * Ignore the event that came without a BSSID or
+				 * for the old connection since this is likely
+				 * not relevant to the new Connect command.
+				 */
+				wpa_printf(MSG_DEBUG,
+					   "nl80211: Ignore connection failure event triggered during reassociation");
+				return;
+			}
+		}
+		if (resp_ie) {
+			event.assoc_reject.resp_ies = nla_data(resp_ie);
+			event.assoc_reject.resp_ies_len = nla_len(resp_ie);
+		}
+		event.assoc_reject.status_code = status_code;
+		wpa_supplicant_event(drv->ctx, EVENT_ASSOC_REJECT, &event);
+		return;
+	}
+
+	drv->associated = 1;
+	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);
+		event.assoc_info.req_ies_len = nla_len(req_ie);
+	}
+	if (resp_ie) {
+		event.assoc_info.resp_ies = nla_data(resp_ie);
+		event.assoc_info.resp_ies_len = nla_len(resp_ie);
+	}
+
+	event.assoc_info.freq = nl80211_get_assoc_freq(drv);
+
+	if (authorized && nla_get_u8(authorized)) {
+		event.assoc_info.authorized = 1;
+		wpa_printf(MSG_DEBUG, "nl80211: connection authorized");
+	}
+	if (key_replay_ctr) {
+		event.assoc_info.key_replay_ctr = nla_data(key_replay_ctr);
+		event.assoc_info.key_replay_ctr_len = nla_len(key_replay_ctr);
+	}
+	if (ptk_kck) {
+		event.assoc_info.ptk_kck = nla_data(ptk_kck);
+		event.assoc_info.ptk_kck_len = nla_len(ptk_kck);
+	}
+	if (ptk_kek) {
+		event.assoc_info.ptk_kek = nla_data(ptk_kek);
+		event.assoc_info.ptk_kek_len = nla_len(ptk_kek);
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
+}
+
+
+static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
+				  struct nlattr *reason, struct nlattr *addr,
+				  struct nlattr *by_ap)
+{
+	union wpa_event_data data;
+	unsigned int locally_generated = by_ap == NULL;
+
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+		/*
+		 * Avoid reporting two disassociation events that could
+		 * confuse the core code.
+		 */
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+			   "event when using userspace SME");
+		return;
+	}
+
+	if (drv->ignore_next_local_disconnect) {
+		drv->ignore_next_local_disconnect = 0;
+		if (locally_generated) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore disconnect "
+				   "event triggered during reassociation");
+			return;
+		}
+		wpa_printf(MSG_WARNING, "nl80211: Was expecting local "
+			   "disconnect but got another disconnect "
+			   "event first");
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Disconnect event");
+	nl80211_mark_disconnected(drv);
+	os_memset(&data, 0, sizeof(data));
+	if (reason)
+		data.deauth_info.reason_code = nla_get_u16(reason);
+	data.deauth_info.locally_generated = by_ap == NULL;
+	wpa_supplicant_event(drv->ctx, EVENT_DEAUTH, &data);
+}
+
+
+static int calculate_chan_offset(int width, int freq, int cf1, int cf2)
+{
+	int freq1 = 0;
+
+	switch (convert2width(width)) {
+	case CHAN_WIDTH_20_NOHT:
+	case CHAN_WIDTH_20:
+		return 0;
+	case CHAN_WIDTH_40:
+		freq1 = cf1 - 10;
+		break;
+	case CHAN_WIDTH_80:
+		freq1 = cf1 - 30;
+		break;
+	case CHAN_WIDTH_160:
+		freq1 = cf1 - 70;
+		break;
+	case CHAN_WIDTH_UNKNOWN:
+	case CHAN_WIDTH_80P80:
+		/* FIXME: implement this */
+		return 0;
+	}
+
+	return (abs(freq - freq1) / 20) % 2 == 0 ? 1 : -1;
+}
+
+
+static void mlme_event_ch_switch(struct wpa_driver_nl80211_data *drv,
+				 struct nlattr *ifindex, struct nlattr *freq,
+				 struct nlattr *type, struct nlattr *bw,
+				 struct nlattr *cf1, struct nlattr *cf2)
+{
+	struct i802_bss *bss;
+	union wpa_event_data data;
+	int ht_enabled = 1;
+	int chan_offset = 0;
+	int ifidx;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Channel switch event");
+
+	if (!freq)
+		return;
+
+	ifidx = nla_get_u32(ifindex);
+	bss = get_bss_ifindex(drv, ifidx);
+	if (bss == NULL) {
+		wpa_printf(MSG_WARNING, "nl80211: Unknown ifindex (%d) for channel switch, ignoring",
+			   ifidx);
+		return;
+	}
+
+	if (type) {
+		enum nl80211_channel_type ch_type = nla_get_u32(type);
+
+		wpa_printf(MSG_DEBUG, "nl80211: Channel type: %d", ch_type);
+		switch (ch_type) {
+		case NL80211_CHAN_NO_HT:
+			ht_enabled = 0;
+			break;
+		case NL80211_CHAN_HT20:
+			break;
+		case NL80211_CHAN_HT40PLUS:
+			chan_offset = 1;
+			break;
+		case NL80211_CHAN_HT40MINUS:
+			chan_offset = -1;
+			break;
+		}
+	} else if (bw && cf1) {
+		/* This can happen for example with VHT80 ch switch */
+		chan_offset = calculate_chan_offset(nla_get_u32(bw),
+						    nla_get_u32(freq),
+						    nla_get_u32(cf1),
+						    cf2 ? nla_get_u32(cf2) : 0);
+	} else {
+		wpa_printf(MSG_WARNING, "nl80211: Unknown secondary channel information - following channel definition calculations may fail");
+	}
+
+	os_memset(&data, 0, sizeof(data));
+	data.ch_switch.freq = nla_get_u32(freq);
+	data.ch_switch.ht_enabled = ht_enabled;
+	data.ch_switch.ch_offset = chan_offset;
+	if (bw)
+		data.ch_switch.ch_width = convert2width(nla_get_u32(bw));
+	if (cf1)
+		data.ch_switch.cf1 = nla_get_u32(cf1);
+	if (cf2)
+		data.ch_switch.cf2 = nla_get_u32(cf2);
+
+	bss->freq = data.ch_switch.freq;
+
+	wpa_supplicant_event(bss->ctx, EVENT_CH_SWITCH, &data);
+}
+
+
+static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
+			       enum nl80211_commands cmd, struct nlattr *addr)
+{
+	union wpa_event_data event;
+	enum wpa_event_type ev;
+
+	if (nla_len(addr) != ETH_ALEN)
+		return;
+
+	wpa_printf(MSG_DEBUG, "nl80211: MLME event %d; timeout with " MACSTR,
+		   cmd, MAC2STR((u8 *) nla_data(addr)));
+
+	if (cmd == NL80211_CMD_AUTHENTICATE)
+		ev = EVENT_AUTH_TIMED_OUT;
+	else if (cmd == NL80211_CMD_ASSOCIATE)
+		ev = EVENT_ASSOC_TIMED_OUT;
+	else
+		return;
+
+	os_memset(&event, 0, sizeof(event));
+	os_memcpy(event.timeout_event.addr, nla_data(addr), ETH_ALEN);
+	wpa_supplicant_event(drv->ctx, ev, &event);
+}
+
+
+static void mlme_event_mgmt(struct i802_bss *bss,
+			    struct nlattr *freq, struct nlattr *sig,
+			    const u8 *frame, size_t len)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	const struct ieee80211_mgmt *mgmt;
+	union wpa_event_data event;
+	u16 fc, stype;
+	int ssi_signal = 0;
+	int rx_freq = 0;
+
+	wpa_printf(MSG_MSGDUMP, "nl80211: Frame event");
+	mgmt = (const struct ieee80211_mgmt *) frame;
+	if (len < 24) {
+		wpa_printf(MSG_DEBUG, "nl80211: Too short management frame");
+		return;
+	}
+
+	fc = le_to_host16(mgmt->frame_control);
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	if (sig)
+		ssi_signal = (s32) nla_get_u32(sig);
+
+	os_memset(&event, 0, sizeof(event));
+	if (freq) {
+		event.rx_mgmt.freq = nla_get_u32(freq);
+		rx_freq = drv->last_mgmt_freq = event.rx_mgmt.freq;
+	}
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: RX frame sa=" MACSTR
+		   " freq=%d ssi_signal=%d fc=0x%x seq_ctrl=0x%x stype=%u (%s) len=%u",
+		   MAC2STR(mgmt->sa), rx_freq, ssi_signal, fc,
+		   le_to_host16(mgmt->seq_ctrl), stype, fc2str(fc),
+		   (unsigned int) len);
+	event.rx_mgmt.frame = frame;
+	event.rx_mgmt.frame_len = len;
+	event.rx_mgmt.ssi_signal = ssi_signal;
+	event.rx_mgmt.drv_priv = bss;
+	wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+}
+
+
+static void mlme_event_mgmt_tx_status(struct wpa_driver_nl80211_data *drv,
+				      struct nlattr *cookie, const u8 *frame,
+				      size_t len, struct nlattr *ack)
+{
+	union wpa_event_data event;
+	const struct ieee80211_hdr *hdr;
+	u16 fc;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Frame TX status event");
+	if (!is_ap_interface(drv->nlmode)) {
+		u64 cookie_val;
+
+		if (!cookie)
+			return;
+
+		cookie_val = nla_get_u64(cookie);
+		wpa_printf(MSG_DEBUG, "nl80211: Action TX status:"
+			   " cookie=0%llx%s (ack=%d)",
+			   (long long unsigned int) cookie_val,
+			   cookie_val == drv->send_action_cookie ?
+			   " (match)" : " (unknown)", ack != NULL);
+		if (cookie_val != drv->send_action_cookie)
+			return;
+	}
+
+	hdr = (const struct ieee80211_hdr *) frame;
+	fc = le_to_host16(hdr->frame_control);
+
+	os_memset(&event, 0, sizeof(event));
+	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+	event.tx_status.dst = hdr->addr1;
+	event.tx_status.data = frame;
+	event.tx_status.data_len = len;
+	event.tx_status.ack = ack != NULL;
+	wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
+}
+
+
+static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
+				       enum wpa_event_type type,
+				       const u8 *frame, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt;
+	union wpa_event_data event;
+	const u8 *bssid = NULL;
+	u16 reason_code = 0;
+
+	if (type == EVENT_DEAUTH)
+		wpa_printf(MSG_DEBUG, "nl80211: Deauthenticate event");
+	else
+		wpa_printf(MSG_DEBUG, "nl80211: Disassociate event");
+
+	mgmt = (const struct ieee80211_mgmt *) frame;
+	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) {
+			/*
+			 * We have presumably received this deauth as a
+			 * response to a clear_state_mismatch() outgoing
+			 * deauth.  Don't let it take us offline!
+			 */
+			wpa_printf(MSG_DEBUG, "nl80211: Deauth received "
+				   "from Unknown BSSID " MACSTR " -- ignoring",
+				   MAC2STR(bssid));
+			return;
+		}
+	}
+
+	nl80211_mark_disconnected(drv);
+	os_memset(&event, 0, sizeof(event));
+
+	/* Note: Same offset for Reason Code in both frame subtypes */
+	if (len >= 24 + sizeof(mgmt->u.deauth))
+		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+	if (type == EVENT_DISASSOC) {
+		event.disassoc_info.locally_generated =
+			!os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+		event.disassoc_info.addr = bssid;
+		event.disassoc_info.reason_code = reason_code;
+		if (frame + len > mgmt->u.disassoc.variable) {
+			event.disassoc_info.ie = mgmt->u.disassoc.variable;
+			event.disassoc_info.ie_len = frame + len -
+				mgmt->u.disassoc.variable;
+		}
+	} else {
+		if (drv->ignore_deauth_event) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event due to previous forced deauth-during-auth");
+			drv->ignore_deauth_event = 0;
+			return;
+		}
+		event.deauth_info.locally_generated =
+			!os_memcmp(mgmt->sa, drv->first_bss->addr, ETH_ALEN);
+		if (drv->ignore_next_local_deauth) {
+			drv->ignore_next_local_deauth = 0;
+			if (event.deauth_info.locally_generated) {
+				wpa_printf(MSG_DEBUG, "nl80211: Ignore deauth event triggered due to own deauth request");
+				return;
+			}
+			wpa_printf(MSG_WARNING, "nl80211: Was expecting local deauth but got another disconnect event first");
+		}
+		event.deauth_info.addr = bssid;
+		event.deauth_info.reason_code = reason_code;
+		if (frame + len > mgmt->u.deauth.variable) {
+			event.deauth_info.ie = mgmt->u.deauth.variable;
+			event.deauth_info.ie_len = frame + len -
+				mgmt->u.deauth.variable;
+		}
+	}
+
+	wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+static void mlme_event_unprot_disconnect(struct wpa_driver_nl80211_data *drv,
+					 enum wpa_event_type type,
+					 const u8 *frame, size_t len)
+{
+	const struct ieee80211_mgmt *mgmt;
+	union wpa_event_data event;
+	u16 reason_code = 0;
+
+	if (type == EVENT_UNPROT_DEAUTH)
+		wpa_printf(MSG_DEBUG, "nl80211: Unprot Deauthenticate event");
+	else
+		wpa_printf(MSG_DEBUG, "nl80211: Unprot Disassociate event");
+
+	if (len < 24)
+		return;
+
+	mgmt = (const struct ieee80211_mgmt *) frame;
+
+	os_memset(&event, 0, sizeof(event));
+	/* Note: Same offset for Reason Code in both frame subtypes */
+	if (len >= 24 + sizeof(mgmt->u.deauth))
+		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
+
+	if (type == EVENT_UNPROT_DISASSOC) {
+		event.unprot_disassoc.sa = mgmt->sa;
+		event.unprot_disassoc.da = mgmt->da;
+		event.unprot_disassoc.reason_code = reason_code;
+	} else {
+		event.unprot_deauth.sa = mgmt->sa;
+		event.unprot_deauth.da = mgmt->da;
+		event.unprot_deauth.reason_code = reason_code;
+	}
+
+	wpa_supplicant_event(drv->ctx, type, &event);
+}
+
+
+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 nlattr *wmm)
+{
+	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 (%s) without frame data",
+			   cmd, nl80211_command_to_string(cmd));
+		return;
+	}
+
+	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));
+
+	switch (cmd) {
+	case NL80211_CMD_AUTHENTICATE:
+		mlme_event_auth(drv, nla_data(frame), nla_len(frame));
+		break;
+	case NL80211_CMD_ASSOCIATE:
+		mlme_event_assoc(drv, nla_data(frame), nla_len(frame), wmm);
+		break;
+	case NL80211_CMD_DEAUTHENTICATE:
+		mlme_event_deauth_disassoc(drv, EVENT_DEAUTH,
+					   nla_data(frame), nla_len(frame));
+		break;
+	case NL80211_CMD_DISASSOCIATE:
+		mlme_event_deauth_disassoc(drv, EVENT_DISASSOC,
+					   nla_data(frame), nla_len(frame));
+		break;
+	case NL80211_CMD_FRAME:
+		mlme_event_mgmt(bss, freq, sig, nla_data(frame),
+				nla_len(frame));
+		break;
+	case NL80211_CMD_FRAME_TX_STATUS:
+		mlme_event_mgmt_tx_status(drv, cookie, nla_data(frame),
+					  nla_len(frame), ack);
+		break;
+	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+		mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DEAUTH,
+					     nla_data(frame), nla_len(frame));
+		break;
+	case NL80211_CMD_UNPROT_DISASSOCIATE:
+		mlme_event_unprot_disconnect(drv, EVENT_UNPROT_DISASSOC,
+					     nla_data(frame), nla_len(frame));
+		break;
+	default:
+		break;
+	}
+}
+
+
+static void mlme_event_michael_mic_failure(struct i802_bss *bss,
+					   struct nlattr *tb[])
+{
+	union wpa_event_data data;
+
+	wpa_printf(MSG_DEBUG, "nl80211: MLME event Michael MIC failure");
+	os_memset(&data, 0, sizeof(data));
+	if (tb[NL80211_ATTR_MAC]) {
+		wpa_hexdump(MSG_DEBUG, "nl80211: Source MAC address",
+			    nla_data(tb[NL80211_ATTR_MAC]),
+			    nla_len(tb[NL80211_ATTR_MAC]));
+		data.michael_mic_failure.src = nla_data(tb[NL80211_ATTR_MAC]);
+	}
+	if (tb[NL80211_ATTR_KEY_SEQ]) {
+		wpa_hexdump(MSG_DEBUG, "nl80211: TSC",
+			    nla_data(tb[NL80211_ATTR_KEY_SEQ]),
+			    nla_len(tb[NL80211_ATTR_KEY_SEQ]));
+	}
+	if (tb[NL80211_ATTR_KEY_TYPE]) {
+		enum nl80211_key_type key_type =
+			nla_get_u32(tb[NL80211_ATTR_KEY_TYPE]);
+		wpa_printf(MSG_DEBUG, "nl80211: Key Type %d", key_type);
+		if (key_type == NL80211_KEYTYPE_PAIRWISE)
+			data.michael_mic_failure.unicast = 1;
+	} else
+		data.michael_mic_failure.unicast = 1;
+
+	if (tb[NL80211_ATTR_KEY_IDX]) {
+		u8 key_id = nla_get_u8(tb[NL80211_ATTR_KEY_IDX]);
+		wpa_printf(MSG_DEBUG, "nl80211: Key Id %d", key_id);
+	}
+
+	wpa_supplicant_event(bss->ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+}
+
+
+static void mlme_event_join_ibss(struct wpa_driver_nl80211_data *drv,
+				 struct nlattr *tb[])
+{
+	unsigned int freq;
+
+	if (tb[NL80211_ATTR_MAC] == NULL) {
+		wpa_printf(MSG_DEBUG, "nl80211: No address in IBSS joined "
+			   "event");
+		return;
+	}
+	os_memcpy(drv->bssid, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+	drv->associated = 1;
+	wpa_printf(MSG_DEBUG, "nl80211: IBSS " MACSTR " joined",
+		   MAC2STR(drv->bssid));
+
+	freq = nl80211_get_assoc_freq(drv);
+	if (freq) {
+		wpa_printf(MSG_DEBUG, "nl80211: IBSS on frequency %u MHz",
+			   freq);
+		drv->first_bss->freq = freq;
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+}
+
+
+static void mlme_event_remain_on_channel(struct wpa_driver_nl80211_data *drv,
+					 int cancel_event, struct nlattr *tb[])
+{
+	unsigned int freq, chan_type, duration;
+	union wpa_event_data data;
+	u64 cookie;
+
+	if (tb[NL80211_ATTR_WIPHY_FREQ])
+		freq = nla_get_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+	else
+		freq = 0;
+
+	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
+		chan_type = nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+	else
+		chan_type = 0;
+
+	if (tb[NL80211_ATTR_DURATION])
+		duration = nla_get_u32(tb[NL80211_ATTR_DURATION]);
+	else
+		duration = 0;
+
+	if (tb[NL80211_ATTR_COOKIE])
+		cookie = nla_get_u64(tb[NL80211_ATTR_COOKIE]);
+	else
+		cookie = 0;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Remain-on-channel event (cancel=%d "
+		   "freq=%u channel_type=%u duration=%u cookie=0x%llx (%s))",
+		   cancel_event, freq, chan_type, duration,
+		   (long long unsigned int) cookie,
+		   cookie == drv->remain_on_chan_cookie ? "match" : "unknown");
+
+	if (cookie != drv->remain_on_chan_cookie)
+		return; /* not for us */
+
+	if (cancel_event)
+		drv->pending_remain_on_chan = 0;
+
+	os_memset(&data, 0, sizeof(data));
+	data.remain_on_channel.freq = freq;
+	data.remain_on_channel.duration = duration;
+	wpa_supplicant_event(drv->ctx, cancel_event ?
+			     EVENT_CANCEL_REMAIN_ON_CHANNEL :
+			     EVENT_REMAIN_ON_CHANNEL, &data);
+}
+
+
+static void mlme_event_ft_event(struct wpa_driver_nl80211_data *drv,
+				struct nlattr *tb[])
+{
+	union wpa_event_data data;
+
+	os_memset(&data, 0, sizeof(data));
+
+	if (tb[NL80211_ATTR_IE]) {
+		data.ft_ies.ies = nla_data(tb[NL80211_ATTR_IE]);
+		data.ft_ies.ies_len = nla_len(tb[NL80211_ATTR_IE]);
+	}
+
+	if (tb[NL80211_ATTR_IE_RIC]) {
+		data.ft_ies.ric_ies = nla_data(tb[NL80211_ATTR_IE_RIC]);
+		data.ft_ies.ric_ies_len = nla_len(tb[NL80211_ATTR_IE_RIC]);
+	}
+
+	if (tb[NL80211_ATTR_MAC])
+		os_memcpy(data.ft_ies.target_ap,
+			  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+	wpa_printf(MSG_DEBUG, "nl80211: FT event target_ap " MACSTR,
+		   MAC2STR(data.ft_ies.target_ap));
+
+	wpa_supplicant_event(drv->ctx, EVENT_FT_RESPONSE, &data);
+}
+
+
+static void send_scan_event(struct wpa_driver_nl80211_data *drv, int aborted,
+			    struct nlattr *tb[])
+{
+	union wpa_event_data event;
+	struct nlattr *nl;
+	int rem;
+	struct scan_info *info;
+#define MAX_REPORT_FREQS 50
+	int freqs[MAX_REPORT_FREQS];
+	int num_freqs = 0;
+
+	if (drv->scan_for_auth) {
+		drv->scan_for_auth = 0;
+		wpa_printf(MSG_DEBUG, "nl80211: Scan results for missing "
+			   "cfg80211 BSS entry");
+		wpa_driver_nl80211_authenticate_retry(drv);
+		return;
+	}
+
+	os_memset(&event, 0, sizeof(event));
+	info = &event.scan_info;
+	info->aborted = aborted;
+
+	if (tb[NL80211_ATTR_SCAN_SSIDS]) {
+		nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_SSIDS], rem) {
+			struct wpa_driver_scan_ssid *s =
+				&info->ssids[info->num_ssids];
+			s->ssid = nla_data(nl);
+			s->ssid_len = nla_len(nl);
+			wpa_printf(MSG_DEBUG, "nl80211: Scan probed for SSID '%s'",
+				   wpa_ssid_txt(s->ssid, s->ssid_len));
+			info->num_ssids++;
+			if (info->num_ssids == WPAS_MAX_SCAN_SSIDS)
+				break;
+		}
+	}
+	if (tb[NL80211_ATTR_SCAN_FREQUENCIES]) {
+		char msg[200], *pos, *end;
+		int res;
+
+		pos = msg;
+		end = pos + sizeof(msg);
+		*pos = '\0';
+
+		nla_for_each_nested(nl, tb[NL80211_ATTR_SCAN_FREQUENCIES], rem)
+		{
+			freqs[num_freqs] = nla_get_u32(nl);
+			res = os_snprintf(pos, end - pos, " %d",
+					  freqs[num_freqs]);
+			if (!os_snprintf_error(end - pos, res))
+				pos += res;
+			num_freqs++;
+			if (num_freqs == MAX_REPORT_FREQS - 1)
+				break;
+		}
+		info->freqs = freqs;
+		info->num_freqs = num_freqs;
+		wpa_printf(MSG_DEBUG, "nl80211: Scan included frequencies:%s",
+			   msg);
+	}
+	wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, &event);
+}
+
+
+static void nl80211_cqm_event(struct wpa_driver_nl80211_data *drv,
+			      struct nlattr *tb[])
+{
+	static struct nla_policy cqm_policy[NL80211_ATTR_CQM_MAX + 1] = {
+		[NL80211_ATTR_CQM_RSSI_THOLD] = { .type = NLA_U32 },
+		[NL80211_ATTR_CQM_RSSI_HYST] = { .type = NLA_U8 },
+		[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] = { .type = NLA_U32 },
+		[NL80211_ATTR_CQM_PKT_LOSS_EVENT] = { .type = NLA_U32 },
+	};
+	struct nlattr *cqm[NL80211_ATTR_CQM_MAX + 1];
+	enum nl80211_cqm_rssi_threshold_event event;
+	union wpa_event_data ed;
+	struct wpa_signal_info sig;
+	int res;
+
+	if (tb[NL80211_ATTR_CQM] == NULL ||
+	    nla_parse_nested(cqm, NL80211_ATTR_CQM_MAX, tb[NL80211_ATTR_CQM],
+			     cqm_policy)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid CQM event");
+		return;
+	}
+
+	os_memset(&ed, 0, sizeof(ed));
+
+	if (cqm[NL80211_ATTR_CQM_PKT_LOSS_EVENT]) {
+		if (!tb[NL80211_ATTR_MAC])
+			return;
+		os_memcpy(ed.low_ack.addr, nla_data(tb[NL80211_ATTR_MAC]),
+			  ETH_ALEN);
+		wpa_supplicant_event(drv->ctx, EVENT_STATION_LOW_ACK, &ed);
+		return;
+	}
+
+	if (cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT] == NULL)
+		return;
+	event = nla_get_u32(cqm[NL80211_ATTR_CQM_RSSI_THRESHOLD_EVENT]);
+
+	if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH) {
+		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
+			   "event: RSSI high");
+		ed.signal_change.above_threshold = 1;
+	} else if (event == NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW) {
+		wpa_printf(MSG_DEBUG, "nl80211: Connection quality monitor "
+			   "event: RSSI low");
+		ed.signal_change.above_threshold = 0;
+	} else
+		return;
+
+	res = nl80211_get_link_signal(drv, &sig);
+	if (res == 0) {
+		ed.signal_change.current_signal = sig.current_signal;
+		ed.signal_change.current_txrate = sig.current_txrate;
+		wpa_printf(MSG_DEBUG, "nl80211: Signal: %d dBm  txrate: %d",
+			   sig.current_signal, sig.current_txrate);
+	}
+
+	res = nl80211_get_link_noise(drv, &sig);
+	if (res == 0) {
+		ed.signal_change.current_noise = sig.current_noise;
+		wpa_printf(MSG_DEBUG, "nl80211: Noise: %d dBm",
+			   sig.current_noise);
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_SIGNAL_CHANGE, &ed);
+}
+
+
+static void nl80211_new_peer_candidate(struct wpa_driver_nl80211_data *drv,
+				       struct nlattr **tb)
+{
+	const u8 *addr;
+	union wpa_event_data data;
+
+	if (drv->nlmode != NL80211_IFTYPE_MESH_POINT)
+		return;
+
+	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_IE])
+		return;
+
+	addr = nla_data(tb[NL80211_ATTR_MAC]);
+	wpa_printf(MSG_DEBUG, "nl80211: New peer candidate" MACSTR,
+		   MAC2STR(addr));
+
+	os_memset(&data, 0, sizeof(data));
+	data.mesh_peer.peer = addr;
+	data.mesh_peer.ies = nla_data(tb[NL80211_ATTR_IE]);
+	data.mesh_peer.ie_len = nla_len(tb[NL80211_ATTR_IE]);
+	wpa_supplicant_event(drv->ctx, EVENT_NEW_PEER_CANDIDATE, &data);
+}
+
+
+static void nl80211_new_station_event(struct wpa_driver_nl80211_data *drv,
+				      struct i802_bss *bss,
+				      struct nlattr **tb)
+{
+	u8 *addr;
+	union wpa_event_data data;
+
+	if (tb[NL80211_ATTR_MAC] == NULL)
+		return;
+	addr = nla_data(tb[NL80211_ATTR_MAC]);
+	wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
+
+	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+		u8 *ies = NULL;
+		size_t ies_len = 0;
+		if (tb[NL80211_ATTR_IE]) {
+			ies = nla_data(tb[NL80211_ATTR_IE]);
+			ies_len = nla_len(tb[NL80211_ATTR_IE]);
+		}
+		wpa_hexdump(MSG_DEBUG, "nl80211: Assoc Req IEs", ies, ies_len);
+		drv_event_assoc(bss->ctx, addr, ies, ies_len, 0);
+		return;
+	}
+
+	if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.ibss_rsn_start.peer, addr, ETH_ALEN);
+	wpa_supplicant_event(bss->ctx, EVENT_IBSS_RSN_START, &data);
+}
+
+
+static void nl80211_del_station_event(struct wpa_driver_nl80211_data *drv,
+				      struct nlattr **tb)
+{
+	u8 *addr;
+	union wpa_event_data data;
+
+	if (tb[NL80211_ATTR_MAC] == NULL)
+		return;
+	addr = nla_data(tb[NL80211_ATTR_MAC]);
+	wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
+		   MAC2STR(addr));
+
+	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
+		drv_event_disassoc(drv->ctx, addr);
+		return;
+	}
+
+	if (drv->nlmode != NL80211_IFTYPE_ADHOC)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.ibss_peer_lost.peer, addr, ETH_ALEN);
+	wpa_supplicant_event(drv->ctx, EVENT_IBSS_PEER_LOST, &data);
+}
+
+
+static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
+					struct nlattr **tb)
+{
+	struct nlattr *rekey_info[NUM_NL80211_REKEY_DATA];
+	static struct nla_policy rekey_policy[NUM_NL80211_REKEY_DATA] = {
+		[NL80211_REKEY_DATA_KEK] = {
+			.minlen = NL80211_KEK_LEN,
+			.maxlen = NL80211_KEK_LEN,
+		},
+		[NL80211_REKEY_DATA_KCK] = {
+			.minlen = NL80211_KCK_LEN,
+			.maxlen = NL80211_KCK_LEN,
+		},
+		[NL80211_REKEY_DATA_REPLAY_CTR] = {
+			.minlen = NL80211_REPLAY_CTR_LEN,
+			.maxlen = NL80211_REPLAY_CTR_LEN,
+		},
+	};
+	union wpa_event_data data;
+
+	if (!tb[NL80211_ATTR_MAC])
+		return;
+	if (!tb[NL80211_ATTR_REKEY_DATA])
+		return;
+	if (nla_parse_nested(rekey_info, MAX_NL80211_REKEY_DATA,
+			     tb[NL80211_ATTR_REKEY_DATA], rekey_policy))
+		return;
+	if (!rekey_info[NL80211_REKEY_DATA_REPLAY_CTR])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	data.driver_gtk_rekey.bssid = nla_data(tb[NL80211_ATTR_MAC]);
+	wpa_printf(MSG_DEBUG, "nl80211: Rekey offload event for BSSID " MACSTR,
+		   MAC2STR(data.driver_gtk_rekey.bssid));
+	data.driver_gtk_rekey.replay_ctr =
+		nla_data(rekey_info[NL80211_REKEY_DATA_REPLAY_CTR]);
+	wpa_hexdump(MSG_DEBUG, "nl80211: Rekey offload - Replay Counter",
+		    data.driver_gtk_rekey.replay_ctr, NL80211_REPLAY_CTR_LEN);
+	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_GTK_REKEY, &data);
+}
+
+
+static void nl80211_pmksa_candidate_event(struct wpa_driver_nl80211_data *drv,
+					  struct nlattr **tb)
+{
+	struct nlattr *cand[NUM_NL80211_PMKSA_CANDIDATE];
+	static struct nla_policy cand_policy[NUM_NL80211_PMKSA_CANDIDATE] = {
+		[NL80211_PMKSA_CANDIDATE_INDEX] = { .type = NLA_U32 },
+		[NL80211_PMKSA_CANDIDATE_BSSID] = {
+			.minlen = ETH_ALEN,
+			.maxlen = ETH_ALEN,
+		},
+		[NL80211_PMKSA_CANDIDATE_PREAUTH] = { .type = NLA_FLAG },
+	};
+	union wpa_event_data data;
+
+	wpa_printf(MSG_DEBUG, "nl80211: PMKSA candidate event");
+
+	if (!tb[NL80211_ATTR_PMKSA_CANDIDATE])
+		return;
+	if (nla_parse_nested(cand, MAX_NL80211_PMKSA_CANDIDATE,
+			     tb[NL80211_ATTR_PMKSA_CANDIDATE], cand_policy))
+		return;
+	if (!cand[NL80211_PMKSA_CANDIDATE_INDEX] ||
+	    !cand[NL80211_PMKSA_CANDIDATE_BSSID])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.pmkid_candidate.bssid,
+		  nla_data(cand[NL80211_PMKSA_CANDIDATE_BSSID]), ETH_ALEN);
+	data.pmkid_candidate.index =
+		nla_get_u32(cand[NL80211_PMKSA_CANDIDATE_INDEX]);
+	data.pmkid_candidate.preauth =
+		cand[NL80211_PMKSA_CANDIDATE_PREAUTH] != NULL;
+	wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+}
+
+
+static void nl80211_client_probe_event(struct wpa_driver_nl80211_data *drv,
+				       struct nlattr **tb)
+{
+	union wpa_event_data data;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Probe client event");
+
+	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_ACK])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.client_poll.addr,
+		  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+	wpa_supplicant_event(drv->ctx, EVENT_DRIVER_CLIENT_POLL_OK, &data);
+}
+
+
+static void nl80211_tdls_oper_event(struct wpa_driver_nl80211_data *drv,
+				    struct nlattr **tb)
+{
+	union wpa_event_data data;
+
+	wpa_printf(MSG_DEBUG, "nl80211: TDLS operation event");
+
+	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_TDLS_OPERATION])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.tdls.peer, nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+	switch (nla_get_u8(tb[NL80211_ATTR_TDLS_OPERATION])) {
+	case NL80211_TDLS_SETUP:
+		wpa_printf(MSG_DEBUG, "nl80211: TDLS setup request for peer "
+			   MACSTR, MAC2STR(data.tdls.peer));
+		data.tdls.oper = TDLS_REQUEST_SETUP;
+		break;
+	case NL80211_TDLS_TEARDOWN:
+		wpa_printf(MSG_DEBUG, "nl80211: TDLS teardown request for peer "
+			   MACSTR, MAC2STR(data.tdls.peer));
+		data.tdls.oper = TDLS_REQUEST_TEARDOWN;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "nl80211: Unsupported TDLS operatione "
+			   "event");
+		return;
+	}
+	if (tb[NL80211_ATTR_REASON_CODE]) {
+		data.tdls.reason_code =
+			nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_TDLS, &data);
+}
+
+
+static void nl80211_stop_ap(struct wpa_driver_nl80211_data *drv,
+			    struct nlattr **tb)
+{
+	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_UNAVAILABLE, NULL);
+}
+
+
+static void nl80211_connect_failed_event(struct wpa_driver_nl80211_data *drv,
+					 struct nlattr **tb)
+{
+	union wpa_event_data data;
+	u32 reason;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Connect failed event");
+
+	if (!tb[NL80211_ATTR_MAC] || !tb[NL80211_ATTR_CONN_FAILED_REASON])
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	os_memcpy(data.connect_failed_reason.addr,
+		  nla_data(tb[NL80211_ATTR_MAC]), ETH_ALEN);
+
+	reason = nla_get_u32(tb[NL80211_ATTR_CONN_FAILED_REASON]);
+	switch (reason) {
+	case NL80211_CONN_FAIL_MAX_CLIENTS:
+		wpa_printf(MSG_DEBUG, "nl80211: Max client reached");
+		data.connect_failed_reason.code = MAX_CLIENT_REACHED;
+		break;
+	case NL80211_CONN_FAIL_BLOCKED_CLIENT:
+		wpa_printf(MSG_DEBUG, "nl80211: Blocked client " MACSTR
+			   " tried to connect",
+			   MAC2STR(data.connect_failed_reason.addr));
+		data.connect_failed_reason.code = BLOCKED_CLIENT;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "nl8021l: Unknown connect failed reason "
+			   "%u", reason);
+		return;
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_CONNECT_FAILED_REASON, &data);
+}
+
+
+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_u32(tb[NL80211_ATTR_WIPHY_FREQ]);
+	event_type = nla_get_u32(tb[NL80211_ATTR_RADAR_EVENT]);
+
+	/* Check HT params */
+	if (tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+		data.dfs_event.ht_enabled = 1;
+		data.dfs_event.chan_offset = 0;
+
+		switch (nla_get_u32(tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE])) {
+		case NL80211_CHAN_NO_HT:
+			data.dfs_event.ht_enabled = 0;
+			break;
+		case NL80211_CHAN_HT20:
+			break;
+		case NL80211_CHAN_HT40PLUS:
+			data.dfs_event.chan_offset = 1;
+			break;
+		case NL80211_CHAN_HT40MINUS:
+			data.dfs_event.chan_offset = -1;
+			break;
+		}
+	}
+
+	/* Get VHT params */
+	if (tb[NL80211_ATTR_CHANNEL_WIDTH])
+		data.dfs_event.chan_width =
+			convert2width(nla_get_u32(
+					      tb[NL80211_ATTR_CHANNEL_WIDTH]));
+	if (tb[NL80211_ATTR_CENTER_FREQ1])
+		data.dfs_event.cf1 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ1]);
+	if (tb[NL80211_ATTR_CENTER_FREQ2])
+		data.dfs_event.cf2 = nla_get_u32(tb[NL80211_ATTR_CENTER_FREQ2]);
+
+	wpa_printf(MSG_DEBUG, "nl80211: DFS event on freq %d MHz, ht: %d, offset: %d, width: %d, cf1: %dMHz, cf2: %dMHz",
+		   data.dfs_event.freq, data.dfs_event.ht_enabled,
+		   data.dfs_event.chan_offset, data.dfs_event.chan_width,
+		   data.dfs_event.cf1, data.dfs_event.cf2);
+
+	switch (event_type) {
+	case NL80211_RADAR_DETECTED:
+		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)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	union wpa_event_data event;
+
+	if (!tb[NL80211_ATTR_MAC])
+		return;
+
+	os_memset(&event, 0, sizeof(event));
+	event.rx_from_unknown.bssid = bss->addr;
+	event.rx_from_unknown.addr = nla_data(tb[NL80211_ATTR_MAC]);
+	event.rx_from_unknown.wds = wds;
+
+	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void qca_nl80211_avoid_freq(struct wpa_driver_nl80211_data *drv,
+				   const u8 *data, size_t len)
+{
+	u32 i, count;
+	union wpa_event_data event;
+	struct wpa_freq_range *range = NULL;
+	const struct qca_avoid_freq_list *freq_range;
+
+	freq_range = (const struct qca_avoid_freq_list *) data;
+	if (len < sizeof(freq_range->count))
+		return;
+
+	count = freq_range->count;
+	if (len < sizeof(freq_range->count) +
+	    count * sizeof(struct qca_avoid_freq_range)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Ignored too short avoid frequency list (len=%u)",
+			   (unsigned int) len);
+		return;
+	}
+
+	if (count > 0) {
+		range = os_calloc(count, sizeof(struct wpa_freq_range));
+		if (range == NULL)
+			return;
+	}
+
+	os_memset(&event, 0, sizeof(event));
+	for (i = 0; i < count; i++) {
+		unsigned int idx = event.freq_range.num;
+		range[idx].min = freq_range->range[i].start_freq;
+		range[idx].max = freq_range->range[i].end_freq;
+		wpa_printf(MSG_DEBUG, "nl80211: Avoid frequency range: %u-%u",
+			   range[idx].min, range[idx].max);
+		if (range[idx].min > range[idx].max) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore invalid frequency range");
+			continue;
+		}
+		event.freq_range.num++;
+	}
+	event.freq_range.range = range;
+
+	wpa_supplicant_event(drv->ctx, EVENT_AVOID_FREQUENCIES, &event);
+
+	os_free(range);
+}
+
+
+static void qca_nl80211_acs_select_ch(struct wpa_driver_nl80211_data *drv,
+				   const u8 *data, size_t len)
+{
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ACS_MAX + 1];
+	union wpa_event_data event;
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: ACS channel selection vendor event received");
+
+	if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ACS_MAX,
+		      (struct nlattr *) data, len, NULL))
+		return;
+
+	if (!tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL] ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL])
+		return;
+
+	os_memset(&event, 0, sizeof(event));
+	event.acs_selected_channels.pri_channel =
+		nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_PRIMARY_CHANNEL]);
+	event.acs_selected_channels.sec_channel =
+		nla_get_u8(tb[QCA_WLAN_VENDOR_ATTR_ACS_SECONDARY_CHANNEL]);
+
+	wpa_supplicant_event(drv->ctx, EVENT_ACS_CHANNEL_SELECTED, &event);
+}
+
+
+static void qca_nl80211_key_mgmt_auth(struct wpa_driver_nl80211_data *drv,
+				      const u8 *data, size_t len)
+{
+	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX + 1];
+	u8 *bssid;
+
+	wpa_printf(MSG_DEBUG,
+		   "nl80211: Key management roam+auth vendor event received");
+
+	if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_MAX,
+		      (struct nlattr *) data, len, NULL))
+		return;
+	if (!tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID] ||
+	    nla_len(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]) != ETH_ALEN ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE] ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE] ||
+	    !tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED])
+		return;
+
+	bssid = nla_data(tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID]);
+	wpa_printf(MSG_DEBUG, "  * roam BSSID " MACSTR, MAC2STR(bssid));
+
+	mlme_event_connect(drv, NL80211_CMD_ROAM, NULL,
+			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_BSSID],
+			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_REQ_IE],
+			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_RESP_IE],
+			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_AUTHORIZED],
+			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_KEY_REPLAY_CTR],
+			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KCK],
+			   tb[QCA_WLAN_VENDOR_ATTR_ROAM_AUTH_PTK_KEK]);
+}
+
+
+static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv,
+				     u32 subcmd, u8 *data, size_t len)
+{
+	switch (subcmd) {
+	case QCA_NL80211_VENDOR_SUBCMD_AVOID_FREQUENCY:
+		qca_nl80211_avoid_freq(drv, data, len);
+		break;
+	case QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH:
+		qca_nl80211_key_mgmt_auth(drv, data, len);
+		break;
+	case QCA_NL80211_VENDOR_SUBCMD_DO_ACS:
+		qca_nl80211_acs_select_ch(drv, data, len);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignore unsupported QCA vendor event %u",
+			   subcmd);
+		break;
+	}
+}
+
+
+static void nl80211_vendor_event(struct wpa_driver_nl80211_data *drv,
+				 struct nlattr **tb)
+{
+	u32 vendor_id, subcmd, wiphy = 0;
+	int wiphy_idx;
+	u8 *data = NULL;
+	size_t len = 0;
+
+	if (!tb[NL80211_ATTR_VENDOR_ID] ||
+	    !tb[NL80211_ATTR_VENDOR_SUBCMD])
+		return;
+
+	vendor_id = nla_get_u32(tb[NL80211_ATTR_VENDOR_ID]);
+	subcmd = nla_get_u32(tb[NL80211_ATTR_VENDOR_SUBCMD]);
+
+	if (tb[NL80211_ATTR_WIPHY])
+		wiphy = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+	wpa_printf(MSG_DEBUG, "nl80211: Vendor event: wiphy=%u vendor_id=0x%x subcmd=%u",
+		   wiphy, vendor_id, subcmd);
+
+	if (tb[NL80211_ATTR_VENDOR_DATA]) {
+		data = nla_data(tb[NL80211_ATTR_VENDOR_DATA]);
+		len = nla_len(tb[NL80211_ATTR_VENDOR_DATA]);
+		wpa_hexdump(MSG_MSGDUMP, "nl80211: Vendor data", data, len);
+	}
+
+	wiphy_idx = nl80211_get_wiphy_index(drv->first_bss);
+	if (wiphy_idx >= 0 && wiphy_idx != (int) wiphy) {
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore vendor event for foreign wiphy %u (own: %d)",
+			   wiphy, wiphy_idx);
+		return;
+	}
+
+	switch (vendor_id) {
+	case OUI_QCA:
+		nl80211_vendor_event_qca(drv, subcmd, data, len);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore unsupported vendor event");
+		break;
+	}
+}
+
+
+static void nl80211_reg_change_event(struct wpa_driver_nl80211_data *drv,
+				     struct nlattr *tb[])
+{
+	union wpa_event_data data;
+	enum nl80211_reg_initiator init;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Regulatory domain change");
+
+	if (tb[NL80211_ATTR_REG_INITIATOR] == NULL)
+		return;
+
+	os_memset(&data, 0, sizeof(data));
+	init = nla_get_u8(tb[NL80211_ATTR_REG_INITIATOR]);
+	wpa_printf(MSG_DEBUG, " * initiator=%d", init);
+	switch (init) {
+	case NL80211_REGDOM_SET_BY_CORE:
+		data.channel_list_changed.initiator = REGDOM_SET_BY_CORE;
+		break;
+	case NL80211_REGDOM_SET_BY_USER:
+		data.channel_list_changed.initiator = REGDOM_SET_BY_USER;
+		break;
+	case NL80211_REGDOM_SET_BY_DRIVER:
+		data.channel_list_changed.initiator = REGDOM_SET_BY_DRIVER;
+		break;
+	case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+		data.channel_list_changed.initiator = REGDOM_SET_BY_COUNTRY_IE;
+		break;
+	}
+
+	if (tb[NL80211_ATTR_REG_TYPE]) {
+		enum nl80211_reg_type type;
+		type = nla_get_u8(tb[NL80211_ATTR_REG_TYPE]);
+		wpa_printf(MSG_DEBUG, " * type=%d", type);
+		switch (type) {
+		case NL80211_REGDOM_TYPE_COUNTRY:
+			data.channel_list_changed.type = REGDOM_TYPE_COUNTRY;
+			break;
+		case NL80211_REGDOM_TYPE_WORLD:
+			data.channel_list_changed.type = REGDOM_TYPE_WORLD;
+			break;
+		case NL80211_REGDOM_TYPE_CUSTOM_WORLD:
+			data.channel_list_changed.type =
+				REGDOM_TYPE_CUSTOM_WORLD;
+			break;
+		case NL80211_REGDOM_TYPE_INTERSECTION:
+			data.channel_list_changed.type =
+				REGDOM_TYPE_INTERSECTION;
+			break;
+		}
+	}
+
+	if (tb[NL80211_ATTR_REG_ALPHA2]) {
+		os_strlcpy(data.channel_list_changed.alpha2,
+			   nla_get_string(tb[NL80211_ATTR_REG_ALPHA2]),
+			   sizeof(data.channel_list_changed.alpha2));
+		wpa_printf(MSG_DEBUG, " * alpha2=%s",
+			   data.channel_list_changed.alpha2);
+	}
+
+	wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED, &data);
+}
+
+
+static void do_process_drv_event(struct i802_bss *bss, int cmd,
+				 struct nlattr **tb)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	union wpa_event_data data;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Drv Event %d (%s) received for %s",
+		   cmd, nl80211_command_to_string(cmd), bss->ifname);
+
+	if (cmd == NL80211_CMD_ROAM &&
+	    (drv->capa.flags & WPA_DRIVER_FLAGS_KEY_MGMT_OFFLOAD)) {
+		/*
+		 * Device will use roam+auth vendor event to indicate
+		 * roaming, so ignore the regular roam event.
+		 */
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignore roam event (cmd=%d), device will use vendor event roam+auth",
+			   cmd);
+		return;
+	}
+
+	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED &&
+	    (cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
+	     cmd == NL80211_CMD_SCAN_ABORTED)) {
+		wpa_driver_nl80211_set_mode(drv->first_bss,
+					    drv->ap_scan_as_station);
+		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+	}
+
+	switch (cmd) {
+	case NL80211_CMD_TRIGGER_SCAN:
+		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan trigger");
+		drv->scan_state = SCAN_STARTED;
+		if (drv->scan_for_auth) {
+			/*
+			 * Cannot indicate EVENT_SCAN_STARTED here since we skip
+			 * EVENT_SCAN_RESULTS in scan_for_auth case and the
+			 * upper layer implementation could get confused about
+			 * scanning state.
+			 */
+			wpa_printf(MSG_DEBUG, "nl80211: Do not indicate scan-start event due to internal scan_for_auth");
+			break;
+		}
+		wpa_supplicant_event(drv->ctx, EVENT_SCAN_STARTED, NULL);
+		break;
+	case NL80211_CMD_START_SCHED_SCAN:
+		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan started");
+		drv->scan_state = SCHED_SCAN_STARTED;
+		break;
+	case NL80211_CMD_SCHED_SCAN_STOPPED:
+		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Sched scan stopped");
+		drv->scan_state = SCHED_SCAN_STOPPED;
+		wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
+		break;
+	case NL80211_CMD_NEW_SCAN_RESULTS:
+		wpa_dbg(drv->ctx, MSG_DEBUG,
+			"nl80211: New scan results available");
+		drv->scan_state = SCAN_COMPLETED;
+		drv->scan_complete_events = 1;
+		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+				     drv->ctx);
+		send_scan_event(drv, 0, tb);
+		break;
+	case NL80211_CMD_SCHED_SCAN_RESULTS:
+		wpa_dbg(drv->ctx, MSG_DEBUG,
+			"nl80211: New sched scan results available");
+		drv->scan_state = SCHED_SCAN_RESULTS;
+		send_scan_event(drv, 0, tb);
+		break;
+	case NL80211_CMD_SCAN_ABORTED:
+		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Scan aborted");
+		drv->scan_state = SCAN_ABORTED;
+		/*
+		 * Need to indicate that scan results are available in order
+		 * not to make wpa_supplicant stop its scanning.
+		 */
+		eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+				     drv->ctx);
+		send_scan_event(drv, 1, tb);
+		break;
+	case NL80211_CMD_AUTHENTICATE:
+	case NL80211_CMD_ASSOCIATE:
+	case NL80211_CMD_DEAUTHENTICATE:
+	case NL80211_CMD_DISASSOCIATE:
+	case NL80211_CMD_FRAME_TX_STATUS:
+	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
+	case NL80211_CMD_UNPROT_DISASSOCIATE:
+		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],
+			   tb[NL80211_ATTR_RX_SIGNAL_DBM],
+			   tb[NL80211_ATTR_STA_WME]);
+		break;
+	case NL80211_CMD_CONNECT:
+	case NL80211_CMD_ROAM:
+		mlme_event_connect(drv, cmd,
+				   tb[NL80211_ATTR_STATUS_CODE],
+				   tb[NL80211_ATTR_MAC],
+				   tb[NL80211_ATTR_REQ_IE],
+				   tb[NL80211_ATTR_RESP_IE],
+				   NULL, NULL, NULL, NULL);
+		break;
+	case NL80211_CMD_CH_SWITCH_NOTIFY:
+		mlme_event_ch_switch(drv,
+				     tb[NL80211_ATTR_IFINDEX],
+				     tb[NL80211_ATTR_WIPHY_FREQ],
+				     tb[NL80211_ATTR_WIPHY_CHANNEL_TYPE],
+				     tb[NL80211_ATTR_CHANNEL_WIDTH],
+				     tb[NL80211_ATTR_CENTER_FREQ1],
+				     tb[NL80211_ATTR_CENTER_FREQ2]);
+		break;
+	case NL80211_CMD_DISCONNECT:
+		mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
+				      tb[NL80211_ATTR_MAC],
+				      tb[NL80211_ATTR_DISCONNECTED_BY_AP]);
+		break;
+	case NL80211_CMD_MICHAEL_MIC_FAILURE:
+		mlme_event_michael_mic_failure(bss, tb);
+		break;
+	case NL80211_CMD_JOIN_IBSS:
+		mlme_event_join_ibss(drv, tb);
+		break;
+	case NL80211_CMD_REMAIN_ON_CHANNEL:
+		mlme_event_remain_on_channel(drv, 0, tb);
+		break;
+	case NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL:
+		mlme_event_remain_on_channel(drv, 1, tb);
+		break;
+	case NL80211_CMD_NOTIFY_CQM:
+		nl80211_cqm_event(drv, tb);
+		break;
+	case NL80211_CMD_REG_CHANGE:
+		nl80211_reg_change_event(drv, tb);
+		break;
+	case NL80211_CMD_REG_BEACON_HINT:
+		wpa_printf(MSG_DEBUG, "nl80211: Regulatory beacon hint");
+		os_memset(&data, 0, sizeof(data));
+		data.channel_list_changed.initiator = REGDOM_BEACON_HINT;
+		wpa_supplicant_event(drv->ctx, EVENT_CHANNEL_LIST_CHANGED,
+				     &data);
+		break;
+	case NL80211_CMD_NEW_STATION:
+		nl80211_new_station_event(drv, bss, tb);
+		break;
+	case NL80211_CMD_DEL_STATION:
+		nl80211_del_station_event(drv, tb);
+		break;
+	case NL80211_CMD_SET_REKEY_OFFLOAD:
+		nl80211_rekey_offload_event(drv, tb);
+		break;
+	case NL80211_CMD_PMKSA_CANDIDATE:
+		nl80211_pmksa_candidate_event(drv, tb);
+		break;
+	case NL80211_CMD_PROBE_CLIENT:
+		nl80211_client_probe_event(drv, tb);
+		break;
+	case NL80211_CMD_TDLS_OPER:
+		nl80211_tdls_oper_event(drv, tb);
+		break;
+	case NL80211_CMD_CONN_FAILED:
+		nl80211_connect_failed_event(drv, tb);
+		break;
+	case NL80211_CMD_FT_EVENT:
+		mlme_event_ft_event(drv, tb);
+		break;
+	case NL80211_CMD_RADAR_DETECT:
+		nl80211_radar_event(drv, tb);
+		break;
+	case NL80211_CMD_STOP_AP:
+		nl80211_stop_ap(drv, tb);
+		break;
+	case NL80211_CMD_VENDOR:
+		nl80211_vendor_event(drv, tb);
+		break;
+	case NL80211_CMD_NEW_PEER_CANDIDATE:
+		nl80211_new_peer_candidate(drv, tb);
+		break;
+	default:
+		wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: Ignored unknown event "
+			"(cmd=%d)", cmd);
+		break;
+	}
+}
+
+
+int process_global_event(struct nl_msg *msg, void *arg)
+{
+	struct nl80211_global *global = arg;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	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 && !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;
+			}
+		}
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Ignored event (cmd=%d) for foreign interface (ifindex %d wdev 0x%llx)",
+			   gnlh->cmd, ifidx, (long long unsigned int) wdev_id);
+	}
+
+	return NL_SKIP;
+}
+
+
+int process_bss_event(struct nl_msg *msg, void *arg)
+{
+	struct i802_bss *bss = arg;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+	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, 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],
+			   tb[NL80211_ATTR_RX_SIGNAL_DBM],
+			   tb[NL80211_ATTR_STA_WME]);
+		break;
+	case NL80211_CMD_UNEXPECTED_FRAME:
+		nl80211_spurious_frame(bss, tb, 0);
+		break;
+	case NL80211_CMD_UNEXPECTED_4ADDR_FRAME:
+		nl80211_spurious_frame(bss, tb, 1);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "nl80211: Ignored unknown event "
+			   "(cmd=%d)", gnlh->cmd);
+		break;
+	}
+
+	return NL_SKIP;
+}
diff --git a/src/drivers/driver_nl80211_monitor.c b/src/drivers/driver_nl80211_monitor.c
new file mode 100644
index 0000000..45385da
--- /dev/null
+++ b/src/drivers/driver_nl80211_monitor.c
@@ -0,0 +1,491 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - AP monitor interface
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netpacket/packet.h>
+#include <linux/filter.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "linux_ioctl.h"
+#include "radiotap_iter.h"
+#include "driver_nl80211.h"
+
+
+static void handle_tx_callback(void *ctx, u8 *buf, size_t len, int ok)
+{
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+	union wpa_event_data event;
+
+	hdr = (struct ieee80211_hdr *) buf;
+	fc = le_to_host16(hdr->frame_control);
+
+	os_memset(&event, 0, sizeof(event));
+	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
+	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
+	event.tx_status.dst = hdr->addr1;
+	event.tx_status.data = buf;
+	event.tx_status.data_len = len;
+	event.tx_status.ack = ok;
+	wpa_supplicant_event(ctx, EVENT_TX_STATUS, &event);
+}
+
+
+static void from_unknown_sta(struct wpa_driver_nl80211_data *drv,
+			     u8 *buf, size_t len)
+{
+	struct ieee80211_hdr *hdr = (void *)buf;
+	u16 fc;
+	union wpa_event_data event;
+
+	if (len < sizeof(*hdr))
+		return;
+
+	fc = le_to_host16(hdr->frame_control);
+
+	os_memset(&event, 0, sizeof(event));
+	event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+	event.rx_from_unknown.addr = hdr->addr2;
+	event.rx_from_unknown.wds = (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) ==
+		(WLAN_FC_FROMDS | WLAN_FC_TODS);
+	wpa_supplicant_event(drv->ctx, EVENT_RX_FROM_UNKNOWN, &event);
+}
+
+
+static void handle_frame(struct wpa_driver_nl80211_data *drv,
+			 u8 *buf, size_t len, int datarate, int ssi_signal)
+{
+	struct ieee80211_hdr *hdr;
+	u16 fc;
+	union wpa_event_data event;
+
+	hdr = (struct ieee80211_hdr *) buf;
+	fc = le_to_host16(hdr->frame_control);
+
+	switch (WLAN_FC_GET_TYPE(fc)) {
+	case WLAN_FC_TYPE_MGMT:
+		os_memset(&event, 0, sizeof(event));
+		event.rx_mgmt.frame = buf;
+		event.rx_mgmt.frame_len = len;
+		event.rx_mgmt.datarate = datarate;
+		event.rx_mgmt.ssi_signal = ssi_signal;
+		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+		break;
+	case WLAN_FC_TYPE_CTRL:
+		/* can only get here with PS-Poll frames */
+		wpa_printf(MSG_DEBUG, "CTRL");
+		from_unknown_sta(drv, buf, len);
+		break;
+	case WLAN_FC_TYPE_DATA:
+		from_unknown_sta(drv, buf, len);
+		break;
+	}
+}
+
+
+static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	int len;
+	unsigned char buf[3000];
+	struct ieee80211_radiotap_iterator iter;
+	int ret;
+	int datarate = 0, ssi_signal = 0;
+	int injected = 0, failed = 0, rxflags = 0;
+
+	len = recv(sock, buf, sizeof(buf), 0);
+	if (len < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Monitor socket recv failed: %s",
+			   strerror(errno));
+		return;
+	}
+
+	if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len, NULL)) {
+		wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame");
+		return;
+	}
+
+	while (1) {
+		ret = ieee80211_radiotap_iterator_next(&iter);
+		if (ret == -ENOENT)
+			break;
+		if (ret) {
+			wpa_printf(MSG_INFO, "nl80211: received invalid radiotap frame (%d)",
+				   ret);
+			return;
+		}
+		switch (iter.this_arg_index) {
+		case IEEE80211_RADIOTAP_FLAGS:
+			if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
+				len -= 4;
+			break;
+		case IEEE80211_RADIOTAP_RX_FLAGS:
+			rxflags = 1;
+			break;
+		case IEEE80211_RADIOTAP_TX_FLAGS:
+			injected = 1;
+			failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
+					IEEE80211_RADIOTAP_F_TX_FAIL;
+			break;
+		case IEEE80211_RADIOTAP_DATA_RETRIES:
+			break;
+		case IEEE80211_RADIOTAP_CHANNEL:
+			/* TODO: convert from freq/flags to channel number */
+			break;
+		case IEEE80211_RADIOTAP_RATE:
+			datarate = *iter.this_arg * 5;
+			break;
+		case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+			ssi_signal = (s8) *iter.this_arg;
+			break;
+		}
+	}
+
+	if (rxflags && injected)
+		return;
+
+	if (!injected)
+		handle_frame(drv, buf + iter._max_length,
+			     len - iter._max_length, datarate, ssi_signal);
+	else
+		handle_tx_callback(drv->ctx, buf + iter._max_length,
+				   len - iter._max_length, !failed);
+}
+
+
+/*
+ * we post-process the filter code later and rewrite
+ * this to the offset to the last instruction
+ */
+#define PASS	0xFF
+#define FAIL	0xFE
+
+static struct sock_filter msock_filter_insns[] = {
+	/*
+	 * do a little-endian load of the radiotap length field
+	 */
+	/* load lower byte into A */
+	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 2),
+	/* put it into X (== index register) */
+	BPF_STMT(BPF_MISC| BPF_TAX, 0),
+	/* load upper byte into A */
+	BPF_STMT(BPF_LD  | BPF_B | BPF_ABS, 3),
+	/* left-shift it by 8 */
+	BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
+	/* or with X */
+	BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
+	/* put result into X */
+	BPF_STMT(BPF_MISC| BPF_TAX, 0),
+
+	/*
+	 * Allow management frames through, this also gives us those
+	 * management frames that we sent ourselves with status
+	 */
+	/* load the lower byte of the IEEE 802.11 frame control field */
+	BPF_STMT(BPF_LD  | BPF_B | BPF_IND, 0),
+	/* mask off frame type and version */
+	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
+	/* accept frame if it's both 0, fall through otherwise */
+	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
+
+	/*
+	 * TODO: add a bit to radiotap RX flags that indicates
+	 * that the sending station is not associated, then
+	 * add a filter here that filters on our DA and that flag
+	 * to allow us to deauth frames to that bad station.
+	 *
+	 * For now allow all To DS data frames through.
+	 */
+	/* load the IEEE 802.11 frame control field */
+	BPF_STMT(BPF_LD  | BPF_H | BPF_IND, 0),
+	/* mask off frame type, version and DS status */
+	BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0F03),
+	/* accept frame if version 0, type 2 and To DS, fall through otherwise
+	 */
+	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0801, PASS, 0),
+
+#if 0
+	/*
+	 * drop non-data frames
+	 */
+	/* load the lower byte of the frame control field */
+	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
+	/* mask off QoS bit */
+	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x0c),
+	/* drop non-data frames */
+	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 8, 0, FAIL),
+#endif
+	/* load the upper byte of the frame control field */
+	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 1),
+	/* mask off toDS/fromDS */
+	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x03),
+	/* accept WDS frames */
+	BPF_JUMP(BPF_JMP  | BPF_JEQ | BPF_K, 3, PASS, 0),
+
+	/*
+	 * add header length to index
+	 */
+	/* load the lower byte of the frame control field */
+	BPF_STMT(BPF_LD   | BPF_B | BPF_IND, 0),
+	/* mask off QoS bit */
+	BPF_STMT(BPF_ALU  | BPF_AND | BPF_K, 0x80),
+	/* right shift it by 6 to give 0 or 2 */
+	BPF_STMT(BPF_ALU  | BPF_RSH | BPF_K, 6),
+	/* add data frame header length */
+	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_K, 24),
+	/* add index, was start of 802.11 header */
+	BPF_STMT(BPF_ALU  | BPF_ADD | BPF_X, 0),
+	/* move to index, now start of LL header */
+	BPF_STMT(BPF_MISC | BPF_TAX, 0),
+
+	/*
+	 * Accept empty data frames, we use those for
+	 * polling activity.
+	 */
+	BPF_STMT(BPF_LD  | BPF_W | BPF_LEN, 0),
+	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
+
+	/*
+	 * Accept EAPOL frames
+	 */
+	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 0),
+	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
+	BPF_STMT(BPF_LD  | BPF_W | BPF_IND, 4),
+	BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
+
+	/* keep these last two statements or change the code below */
+	/* return 0 == "DROP" */
+	BPF_STMT(BPF_RET | BPF_K, 0),
+	/* return ~0 == "keep all" */
+	BPF_STMT(BPF_RET | BPF_K, ~0),
+};
+
+static struct sock_fprog msock_filter = {
+	.len = ARRAY_SIZE(msock_filter_insns),
+	.filter = msock_filter_insns,
+};
+
+
+static int add_monitor_filter(int s)
+{
+	int idx;
+
+	/* rewrite all PASS/FAIL jump offsets */
+	for (idx = 0; idx < msock_filter.len; idx++) {
+		struct sock_filter *insn = &msock_filter_insns[idx];
+
+		if (BPF_CLASS(insn->code) == BPF_JMP) {
+			if (insn->code == (BPF_JMP|BPF_JA)) {
+				if (insn->k == PASS)
+					insn->k = msock_filter.len - idx - 2;
+				else if (insn->k == FAIL)
+					insn->k = msock_filter.len - idx - 3;
+			}
+
+			if (insn->jt == PASS)
+				insn->jt = msock_filter.len - idx - 2;
+			else if (insn->jt == FAIL)
+				insn->jt = msock_filter.len - idx - 3;
+
+			if (insn->jf == PASS)
+				insn->jf = msock_filter.len - idx - 2;
+			else if (insn->jf == FAIL)
+				insn->jf = msock_filter.len - idx - 3;
+		}
+	}
+
+	if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
+		       &msock_filter, sizeof(msock_filter))) {
+		wpa_printf(MSG_ERROR, "nl80211: setsockopt(SO_ATTACH_FILTER) failed: %s",
+			   strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void nl80211_remove_monitor_interface(struct wpa_driver_nl80211_data *drv)
+{
+	if (drv->monitor_refcount > 0)
+		drv->monitor_refcount--;
+	wpa_printf(MSG_DEBUG, "nl80211: Remove monitor interface: refcount=%d",
+		   drv->monitor_refcount);
+	if (drv->monitor_refcount > 0)
+		return;
+
+	if (drv->monitor_ifidx >= 0) {
+		nl80211_remove_iface(drv, drv->monitor_ifidx);
+		drv->monitor_ifidx = -1;
+	}
+	if (drv->monitor_sock >= 0) {
+		eloop_unregister_read_sock(drv->monitor_sock);
+		close(drv->monitor_sock);
+		drv->monitor_sock = -1;
+	}
+}
+
+
+int nl80211_create_monitor_interface(struct wpa_driver_nl80211_data *drv)
+{
+	char buf[IFNAMSIZ];
+	struct sockaddr_ll ll;
+	int optval;
+	socklen_t optlen;
+
+	if (drv->monitor_ifidx >= 0) {
+		drv->monitor_refcount++;
+		wpa_printf(MSG_DEBUG, "nl80211: Re-use existing monitor interface: refcount=%d",
+			   drv->monitor_refcount);
+		return 0;
+	}
+
+	if (os_strncmp(drv->first_bss->ifname, "p2p-", 4) == 0) {
+		/*
+		 * P2P interface name is of the format p2p-%s-%d. For monitor
+		 * interface name corresponding to P2P GO, replace "p2p-" with
+		 * "mon-" to retain the same interface name length and to
+		 * indicate that it is a monitor interface.
+		 */
+		snprintf(buf, IFNAMSIZ, "mon-%s", drv->first_bss->ifname + 4);
+	} else {
+		/* Non-P2P interface with AP functionality. */
+		snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss->ifname);
+	}
+
+	buf[IFNAMSIZ - 1] = '\0';
+
+	drv->monitor_ifidx =
+		nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL,
+				     0, NULL, NULL, 0);
+
+	if (drv->monitor_ifidx == -EOPNOTSUPP) {
+		/*
+		 * This is backward compatibility for a few versions of
+		 * the kernel only that didn't advertise the right
+		 * attributes for the only driver that then supported
+		 * AP mode w/o monitor -- ath6kl.
+		 */
+		wpa_printf(MSG_DEBUG, "nl80211: Driver does not support "
+			   "monitor interface type - try to run without it");
+		drv->device_ap_sme = 1;
+	}
+
+	if (drv->monitor_ifidx < 0)
+		return -1;
+
+	if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
+		goto error;
+
+	memset(&ll, 0, sizeof(ll));
+	ll.sll_family = AF_PACKET;
+	ll.sll_ifindex = drv->monitor_ifidx;
+	drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+	if (drv->monitor_sock < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: socket[PF_PACKET,SOCK_RAW] failed: %s",
+			   strerror(errno));
+		goto error;
+	}
+
+	if (add_monitor_filter(drv->monitor_sock)) {
+		wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
+			   "interface; do filtering in user space");
+		/* This works, but will cost in performance. */
+	}
+
+	if (bind(drv->monitor_sock, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: monitor socket bind failed: %s",
+			   strerror(errno));
+		goto error;
+	}
+
+	optlen = sizeof(optval);
+	optval = 20;
+	if (setsockopt
+	    (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to set socket priority: %s",
+			   strerror(errno));
+		goto error;
+	}
+
+	if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
+				     drv, NULL)) {
+		wpa_printf(MSG_INFO, "nl80211: Could not register monitor read socket");
+		goto error;
+	}
+
+	drv->monitor_refcount++;
+	return 0;
+ error:
+	nl80211_remove_monitor_interface(drv);
+	return -1;
+}
+
+
+int nl80211_send_monitor(struct wpa_driver_nl80211_data *drv,
+			 const void *data, size_t len,
+			 int encrypt, int noack)
+{
+	__u8 rtap_hdr[] = {
+		0x00, 0x00, /* radiotap version */
+		0x0e, 0x00, /* radiotap length */
+		0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+		IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
+		0x00,       /* padding */
+		0x00, 0x00, /* RX and TX flags to indicate that */
+		0x00, 0x00, /* this is the injected frame directly */
+	};
+	struct iovec iov[2] = {
+		{
+			.iov_base = &rtap_hdr,
+			.iov_len = sizeof(rtap_hdr),
+		},
+		{
+			.iov_base = (void *) data,
+			.iov_len = len,
+		}
+	};
+	struct msghdr msg = {
+		.msg_name = NULL,
+		.msg_namelen = 0,
+		.msg_iov = iov,
+		.msg_iovlen = 2,
+		.msg_control = NULL,
+		.msg_controllen = 0,
+		.msg_flags = 0,
+	};
+	int res;
+	u16 txflags = 0;
+
+	if (encrypt)
+		rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
+
+	if (drv->monitor_sock < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: No monitor socket available "
+			   "for %s", __func__);
+		return -1;
+	}
+
+	if (noack)
+		txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
+	WPA_PUT_LE16(&rtap_hdr[12], txflags);
+
+	res = sendmsg(drv->monitor_sock, &msg, 0);
+	if (res < 0) {
+		wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
+		return -1;
+	}
+	return 0;
+}
diff --git a/src/drivers/driver_nl80211_scan.c b/src/drivers/driver_nl80211_scan.c
new file mode 100644
index 0000000..7538d60
--- /dev/null
+++ b/src/drivers/driver_nl80211_scan.c
@@ -0,0 +1,796 @@
+/*
+ * Driver interaction with Linux nl80211/cfg80211 - Scanning
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <netlink/genl/genl.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "driver_nl80211.h"
+
+
+static int get_noise_for_scan_results(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *sinfo[NL80211_SURVEY_INFO_MAX + 1];
+	static struct nla_policy survey_policy[NL80211_SURVEY_INFO_MAX + 1] = {
+		[NL80211_SURVEY_INFO_FREQUENCY] = { .type = NLA_U32 },
+		[NL80211_SURVEY_INFO_NOISE] = { .type = NLA_U8 },
+	};
+	struct wpa_scan_results *scan_results = arg;
+	struct wpa_scan_res *scan_res;
+	size_t i;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (!tb[NL80211_ATTR_SURVEY_INFO]) {
+		wpa_printf(MSG_DEBUG, "nl80211: Survey data missing");
+		return NL_SKIP;
+	}
+
+	if (nla_parse_nested(sinfo, NL80211_SURVEY_INFO_MAX,
+			     tb[NL80211_ATTR_SURVEY_INFO],
+			     survey_policy)) {
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to parse nested "
+			   "attributes");
+		return NL_SKIP;
+	}
+
+	if (!sinfo[NL80211_SURVEY_INFO_NOISE])
+		return NL_SKIP;
+
+	if (!sinfo[NL80211_SURVEY_INFO_FREQUENCY])
+		return NL_SKIP;
+
+	for (i = 0; i < scan_results->num; ++i) {
+		scan_res = scan_results->res[i];
+		if (!scan_res)
+			continue;
+		if ((int) nla_get_u32(sinfo[NL80211_SURVEY_INFO_FREQUENCY]) !=
+		    scan_res->freq)
+			continue;
+		if (!(scan_res->flags & WPA_SCAN_NOISE_INVALID))
+			continue;
+		scan_res->noise = (s8)
+			nla_get_u8(sinfo[NL80211_SURVEY_INFO_NOISE]);
+		scan_res->flags &= ~WPA_SCAN_NOISE_INVALID;
+	}
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_get_noise_for_scan_results(
+	struct wpa_driver_nl80211_data *drv,
+	struct wpa_scan_results *scan_res)
+{
+	struct nl_msg *msg;
+
+	msg = nl80211_drv_msg(drv, NLM_F_DUMP, NL80211_CMD_GET_SURVEY);
+	return send_and_recv_msgs(drv, msg, get_noise_for_scan_results,
+				  scan_res);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Driver private data
+ * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
+		wpa_driver_nl80211_set_mode(drv->first_bss,
+					    drv->ap_scan_as_station);
+		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
+	}
+	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static struct nl_msg *
+nl80211_scan_common(struct i802_bss *bss, u8 cmd,
+		    struct wpa_driver_scan_params *params)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	size_t i;
+	u32 scan_flags = 0;
+
+	msg = nl80211_cmd_msg(bss, 0, cmd);
+	if (!msg)
+		return NULL;
+
+	if (params->num_ssids) {
+		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(msg, i + 1, params->ssids[i].ssid_len,
+				    params->ssids[i].ssid))
+				goto fail;
+		}
+		nla_nest_end(msg, ssids);
+	}
+
+	if (params->extra_ies) {
+		wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+			    params->extra_ies, params->extra_ies_len);
+		if (nla_put(msg, NL80211_ATTR_IE, params->extra_ies_len,
+			    params->extra_ies))
+			goto fail;
+	}
+
+	if (params->freqs) {
+		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(msg, i + 1, params->freqs[i]))
+				goto fail;
+		}
+		nla_nest_end(msg, freqs);
+	}
+
+	os_free(drv->filter_ssids);
+	drv->filter_ssids = params->filter_ssids;
+	params->filter_ssids = NULL;
+	drv->num_filter_ssids = params->num_filter_ssids;
+
+	if (params->only_new_results) {
+		wpa_printf(MSG_DEBUG, "nl80211: Add NL80211_SCAN_FLAG_FLUSH");
+		scan_flags |= NL80211_SCAN_FLAG_FLUSH;
+	}
+
+	if (params->low_priority && drv->have_low_prio_scan) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Add NL80211_SCAN_FLAG_LOW_PRIORITY");
+		scan_flags |= NL80211_SCAN_FLAG_LOW_PRIORITY;
+	}
+
+	if (params->mac_addr_rand) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Add NL80211_SCAN_FLAG_RANDOM_ADDR");
+		scan_flags |= NL80211_SCAN_FLAG_RANDOM_ADDR;
+
+		if (params->mac_addr) {
+			wpa_printf(MSG_DEBUG, "nl80211: MAC address: " MACSTR,
+				   MAC2STR(params->mac_addr));
+			if (nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN,
+				    params->mac_addr))
+				goto fail;
+		}
+
+		if (params->mac_addr_mask) {
+			wpa_printf(MSG_DEBUG, "nl80211: MAC address mask: "
+				   MACSTR, MAC2STR(params->mac_addr_mask));
+			if (nla_put(msg, NL80211_ATTR_MAC_MASK, ETH_ALEN,
+				    params->mac_addr_mask))
+				goto fail;
+		}
+	}
+
+	if (scan_flags &&
+	    nla_put_u32(msg, NL80211_ATTR_SCAN_FLAGS, scan_flags))
+		goto fail;
+
+	return msg;
+
+fail:
+	nlmsg_free(msg);
+	return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @bss: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_nl80211_scan(struct i802_bss *bss,
+			    struct wpa_driver_scan_params *params)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = -1, timeout;
+	struct nl_msg *msg = NULL;
+
+	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: scan request");
+	drv->scan_for_auth = 0;
+
+	msg = nl80211_scan_common(bss, NL80211_CMD_TRIGGER_SCAN, params);
+	if (!msg)
+		return -1;
+
+	if (params->p2p_probe) {
+		struct nlattr *rates;
+
+		wpa_printf(MSG_DEBUG, "nl80211: P2P probe - mask SuppRates");
+
+		rates = nla_nest_start(msg, NL80211_ATTR_SCAN_SUPP_RATES);
+		if (rates == NULL)
+			goto fail;
+
+		/*
+		 * Remove 2.4 GHz rates 1, 2, 5.5, 11 Mbps from supported rates
+		 * by masking out everything else apart from the OFDM rates 6,
+		 * 9, 12, 18, 24, 36, 48, 54 Mbps from non-MCS rates. All 5 GHz
+		 * rates are left enabled.
+		 */
+		if (nla_put(msg, NL80211_BAND_2GHZ, 8,
+			    "\x0c\x12\x18\x24\x30\x48\x60\x6c"))
+			goto fail;
+		nla_nest_end(msg, rates);
+
+		if (nla_put_flag(msg, NL80211_ATTR_TX_NO_CCK_RATE))
+			goto fail;
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
+			   "(%s)", ret, strerror(-ret));
+		if (drv->hostapd && is_ap_interface(drv->nlmode)) {
+			enum nl80211_iftype old_mode = drv->nlmode;
+
+			/*
+			 * mac80211 does not allow scan requests in AP mode, so
+			 * try to do this in station mode.
+			 */
+			if (wpa_driver_nl80211_set_mode(
+				    bss, NL80211_IFTYPE_STATION))
+				goto fail;
+
+			if (wpa_driver_nl80211_scan(bss, params)) {
+				wpa_driver_nl80211_set_mode(bss, drv->nlmode);
+				goto fail;
+			}
+
+			/* Restore AP mode when processing scan results */
+			drv->ap_scan_as_station = old_mode;
+			ret = 0;
+		} else
+			goto fail;
+	}
+
+	drv->scan_state = SCAN_REQUESTED;
+	/* Not all drivers generate "scan completed" wireless event, so try to
+	 * read results after a timeout. */
+	timeout = 10;
+	if (drv->scan_complete_events) {
+		/*
+		 * The driver seems to deliver events to notify when scan is
+		 * complete, so use longer timeout to avoid race conditions
+		 * with scanning and following association request.
+		 */
+		timeout = 30;
+	}
+	wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+		   "seconds", ret, timeout);
+	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+	eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
+			       drv, drv->ctx);
+
+fail:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_sched_scan - Initiate a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * @params: Scan parameters
+ * @interval: Interval between scan cycles in milliseconds
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+int wpa_driver_nl80211_sched_scan(void *priv,
+				  struct wpa_driver_scan_params *params,
+				  u32 interval)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret = -1;
+	struct nl_msg *msg;
+	size_t i;
+
+	wpa_dbg(drv->ctx, MSG_DEBUG, "nl80211: sched_scan request");
+
+#ifdef ANDROID
+	if (!drv->capa.sched_scan_supported)
+		return android_pno_start(bss, params);
+#endif /* ANDROID */
+
+	msg = nl80211_scan_common(bss, NL80211_CMD_START_SCHED_SCAN, params);
+	if (!msg ||
+	    nla_put_u32(msg, NL80211_ATTR_SCHED_SCAN_INTERVAL, interval))
+		goto fail;
+
+	if ((drv->num_filter_ssids &&
+	    (int) drv->num_filter_ssids <= drv->capa.max_match_sets) ||
+	    params->filter_rssi) {
+		struct nlattr *match_sets;
+		match_sets = nla_nest_start(msg, NL80211_ATTR_SCHED_SCAN_MATCH);
+		if (match_sets == NULL)
+			goto fail;
+
+		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 = nla_nest_start(msg, i + 1);
+			if (match_set_ssid == NULL ||
+			    nla_put(msg, NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+				    drv->filter_ssids[i].ssid_len,
+				    drv->filter_ssids[i].ssid) ||
+			    (params->filter_rssi &&
+			     nla_put_u32(msg,
+					 NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+					 params->filter_rssi)))
+				goto fail;
+
+			nla_nest_end(msg, match_set_ssid);
+		}
+
+		/*
+		 * Due to backward compatibility code, newer kernels treat this
+		 * matchset (with only an RSSI filter) as the default for all
+		 * other matchsets, unless it's the only one, in which case the
+		 * matchset will actually allow all SSIDs above the RSSI.
+		 */
+		if (params->filter_rssi) {
+			struct nlattr *match_set_rssi;
+			match_set_rssi = nla_nest_start(msg, 0);
+			if (match_set_rssi == NULL ||
+			    nla_put_u32(msg, NL80211_SCHED_SCAN_MATCH_ATTR_RSSI,
+					params->filter_rssi))
+				goto fail;
+			wpa_printf(MSG_MSGDUMP,
+				   "nl80211: Sched scan RSSI filter %d dBm",
+				   params->filter_rssi);
+			nla_nest_end(msg, match_set_rssi);
+		}
+
+		nla_nest_end(msg, match_sets);
+	}
+
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+
+	/* TODO: if we get an error here, we should fall back to normal scan */
+
+	msg = NULL;
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "nl80211: Sched scan start failed: "
+			   "ret=%d (%s)", ret, strerror(-ret));
+		goto fail;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Sched scan requested (ret=%d) - "
+		   "scan interval %d msec", ret, interval);
+
+fail:
+	nlmsg_free(msg);
+	return ret;
+}
+
+
+/**
+ * wpa_driver_nl80211_stop_sched_scan - Stop a scheduled scan
+ * @priv: Pointer to private driver data from wpa_driver_nl80211_init()
+ * Returns: 0 on success, -1 on failure or if not supported
+ */
+int wpa_driver_nl80211_stop_sched_scan(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	int ret;
+	struct nl_msg *msg;
+
+#ifdef ANDROID
+	if (!drv->capa.sched_scan_supported)
+		return android_pno_stop(bss);
+#endif /* ANDROID */
+
+	msg = nl80211_drv_msg(drv, 0, NL80211_CMD_STOP_SCHED_SCAN);
+	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	if (ret) {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Sched scan stop failed: ret=%d (%s)",
+			   ret, strerror(-ret));
+	} else {
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: Sched scan stop sent");
+	}
+
+	return ret;
+}
+
+
+static const u8 * nl80211_get_ie(const u8 *ies, size_t ies_len, u8 ie)
+{
+	const u8 *end, *pos;
+
+	if (ies == NULL)
+		return NULL;
+
+	pos = ies;
+	end = ies + ies_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == ie)
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+
+static int nl80211_scan_filtered(struct wpa_driver_nl80211_data *drv,
+				 const u8 *ie, size_t ie_len)
+{
+	const u8 *ssid;
+	size_t i;
+
+	if (drv->filter_ssids == NULL)
+		return 0;
+
+	ssid = nl80211_get_ie(ie, ie_len, WLAN_EID_SSID);
+	if (ssid == NULL)
+		return 1;
+
+	for (i = 0; i < drv->num_filter_ssids; i++) {
+		if (ssid[1] == drv->filter_ssids[i].ssid_len &&
+		    os_memcmp(ssid + 2, drv->filter_ssids[i].ssid, ssid[1]) ==
+		    0)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+int bss_info_handler(struct nl_msg *msg, void *arg)
+{
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *bss[NL80211_BSS_MAX + 1];
+	static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+		[NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+		[NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+		[NL80211_BSS_TSF] = { .type = NLA_U64 },
+		[NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
+		[NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
+		[NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+		[NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
+		[NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
+		[NL80211_BSS_STATUS] = { .type = NLA_U32 },
+		[NL80211_BSS_SEEN_MS_AGO] = { .type = NLA_U32 },
+		[NL80211_BSS_BEACON_IES] = { .type = NLA_UNSPEC },
+	};
+	struct nl80211_bss_info_arg *_arg = arg;
+	struct wpa_scan_results *res = _arg->res;
+	struct wpa_scan_res **tmp;
+	struct wpa_scan_res *r;
+	const u8 *ie, *beacon_ie;
+	size_t ie_len, beacon_ie_len;
+	u8 *pos;
+	size_t i;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+	if (!tb[NL80211_ATTR_BSS])
+		return NL_SKIP;
+	if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+			     bss_policy))
+		return NL_SKIP;
+	if (bss[NL80211_BSS_STATUS]) {
+		enum nl80211_bss_status status;
+		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+		    bss[NL80211_BSS_FREQUENCY]) {
+			_arg->assoc_freq =
+				nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+			wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
+				   _arg->assoc_freq);
+		}
+		if (status == NL80211_BSS_STATUS_IBSS_JOINED &&
+		    bss[NL80211_BSS_FREQUENCY]) {
+			_arg->ibss_freq =
+				nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+			wpa_printf(MSG_DEBUG, "nl80211: IBSS-joined on %u MHz",
+				   _arg->ibss_freq);
+		}
+		if (status == NL80211_BSS_STATUS_ASSOCIATED &&
+		    bss[NL80211_BSS_BSSID]) {
+			os_memcpy(_arg->assoc_bssid,
+				  nla_data(bss[NL80211_BSS_BSSID]), ETH_ALEN);
+			wpa_printf(MSG_DEBUG, "nl80211: Associated with "
+				   MACSTR, MAC2STR(_arg->assoc_bssid));
+		}
+	}
+	if (!res)
+		return NL_SKIP;
+	if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+		ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+		ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+	} else {
+		ie = NULL;
+		ie_len = 0;
+	}
+	if (bss[NL80211_BSS_BEACON_IES]) {
+		beacon_ie = nla_data(bss[NL80211_BSS_BEACON_IES]);
+		beacon_ie_len = nla_len(bss[NL80211_BSS_BEACON_IES]);
+	} else {
+		beacon_ie = NULL;
+		beacon_ie_len = 0;
+	}
+
+	if (nl80211_scan_filtered(_arg->drv, ie ? ie : beacon_ie,
+				  ie ? ie_len : beacon_ie_len))
+		return NL_SKIP;
+
+	r = os_zalloc(sizeof(*r) + ie_len + beacon_ie_len);
+	if (r == NULL)
+		return NL_SKIP;
+	if (bss[NL80211_BSS_BSSID])
+		os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
+			  ETH_ALEN);
+	if (bss[NL80211_BSS_FREQUENCY])
+		r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+	if (bss[NL80211_BSS_BEACON_INTERVAL])
+		r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
+	if (bss[NL80211_BSS_CAPABILITY])
+		r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
+	r->flags |= WPA_SCAN_NOISE_INVALID;
+	if (bss[NL80211_BSS_SIGNAL_MBM]) {
+		r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
+		r->level /= 100; /* mBm to dBm */
+		r->flags |= WPA_SCAN_LEVEL_DBM | WPA_SCAN_QUAL_INVALID;
+	} else if (bss[NL80211_BSS_SIGNAL_UNSPEC]) {
+		r->level = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
+		r->flags |= WPA_SCAN_QUAL_INVALID;
+	} else
+		r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
+	if (bss[NL80211_BSS_TSF])
+		r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
+	if (bss[NL80211_BSS_SEEN_MS_AGO])
+		r->age = nla_get_u32(bss[NL80211_BSS_SEEN_MS_AGO]);
+	r->ie_len = ie_len;
+	pos = (u8 *) (r + 1);
+	if (ie) {
+		os_memcpy(pos, ie, ie_len);
+		pos += ie_len;
+	}
+	r->beacon_ie_len = beacon_ie_len;
+	if (beacon_ie)
+		os_memcpy(pos, beacon_ie, beacon_ie_len);
+
+	if (bss[NL80211_BSS_STATUS]) {
+		enum nl80211_bss_status status;
+		status = nla_get_u32(bss[NL80211_BSS_STATUS]);
+		switch (status) {
+		case NL80211_BSS_STATUS_AUTHENTICATED:
+			r->flags |= WPA_SCAN_AUTHENTICATED;
+			break;
+		case NL80211_BSS_STATUS_ASSOCIATED:
+			r->flags |= WPA_SCAN_ASSOCIATED;
+			break;
+		default:
+			break;
+		}
+	}
+
+	/*
+	 * cfg80211 maintains separate BSS table entries for APs if the same
+	 * BSSID,SSID pair is seen on multiple channels. wpa_supplicant does
+	 * not use frequency as a separate key in the BSS table, so filter out
+	 * duplicated entries. Prefer associated BSS entry in such a case in
+	 * order to get the correct frequency into the BSS table. Similarly,
+	 * prefer newer entries over older.
+	 */
+	for (i = 0; i < res->num; i++) {
+		const u8 *s1, *s2;
+		if (os_memcmp(res->res[i]->bssid, r->bssid, ETH_ALEN) != 0)
+			continue;
+
+		s1 = nl80211_get_ie((u8 *) (res->res[i] + 1),
+				    res->res[i]->ie_len, WLAN_EID_SSID);
+		s2 = nl80211_get_ie((u8 *) (r + 1), r->ie_len, WLAN_EID_SSID);
+		if (s1 == NULL || s2 == NULL || s1[1] != s2[1] ||
+		    os_memcmp(s1, s2, 2 + s1[1]) != 0)
+			continue;
+
+		/* Same BSSID,SSID was already included in scan results */
+		wpa_printf(MSG_DEBUG, "nl80211: Remove duplicated scan result "
+			   "for " MACSTR, MAC2STR(r->bssid));
+
+		if (((r->flags & WPA_SCAN_ASSOCIATED) &&
+		     !(res->res[i]->flags & WPA_SCAN_ASSOCIATED)) ||
+		    r->age < res->res[i]->age) {
+			os_free(res->res[i]);
+			res->res[i] = r;
+		} else
+			os_free(r);
+		return NL_SKIP;
+	}
+
+	tmp = os_realloc_array(res->res, res->num + 1,
+			       sizeof(struct wpa_scan_res *));
+	if (tmp == NULL) {
+		os_free(r);
+		return NL_SKIP;
+	}
+	tmp[res->num++] = r;
+	res->res = tmp;
+
+	return NL_SKIP;
+}
+
+
+static void clear_state_mismatch(struct wpa_driver_nl80211_data *drv,
+				 const u8 *addr)
+{
+	if (drv->capa.flags & WPA_DRIVER_FLAGS_SME) {
+		wpa_printf(MSG_DEBUG, "nl80211: Clear possible state "
+			   "mismatch (" MACSTR ")", MAC2STR(addr));
+		wpa_driver_nl80211_mlme(drv, addr,
+					NL80211_CMD_DEAUTHENTICATE,
+					WLAN_REASON_PREV_AUTH_NOT_VALID, 1);
+	}
+}
+
+
+static void wpa_driver_nl80211_check_bss_status(
+	struct wpa_driver_nl80211_data *drv, struct wpa_scan_results *res)
+{
+	size_t i;
+
+	for (i = 0; i < res->num; i++) {
+		struct wpa_scan_res *r = res->res[i];
+		if (r->flags & WPA_SCAN_AUTHENTICATED) {
+			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
+				   "indicates BSS status with " MACSTR
+				   " as authenticated",
+				   MAC2STR(r->bssid));
+			if (is_sta_interface(drv->nlmode) &&
+			    os_memcmp(r->bssid, drv->bssid, ETH_ALEN) != 0 &&
+			    os_memcmp(r->bssid, drv->auth_bssid, ETH_ALEN) !=
+			    0) {
+				wpa_printf(MSG_DEBUG, "nl80211: Unknown BSSID"
+					   " in local state (auth=" MACSTR
+					   " assoc=" MACSTR ")",
+					   MAC2STR(drv->auth_bssid),
+					   MAC2STR(drv->bssid));
+				clear_state_mismatch(drv, r->bssid);
+			}
+		}
+
+		if (r->flags & WPA_SCAN_ASSOCIATED) {
+			wpa_printf(MSG_DEBUG, "nl80211: Scan results "
+				   "indicate BSS status with " MACSTR
+				   " as associated",
+				   MAC2STR(r->bssid));
+			if (is_sta_interface(drv->nlmode) &&
+			    !drv->associated) {
+				wpa_printf(MSG_DEBUG, "nl80211: Local state "
+					   "(not associated) does not match "
+					   "with BSS state");
+				clear_state_mismatch(drv, r->bssid);
+			} else if (is_sta_interface(drv->nlmode) &&
+				   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
+				   0) {
+				wpa_printf(MSG_DEBUG, "nl80211: Local state "
+					   "(associated with " MACSTR ") does "
+					   "not match with BSS state",
+					   MAC2STR(drv->bssid));
+				clear_state_mismatch(drv, r->bssid);
+				clear_state_mismatch(drv, drv->bssid);
+			}
+		}
+	}
+}
+
+
+static struct wpa_scan_results *
+nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
+{
+	struct nl_msg *msg;
+	struct wpa_scan_results *res;
+	int ret;
+	struct nl80211_bss_info_arg arg;
+
+	res = os_zalloc(sizeof(*res));
+	if (res == NULL)
+		return NULL;
+	if (!(msg = nl80211_cmd_msg(drv->first_bss, NLM_F_DUMP,
+				    NL80211_CMD_GET_SCAN))) {
+		wpa_scan_results_free(res);
+		return NULL;
+	}
+
+	arg.drv = drv;
+	arg.res = res;
+	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
+	if (ret == 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Received scan results (%lu "
+			   "BSSes)", (unsigned long) res->num);
+		nl80211_get_noise_for_scan_results(drv, res);
+		return res;
+	}
+	wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+		   "(%s)", ret, strerror(-ret));
+	wpa_scan_results_free(res);
+	return NULL;
+}
+
+
+/**
+ * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+struct wpa_scan_results * wpa_driver_nl80211_get_scan_results(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct wpa_scan_results *res;
+
+	res = nl80211_get_scan_results(drv);
+	if (res)
+		wpa_driver_nl80211_check_bss_status(drv, res);
+	return res;
+}
+
+
+void nl80211_dump_scan(struct wpa_driver_nl80211_data *drv)
+{
+	struct wpa_scan_results *res;
+	size_t i;
+
+	res = nl80211_get_scan_results(drv);
+	if (res == NULL) {
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to get scan results");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "nl80211: Scan result dump");
+	for (i = 0; i < res->num; i++) {
+		struct wpa_scan_res *r = res->res[i];
+		wpa_printf(MSG_DEBUG, "nl80211: %d/%d " MACSTR "%s%s",
+			   (int) i, (int) res->num, MAC2STR(r->bssid),
+			   r->flags & WPA_SCAN_AUTHENTICATED ? " [auth]" : "",
+			   r->flags & WPA_SCAN_ASSOCIATED ? " [assoc]" : "");
+	}
+
+	wpa_scan_results_free(res);
+}
diff --git a/src/drivers/driver_none.c b/src/drivers/driver_none.c
index d75c14b..6ff3eae 100644
--- a/src/drivers/driver_none.c
+++ b/src/drivers/driver_none.c
@@ -74,13 +74,6 @@
 }
 
 
-static int none_driver_send_eapol(void *priv, const u8 *dest, u16 proto,
-				  const u8 *data, size_t data_len)
-{
-	return -1;
-}
-
-
 const struct wpa_driver_ops wpa_driver_none_ops = {
 	.name = "none",
 	.desc = "no driver (RADIUS server/WPS ER)",
@@ -89,5 +82,4 @@
 	.send_ether = none_driver_send_ether,
 	.init = none_driver_init,
 	.deinit = none_driver_deinit,
-	.send_eapol = none_driver_send_eapol,
 };
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
index ed88e71..de23fbd 100644
--- a/src/drivers/driver_privsep.c
+++ b/src/drivers/driver_privsep.c
@@ -35,7 +35,7 @@
 		     (struct sockaddr *) &drv->priv_addr,
 		     sizeof(drv->priv_addr));
 	if (res < 0)
-		perror("sendto");
+		wpa_printf(MSG_ERROR, "sendto: %s", strerror(errno));
 	return res < 0 ? -1 : 0;
 }
 
@@ -59,7 +59,8 @@
 	msg.msg_namelen = sizeof(drv->priv_addr);
 
 	if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
-		perror("sendmsg(cmd_socket)");
+		wpa_printf(MSG_ERROR, "sendmsg(cmd_socket): %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -74,14 +75,15 @@
 		tv.tv_usec = 0;
 		res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
 		if (res < 0 && errno != EINTR) {
-			perror("select");
+			wpa_printf(MSG_ERROR, "select: %s", strerror(errno));
 			return -1;
 		}
 
 		if (FD_ISSET(drv->cmd_socket, &rfds)) {
 			res = recv(drv->cmd_socket, reply, *reply_len, 0);
 			if (res < 0) {
-				perror("recv");
+				wpa_printf(MSG_ERROR, "recv: %s",
+					   strerror(errno));
 				return -1;
 			}
 			*reply_len = res;
@@ -228,7 +230,7 @@
 
 	wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
 		   "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
-		   __func__, priv, params->freq, params->pairwise_suite,
+		   __func__, priv, params->freq.freq, params->pairwise_suite,
 		   params->group_suite, params->key_mgmt_suite,
 		   params->auth_alg, params->mode);
 
@@ -241,7 +243,9 @@
 		os_memcpy(data->bssid, params->bssid, ETH_ALEN);
 	os_memcpy(data->ssid, params->ssid, params->ssid_len);
 	data->ssid_len = params->ssid_len;
-	data->freq = params->freq;
+	data->hwmode = params->freq.mode;
+	data->freq = params->freq.freq;
+	data->channel = params->freq.channel;
 	data->pairwise_suite = params->pairwise_suite;
 	data->group_suite = params->group_suite;
 	data->key_mgmt_suite = params->key_mgmt_suite;
@@ -439,7 +443,8 @@
 	res = recvfrom(sock, buf, buflen, 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (res < 0) {
-		perror("recvfrom(priv_socket)");
+		wpa_printf(MSG_ERROR, "recvfrom(priv_socket): %s",
+			   strerror(errno));
 		os_free(buf);
 		return;
 	}
@@ -629,7 +634,7 @@
 
 	drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (drv->priv_socket < 0) {
-		perror("socket(PF_UNIX)");
+		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
 		os_free(drv->own_socket_path);
 		drv->own_socket_path = NULL;
 		return -1;
@@ -640,7 +645,9 @@
 	os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
 	if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
 	    0) {
-		perror("privsep-set-params priv-sock: bind(PF_UNIX)");
+		wpa_printf(MSG_ERROR,
+			   "privsep-set-params priv-sock: bind(PF_UNIX): %s",
+			   strerror(errno));
 		close(drv->priv_socket);
 		drv->priv_socket = -1;
 		unlink(drv->own_socket_path);
@@ -654,7 +661,7 @@
 
 	drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (drv->cmd_socket < 0) {
-		perror("socket(PF_UNIX)");
+		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
 		os_free(drv->own_cmd_path);
 		drv->own_cmd_path = NULL;
 		return -1;
@@ -665,7 +672,9 @@
 	os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
 	if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
 	{
-		perror("privsep-set-params cmd-sock: bind(PF_UNIX)");
+		wpa_printf(MSG_ERROR,
+			   "privsep-set-params cmd-sock: bind(PF_UNIX): %s",
+			   strerror(errno));
 		close(drv->cmd_socket);
 		drv->cmd_socket = -1;
 		unlink(drv->own_cmd_path);
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index 9ce3fa2..d3e0595 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -91,7 +91,8 @@
 	mii->reg_num = reg;
 
 	if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) {
-		perror("ioctl[SIOCGMIIREG]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGMIIREG]: %s",
+			   strerror(errno));
 		return 0x00;
 	}
 	return mii->val_out;
@@ -108,7 +109,8 @@
 	mii->val_in = val;
 
 	if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) {
-		perror("ioctl[SIOCSMIIREG");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSMIIREG]: %s",
+			   strerror(errno));
 	}
 }
 
@@ -394,7 +396,8 @@
 	os_memset(&drv->ifr, 0, sizeof(drv->ifr));
 	os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ);
 	if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) {
-		perror("ioctl[SIOCGMIIPHY]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGMIIPHY]: %s",
+			   strerror(errno));
 		os_free(drv);
 		return NULL;
 	}
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
deleted file mode 100644
index 66edfa7..0000000
--- a/src/drivers/driver_test.c
+++ /dev/null
@@ -1,2683 +0,0 @@
-/*
- * Testing driver interface for a simulated network driver
- * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
- *
- * This software may be distributed under the terms of the BSD license.
- * See README for more details.
- */
-
-/* Make sure we get winsock2.h for Windows build to get sockaddr_storage */
-#include "build_config.h"
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock2.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#include "utils/includes.h"
-
-#ifndef CONFIG_NATIVE_WINDOWS
-#include <sys/un.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#define DRIVER_TEST_UNIX
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-#include "utils/common.h"
-#include "utils/eloop.h"
-#include "utils/list.h"
-#include "utils/trace.h"
-#include "common/ieee802_11_defs.h"
-#include "crypto/sha1.h"
-#include "l2_packet/l2_packet.h"
-#include "wps/wps.h"
-#include "driver.h"
-
-
-struct test_client_socket {
-	struct test_client_socket *next;
-	u8 addr[ETH_ALEN];
-	struct sockaddr_un un;
-	socklen_t unlen;
-	struct test_driver_bss *bss;
-};
-
-struct test_driver_bss {
-	struct wpa_driver_test_data *drv;
-	struct dl_list list;
-	void *bss_ctx;
-	char ifname[IFNAMSIZ];
-	u8 bssid[ETH_ALEN];
-	u8 *ie;
-	size_t ielen;
-	u8 *wps_beacon_ie;
-	size_t wps_beacon_ie_len;
-	u8 *wps_probe_resp_ie;
-	size_t wps_probe_resp_ie_len;
-	u8 ssid[32];
-	size_t ssid_len;
-	int privacy;
-};
-
-struct wpa_driver_test_global {
-	int bss_add_used;
-	u8 req_addr[ETH_ALEN];
-};
-
-struct wpa_driver_test_data {
-	struct wpa_driver_test_global *global;
-	void *ctx;
-	WPA_TRACE_REF(ctx);
-	u8 own_addr[ETH_ALEN];
-	int test_socket;
-#ifdef DRIVER_TEST_UNIX
-	struct sockaddr_un hostapd_addr;
-#endif /* DRIVER_TEST_UNIX */
-	int hostapd_addr_set;
-	struct sockaddr_in hostapd_addr_udp;
-	int hostapd_addr_udp_set;
-	char *own_socket_path;
-	char *test_dir;
-#define MAX_SCAN_RESULTS 30
-	struct wpa_scan_res *scanres[MAX_SCAN_RESULTS];
-	size_t num_scanres;
-	int use_associnfo;
-	u8 assoc_wpa_ie[80];
-	size_t assoc_wpa_ie_len;
-	int associated;
-	u8 *probe_req_ie;
-	size_t probe_req_ie_len;
-	u8 probe_req_ssid[32];
-	size_t probe_req_ssid_len;
-	int ibss;
-	int ap;
-
-	struct test_client_socket *cli;
-	struct dl_list bss;
-	int udp_port;
-
-	int alloc_iface_idx;
-
-	int probe_req_report;
-	unsigned int remain_on_channel_freq;
-	unsigned int remain_on_channel_duration;
-
-	int current_freq;
-};
-
-
-static void wpa_driver_test_deinit(void *priv);
-static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
-				  const char *dir, int ap);
-static void wpa_driver_test_close_test_socket(
-	struct wpa_driver_test_data *drv);
-static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx);
-
-
-static void test_driver_free_bss(struct test_driver_bss *bss)
-{
-	os_free(bss->ie);
-	os_free(bss->wps_beacon_ie);
-	os_free(bss->wps_probe_resp_ie);
-	os_free(bss);
-}
-
-
-static void test_driver_free_bsses(struct wpa_driver_test_data *drv)
-{
-	struct test_driver_bss *bss, *tmp;
-
-	dl_list_for_each_safe(bss, tmp, &drv->bss, struct test_driver_bss,
-			      list) {
-		dl_list_del(&bss->list);
-		test_driver_free_bss(bss);
-	}
-}
-
-
-static struct test_client_socket *
-test_driver_get_cli(struct wpa_driver_test_data *drv, struct sockaddr_un *from,
-		    socklen_t fromlen)
-{
-	struct test_client_socket *cli = drv->cli;
-
-	while (cli) {
-		if (cli->unlen == fromlen &&
-		    strncmp(cli->un.sun_path, from->sun_path,
-			    fromlen - sizeof(cli->un.sun_family)) == 0)
-			return cli;
-		cli = cli->next;
-	}
-
-	return NULL;
-}
-
-
-static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data,
-				  size_t data_len, int encrypt,
-				  const u8 *own_addr, u32 flags)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_client_socket *cli;
-	struct msghdr msg;
-	struct iovec io[3];
-	struct l2_ethhdr eth;
-
-	if (drv->test_socket < 0)
-		return -1;
-
-	cli = drv->cli;
-	while (cli) {
-		if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
-			break;
-		cli = cli->next;
-	}
-
-	if (!cli) {
-		wpa_printf(MSG_DEBUG, "%s: no destination client entry",
-			   __func__);
-		return -1;
-	}
-
-	memcpy(eth.h_dest, addr, ETH_ALEN);
-	memcpy(eth.h_source, own_addr, ETH_ALEN);
-	eth.h_proto = host_to_be16(ETH_P_EAPOL);
-
-	io[0].iov_base = "EAPOL ";
-	io[0].iov_len = 6;
-	io[1].iov_base = &eth;
-	io[1].iov_len = sizeof(eth);
-	io[2].iov_base = (u8 *) data;
-	io[2].iov_len = data_len;
-
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 3;
-	msg.msg_name = &cli->un;
-	msg.msg_namelen = cli->unlen;
-	return sendmsg(drv->test_socket, &msg, 0);
-}
-
-
-static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
-				  u16 proto, const u8 *data, size_t data_len)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct msghdr msg;
-	struct iovec io[3];
-	struct l2_ethhdr eth;
-	char desttxt[30];
-	struct sockaddr_un addr;
-	struct dirent *dent;
-	DIR *dir;
-	int ret = 0, broadcast = 0, count = 0;
-
-	if (drv->test_socket < 0 || drv->test_dir == NULL) {
-		wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d "
-			   "test_dir=%p)",
-			   __func__, drv->test_socket, drv->test_dir);
-		return -1;
-	}
-
-	broadcast = memcmp(dst, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
-	snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dst));
-
-	memcpy(eth.h_dest, dst, ETH_ALEN);
-	memcpy(eth.h_source, src, ETH_ALEN);
-	eth.h_proto = host_to_be16(proto);
-
-	io[0].iov_base = "ETHER ";
-	io[0].iov_len = 6;
-	io[1].iov_base = &eth;
-	io[1].iov_len = sizeof(eth);
-	io[2].iov_base = (u8 *) data;
-	io[2].iov_len = data_len;
-
-	memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 3;
-
-	dir = opendir(drv->test_dir);
-	if (dir == NULL) {
-		perror("test_driver: opendir");
-		return -1;
-	}
-	while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
-		/* Skip the file if it is not a socket. Also accept
-		 * DT_UNKNOWN (0) in case the C library or underlying file
-		 * system does not support d_type. */
-		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
-			continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
-		if (strcmp(dent->d_name, ".") == 0 ||
-		    strcmp(dent->d_name, "..") == 0)
-			continue;
-
-		memset(&addr, 0, sizeof(addr));
-		addr.sun_family = AF_UNIX;
-		snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
-			 drv->test_dir, dent->d_name);
-
-		if (strcmp(addr.sun_path, drv->own_socket_path) == 0)
-			continue;
-		if (!broadcast && strstr(dent->d_name, desttxt) == NULL)
-			continue;
-
-		wpa_printf(MSG_DEBUG, "%s: Send ether frame to %s",
-			   __func__, dent->d_name);
-
-		msg.msg_name = &addr;
-		msg.msg_namelen = sizeof(addr);
-		ret = sendmsg(drv->test_socket, &msg, 0);
-		if (ret < 0)
-			perror("driver_test: sendmsg");
-		count++;
-	}
-	closedir(dir);
-
-	if (!broadcast && count == 0) {
-		wpa_printf(MSG_DEBUG, "%s: Destination " MACSTR " not found",
-			   __func__, MAC2STR(dst));
-		return -1;
-	}
-
-	return ret;
-}
-
-
-static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
-				     size_t data_len, int noack)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct msghdr msg;
-	struct iovec io[2];
-	const u8 *dest;
-	struct sockaddr_un addr;
-	struct dirent *dent;
-	DIR *dir;
-	int broadcast;
-	int ret = 0;
-	struct ieee80211_hdr *hdr;
-	u16 fc;
-	char cmd[50];
-	int freq;
-#ifdef HOSTAPD
-	char desttxt[30];
-#endif /* HOSTAPD */
-	union wpa_event_data event;
-
-	wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len);
-	if (drv->test_socket < 0 || data_len < 10) {
-		wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d len=%lu"
-			   " test_dir=%p)",
-			   __func__, drv->test_socket,
-			   (unsigned long) data_len,
-			   drv->test_dir);
-		return -1;
-	}
-
-	dest = data + 4;
-	broadcast = os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
-
-#ifdef HOSTAPD
-	snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest));
-#endif /* HOSTAPD */
-
-	if (drv->remain_on_channel_freq)
-		freq = drv->remain_on_channel_freq;
-	else
-		freq = drv->current_freq;
-	wpa_printf(MSG_DEBUG, "test_driver(%s): MLME TX on freq %d MHz",
-		   dbss->ifname, freq);
-	os_snprintf(cmd, sizeof(cmd), "MLME freq=%d ", freq);
-	io[0].iov_base = cmd;
-	io[0].iov_len = os_strlen(cmd);
-	io[1].iov_base = (void *) data;
-	io[1].iov_len = data_len;
-
-	os_memset(&msg, 0, sizeof(msg));
-	msg.msg_iov = io;
-	msg.msg_iovlen = 2;
-
-#ifdef HOSTAPD
-	if (drv->test_dir == NULL) {
-		wpa_printf(MSG_DEBUG, "%s: test_dir == NULL", __func__);
-		return -1;
-	}
-
-	dir = opendir(drv->test_dir);
-	if (dir == NULL) {
-		perror("test_driver: opendir");
-		return -1;
-	}
-	while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
-		/* Skip the file if it is not a socket. Also accept
-		 * DT_UNKNOWN (0) in case the C library or underlying file
-		 * system does not support d_type. */
-		if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
-			continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
-		if (os_strcmp(dent->d_name, ".") == 0 ||
-		    os_strcmp(dent->d_name, "..") == 0)
-			continue;
-
-		os_memset(&addr, 0, sizeof(addr));
-		addr.sun_family = AF_UNIX;
-		os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
-			    drv->test_dir, dent->d_name);
-
-		if (os_strcmp(addr.sun_path, drv->own_socket_path) == 0)
-			continue;
-		if (!broadcast && os_strstr(dent->d_name, desttxt) == NULL)
-			continue;
-
-		wpa_printf(MSG_DEBUG, "%s: Send management frame to %s",
-			   __func__, dent->d_name);
-
-		msg.msg_name = &addr;
-		msg.msg_namelen = sizeof(addr);
-		ret = sendmsg(drv->test_socket, &msg, 0);
-		if (ret < 0)
-			perror("driver_test: sendmsg(test_socket)");
-	}
-	closedir(dir);
-#else /* HOSTAPD */
-
-	if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 ||
-	    drv->test_dir == NULL) {
-		if (drv->hostapd_addr_udp_set) {
-			msg.msg_name = &drv->hostapd_addr_udp;
-			msg.msg_namelen = sizeof(drv->hostapd_addr_udp);
-		} else {
-#ifdef DRIVER_TEST_UNIX
-			msg.msg_name = &drv->hostapd_addr;
-			msg.msg_namelen = sizeof(drv->hostapd_addr);
-#endif /* DRIVER_TEST_UNIX */
-		}
-	} else if (broadcast) {
-		dir = opendir(drv->test_dir);
-		if (dir == NULL)
-			return -1;
-		while ((dent = readdir(dir))) {
-#ifdef _DIRENT_HAVE_D_TYPE
-			/* Skip the file if it is not a socket.
-			 * Also accept DT_UNKNOWN (0) in case
-			 * the C library or underlying file
-			 * system does not support d_type. */
-			if (dent->d_type != DT_SOCK &&
-			    dent->d_type != DT_UNKNOWN)
-				continue;
-#endif /* _DIRENT_HAVE_D_TYPE */
-			if (os_strcmp(dent->d_name, ".") == 0 ||
-			    os_strcmp(dent->d_name, "..") == 0)
-				continue;
-			wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s",
-				   __func__, dent->d_name);
-			os_memset(&addr, 0, sizeof(addr));
-			addr.sun_family = AF_UNIX;
-			os_snprintf(addr.sun_path, sizeof(addr.sun_path),
-				    "%s/%s", drv->test_dir, dent->d_name);
-
-			msg.msg_name = &addr;
-			msg.msg_namelen = sizeof(addr);
-
-			ret = sendmsg(drv->test_socket, &msg, 0);
-			if (ret < 0)
-				perror("driver_test: sendmsg(test_socket)");
-		}
-		closedir(dir);
-		return ret;
-	} else {
-		struct stat st;
-		os_memset(&addr, 0, sizeof(addr));
-		addr.sun_family = AF_UNIX;
-		os_snprintf(addr.sun_path, sizeof(addr.sun_path),
-			    "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest));
-		if (stat(addr.sun_path, &st) < 0) {
-			os_snprintf(addr.sun_path, sizeof(addr.sun_path),
-				    "%s/STA-" MACSTR,
-				    drv->test_dir, MAC2STR(dest));
-		}
-		msg.msg_name = &addr;
-		msg.msg_namelen = sizeof(addr);
-	}
-
-	if (sendmsg(drv->test_socket, &msg, 0) < 0) {
-		perror("sendmsg(test_socket)");
-		return -1;
-	}
-#endif /* HOSTAPD */
-
-	hdr = (struct ieee80211_hdr *) data;
-	fc = le_to_host16(hdr->frame_control);
-
-	os_memset(&event, 0, sizeof(event));
-	event.tx_status.type = WLAN_FC_GET_TYPE(fc);
-	event.tx_status.stype = WLAN_FC_GET_STYPE(fc);
-	event.tx_status.dst = hdr->addr1;
-	event.tx_status.data = data;
-	event.tx_status.data_len = data_len;
-	event.tx_status.ack = ret >= 0;
-	wpa_supplicant_event(drv->ctx, EVENT_TX_STATUS, &event);
-
-	return ret;
-}
-
-
-static void test_driver_scan(struct wpa_driver_test_data *drv,
-			     struct sockaddr_un *from, socklen_t fromlen,
-			     char *data)
-{
-	char buf[512], *pos, *end;
-	int ret;
-	struct test_driver_bss *bss;
-	u8 sa[ETH_ALEN];
-	u8 ie[512];
-	size_t ielen;
-	union wpa_event_data event;
-
-	/* data: optional [ ' ' | STA-addr | ' ' | IEs(hex) ] */
-
-	wpa_printf(MSG_DEBUG, "test_driver: SCAN");
-
-	if (*data) {
-		if (*data != ' ' ||
-		    hwaddr_aton(data + 1, sa)) {
-			wpa_printf(MSG_DEBUG, "test_driver: Unexpected SCAN "
-				   "command format");
-			return;
-		}
-
-		data += 18;
-		while (*data == ' ')
-			data++;
-		ielen = os_strlen(data) / 2;
-		if (ielen > sizeof(ie))
-			ielen = sizeof(ie);
-		if (hexstr2bin(data, ie, ielen) < 0)
-			ielen = 0;
-
-		wpa_printf(MSG_DEBUG, "test_driver: Scan from " MACSTR,
-			   MAC2STR(sa));
-		wpa_hexdump(MSG_MSGDUMP, "test_driver: scan IEs", ie, ielen);
-
-		os_memset(&event, 0, sizeof(event));
-		event.rx_probe_req.sa = sa;
-		event.rx_probe_req.ie = ie;
-		event.rx_probe_req.ie_len = ielen;
-		wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event);
-	}
-
-	dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
-		pos = buf;
-		end = buf + sizeof(buf);
-
-		/* reply: SCANRESP BSSID SSID IEs */
-		ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
-			       MAC2STR(bss->bssid));
-		if (ret < 0 || ret >= end - pos)
-			return;
-		pos += ret;
-		pos += wpa_snprintf_hex(pos, end - pos,
-					bss->ssid, bss->ssid_len);
-		ret = snprintf(pos, end - pos, " ");
-		if (ret < 0 || ret >= end - pos)
-			return;
-		pos += ret;
-		pos += wpa_snprintf_hex(pos, end - pos, bss->ie, bss->ielen);
-		pos += wpa_snprintf_hex(pos, end - pos, bss->wps_probe_resp_ie,
-					bss->wps_probe_resp_ie_len);
-
-		if (bss->privacy) {
-			ret = snprintf(pos, end - pos, " PRIVACY");
-			if (ret < 0 || ret >= end - pos)
-				return;
-			pos += ret;
-		}
-
-		sendto(drv->test_socket, buf, pos - buf, 0,
-		       (struct sockaddr *) from, fromlen);
-	}
-}
-
-
-static void test_driver_assoc(struct wpa_driver_test_data *drv,
-			      struct sockaddr_un *from, socklen_t fromlen,
-			      char *data)
-{
-	struct test_client_socket *cli;
-	u8 ie[256], ssid[32];
-	size_t ielen, ssid_len = 0;
-	char *pos, *pos2, cmd[50];
-	struct test_driver_bss *bss, *tmp;
-
-	/* data: STA-addr SSID(hex) IEs(hex) */
-
-	cli = os_zalloc(sizeof(*cli));
-	if (cli == NULL)
-		return;
-
-	if (hwaddr_aton(data, cli->addr)) {
-		printf("test_socket: Invalid MAC address '%s' in ASSOC\n",
-		       data);
-		os_free(cli);
-		return;
-	}
-	pos = data + 17;
-	while (*pos == ' ')
-		pos++;
-	pos2 = strchr(pos, ' ');
-	ielen = 0;
-	if (pos2) {
-		ssid_len = (pos2 - pos) / 2;
-		if (hexstr2bin(pos, ssid, ssid_len) < 0) {
-			wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__);
-			os_free(cli);
-			return;
-		}
-		wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID",
-				  ssid, ssid_len);
-
-		pos = pos2 + 1;
-		ielen = strlen(pos) / 2;
-		if (ielen > sizeof(ie))
-			ielen = sizeof(ie);
-		if (hexstr2bin(pos, ie, ielen) < 0)
-			ielen = 0;
-	}
-
-	bss = NULL;
-	dl_list_for_each(tmp, &drv->bss, struct test_driver_bss, list) {
-		if (tmp->ssid_len == ssid_len &&
-		    os_memcmp(tmp->ssid, ssid, ssid_len) == 0) {
-			bss = tmp;
-			break;
-		}
-	}
-	if (bss == NULL) {
-		wpa_printf(MSG_DEBUG, "%s: No matching SSID found from "
-			   "configured BSSes", __func__);
-		os_free(cli);
-		return;
-	}
-
-	cli->bss = bss;
-	memcpy(&cli->un, from, sizeof(cli->un));
-	cli->unlen = fromlen;
-	cli->next = drv->cli;
-	drv->cli = cli;
-	wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path",
-			  (const u8 *) cli->un.sun_path,
-			  cli->unlen - sizeof(cli->un.sun_family));
-
-	snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0",
-		 MAC2STR(bss->bssid));
-	sendto(drv->test_socket, cmd, strlen(cmd), 0,
-	       (struct sockaddr *) from, fromlen);
-
-	drv_event_assoc(bss->bss_ctx, cli->addr, ie, ielen, 0);
-}
-
-
-static void test_driver_disassoc(struct wpa_driver_test_data *drv,
-				 struct sockaddr_un *from, socklen_t fromlen)
-{
-	struct test_client_socket *cli;
-
-	cli = test_driver_get_cli(drv, from, fromlen);
-	if (!cli)
-		return;
-
-	drv_event_disassoc(drv->ctx, cli->addr);
-}
-
-
-static void test_driver_eapol(struct wpa_driver_test_data *drv,
-			      struct sockaddr_un *from, socklen_t fromlen,
-			      u8 *data, size_t datalen)
-{
-#ifdef HOSTAPD
-	struct test_client_socket *cli;
-#endif /* HOSTAPD */
-	const u8 *src = NULL;
-
-	if (datalen > 14) {
-		/* Skip Ethernet header */
-		src = data + ETH_ALEN;
-		wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src="
-			   MACSTR " proto=%04x",
-			   MAC2STR(data), MAC2STR(src),
-			   WPA_GET_BE16(data + 2 * ETH_ALEN));
-		data += 14;
-		datalen -= 14;
-	}
-
-#ifdef HOSTAPD
-	cli = test_driver_get_cli(drv, from, fromlen);
-	if (cli) {
-		drv_event_eapol_rx(cli->bss->bss_ctx, cli->addr, data,
-				   datalen);
-	} else {
-		wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown "
-			   "client");
-	}
-#else /* HOSTAPD */
-	if (src)
-		drv_event_eapol_rx(drv->ctx, src, data, datalen);
-#endif /* HOSTAPD */
-}
-
-
-static void test_driver_ether(struct wpa_driver_test_data *drv,
-			      struct sockaddr_un *from, socklen_t fromlen,
-			      u8 *data, size_t datalen)
-{
-	struct l2_ethhdr *eth;
-
-	if (datalen < sizeof(*eth))
-		return;
-
-	eth = (struct l2_ethhdr *) data;
-	wpa_printf(MSG_DEBUG, "test_driver: RX ETHER dst=" MACSTR " src="
-		   MACSTR " proto=%04x",
-		   MAC2STR(eth->h_dest), MAC2STR(eth->h_source),
-		   be_to_host16(eth->h_proto));
-
-#ifdef CONFIG_IEEE80211R
-	if (be_to_host16(eth->h_proto) == ETH_P_RRB) {
-		union wpa_event_data ev;
-		os_memset(&ev, 0, sizeof(ev));
-		ev.ft_rrb_rx.src = eth->h_source;
-		ev.ft_rrb_rx.data = data + sizeof(*eth);
-		ev.ft_rrb_rx.data_len = datalen - sizeof(*eth);
-	}
-#endif /* CONFIG_IEEE80211R */
-}
-
-
-static void test_driver_mlme(struct wpa_driver_test_data *drv,
-			     struct sockaddr_un *from, socklen_t fromlen,
-			     u8 *data, size_t datalen)
-{
-	struct ieee80211_hdr *hdr;
-	u16 fc;
-	union wpa_event_data event;
-	int freq = 0, own_freq;
-	struct test_driver_bss *bss;
-
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
-	if (datalen > 6 && os_memcmp(data, "freq=", 5) == 0) {
-		size_t pos;
-		for (pos = 5; pos < datalen; pos++) {
-			if (data[pos] == ' ')
-				break;
-		}
-		if (pos < datalen) {
-			freq = atoi((const char *) &data[5]);
-			wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
-				   "freq %d MHz", bss->ifname, freq);
-			pos++;
-			data += pos;
-			datalen -= pos;
-		}
-	}
-
-	if (drv->remain_on_channel_freq)
-		own_freq = drv->remain_on_channel_freq;
-	else
-		own_freq = drv->current_freq;
-
-	if (freq && own_freq && freq != own_freq) {
-		wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
-			   "another frequency %d MHz (own %d MHz)",
-			   bss->ifname, freq, own_freq);
-		return;
-	}
-
-	hdr = (struct ieee80211_hdr *) data;
-
-	if (test_driver_get_cli(drv, from, fromlen) == NULL && datalen >= 16) {
-		struct test_client_socket *cli;
-		cli = os_zalloc(sizeof(*cli));
-		if (cli == NULL)
-			return;
-		wpa_printf(MSG_DEBUG, "Adding client entry for " MACSTR,
-			   MAC2STR(hdr->addr2));
-		memcpy(cli->addr, hdr->addr2, ETH_ALEN);
-		memcpy(&cli->un, from, sizeof(cli->un));
-		cli->unlen = fromlen;
-		cli->next = drv->cli;
-		drv->cli = cli;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "test_driver_mlme: received frame",
-		    data, datalen);
-	fc = le_to_host16(hdr->frame_control);
-	if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) {
-		wpa_printf(MSG_ERROR, "%s: received non-mgmt frame",
-			   __func__);
-		return;
-	}
-
-	os_memset(&event, 0, sizeof(event));
-	event.rx_mgmt.frame = data;
-	event.rx_mgmt.frame_len = datalen;
-	wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
-}
-
-
-static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx)
-{
-	struct wpa_driver_test_data *drv = eloop_ctx;
-	char buf[2000];
-	int res;
-	struct sockaddr_un from;
-	socklen_t fromlen = sizeof(from);
-
-	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
-		       (struct sockaddr *) &from, &fromlen);
-	if (res < 0) {
-		perror("recvfrom(test_socket)");
-		return;
-	}
-	buf[res] = '\0';
-
-	wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
-
-	if (strncmp(buf, "SCAN", 4) == 0) {
-		test_driver_scan(drv, &from, fromlen, buf + 4);
-	} else if (strncmp(buf, "ASSOC ", 6) == 0) {
-		test_driver_assoc(drv, &from, fromlen, buf + 6);
-	} else if (strcmp(buf, "DISASSOC") == 0) {
-		test_driver_disassoc(drv, &from, fromlen);
-	} else if (strncmp(buf, "EAPOL ", 6) == 0) {
-		test_driver_eapol(drv, &from, fromlen, (u8 *) buf + 6,
-				  res - 6);
-	} else if (strncmp(buf, "ETHER ", 6) == 0) {
-		test_driver_ether(drv, &from, fromlen, (u8 *) buf + 6,
-				  res - 6);
-	} else if (strncmp(buf, "MLME ", 5) == 0) {
-		test_driver_mlme(drv, &from, fromlen, (u8 *) buf + 5, res - 5);
-	} else {
-		wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
-				  (u8 *) buf, res);
-	}
-}
-
-
-static int test_driver_set_generic_elem(void *priv,
-					const u8 *elem, size_t elem_len)
-{
-	struct test_driver_bss *bss = priv;
-
-	os_free(bss->ie);
-
-	if (elem == NULL) {
-		bss->ie = NULL;
-		bss->ielen = 0;
-		return 0;
-	}
-
-	bss->ie = os_malloc(elem_len);
-	if (bss->ie == NULL) {
-		bss->ielen = 0;
-		return -1;
-	}
-
-	memcpy(bss->ie, elem, elem_len);
-	bss->ielen = elem_len;
-	return 0;
-}
-
-
-static int test_driver_set_ap_wps_ie(void *priv, const struct wpabuf *beacon,
-				     const struct wpabuf *proberesp,
-				     const struct wpabuf *assocresp)
-{
-	struct test_driver_bss *bss = priv;
-
-	if (beacon == NULL)
-		wpa_printf(MSG_DEBUG, "test_driver: Clear Beacon WPS IE");
-	else
-		wpa_hexdump_buf(MSG_DEBUG, "test_driver: Beacon WPS IE",
-				beacon);
-
-	os_free(bss->wps_beacon_ie);
-
-	if (beacon == NULL) {
-		bss->wps_beacon_ie = NULL;
-		bss->wps_beacon_ie_len = 0;
-	} else {
-		bss->wps_beacon_ie = os_malloc(wpabuf_len(beacon));
-		if (bss->wps_beacon_ie == NULL) {
-			bss->wps_beacon_ie_len = 0;
-			return -1;
-		}
-
-		os_memcpy(bss->wps_beacon_ie, wpabuf_head(beacon),
-			  wpabuf_len(beacon));
-		bss->wps_beacon_ie_len = wpabuf_len(beacon);
-	}
-
-	if (proberesp == NULL)
-		wpa_printf(MSG_DEBUG, "test_driver: Clear Probe Response WPS "
-			   "IE");
-	else
-		wpa_hexdump_buf(MSG_DEBUG, "test_driver: Probe Response WPS "
-				"IE", proberesp);
-
-	os_free(bss->wps_probe_resp_ie);
-
-	if (proberesp == NULL) {
-		bss->wps_probe_resp_ie = NULL;
-		bss->wps_probe_resp_ie_len = 0;
-	} else {
-		bss->wps_probe_resp_ie = os_malloc(wpabuf_len(proberesp));
-		if (bss->wps_probe_resp_ie == NULL) {
-			bss->wps_probe_resp_ie_len = 0;
-			return -1;
-		}
-
-		os_memcpy(bss->wps_probe_resp_ie, wpabuf_head(proberesp),
-			  wpabuf_len(proberesp));
-		bss->wps_probe_resp_ie_len = wpabuf_len(proberesp);
-	}
-
-	return 0;
-}
-
-
-static int test_driver_sta_deauth(void *priv, const u8 *own_addr,
-				  const u8 *addr, int reason)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_client_socket *cli;
-
-	if (drv->test_socket < 0)
-		return -1;
-
-	cli = drv->cli;
-	while (cli) {
-		if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
-			break;
-		cli = cli->next;
-	}
-
-	if (!cli)
-		return -1;
-
-	return sendto(drv->test_socket, "DEAUTH", 6, 0,
-		      (struct sockaddr *) &cli->un, cli->unlen);
-}
-
-
-static int test_driver_sta_disassoc(void *priv, const u8 *own_addr,
-				    const u8 *addr, int reason)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_client_socket *cli;
-
-	if (drv->test_socket < 0)
-		return -1;
-
-	cli = drv->cli;
-	while (cli) {
-		if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
-			break;
-		cli = cli->next;
-	}
-
-	if (!cli)
-		return -1;
-
-	return sendto(drv->test_socket, "DISASSOC", 8, 0,
-		      (struct sockaddr *) &cli->un, cli->unlen);
-}
-
-
-static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid,
-			       void *bss_ctx, void **drv_priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_driver_bss *bss;
-
-	wpa_printf(MSG_DEBUG, "%s(ifname=%s bssid=" MACSTR ")",
-		   __func__, ifname, MAC2STR(bssid));
-
-	bss = os_zalloc(sizeof(*bss));
-	if (bss == NULL)
-		return -1;
-
-	bss->bss_ctx = bss_ctx;
-	bss->drv = drv;
-	os_strlcpy(bss->ifname, ifname, IFNAMSIZ);
-	os_memcpy(bss->bssid, bssid, ETH_ALEN);
-
-	dl_list_add(&drv->bss, &bss->list);
-	if (drv->global) {
-		drv->global->bss_add_used = 1;
-		os_memcpy(drv->global->req_addr, bssid, ETH_ALEN);
-	}
-
-	if (drv_priv)
-		*drv_priv = bss;
-
-	return 0;
-}
-
-
-static int test_driver_bss_remove(void *priv, const char *ifname)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_driver_bss *bss;
-	struct test_client_socket *cli, *prev_c;
-
-	wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname);
-
-	dl_list_for_each(bss, &drv->bss, struct test_driver_bss, list) {
-		if (strcmp(bss->ifname, ifname) != 0)
-			continue;
-
-		for (prev_c = NULL, cli = drv->cli; cli;
-		     prev_c = cli, cli = cli->next) {
-			if (cli->bss != bss)
-				continue;
-			if (prev_c)
-				prev_c->next = cli->next;
-			else
-				drv->cli = cli->next;
-			os_free(cli);
-			break;
-		}
-
-		dl_list_del(&bss->list);
-		test_driver_free_bss(bss);
-		return 0;
-	}
-
-	return -1;
-}
-
-
-static int test_driver_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, int use_existing)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-
-	wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s bss_ctx=%p)",
-		   __func__, type, ifname, bss_ctx);
-	if (addr)
-		os_memcpy(if_addr, addr, ETH_ALEN);
-	else {
-		drv->alloc_iface_idx++;
-		if_addr[0] = 0x02; /* locally administered */
-		sha1_prf(drv->own_addr, ETH_ALEN,
-			 "hostapd test addr generation",
-			 (const u8 *) &drv->alloc_iface_idx,
-			 sizeof(drv->alloc_iface_idx),
-			 if_addr + 1, ETH_ALEN - 1);
-	}
-	if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO ||
-	    type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP)
-		return test_driver_bss_add(priv, ifname, if_addr, bss_ctx,
-					   drv_priv);
-	return 0;
-}
-
-
-static int test_driver_if_remove(void *priv, enum wpa_driver_if_type type,
-				 const char *ifname)
-{
-	wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname);
-	if (type == WPA_IF_AP_BSS || type == WPA_IF_P2P_GO ||
-	    type == WPA_IF_P2P_CLIENT || type == WPA_IF_P2P_GROUP)
-		return test_driver_bss_remove(priv, ifname);
-	return 0;
-}
-
-
-static int test_driver_set_ssid(void *priv, const u8 *buf, int len)
-{
-	struct test_driver_bss *bss = priv;
-
-	wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, bss->ifname);
-	if (len < 0)
-		return -1;
-	wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len);
-
-	if ((size_t) len > sizeof(bss->ssid))
-		return -1;
-
-	os_memcpy(bss->ssid, buf, len);
-	bss->ssid_len = len;
-
-	return 0;
-}
-
-
-static int test_driver_set_privacy(void *priv, int enabled)
-{
-	struct test_driver_bss *dbss = priv;
-
-	wpa_printf(MSG_DEBUG, "%s(enabled=%d)",  __func__, enabled);
-	dbss->privacy = enabled;
-
-	return 0;
-}
-
-
-static int test_driver_set_sta_vlan(void *priv, const u8 *addr,
-				    const char *ifname, int vlan_id)
-{
-	wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " ifname=%s vlan_id=%d)",
-		   __func__, MAC2STR(addr), ifname, vlan_id);
-	return 0;
-}
-
-
-static int test_driver_sta_add(void *priv,
-			       struct hostapd_sta_add_params *params)
-{
-	struct test_driver_bss *bss = priv;
-	struct wpa_driver_test_data *drv = bss->drv;
-	struct test_client_socket *cli;
-
-	wpa_printf(MSG_DEBUG, "%s(ifname=%s addr=" MACSTR " aid=%d "
-		   "capability=0x%x listen_interval=%d)",
-		   __func__, bss->ifname, MAC2STR(params->addr), params->aid,
-		   params->capability, params->listen_interval);
-	wpa_hexdump(MSG_DEBUG, "test_driver_sta_add - supp_rates",
-		    params->supp_rates, params->supp_rates_len);
-
-	cli = drv->cli;
-	while (cli) {
-		if (os_memcmp(cli->addr, params->addr, ETH_ALEN) == 0)
-			break;
-		cli = cli->next;
-	}
-	if (!cli) {
-		wpa_printf(MSG_DEBUG, "%s: no matching client entry",
-			   __func__);
-		return -1;
-	}
-
-	cli->bss = bss;
-
-	return 0;
-}
-
-
-static struct wpa_driver_test_data * test_alloc_data(void *ctx,
-						     const char *ifname)
-{
-	struct wpa_driver_test_data *drv;
-	struct test_driver_bss *bss;
-
-	drv = os_zalloc(sizeof(struct wpa_driver_test_data));
-	if (drv == NULL) {
-		wpa_printf(MSG_ERROR, "Could not allocate memory for test "
-			   "driver data");
-		return NULL;
-	}
-
-	bss = os_zalloc(sizeof(struct test_driver_bss));
-	if (bss == NULL) {
-		os_free(drv);
-		return NULL;
-	}
-
-	drv->ctx = ctx;
-	wpa_trace_add_ref(drv, ctx, ctx);
-	dl_list_init(&drv->bss);
-	dl_list_add(&drv->bss, &bss->list);
-	os_strlcpy(bss->ifname, ifname, IFNAMSIZ);
-	bss->bss_ctx = ctx;
-	bss->drv = drv;
-
-	/* Generate a MAC address to help testing with multiple STAs */
-	drv->own_addr[0] = 0x02; /* locally administered */
-	sha1_prf((const u8 *) ifname, os_strlen(ifname),
-		 "test mac addr generation",
-		 NULL, 0, drv->own_addr + 1, ETH_ALEN - 1);
-
-	return drv;
-}
-
-
-static void * test_driver_init(struct hostapd_data *hapd,
-			       struct wpa_init_params *params)
-{
-	struct wpa_driver_test_data *drv;
-	struct sockaddr_un addr_un;
-	struct sockaddr_in addr_in;
-	struct sockaddr *addr;
-	socklen_t alen;
-	struct test_driver_bss *bss;
-
-	drv = test_alloc_data(hapd, params->ifname);
-	if (drv == NULL)
-		return NULL;
-	drv->ap = 1;
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-	drv->global = params->global_priv;
-
-	bss->bss_ctx = hapd;
-	os_memcpy(bss->bssid, drv->own_addr, ETH_ALEN);
-	os_memcpy(params->own_addr, drv->own_addr, ETH_ALEN);
-
-	if (params->test_socket) {
-		if (os_strlen(params->test_socket) >=
-		    sizeof(addr_un.sun_path)) {
-			printf("Too long test_socket path\n");
-			wpa_driver_test_deinit(bss);
-			return NULL;
-		}
-		if (strncmp(params->test_socket, "DIR:", 4) == 0) {
-			size_t len = strlen(params->test_socket) + 30;
-			drv->test_dir = os_strdup(params->test_socket + 4);
-			drv->own_socket_path = os_malloc(len);
-			if (drv->own_socket_path) {
-				snprintf(drv->own_socket_path, len,
-					 "%s/AP-" MACSTR,
-					 params->test_socket + 4,
-					 MAC2STR(params->own_addr));
-			}
-		} else if (strncmp(params->test_socket, "UDP:", 4) == 0) {
-			drv->udp_port = atoi(params->test_socket + 4);
-		} else {
-			drv->own_socket_path = os_strdup(params->test_socket);
-		}
-		if (drv->own_socket_path == NULL && drv->udp_port == 0) {
-			wpa_driver_test_deinit(bss);
-			return NULL;
-		}
-
-		drv->test_socket = socket(drv->udp_port ? PF_INET : PF_UNIX,
-					  SOCK_DGRAM, 0);
-		if (drv->test_socket < 0) {
-			perror("socket");
-			wpa_driver_test_deinit(bss);
-			return NULL;
-		}
-
-		if (drv->udp_port) {
-			os_memset(&addr_in, 0, sizeof(addr_in));
-			addr_in.sin_family = AF_INET;
-			addr_in.sin_port = htons(drv->udp_port);
-			addr = (struct sockaddr *) &addr_in;
-			alen = sizeof(addr_in);
-		} else {
-			os_memset(&addr_un, 0, sizeof(addr_un));
-			addr_un.sun_family = AF_UNIX;
-			os_strlcpy(addr_un.sun_path, drv->own_socket_path,
-				   sizeof(addr_un.sun_path));
-			addr = (struct sockaddr *) &addr_un;
-			alen = sizeof(addr_un);
-		}
-		if (bind(drv->test_socket, addr, alen) < 0) {
-			perror("test-driver-init: bind(PF_UNIX)");
-			close(drv->test_socket);
-			if (drv->own_socket_path)
-				unlink(drv->own_socket_path);
-			wpa_driver_test_deinit(bss);
-			return NULL;
-		}
-		eloop_register_read_sock(drv->test_socket,
-					 test_driver_receive_unix, drv, NULL);
-	} else
-		drv->test_socket = -1;
-
-	return bss;
-}
-
-
-static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_test_data *drv = eloop_ctx;
-
-#ifdef DRIVER_TEST_UNIX
-	if (drv->associated && drv->hostapd_addr_set) {
-		struct stat st;
-		if (stat(drv->hostapd_addr.sun_path, &st) < 0) {
-			wpa_printf(MSG_DEBUG, "%s: lost connection to AP: %s",
-				   __func__, strerror(errno));
-			drv->associated = 0;
-			wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-		}
-	}
-#endif /* DRIVER_TEST_UNIX */
-
-	eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
-}
-
-
-static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-#ifdef DRIVER_TEST_UNIX
-static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
-				const char *path)
-{
-	struct dirent *dent;
-	DIR *dir;
-	struct sockaddr_un addr;
-	char cmd[512], *pos, *end;
-	int ret;
-
-	dir = opendir(path);
-	if (dir == NULL)
-		return;
-
-	end = cmd + sizeof(cmd);
-	pos = cmd;
-	ret = os_snprintf(pos, end - pos, "SCAN " MACSTR,
-			  MAC2STR(drv->own_addr));
-	if (ret >= 0 && ret < end - pos)
-		pos += ret;
-	if (drv->probe_req_ie) {
-		ret = os_snprintf(pos, end - pos, " ");
-		if (ret >= 0 && ret < end - pos)
-			pos += ret;
-		pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie,
-					drv->probe_req_ie_len);
-	}
-	if (drv->probe_req_ssid_len) {
-		/* Add SSID IE */
-		ret = os_snprintf(pos, end - pos, "%02x%02x",
-				  WLAN_EID_SSID,
-				  (unsigned int) drv->probe_req_ssid_len);
-		if (ret >= 0 && ret < end - pos)
-			pos += ret;
-		pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ssid,
-					drv->probe_req_ssid_len);
-	}
-	end[-1] = '\0';
-
-	while ((dent = readdir(dir))) {
-		if (os_strncmp(dent->d_name, "AP-", 3) != 0 &&
-		    os_strncmp(dent->d_name, "STA-", 4) != 0)
-			continue;
-		if (drv->own_socket_path) {
-			size_t olen, dlen;
-			olen = os_strlen(drv->own_socket_path);
-			dlen = os_strlen(dent->d_name);
-			if (olen >= dlen &&
-			    os_strcmp(dent->d_name,
-				      drv->own_socket_path + olen - dlen) == 0)
-				continue;
-		}
-		wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name);
-
-		os_memset(&addr, 0, sizeof(addr));
-		addr.sun_family = AF_UNIX;
-		os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
-			    path, dent->d_name);
-
-		if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
-			   (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-			perror("sendto(test_socket)");
-		}
-	}
-	closedir(dir);
-}
-#endif /* DRIVER_TEST_UNIX */
-
-
-static int wpa_driver_test_scan(void *priv,
-				struct wpa_driver_scan_params *params)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	size_t i;
-
-	wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
-
-	os_free(drv->probe_req_ie);
-	if (params->extra_ies) {
-		drv->probe_req_ie = os_malloc(params->extra_ies_len);
-		if (drv->probe_req_ie == NULL) {
-			drv->probe_req_ie_len = 0;
-			return -1;
-		}
-		os_memcpy(drv->probe_req_ie, params->extra_ies,
-			  params->extra_ies_len);
-		drv->probe_req_ie_len = params->extra_ies_len;
-	} else {
-		drv->probe_req_ie = NULL;
-		drv->probe_req_ie_len = 0;
-	}
-
-	for (i = 0; i < params->num_ssids; i++)
-		wpa_hexdump(MSG_DEBUG, "Scan SSID",
-			    params->ssids[i].ssid, params->ssids[i].ssid_len);
-	drv->probe_req_ssid_len = 0;
-	if (params->num_ssids) {
-		os_memcpy(drv->probe_req_ssid, params->ssids[0].ssid,
-			  params->ssids[0].ssid_len);
-		drv->probe_req_ssid_len = params->ssids[0].ssid_len;
-	}
-	wpa_hexdump(MSG_DEBUG, "Scan extra IE(s)",
-		    params->extra_ies, params->extra_ies_len);
-
-	drv->num_scanres = 0;
-
-#ifdef DRIVER_TEST_UNIX
-	if (drv->test_socket >= 0 && drv->test_dir)
-		wpa_driver_scan_dir(drv, drv->test_dir);
-
-	if (drv->test_socket >= 0 && drv->hostapd_addr_set &&
-	    sendto(drv->test_socket, "SCAN", 4, 0,
-		   (struct sockaddr *) &drv->hostapd_addr,
-		   sizeof(drv->hostapd_addr)) < 0) {
-		perror("sendto(test_socket)");
-	}
-#endif /* DRIVER_TEST_UNIX */
-
-	if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
-	    sendto(drv->test_socket, "SCAN", 4, 0,
-		   (struct sockaddr *) &drv->hostapd_addr_udp,
-		   sizeof(drv->hostapd_addr_udp)) < 0) {
-		perror("sendto(test_socket)");
-	}
-
-	eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(1, 0, wpa_driver_test_scan_timeout, drv,
-			       drv->ctx);
-	return 0;
-}
-
-
-static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct wpa_scan_results *res;
-	size_t i;
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL)
-		return NULL;
-
-	res->res = os_calloc(drv->num_scanres, sizeof(struct wpa_scan_res *));
-	if (res->res == NULL) {
-		os_free(res);
-		return NULL;
-	}
-
-	for (i = 0; i < drv->num_scanres; i++) {
-		struct wpa_scan_res *r;
-		if (drv->scanres[i] == NULL)
-			continue;
-		r = os_malloc(sizeof(*r) + drv->scanres[i]->ie_len);
-		if (r == NULL)
-			break;
-		os_memcpy(r, drv->scanres[i],
-			  sizeof(*r) + drv->scanres[i]->ie_len);
-		res->res[res->num++] = r;
-	}
-
-	return res;
-}
-
-
-static int wpa_driver_test_set_key(const char *ifname, void *priv,
-				   enum wpa_alg alg, const u8 *addr,
-				   int key_idx, int set_tx,
-				   const u8 *seq, size_t seq_len,
-				   const u8 *key, size_t key_len)
-{
-	wpa_printf(MSG_DEBUG, "%s: ifname=%s priv=%p alg=%d key_idx=%d "
-		   "set_tx=%d",
-		   __func__, ifname, priv, alg, key_idx, set_tx);
-	if (addr)
-		wpa_printf(MSG_DEBUG, "   addr=" MACSTR, MAC2STR(addr));
-	if (seq)
-		wpa_hexdump(MSG_DEBUG, "   seq", seq, seq_len);
-	if (key)
-		wpa_hexdump_key(MSG_DEBUG, "   key", key, key_len);
-	return 0;
-}
-
-
-static int wpa_driver_update_mode(struct wpa_driver_test_data *drv, int ap)
-{
-	if (ap && !drv->ap) {
-		wpa_driver_test_close_test_socket(drv);
-		wpa_driver_test_attach(drv, drv->test_dir, 1);
-		drv->ap = 1;
-	} else if (!ap && drv->ap) {
-		wpa_driver_test_close_test_socket(drv);
-		wpa_driver_test_attach(drv, drv->test_dir, 0);
-		drv->ap = 0;
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_test_associate(
-	void *priv, struct wpa_driver_associate_params *params)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
-		   "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
-		   __func__, priv, params->freq.freq, params->pairwise_suite,
-		   params->group_suite, params->key_mgmt_suite,
-		   params->auth_alg, params->mode);
-	wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP);
-	if (params->bssid) {
-		wpa_printf(MSG_DEBUG, "   bssid=" MACSTR,
-			   MAC2STR(params->bssid));
-	}
-	if (params->ssid) {
-		wpa_hexdump_ascii(MSG_DEBUG, "   ssid",
-				  params->ssid, params->ssid_len);
-	}
-	if (params->wpa_ie) {
-		wpa_hexdump(MSG_DEBUG, "   wpa_ie",
-			    params->wpa_ie, params->wpa_ie_len);
-		drv->assoc_wpa_ie_len = params->wpa_ie_len;
-		if (drv->assoc_wpa_ie_len > sizeof(drv->assoc_wpa_ie))
-			drv->assoc_wpa_ie_len = sizeof(drv->assoc_wpa_ie);
-		os_memcpy(drv->assoc_wpa_ie, params->wpa_ie,
-			  drv->assoc_wpa_ie_len);
-	} else
-		drv->assoc_wpa_ie_len = 0;
-
-	wpa_driver_update_mode(drv, params->mode == IEEE80211_MODE_AP);
-
-	drv->ibss = params->mode == IEEE80211_MODE_IBSS;
-	dbss->privacy = params->key_mgmt_suite &
-		(WPA_KEY_MGMT_IEEE8021X |
-		 WPA_KEY_MGMT_PSK |
-		 WPA_KEY_MGMT_WPA_NONE |
-		 WPA_KEY_MGMT_FT_IEEE8021X |
-		 WPA_KEY_MGMT_FT_PSK |
-		 WPA_KEY_MGMT_IEEE8021X_SHA256 |
-		 WPA_KEY_MGMT_PSK_SHA256);
-	if (params->wep_key_len[params->wep_tx_keyidx])
-		dbss->privacy = 1;
-
-#ifdef DRIVER_TEST_UNIX
-	if (drv->test_dir && params->bssid &&
-	    params->mode != IEEE80211_MODE_IBSS) {
-		os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
-		drv->hostapd_addr.sun_family = AF_UNIX;
-		os_snprintf(drv->hostapd_addr.sun_path,
-			    sizeof(drv->hostapd_addr.sun_path),
-			    "%s/AP-" MACSTR,
-			    drv->test_dir, MAC2STR(params->bssid));
-		drv->hostapd_addr_set = 1;
-	}
-#endif /* DRIVER_TEST_UNIX */
-
-	if (params->mode == IEEE80211_MODE_AP) {
-		if (params->ssid)
-			os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
-		dbss->ssid_len = params->ssid_len;
-		os_memcpy(dbss->bssid, drv->own_addr, ETH_ALEN);
-		if (params->wpa_ie && params->wpa_ie_len) {
-			dbss->ie = os_malloc(params->wpa_ie_len);
-			if (dbss->ie) {
-				os_memcpy(dbss->ie, params->wpa_ie,
-					  params->wpa_ie_len);
-				dbss->ielen = params->wpa_ie_len;
-			}
-		}
-	} else if (drv->test_socket >= 0 &&
-		   (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) {
-		char cmd[200], *pos, *end;
-		int ret;
-		end = cmd + sizeof(cmd);
-		pos = cmd;
-		ret = os_snprintf(pos, end - pos, "ASSOC " MACSTR " ",
-				  MAC2STR(drv->own_addr));
-		if (ret >= 0 && ret < end - pos)
-			pos += ret;
-		if (params->ssid)
-			pos += wpa_snprintf_hex(pos, end - pos, params->ssid,
-						params->ssid_len);
-		ret = os_snprintf(pos, end - pos, " ");
-		if (ret >= 0 && ret < end - pos)
-			pos += ret;
-		pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie,
-					params->wpa_ie_len);
-		end[-1] = '\0';
-#ifdef DRIVER_TEST_UNIX
-		if (drv->hostapd_addr_set &&
-		    sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
-			   (struct sockaddr *) &drv->hostapd_addr,
-			   sizeof(drv->hostapd_addr)) < 0) {
-			perror("sendto(test_socket)");
-			return -1;
-		}
-#endif /* DRIVER_TEST_UNIX */
-		if (drv->hostapd_addr_udp_set &&
-		    sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
-			   (struct sockaddr *) &drv->hostapd_addr_udp,
-			   sizeof(drv->hostapd_addr_udp)) < 0) {
-			perror("sendto(test_socket)");
-			return -1;
-		}
-
-		if (params->ssid)
-			os_memcpy(dbss->ssid, params->ssid, params->ssid_len);
-		dbss->ssid_len = params->ssid_len;
-	} else {
-		drv->associated = 1;
-		if (params->mode == IEEE80211_MODE_IBSS) {
-			if (params->ssid)
-				os_memcpy(dbss->ssid, params->ssid,
-					  params->ssid_len);
-			dbss->ssid_len = params->ssid_len;
-			if (params->bssid)
-				os_memcpy(dbss->bssid, params->bssid,
-					  ETH_ALEN);
-			else {
-				os_get_random(dbss->bssid, ETH_ALEN);
-				dbss->bssid[0] &= ~0x01;
-				dbss->bssid[0] |= 0x02;
-			}
-		}
-		wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-	}
-
-	return 0;
-}
-
-
-static int wpa_driver_test_get_bssid(void *priv, u8 *bssid)
-{
-	struct test_driver_bss *dbss = priv;
-	os_memcpy(bssid, dbss->bssid, ETH_ALEN);
-	return 0;
-}
-
-
-static int wpa_driver_test_get_ssid(void *priv, u8 *ssid)
-{
-	struct test_driver_bss *dbss = priv;
-	os_memcpy(ssid, dbss->ssid, 32);
-	return dbss->ssid_len;
-}
-
-
-static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv)
-{
-#ifdef DRIVER_TEST_UNIX
-	if (drv->test_socket >= 0 &&
-	    sendto(drv->test_socket, "DISASSOC", 8, 0,
-		   (struct sockaddr *) &drv->hostapd_addr,
-		   sizeof(drv->hostapd_addr)) < 0) {
-		perror("sendto(test_socket)");
-		return -1;
-	}
-#endif /* DRIVER_TEST_UNIX */
-	if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
-	    sendto(drv->test_socket, "DISASSOC", 8, 0,
-		   (struct sockaddr *) &drv->hostapd_addr_udp,
-		   sizeof(drv->hostapd_addr_udp)) < 0) {
-		perror("sendto(test_socket)");
-		return -1;
-	}
-	return 0;
-}
-
-
-static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
-		   __func__, MAC2STR(addr), reason_code);
-	os_memset(dbss->bssid, 0, ETH_ALEN);
-	drv->associated = 0;
-	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-	return wpa_driver_test_send_disassoc(drv);
-}
-
-
-static const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
-{
-	const u8 *end, *pos;
-
-	pos = (const u8 *) (res + 1);
-	end = pos + res->ie_len;
-
-	while (pos + 1 < end) {
-		if (pos + 2 + pos[1] > end)
-			break;
-		if (pos[0] == ie)
-			return pos;
-		pos += 2 + pos[1];
-	}
-
-	return NULL;
-}
-
-
-static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
-				     struct sockaddr *from,
-				     socklen_t fromlen,
-				     const char *data)
-{
-	struct wpa_scan_res *res;
-	const char *pos, *pos2;
-	size_t len;
-	u8 *ie_pos, *ie_start, *ie_end;
-#define MAX_IE_LEN 1000
-	const u8 *ds_params;
-
-	wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data);
-	if (drv->num_scanres >= MAX_SCAN_RESULTS) {
-		wpa_printf(MSG_DEBUG, "test_driver: No room for the new scan "
-			   "result");
-		return;
-	}
-
-	/* SCANRESP BSSID SSID IEs */
-
-	res = os_zalloc(sizeof(*res) + MAX_IE_LEN);
-	if (res == NULL)
-		return;
-	ie_start = ie_pos = (u8 *) (res + 1);
-	ie_end = ie_pos + MAX_IE_LEN;
-
-	if (hwaddr_aton(data, res->bssid)) {
-		wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in scanres");
-		os_free(res);
-		return;
-	}
-
-	pos = data + 17;
-	while (*pos == ' ')
-		pos++;
-	pos2 = os_strchr(pos, ' ');
-	if (pos2 == NULL) {
-		wpa_printf(MSG_DEBUG, "test_driver: invalid SSID termination "
-			   "in scanres");
-		os_free(res);
-		return;
-	}
-	len = (pos2 - pos) / 2;
-	if (len > 32)
-		len = 32;
-	/*
-	 * Generate SSID IE from the SSID field since this IE is not included
-	 * in the main IE field.
-	 */
-	*ie_pos++ = WLAN_EID_SSID;
-	*ie_pos++ = len;
-	if (hexstr2bin(pos, ie_pos, len) < 0) {
-		wpa_printf(MSG_DEBUG, "test_driver: invalid SSID in scanres");
-		os_free(res);
-		return;
-	}
-	ie_pos += len;
-
-	pos = pos2 + 1;
-	pos2 = os_strchr(pos, ' ');
-	if (pos2 == NULL)
-		len = os_strlen(pos) / 2;
-	else
-		len = (pos2 - pos) / 2;
-	if ((int) len > ie_end - ie_pos)
-		len = ie_end - ie_pos;
-	if (hexstr2bin(pos, ie_pos, len) < 0) {
-		wpa_printf(MSG_DEBUG, "test_driver: invalid IEs in scanres");
-		os_free(res);
-		return;
-	}
-	ie_pos += len;
-	res->ie_len = ie_pos - ie_start;
-
-	if (pos2) {
-		pos = pos2 + 1;
-		while (*pos == ' ')
-			pos++;
-		if (os_strstr(pos, "PRIVACY"))
-			res->caps |= IEEE80211_CAP_PRIVACY;
-		if (os_strstr(pos, "IBSS"))
-			res->caps |= IEEE80211_CAP_IBSS;
-	}
-
-	ds_params = wpa_scan_get_ie(res, WLAN_EID_DS_PARAMS);
-	if (ds_params && ds_params[1] > 0) {
-		if (ds_params[2] >= 1 && ds_params[2] <= 13)
-			res->freq = 2407 + ds_params[2] * 5;
-	}
-
-	os_free(drv->scanres[drv->num_scanres]);
-	drv->scanres[drv->num_scanres++] = res;
-}
-
-
-static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv,
-				      struct sockaddr *from,
-				      socklen_t fromlen,
-				      const char *data)
-{
-	struct test_driver_bss *bss;
-
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
-	/* ASSOCRESP BSSID <res> */
-	if (hwaddr_aton(data, bss->bssid)) {
-		wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in "
-			   "assocresp");
-	}
-	if (drv->use_associnfo) {
-		union wpa_event_data event;
-		os_memset(&event, 0, sizeof(event));
-		event.assoc_info.req_ies = drv->assoc_wpa_ie;
-		event.assoc_info.req_ies_len = drv->assoc_wpa_ie_len;
-		wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &event);
-	}
-	drv->associated = 1;
-	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
-}
-
-
-static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv,
-				     struct sockaddr *from,
-				     socklen_t fromlen)
-{
-	drv->associated = 0;
-	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
-}
-
-
-static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
-				  struct sockaddr *from,
-				  socklen_t fromlen,
-				  const u8 *data, size_t data_len)
-{
-	const u8 *src;
-	struct test_driver_bss *bss;
-
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
-	if (data_len > 14) {
-		/* Skip Ethernet header */
-		src = data + ETH_ALEN;
-		data += 14;
-		data_len -= 14;
-	} else
-		src = bss->bssid;
-
-	drv_event_eapol_rx(drv->ctx, src, data, data_len);
-}
-
-
-static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
-				 struct sockaddr *from,
-				 socklen_t fromlen,
-				 const u8 *data, size_t data_len)
-{
-	int freq = 0, own_freq;
-	union wpa_event_data event;
-	const struct ieee80211_mgmt *mgmt;
-	u16 fc;
-	struct test_driver_bss *bss;
-
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-	if (data_len > 6 && os_memcmp(data, "freq=", 5) == 0) {
-		size_t pos;
-		for (pos = 5; pos < data_len; pos++) {
-			if (data[pos] == ' ')
-				break;
-		}
-		if (pos < data_len) {
-			freq = atoi((const char *) &data[5]);
-			wpa_printf(MSG_DEBUG, "test_driver(%s): MLME RX on "
-				   "freq %d MHz", bss->ifname, freq);
-			pos++;
-			data += pos;
-			data_len -= pos;
-		}
-	}
-
-	if (drv->remain_on_channel_freq)
-		own_freq = drv->remain_on_channel_freq;
-	else
-		own_freq = drv->current_freq;
-
-	if (freq && own_freq && freq != own_freq) {
-		wpa_printf(MSG_DEBUG, "test_driver(%s): Ignore MLME RX on "
-			   "another frequency %d MHz (own %d MHz)",
-			   bss->ifname, freq, own_freq);
-		return;
-	}
-
-	os_memset(&event, 0, sizeof(event));
-	event.mlme_rx.buf = data;
-	event.mlme_rx.len = data_len;
-	event.mlme_rx.freq = freq;
-	wpa_supplicant_event(drv->ctx, EVENT_MLME_RX, &event);
-
-	mgmt = (const struct ieee80211_mgmt *) data;
-	fc = le_to_host16(mgmt->frame_control);
-
-	if (drv->probe_req_report && data_len >= 24) {
-		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
-		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_REQ) {
-			os_memset(&event, 0, sizeof(event));
-			event.rx_probe_req.sa = mgmt->sa;
-			event.rx_probe_req.da = mgmt->da;
-			event.rx_probe_req.bssid = mgmt->bssid;
-			event.rx_probe_req.ie = mgmt->u.probe_req.variable;
-			event.rx_probe_req.ie_len =
-				data_len - (mgmt->u.probe_req.variable - data);
-			wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ,
-					     &event);
-		}
-	}
-}
-
-
-static void wpa_driver_test_scan_cmd(struct wpa_driver_test_data *drv,
-				     struct sockaddr *from,
-				     socklen_t fromlen,
-				     const u8 *data, size_t data_len)
-{
-	char buf[512], *pos, *end;
-	int ret;
-	struct test_driver_bss *bss;
-
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-
-	/* data: optional [ STA-addr | ' ' | IEs(hex) ] */
-
-	if (bss == NULL || !drv->ibss)
-		return;
-
-	pos = buf;
-	end = buf + sizeof(buf);
-
-	/* reply: SCANRESP BSSID SSID IEs */
-	ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
-		       MAC2STR(bss->bssid));
-	if (ret < 0 || ret >= end - pos)
-		return;
-	pos += ret;
-	pos += wpa_snprintf_hex(pos, end - pos,
-				bss->ssid, bss->ssid_len);
-	ret = snprintf(pos, end - pos, " ");
-	if (ret < 0 || ret >= end - pos)
-		return;
-	pos += ret;
-	pos += wpa_snprintf_hex(pos, end - pos, drv->assoc_wpa_ie,
-				drv->assoc_wpa_ie_len);
-
-	if (bss->privacy) {
-		ret = snprintf(pos, end - pos, " PRIVACY");
-		if (ret < 0 || ret >= end - pos)
-			return;
-		pos += ret;
-	}
-
-	ret = snprintf(pos, end - pos, " IBSS");
-	if (ret < 0 || ret >= end - pos)
-		return;
-	pos += ret;
-
-	sendto(drv->test_socket, buf, pos - buf, 0,
-	       (struct sockaddr *) from, fromlen);
-}
-
-
-static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
-					 void *sock_ctx)
-{
-	struct wpa_driver_test_data *drv = eloop_ctx;
-	char *buf;
-	int res;
-	struct sockaddr_storage from;
-	socklen_t fromlen = sizeof(from);
-	const size_t buflen = 2000;
-
-	if (drv->ap) {
-		test_driver_receive_unix(sock, eloop_ctx, sock_ctx);
-		return;
-	}
-
-	buf = os_malloc(buflen);
-	if (buf == NULL)
-		return;
-	res = recvfrom(sock, buf, buflen - 1, 0,
-		       (struct sockaddr *) &from, &fromlen);
-	if (res < 0) {
-		perror("recvfrom(test_socket)");
-		os_free(buf);
-		return;
-	}
-	buf[res] = '\0';
-
-	wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
-
-	if (os_strncmp(buf, "SCANRESP ", 9) == 0) {
-		wpa_driver_test_scanresp(drv, (struct sockaddr *) &from,
-					 fromlen, buf + 9);
-	} else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) {
-		wpa_driver_test_assocresp(drv, (struct sockaddr *) &from,
-					  fromlen, buf + 10);
-	} else if (os_strcmp(buf, "DISASSOC") == 0) {
-		wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
-					 fromlen);
-	} else if (os_strcmp(buf, "DEAUTH") == 0) {
-		wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
-					 fromlen);
-	} else if (os_strncmp(buf, "EAPOL ", 6) == 0) {
-		wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen,
-				      (const u8 *) buf + 6, res - 6);
-	} else if (os_strncmp(buf, "MLME ", 5) == 0) {
-		wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen,
-				     (const u8 *) buf + 5, res - 5);
-	} else if (os_strncmp(buf, "SCAN ", 5) == 0) {
-		wpa_driver_test_scan_cmd(drv, (struct sockaddr *) &from,
-					 fromlen,
-					 (const u8 *) buf + 5, res - 5);
-	} else {
-		wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
-				  (u8 *) buf, res);
-	}
-	os_free(buf);
-}
-
-
-static void * wpa_driver_test_init2(void *ctx, const char *ifname,
-				    void *global_priv)
-{
-	struct wpa_driver_test_data *drv;
-	struct wpa_driver_test_global *global = global_priv;
-	struct test_driver_bss *bss;
-
-	drv = test_alloc_data(ctx, ifname);
-	if (drv == NULL)
-		return NULL;
-	bss = dl_list_first(&drv->bss, struct test_driver_bss, list);
-	drv->global = global_priv;
-	drv->test_socket = -1;
-
-	/* Set dummy BSSID and SSID for testing. */
-	bss->bssid[0] = 0x02;
-	bss->bssid[1] = 0x00;
-	bss->bssid[2] = 0x00;
-	bss->bssid[3] = 0x00;
-	bss->bssid[4] = 0x00;
-	bss->bssid[5] = 0x01;
-	os_memcpy(bss->ssid, "test", 5);
-	bss->ssid_len = 4;
-
-	if (global->bss_add_used) {
-		os_memcpy(drv->own_addr, global->req_addr, ETH_ALEN);
-		global->bss_add_used = 0;
-	}
-
-	eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
-
-	return bss;
-}
-
-
-static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv)
-{
-	if (drv->test_socket >= 0) {
-		eloop_unregister_read_sock(drv->test_socket);
-		close(drv->test_socket);
-		drv->test_socket = -1;
-	}
-
-	if (drv->own_socket_path) {
-		unlink(drv->own_socket_path);
-		os_free(drv->own_socket_path);
-		drv->own_socket_path = NULL;
-	}
-}
-
-
-static void wpa_driver_test_deinit(void *priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	struct test_client_socket *cli, *prev;
-	int i;
-
-	cli = drv->cli;
-	while (cli) {
-		prev = cli;
-		cli = cli->next;
-		os_free(prev);
-	}
-
-#ifdef HOSTAPD
-	/* There should be only one BSS remaining at this point. */
-	if (dl_list_len(&drv->bss) != 1)
-		wpa_printf(MSG_ERROR, "%s: %u remaining BSS entries",
-			   __func__, dl_list_len(&drv->bss));
-#endif /* HOSTAPD */
-
-	test_driver_free_bsses(drv);
-
-	wpa_driver_test_close_test_socket(drv);
-	eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
-	eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL);
-	eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
-	os_free(drv->test_dir);
-	for (i = 0; i < MAX_SCAN_RESULTS; i++)
-		os_free(drv->scanres[i]);
-	os_free(drv->probe_req_ie);
-	wpa_trace_remove_ref(drv, ctx, drv->ctx);
-	os_free(drv);
-}
-
-
-static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
-				  const char *dir, int ap)
-{
-#ifdef DRIVER_TEST_UNIX
-	static unsigned int counter = 0;
-	struct sockaddr_un addr;
-	size_t len;
-
-	os_free(drv->own_socket_path);
-	if (dir) {
-		len = os_strlen(dir) + 30;
-		drv->own_socket_path = os_malloc(len);
-		if (drv->own_socket_path == NULL)
-			return -1;
-		os_snprintf(drv->own_socket_path, len, "%s/%s-" MACSTR,
-			    dir, ap ? "AP" : "STA", MAC2STR(drv->own_addr));
-	} else {
-		drv->own_socket_path = os_malloc(100);
-		if (drv->own_socket_path == NULL)
-			return -1;
-		os_snprintf(drv->own_socket_path, 100,
-			    "/tmp/wpa_supplicant_test-%d-%d",
-			    getpid(), counter++);
-	}
-
-	drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
-	if (drv->test_socket < 0) {
-		perror("socket(PF_UNIX)");
-		os_free(drv->own_socket_path);
-		drv->own_socket_path = NULL;
-		return -1;
-	}
-
-	os_memset(&addr, 0, sizeof(addr));
-	addr.sun_family = AF_UNIX;
-	os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
-	if (bind(drv->test_socket, (struct sockaddr *) &addr,
-		 sizeof(addr)) < 0) {
-		perror("test-driver-attach: bind(PF_UNIX)");
-		close(drv->test_socket);
-		unlink(drv->own_socket_path);
-		os_free(drv->own_socket_path);
-		drv->own_socket_path = NULL;
-		return -1;
-	}
-
-	eloop_register_read_sock(drv->test_socket,
-				 wpa_driver_test_receive_unix, drv, NULL);
-
-	return 0;
-#else /* DRIVER_TEST_UNIX */
-	return -1;
-#endif /* DRIVER_TEST_UNIX */
-}
-
-
-static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv,
-				      char *dst)
-{
-	char *pos;
-
-	pos = os_strchr(dst, ':');
-	if (pos == NULL)
-		return -1;
-	*pos++ = '\0';
-	wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos);
-
-	drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->test_socket < 0) {
-		perror("socket(PF_INET)");
-		return -1;
-	}
-
-	os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp));
-	drv->hostapd_addr_udp.sin_family = AF_INET;
-#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
-	{
-		int a[4];
-		u8 *pos;
-		sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
-		pos = (u8 *) &drv->hostapd_addr_udp.sin_addr;
-		*pos++ = a[0];
-		*pos++ = a[1];
-		*pos++ = a[2];
-		*pos++ = a[3];
-	}
-#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
-	inet_aton(dst, &drv->hostapd_addr_udp.sin_addr);
-#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
-	drv->hostapd_addr_udp.sin_port = htons(atoi(pos));
-
-	drv->hostapd_addr_udp_set = 1;
-
-	eloop_register_read_sock(drv->test_socket,
-				 wpa_driver_test_receive_unix, drv, NULL);
-
-	return 0;
-}
-
-
-static int wpa_driver_test_set_param(void *priv, const char *param)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	const char *pos;
-
-	wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
-	if (param == NULL)
-		return 0;
-
-	wpa_driver_test_close_test_socket(drv);
-
-#ifdef DRIVER_TEST_UNIX
-	pos = os_strstr(param, "test_socket=");
-	if (pos) {
-		const char *pos2;
-		size_t len;
-
-		pos += 12;
-		pos2 = os_strchr(pos, ' ');
-		if (pos2)
-			len = pos2 - pos;
-		else
-			len = os_strlen(pos);
-		if (len > sizeof(drv->hostapd_addr.sun_path))
-			return -1;
-		os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
-		drv->hostapd_addr.sun_family = AF_UNIX;
-		os_memcpy(drv->hostapd_addr.sun_path, pos, len);
-		drv->hostapd_addr_set = 1;
-	}
-#endif /* DRIVER_TEST_UNIX */
-
-	pos = os_strstr(param, "test_dir=");
-	if (pos) {
-		char *end;
-		os_free(drv->test_dir);
-		drv->test_dir = os_strdup(pos + 9);
-		if (drv->test_dir == NULL)
-			return -1;
-		end = os_strchr(drv->test_dir, ' ');
-		if (end)
-			*end = '\0';
-		if (wpa_driver_test_attach(drv, drv->test_dir, 0))
-			return -1;
-	} else {
-		pos = os_strstr(param, "test_udp=");
-		if (pos) {
-			char *dst, *epos;
-			dst = os_strdup(pos + 9);
-			if (dst == NULL)
-				return -1;
-			epos = os_strchr(dst, ' ');
-			if (epos)
-				*epos = '\0';
-			if (wpa_driver_test_attach_udp(drv, dst))
-				return -1;
-			os_free(dst);
-		} else if (wpa_driver_test_attach(drv, NULL, 0))
-			return -1;
-	}
-
-	if (os_strstr(param, "use_associnfo=1")) {
-		wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events");
-		drv->use_associnfo = 1;
-	}
-
-	return 0;
-}
-
-
-static const u8 * wpa_driver_test_get_mac_addr(void *priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	return drv->own_addr;
-}
-
-
-static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
-				      const u8 *data, size_t data_len)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	char *msg;
-	size_t msg_len;
-	struct l2_ethhdr eth;
-	struct sockaddr *addr;
-	socklen_t alen;
-#ifdef DRIVER_TEST_UNIX
-	struct sockaddr_un addr_un;
-#endif /* DRIVER_TEST_UNIX */
-
-	wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len);
-
-	os_memset(&eth, 0, sizeof(eth));
-	os_memcpy(eth.h_dest, dest, ETH_ALEN);
-	os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN);
-	eth.h_proto = host_to_be16(proto);
-
-	msg_len = 6 + sizeof(eth) + data_len;
-	msg = os_malloc(msg_len);
-	if (msg == NULL)
-		return -1;
-	os_memcpy(msg, "EAPOL ", 6);
-	os_memcpy(msg + 6, &eth, sizeof(eth));
-	os_memcpy(msg + 6 + sizeof(eth), data, data_len);
-
-	if (os_memcmp(dest, dbss->bssid, ETH_ALEN) == 0 ||
-	    drv->test_dir == NULL) {
-		if (drv->hostapd_addr_udp_set) {
-			addr = (struct sockaddr *) &drv->hostapd_addr_udp;
-			alen = sizeof(drv->hostapd_addr_udp);
-		} else {
-#ifdef DRIVER_TEST_UNIX
-			addr = (struct sockaddr *) &drv->hostapd_addr;
-			alen = sizeof(drv->hostapd_addr);
-#else /* DRIVER_TEST_UNIX */
-			os_free(msg);
-			return -1;
-#endif /* DRIVER_TEST_UNIX */
-		}
-	} else {
-#ifdef DRIVER_TEST_UNIX
-		struct stat st;
-		os_memset(&addr_un, 0, sizeof(addr_un));
-		addr_un.sun_family = AF_UNIX;
-		os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
-			    "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest));
-		if (stat(addr_un.sun_path, &st) < 0) {
-			os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
-				    "%s/AP-" MACSTR,
-				    drv->test_dir, MAC2STR(dest));
-		}
-		addr = (struct sockaddr *) &addr_un;
-		alen = sizeof(addr_un);
-#else /* DRIVER_TEST_UNIX */
-		os_free(msg);
-		return -1;
-#endif /* DRIVER_TEST_UNIX */
-	}
-
-	if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) {
-		perror("sendmsg(test_socket)");
-		os_free(msg);
-		return -1;
-	}
-
-	os_free(msg);
-	return 0;
-}
-
-
-static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
-{
-	os_memset(capa, 0, sizeof(*capa));
-	capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
-		WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE |
-		WPA_DRIVER_CAPA_KEY_MGMT_FT |
-		WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
-	capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 |
-		WPA_DRIVER_CAPA_ENC_WEP104 |
-		WPA_DRIVER_CAPA_ENC_TKIP |
-		WPA_DRIVER_CAPA_ENC_CCMP;
-	capa->auth = WPA_DRIVER_AUTH_OPEN |
-		WPA_DRIVER_AUTH_SHARED |
-		WPA_DRIVER_AUTH_LEAP;
-	capa->flags |= WPA_DRIVER_FLAGS_AP;
-	capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
-	capa->flags |= WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE;
-	capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
-	capa->max_scan_ssids = 2;
-	capa->max_remain_on_chan = 60000;
-
-	return 0;
-}
-
-
-static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr,
-					      int protect_type,
-					      int key_type)
-{
-	wpa_printf(MSG_DEBUG, "%s: protect_type=%d key_type=%d",
-		   __func__, protect_type, key_type);
-
-	if (addr) {
-		wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR,
-			   __func__, MAC2STR(addr));
-	}
-
-	return 0;
-}
-
-
-static void * wpa_driver_test_global_init(void)
-{
-	struct wpa_driver_test_global *global;
-
-	global = os_zalloc(sizeof(*global));
-	return global;
-}
-
-
-static void wpa_driver_test_global_deinit(void *priv)
-{
-	struct wpa_driver_test_global *global = priv;
-	os_free(global);
-}
-
-
-static struct wpa_interface_info *
-wpa_driver_test_get_interfaces(void *global_priv)
-{
-	/* struct wpa_driver_test_global *global = priv; */
-	struct wpa_interface_info *iface;
-
-	iface = os_zalloc(sizeof(*iface));
-	if (iface == NULL)
-		return iface;
-	iface->ifname = os_strdup("sta0");
-	iface->desc = os_strdup("test interface 0");
-	iface->drv_name = "test";
-	iface->next = os_zalloc(sizeof(*iface));
-	if (iface->next) {
-		iface->next->ifname = os_strdup("sta1");
-		iface->next->desc = os_strdup("test interface 1");
-		iface->next->drv_name = "test";
-	}
-
-	return iface;
-}
-
-
-static struct hostapd_hw_modes *
-wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
-{
-	struct hostapd_hw_modes *modes;
-	size_t i;
-
-	*num_modes = 3;
-	*flags = 0;
-	modes = os_calloc(*num_modes, sizeof(struct hostapd_hw_modes));
-	if (modes == NULL)
-		return NULL;
-	modes[0].mode = HOSTAPD_MODE_IEEE80211G;
-	modes[0].num_channels = 11;
-	modes[0].num_rates = 12;
-	modes[0].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
-	modes[0].rates = os_calloc(modes[0].num_rates, sizeof(int));
-	if (modes[0].channels == NULL || modes[0].rates == NULL)
-		goto fail;
-	for (i = 0; i < 11; i++) {
-		modes[0].channels[i].chan = i + 1;
-		modes[0].channels[i].freq = 2412 + 5 * i;
-		modes[0].channels[i].flag = 0;
-	}
-	modes[0].rates[0] = 10;
-	modes[0].rates[1] = 20;
-	modes[0].rates[2] = 55;
-	modes[0].rates[3] = 110;
-	modes[0].rates[4] = 60;
-	modes[0].rates[5] = 90;
-	modes[0].rates[6] = 120;
-	modes[0].rates[7] = 180;
-	modes[0].rates[8] = 240;
-	modes[0].rates[9] = 360;
-	modes[0].rates[10] = 480;
-	modes[0].rates[11] = 540;
-
-	modes[1].mode = HOSTAPD_MODE_IEEE80211B;
-	modes[1].num_channels = 11;
-	modes[1].num_rates = 4;
-	modes[1].channels = os_calloc(11, sizeof(struct hostapd_channel_data));
-	modes[1].rates = os_calloc(modes[1].num_rates, sizeof(int));
-	if (modes[1].channels == NULL || modes[1].rates == NULL)
-		goto fail;
-	for (i = 0; i < 11; i++) {
-		modes[1].channels[i].chan = i + 1;
-		modes[1].channels[i].freq = 2412 + 5 * i;
-		modes[1].channels[i].flag = 0;
-	}
-	modes[1].rates[0] = 10;
-	modes[1].rates[1] = 20;
-	modes[1].rates[2] = 55;
-	modes[1].rates[3] = 110;
-
-	modes[2].mode = HOSTAPD_MODE_IEEE80211A;
-	modes[2].num_channels = 1;
-	modes[2].num_rates = 8;
-	modes[2].channels = os_calloc(1, sizeof(struct hostapd_channel_data));
-	modes[2].rates = os_calloc(modes[2].num_rates, sizeof(int));
-	if (modes[2].channels == NULL || modes[2].rates == NULL)
-		goto fail;
-	modes[2].channels[0].chan = 60;
-	modes[2].channels[0].freq = 5300;
-	modes[2].channels[0].flag = 0;
-	modes[2].rates[0] = 60;
-	modes[2].rates[1] = 90;
-	modes[2].rates[2] = 120;
-	modes[2].rates[3] = 180;
-	modes[2].rates[4] = 240;
-	modes[2].rates[5] = 360;
-	modes[2].rates[6] = 480;
-	modes[2].rates[7] = 540;
-
-	return modes;
-
-fail:
-	if (modes) {
-		for (i = 0; i < *num_modes; i++) {
-			os_free(modes[i].channels);
-			os_free(modes[i].rates);
-		}
-		os_free(modes);
-	}
-	return NULL;
-}
-
-
-static int wpa_driver_test_set_freq(void *priv,
-				    struct hostapd_freq_params *freq)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "test: set_freq %u MHz", freq->freq);
-	drv->current_freq = freq->freq;
-	return 0;
-}
-
-
-static int wpa_driver_test_send_action(void *priv, unsigned int freq,
-				       unsigned int wait,
-				       const u8 *dst, const u8 *src,
-				       const u8 *bssid,
-				       const u8 *data, size_t data_len,
-				       int no_cck)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	int ret = -1;
-	u8 *buf;
-	struct ieee80211_hdr *hdr;
-
-	wpa_printf(MSG_DEBUG, "test: Send Action frame");
-
-	if ((drv->remain_on_channel_freq &&
-	     freq != drv->remain_on_channel_freq) ||
-	    (drv->remain_on_channel_freq == 0 &&
-	     freq != (unsigned int) drv->current_freq)) {
-		wpa_printf(MSG_DEBUG, "test: Reject Action frame TX on "
-			   "unexpected channel: freq=%u MHz (current_freq=%u "
-			   "MHz, remain-on-channel freq=%u MHz)",
-			   freq, drv->current_freq,
-			   drv->remain_on_channel_freq);
-		return -1;
-	}
-
-	buf = os_zalloc(24 + data_len);
-	if (buf == NULL)
-		return ret;
-	os_memcpy(buf + 24, data, data_len);
-	hdr = (struct ieee80211_hdr *) buf;
-	hdr->frame_control =
-		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_ACTION);
-	os_memcpy(hdr->addr1, dst, ETH_ALEN);
-	os_memcpy(hdr->addr2, src, ETH_ALEN);
-	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
-
-	ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len, 0);
-	os_free(buf);
-	return ret;
-}
-
-
-static void test_remain_on_channel_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_test_data *drv = eloop_ctx;
-	union wpa_event_data data;
-
-	wpa_printf(MSG_DEBUG, "test: Remain-on-channel timeout");
-
-	os_memset(&data, 0, sizeof(data));
-	data.remain_on_channel.freq = drv->remain_on_channel_freq;
-	data.remain_on_channel.duration = drv->remain_on_channel_duration;
-
-	drv->remain_on_channel_freq = 0;
-
-	wpa_supplicant_event(drv->ctx, EVENT_CANCEL_REMAIN_ON_CHANNEL, &data);
-}
-
-
-static int wpa_driver_test_remain_on_channel(void *priv, unsigned int freq,
-					     unsigned int duration)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	union wpa_event_data data;
-
-	wpa_printf(MSG_DEBUG, "%s(freq=%u, duration=%u)",
-		   __func__, freq, duration);
-	if (drv->remain_on_channel_freq &&
-	    drv->remain_on_channel_freq != freq) {
-		wpa_printf(MSG_DEBUG, "test: Refuse concurrent "
-			   "remain_on_channel request");
-		return -1;
-	}
-
-	drv->remain_on_channel_freq = freq;
-	drv->remain_on_channel_duration = duration;
-	eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
-	eloop_register_timeout(duration / 1000, (duration % 1000) * 1000,
-			       test_remain_on_channel_timeout, drv, NULL);
-
-	os_memset(&data, 0, sizeof(data));
-	data.remain_on_channel.freq = freq;
-	data.remain_on_channel.duration = duration;
-	wpa_supplicant_event(drv->ctx, EVENT_REMAIN_ON_CHANNEL, &data);
-
-	return 0;
-}
-
-
-static int wpa_driver_test_cancel_remain_on_channel(void *priv)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	if (!drv->remain_on_channel_freq)
-		return -1;
-	drv->remain_on_channel_freq = 0;
-	eloop_cancel_timeout(test_remain_on_channel_timeout, drv, NULL);
-	return 0;
-}
-
-
-static int wpa_driver_test_probe_req_report(void *priv, int report)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s(report=%d)", __func__, report);
-	drv->probe_req_report = report;
-	return 0;
-}
-
-
-const struct wpa_driver_ops wpa_driver_test_ops = {
-	"test",
-	"wpa_supplicant test driver",
-	.hapd_init = test_driver_init,
-	.hapd_deinit = wpa_driver_test_deinit,
-	.hapd_send_eapol = test_driver_send_eapol,
-	.send_mlme = wpa_driver_test_send_mlme,
-	.set_generic_elem = test_driver_set_generic_elem,
-	.sta_deauth = test_driver_sta_deauth,
-	.sta_disassoc = test_driver_sta_disassoc,
-	.get_hw_feature_data = wpa_driver_test_get_hw_feature_data,
-	.if_add = test_driver_if_add,
-	.if_remove = test_driver_if_remove,
-	.hapd_set_ssid = test_driver_set_ssid,
-	.set_privacy = test_driver_set_privacy,
-	.set_sta_vlan = test_driver_set_sta_vlan,
-	.sta_add = test_driver_sta_add,
-	.send_ether = test_driver_send_ether,
-	.set_ap_wps_ie = test_driver_set_ap_wps_ie,
-	.get_bssid = wpa_driver_test_get_bssid,
-	.get_ssid = wpa_driver_test_get_ssid,
-	.set_key = wpa_driver_test_set_key,
-	.deinit = wpa_driver_test_deinit,
-	.set_param = wpa_driver_test_set_param,
-	.deauthenticate = wpa_driver_test_deauthenticate,
-	.associate = wpa_driver_test_associate,
-	.get_capa = wpa_driver_test_get_capa,
-	.get_mac_addr = wpa_driver_test_get_mac_addr,
-	.send_eapol = wpa_driver_test_send_eapol,
-	.mlme_setprotection = wpa_driver_test_mlme_setprotection,
-	.get_scan_results2 = wpa_driver_test_get_scan_results2,
-	.global_init = wpa_driver_test_global_init,
-	.global_deinit = wpa_driver_test_global_deinit,
-	.init2 = wpa_driver_test_init2,
-	.get_interfaces = wpa_driver_test_get_interfaces,
-	.scan2 = wpa_driver_test_scan,
-	.set_freq = wpa_driver_test_set_freq,
-	.send_action = wpa_driver_test_send_action,
-	.remain_on_channel = wpa_driver_test_remain_on_channel,
-	.cancel_remain_on_channel = wpa_driver_test_cancel_remain_on_channel,
-	.probe_req_report = wpa_driver_test_probe_req_report,
-};
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 1b3a757..a1581b8 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -78,7 +78,7 @@
 	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 
 	if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
-		perror("ioctl[SIOCGIWAP]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIWAP]: %s", strerror(errno));
 		ret = -1;
 	}
 	os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
@@ -108,7 +108,7 @@
 		os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
-		perror("ioctl[SIOCSIWAP]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWAP]: %s", strerror(errno));
 		ret = -1;
 	}
 
@@ -134,7 +134,8 @@
 	iwr.u.essid.length = 32;
 
 	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCGIWESSID]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIWESSID]: %s",
+			   strerror(errno));
 		ret = -1;
 	} else {
 		ret = iwr.u.essid.length;
@@ -192,7 +193,8 @@
 	iwr.u.essid.length = ssid_len;
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCSIWESSID]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWESSID]: %s",
+			   strerror(errno));
 		ret = -1;
 	}
 
@@ -218,7 +220,8 @@
 	iwr.u.freq.e = 1;
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
-		perror("ioctl[SIOCSIWFREQ]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWFREQ]: %s",
+			   strerror(errno));
 		ret = -1;
 	}
 
@@ -815,7 +818,8 @@
 
 	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (drv->ioctl_sock < 0) {
-		perror("socket(PF_INET,SOCK_DGRAM)");
+		wpa_printf(MSG_ERROR, "socket(PF_INET,SOCK_DGRAM): %s",
+			   strerror(errno));
 		goto err1;
 	}
 
@@ -1027,7 +1031,8 @@
 	}
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
-		perror("ioctl[SIOCSIWSCAN]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWSCAN]: %s",
+			   strerror(errno));
 		ret = -1;
 	}
 
@@ -1082,7 +1087,8 @@
 				   "trying larger buffer (%lu bytes)",
 				   (unsigned long) res_buf_len);
 		} else {
-			perror("ioctl[SIOCGIWSCAN]");
+			wpa_printf(MSG_ERROR, "ioctl[SIOCGIWSCAN]: %s",
+				   strerror(errno));
 			os_free(res_buf);
 			return NULL;
 		}
@@ -1533,7 +1539,8 @@
 		sizeof(range->enc_capa);
 
 	if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWRANGE]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIWRANGE]: %s",
+			   strerror(errno));
 		os_free(range);
 		return -1;
 	} else if (iwr.u.data.length >= minlen &&
@@ -1568,8 +1575,9 @@
 		drv->capa.max_scan_ssids = 1;
 
 		wpa_printf(MSG_DEBUG, "  capabilities: key_mgmt 0x%x enc 0x%x "
-			   "flags 0x%x",
-			   drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
+			   "flags 0x%llx",
+			   drv->capa.key_mgmt, drv->capa.enc,
+			   (unsigned long long) drv->capa.flags);
 	} else {
 		wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
 			   "assuming WPA is not supported");
@@ -1612,7 +1620,8 @@
 
 	ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
 	if (ret < 0)
-		perror("ioctl[SIOCSIWENCODEEXT] PMK");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT] PMK: %s",
+			   strerror(errno));
 	os_free(ext);
 
 	return ret;
@@ -1704,7 +1713,8 @@
 			ret = -2;
 		}
 
-		perror("ioctl[SIOCSIWENCODEEXT]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODEEXT]: %s",
+			   strerror(errno));
 	}
 
 	os_free(ext);
@@ -1778,7 +1788,8 @@
 	iwr.u.encoding.length = key_len;
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWENCODE]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s",
+			   strerror(errno));
 		ret = -1;
 	}
 
@@ -1790,7 +1801,9 @@
 		iwr.u.encoding.pointer = (caddr_t) NULL;
 		iwr.u.encoding.length = 0;
 		if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
-			perror("ioctl[SIOCSIWENCODE] (set_tx)");
+			wpa_printf(MSG_ERROR,
+				   "ioctl[SIOCSIWENCODE] (set_tx): %s",
+				   strerror(errno));
 			ret = -1;
 		}
 	}
@@ -1839,7 +1852,8 @@
 	iwr.u.data.length = sizeof(mlme);
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
-		perror("ioctl[SIOCSIWMLME]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMLME]: %s",
+			   strerror(errno));
 		ret = -1;
 	}
 
@@ -1862,7 +1876,8 @@
 	os_memset(&iwr, 0, sizeof(iwr));
 	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
 	if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWMODE]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s",
+			   strerror(errno));
 		iwr.u.mode = IW_MODE_INFRA;
 	}
 
@@ -1927,7 +1942,8 @@
 	iwr.u.data.length = ie_len;
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWGENIE]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWGENIE]: %s",
+			   strerror(errno));
 		ret = -1;
 	}
 
@@ -2004,7 +2020,8 @@
 	}
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWENCODE]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWENCODE]: %s",
+			   strerror(errno));
 		ret = -1;
 	}
 
@@ -2060,12 +2077,12 @@
 	if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
 	    < 0)
 		ret = -1;
-	if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
-		value = IW_AUTH_WPA_VERSION_DISABLED;
-	else if (params->wpa_ie[0] == WLAN_EID_RSN)
+	if (params->wpa_proto & WPA_PROTO_RSN)
 		value = IW_AUTH_WPA_VERSION_WPA2;
-	else
+	else if (params->wpa_proto & WPA_PROTO_WPA)
 		value = IW_AUTH_WPA_VERSION_WPA;
+	else
+		value = IW_AUTH_WPA_VERSION_DISABLED;
 	if (wpa_driver_wext_set_auth_param(drv,
 					   IW_AUTH_WPA_VERSION, value) < 0)
 		ret = -1;
@@ -2084,7 +2101,7 @@
 	value = params->key_mgmt_suite != WPA_KEY_MGMT_NONE ||
 		params->pairwise_suite != WPA_CIPHER_NONE ||
 		params->group_suite != WPA_CIPHER_NONE ||
-		params->wpa_ie_len;
+		(params->wpa_proto & (WPA_PROTO_RSN | WPA_PROTO_WPA));
 	if (wpa_driver_wext_set_auth_param(drv,
 					   IW_AUTH_PRIVACY_INVOKED, value) < 0)
 		ret = -1;
@@ -2181,7 +2198,8 @@
 	}
 
 	if (errno != EBUSY) {
-		perror("ioctl[SIOCSIWMODE]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s",
+			   strerror(errno));
 		goto done;
 	}
 
@@ -2190,7 +2208,8 @@
 	 * down, try to set the mode again, and bring it back up.
 	 */
 	if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
-		perror("ioctl[SIOCGIWMODE]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIWMODE]: %s",
+			   strerror(errno));
 		goto done;
 	}
 
@@ -2203,7 +2222,8 @@
 		/* Try to set the mode again while the interface is down */
 		iwr.u.mode = new_mode;
 		if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
-			perror("ioctl[SIOCSIWMODE]");
+			wpa_printf(MSG_ERROR, "ioctl[SIOCSIWMODE]: %s",
+				   strerror(errno));
 		else
 			ret = 0;
 
@@ -2236,7 +2256,8 @@
 
 	if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
 		if (errno != EOPNOTSUPP)
-			perror("ioctl[SIOCSIWPMKSA]");
+			wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPMKSA]: %s",
+				   strerror(errno));
 		ret = -1;
 	}
 
@@ -2352,6 +2373,33 @@
 }
 
 
+static int wpa_driver_wext_status(void *priv, char *buf, size_t buflen)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	int res;
+	char *pos, *end;
+	unsigned char addr[ETH_ALEN];
+
+	pos = buf;
+	end = buf + buflen;
+
+	if (linux_get_ifhwaddr(drv->ioctl_sock, drv->ifname, addr))
+		return -1;
+
+	res = os_snprintf(pos, end - pos,
+			  "ifindex=%d\n"
+			  "ifname=%s\n"
+			  "addr=" MACSTR "\n",
+			  drv->ifindex,
+			  drv->ifname,
+			  MAC2STR(addr));
+	if (os_snprintf_error(end - pos, res))
+		return pos - buf;
+	pos += res;
+
+	return pos - buf;
+}
+
 const struct wpa_driver_ops wpa_driver_wext_ops = {
 	.name = "wext",
 	.desc = "Linux wireless extensions (generic)",
@@ -2372,4 +2420,5 @@
 	.set_operstate = wpa_driver_wext_set_operstate,
 	.get_radio_name = wext_get_radio_name,
 	.signal_poll = wpa_driver_wext_signal_poll,
+	.status = wpa_driver_wext_status,
 };
diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c
index 21f5e42..f95f3cc 100644
--- a/src/drivers/driver_wired.c
+++ b/src/drivers/driver_wired.c
@@ -100,7 +100,7 @@
 	if (setsockopt(sock, SOL_PACKET,
 		       add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
 		       &mreq, sizeof(mreq)) < 0) {
-		perror("setsockopt");
+		wpa_printf(MSG_ERROR, "setsockopt: %s", strerror(errno));
 		return -1;
 	}
 	return 0;
@@ -158,7 +158,7 @@
 
 	len = recv(sock, buf, sizeof(buf), 0);
 	if (len < 0) {
-		perror("recv");
+		wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
 		return;
 	}
 
@@ -176,7 +176,7 @@
 
 	len = recv(sock, buf, sizeof(buf), 0);
 	if (len < 0) {
-		perror("recv");
+		wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
 		return;
 	}
 
@@ -209,19 +209,21 @@
 
 	drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
 	if (drv->sock < 0) {
-		perror("socket[PF_PACKET,SOCK_RAW]");
+		wpa_printf(MSG_ERROR, "socket[PF_PACKET,SOCK_RAW]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
 	if (eloop_register_read_sock(drv->sock, handle_read, drv->ctx, NULL)) {
-		printf("Could not register read socket\n");
+		wpa_printf(MSG_INFO, "Could not register read socket");
 		return -1;
 	}
 
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 	if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
-		perror("ioctl(SIOCGIFINDEX)");
+		wpa_printf(MSG_ERROR, "ioctl(SIOCGIFINDEX): %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -232,7 +234,7 @@
 		   addr.sll_ifindex);
 
 	if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("bind");
+		wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
 		return -1;
 	}
 
@@ -247,26 +249,28 @@
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
 	if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
-		perror("ioctl(SIOCGIFHWADDR)");
+		wpa_printf(MSG_ERROR, "ioctl(SIOCGIFHWADDR): %s",
+			   strerror(errno));
 		return -1;
 	}
 
 	if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
-		printf("Invalid HW-addr family 0x%04x\n",
-		       ifr.ifr_hwaddr.sa_family);
+		wpa_printf(MSG_INFO, "Invalid HW-addr family 0x%04x",
+			   ifr.ifr_hwaddr.sa_family);
 		return -1;
 	}
 	os_memcpy(own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
 
 	/* setup dhcp listen socket for sta detection */
 	if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
-		perror("socket call failed for dhcp");
+		wpa_printf(MSG_ERROR, "socket call failed for dhcp: %s",
+			   strerror(errno));
 		return -1;
 	}
 
 	if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, drv->ctx,
 				     NULL)) {
-		printf("Could not register read socket\n");
+		wpa_printf(MSG_INFO, "Could not register read socket");
 		return -1;
 	}
 
@@ -277,12 +281,14 @@
 
 	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
 		       sizeof(n)) == -1) {
-		perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
+		wpa_printf(MSG_ERROR, "setsockopt[SOL_SOCKET,SO_REUSEADDR]: %s",
+			   strerror(errno));
 		return -1;
 	}
 	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
 		       sizeof(n)) == -1) {
-		perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
+		wpa_printf(MSG_ERROR, "setsockopt[SOL_SOCKET,SO_BROADCAST]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -290,13 +296,15 @@
 	os_strlcpy(ifr.ifr_ifrn.ifrn_name, drv->ifname, IFNAMSIZ);
 	if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
 		       (char *) &ifr, sizeof(ifr)) < 0) {
-		perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
+		wpa_printf(MSG_ERROR,
+			   "setsockopt[SOL_SOCKET,SO_BINDTODEVICE]: %s",
+			   strerror(errno));
 		return -1;
 	}
 
 	if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
 		 sizeof(struct sockaddr)) == -1) {
-		perror("bind");
+		wpa_printf(MSG_ERROR, "bind: %s", strerror(errno));
 		return -1;
 	}
 
@@ -320,8 +328,9 @@
 	len = sizeof(*hdr) + data_len;
 	hdr = os_zalloc(len);
 	if (hdr == NULL) {
-		printf("malloc() failed for wired_send_eapol(len=%lu)\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_INFO,
+			   "malloc() failed for wired_send_eapol(len=%lu)",
+			   (unsigned long) len);
 		return -1;
 	}
 
@@ -337,9 +346,9 @@
 	os_free(hdr);
 
 	if (res < 0) {
-		perror("wired_send_eapol: send");
-		printf("wired_send_eapol - packet len: %lu - failed\n",
-		       (unsigned long) len);
+		wpa_printf(MSG_ERROR,
+			   "wired_send_eapol - packet len: %lu - failed: send: %s",
+			   (unsigned long) len, strerror(errno));
 	}
 
 	return res;
@@ -353,7 +362,8 @@
 
 	drv = os_zalloc(sizeof(struct wpa_driver_wired_data));
 	if (drv == NULL) {
-		printf("Could not allocate memory for wired driver data\n");
+		wpa_printf(MSG_INFO,
+			   "Could not allocate memory for wired driver data");
 		return NULL;
 	}
 
@@ -374,11 +384,15 @@
 {
 	struct wpa_driver_wired_data *drv = priv;
 
-	if (drv->sock >= 0)
+	if (drv->sock >= 0) {
+		eloop_unregister_read_sock(drv->sock);
 		close(drv->sock);
+	}
 
-	if (drv->dhcp_sock >= 0)
+	if (drv->dhcp_sock >= 0) {
+		eloop_unregister_read_sock(drv->dhcp_sock);
 		close(drv->dhcp_sock);
+	}
 
 	os_free(drv);
 }
@@ -414,14 +428,15 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
 		return -1;
 	}
 
 	os_memset(&ifr, 0, sizeof(ifr));
 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
 	if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
-		perror("ioctl[SIOCGIFFLAGS]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIFFLAGS]: %s",
+			   strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -438,7 +453,7 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
 		return -1;
 	}
 
@@ -446,7 +461,8 @@
 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
 	ifr.ifr_flags = flags & 0xffff;
 	if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
-		perror("ioctl[SIOCSIFFLAGS]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIFFLAGS]: %s",
+			   strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -463,14 +479,15 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
 		return -1;
 	}
 
 	os_memset(&ifmr, 0, sizeof(ifmr));
 	os_strlcpy(ifmr.ifm_name, ifname, IFNAMSIZ);
 	if (ioctl(s, SIOCGIFMEDIA, (caddr_t) &ifmr) < 0) {
-		perror("ioctl[SIOCGIFMEDIA]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOCGIFMEDIA]: %s",
+			   strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -494,7 +511,7 @@
 
 	s = socket(PF_INET, SOCK_DGRAM, 0);
 	if (s < 0) {
-		perror("socket");
+		wpa_printf(MSG_ERROR, "socket: %s", strerror(errno));
 		return -1;
 	}
 
@@ -528,7 +545,8 @@
 #endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
 
 	if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
-		perror("ioctl[SIOC{ADD/DEL}MULTI]");
+		wpa_printf(MSG_ERROR, "ioctl[SIOC{ADD/DEL}MULTI]: %s",
+			   strerror(errno));
 		close(s);
 		return -1;
 	}
@@ -551,7 +569,7 @@
 #ifdef __linux__
 	drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
 	if (drv->pf_sock < 0)
-		perror("socket(PF_PACKET)");
+		wpa_printf(MSG_ERROR, "socket(PF_PACKET): %s", strerror(errno));
 #else /* __linux__ */
 	drv->pf_sock = -1;
 #endif /* __linux__ */
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index d0e42ec..f0c3bb3 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -19,9 +19,6 @@
 #ifdef CONFIG_DRIVER_HOSTAP
 extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
 #endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_MADWIFI
-extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
-#endif /* CONFIG_DRIVER_MADWIFI */
 #ifdef CONFIG_DRIVER_BSD
 extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
 #endif /* CONFIG_DRIVER_BSD */
@@ -38,9 +35,6 @@
  /* driver_macsec_qca.c */
 extern struct wpa_driver_ops wpa_driver_macsec_qca_ops;
 #endif /* CONFIG_DRIVER_MACSEC_QCA */
-#ifdef CONFIG_DRIVER_TEST
-extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
-#endif /* CONFIG_DRIVER_TEST */
 #ifdef CONFIG_DRIVER_ROBOSWITCH
 /* driver_roboswitch.c */
 extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
@@ -64,9 +58,6 @@
 #ifdef CONFIG_DRIVER_HOSTAP
 	&wpa_driver_hostap_ops,
 #endif /* CONFIG_DRIVER_HOSTAP */
-#ifdef CONFIG_DRIVER_MADWIFI
-	&wpa_driver_madwifi_ops,
-#endif /* CONFIG_DRIVER_MADWIFI */
 #ifdef CONFIG_DRIVER_BSD
 	&wpa_driver_bsd_ops,
 #endif /* CONFIG_DRIVER_BSD */
@@ -82,9 +73,6 @@
 #ifdef CONFIG_DRIVER_MACSEC_QCA
 	&wpa_driver_macsec_qca_ops,
 #endif /* CONFIG_DRIVER_MACSEC_QCA */
-#ifdef CONFIG_DRIVER_TEST
-	&wpa_driver_test_ops,
-#endif /* CONFIG_DRIVER_TEST */
 #ifdef CONFIG_DRIVER_ROBOSWITCH
 	&wpa_driver_roboswitch_ops,
 #endif /* CONFIG_DRIVER_ROBOSWITCH */
diff --git a/src/drivers/drivers.mak b/src/drivers/drivers.mak
index cdb913e..ab392bc 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -25,6 +25,10 @@
 ifdef CONFIG_DRIVER_NL80211
 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
 DRV_OBJS += ../src/drivers/driver_nl80211.o
+DRV_OBJS += ../src/drivers/driver_nl80211_capa.o
+DRV_OBJS += ../src/drivers/driver_nl80211_event.o
+DRV_OBJS += ../src/drivers/driver_nl80211_monitor.o
+DRV_OBJS += ../src/drivers/driver_nl80211_scan.o
 DRV_OBJS += ../src/utils/radiotap.o
 NEED_SME=y
 NEED_AP_MLME=y
@@ -72,12 +76,6 @@
 DRV_OBJS += ../src/drivers/driver_openbsd.o
 endif
 
-ifdef CONFIG_DRIVER_TEST
-DRV_CFLAGS += -DCONFIG_DRIVER_TEST
-DRV_OBJS += ../src/drivers/driver_test.o
-NEED_AP_MLME=y
-endif
-
 ifdef CONFIG_DRIVER_NONE
 DRV_CFLAGS += -DCONFIG_DRIVER_NONE
 DRV_OBJS += ../src/drivers/driver_none.o
@@ -94,15 +92,6 @@
 NEED_LINUX_IOCTL=y
 endif
 
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_AP_OBJS += ../src/drivers/driver_madwifi.o
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
 ifdef CONFIG_DRIVER_ATHEROS
 DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
 DRV_AP_OBJS += ../src/drivers/driver_atheros.o
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index 9fa70d9..8da4c53 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -20,6 +20,11 @@
 ifdef CONFIG_DRIVER_NL80211
 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
 DRV_OBJS += src/drivers/driver_nl80211.c
+DRV_OBJS += src/drivers/driver_nl80211_android.c
+DRV_OBJS += src/drivers/driver_nl80211_capa.c
+DRV_OBJS += src/drivers/driver_nl80211_event.c
+DRV_OBJS += src/drivers/driver_nl80211_monitor.c
+DRV_OBJS += src/drivers/driver_nl80211_scan.c
 DRV_OBJS += src/utils/radiotap.c
 NEED_SME=y
 NEED_AP_MLME=y
@@ -67,12 +72,6 @@
 DRV_OBJS += src/drivers/driver_openbsd.c
 endif
 
-ifdef CONFIG_DRIVER_TEST
-DRV_CFLAGS += -DCONFIG_DRIVER_TEST
-DRV_OBJS += src/drivers/driver_test.c
-NEED_AP_MLME=y
-endif
-
 ifdef CONFIG_DRIVER_NONE
 DRV_CFLAGS += -DCONFIG_DRIVER_NONE
 DRV_OBJS += src/drivers/driver_none.c
@@ -89,15 +88,6 @@
 NEED_LINUX_IOCTL=y
 endif
 
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_AP_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_AP_OBJS += src/drivers/driver_madwifi.c
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_L2_PACKET=linux
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
 ifdef CONFIG_DRIVER_ATHEROS
 DRV_AP_CFLAGS += -DCONFIG_DRIVER_ATHEROS
 DRV_AP_OBJS += src/drivers/driver_atheros.c
diff --git a/src/drivers/linux_defines.h b/src/drivers/linux_defines.h
new file mode 100644
index 0000000..a107479
--- /dev/null
+++ b/src/drivers/linux_defines.h
@@ -0,0 +1,46 @@
+/*
+ * Linux defines for values that are not yet included in common C libraries
+ * Copyright (c) 2014, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LINUX_DEFINES_H
+#define LINUX_DEFINES_H
+
+#ifndef SO_WIFI_STATUS
+# if defined(__sparc__)
+#  define SO_WIFI_STATUS	0x0025
+# elif defined(__parisc__)
+#  define SO_WIFI_STATUS	0x4022
+# else
+#  define SO_WIFI_STATUS	41
+# endif
+
+# define SCM_WIFI_STATUS	SO_WIFI_STATUS
+#endif
+
+#ifndef SO_EE_ORIGIN_TXSTATUS
+#define SO_EE_ORIGIN_TXSTATUS	4
+#endif
+
+#ifndef PACKET_TX_TIMESTAMP
+#define PACKET_TX_TIMESTAMP	16
+#endif
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT    0x20000         /* driver signals dormant       */
+#endif
+
+#ifndef IF_OPER_DORMANT
+#define IF_OPER_DORMANT 5
+#endif
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+#endif
+
+#endif /* LINUX_DEFINES_H */
diff --git a/src/drivers/linux_wext.h b/src/drivers/linux_wext.h
index 55cf955..e7c7001 100644
--- a/src/drivers/linux_wext.h
+++ b/src/drivers/linux_wext.h
@@ -19,13 +19,13 @@
 #define _LINUX_SOCKET_H
 #define _LINUX_IF_H
 
-#include <sys/types.h>
+#include <stdint.h>
 #include <net/if.h>
-typedef __uint32_t __u32;
-typedef __int32_t __s32;
-typedef __uint16_t __u16;
-typedef __int16_t __s16;
-typedef __uint8_t __u8;
+typedef uint32_t __u32;
+typedef int32_t __s32;
+typedef uint16_t __u16;
+typedef int16_t __s16;
+typedef uint8_t __u8;
 #ifndef __user
 #define __user
 #endif /* __user */
diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c
index 2fa20b1..0e960f4 100644
--- a/src/drivers/netlink.c
+++ b/src/drivers/netlink.c
@@ -199,8 +199,7 @@
 		rta->rta_type = IFLA_LINKMODE;
 		rta->rta_len = RTA_LENGTH(sizeof(char));
 		*((char *) RTA_DATA(rta)) = linkmode;
-		req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
-			RTA_LENGTH(sizeof(char));
+		req.hdr.nlmsg_len += RTA_SPACE(sizeof(char));
 	}
 	if (operstate != -1) {
 		rta = aliasing_hide_typecast(
@@ -209,8 +208,7 @@
 		rta->rta_type = IFLA_OPERSTATE;
 		rta->rta_len = RTA_LENGTH(sizeof(char));
 		*((char *) RTA_DATA(rta)) = operstate;
-		req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
-			RTA_LENGTH(sizeof(char));
+		req.hdr.nlmsg_len += RTA_SPACE(sizeof(char));
 	}
 
 	wpa_printf(MSG_DEBUG, "netlink: Operstate: ifindex=%d linkmode=%d (%s), operstate=%d (%s)",
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 4b28dc0..b37bd5a 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -227,7 +227,11 @@
  *	the interface identified by %NL80211_ATTR_IFINDEX.
  * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
  *	or, if no MAC address given, all stations, on the interface identified
- *	by %NL80211_ATTR_IFINDEX.
+ *	by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and
+ *	%NL80211_ATTR_REASON_CODE can optionally be used to specify which type
+ *	of disconnection indication should be sent to the station
+ *	(Deauthentication or Disassociation frame and reason code for that
+ *	frame).
  *
  * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
  * 	destination %NL80211_ATTR_MAC on the interface identified by
@@ -639,7 +643,18 @@
  * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
  *	independently of the userspace SME, send this event indicating
  *	%NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the
- *	attributes determining channel width.
+ *	attributes determining channel width.  This indication may also be
+ *	sent when a remotely-initiated switch (e.g., when a STA receives a CSA
+ *	from the remote AP) is completed;
+ *
+ * @NL80211_CMD_CH_SWITCH_STARTED_NOTIFY: Notify that a channel switch
+ *	has been started on an interface, regardless of the initiator
+ *	(ie. whether it was requested from a remote device or
+ *	initiated on our own).  It indicates that
+ *	%NL80211_ATTR_IFINDEX will be on %NL80211_ATTR_WIPHY_FREQ
+ *	after %NL80211_ATTR_CH_SWITCH_COUNT TBTT's.  The userspace may
+ *	decide to react to this indication by requesting other
+ *	interfaces to change channel as well.
  *
  * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
  *	its %NL80211_ATTR_WDEV identifier. It must have been created with
@@ -738,6 +753,27 @@
  *	before removing a station entry entirely, or before disassociating
  *	or similar, cleanup will happen in the driver/device in this case.
  *
+ * @NL80211_CMD_GET_MPP: Get mesh path attributes for mesh proxy path to
+ *	destination %NL80211_ATTR_MAC on the interface identified by
+ *	%NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_JOIN_OCB: Join the OCB network. The center frequency and
+ *	bandwidth of a channel must be given.
+ * @NL80211_CMD_LEAVE_OCB: Leave the OCB network -- no special arguments, the
+ *	network is determined by the network interface.
+ *
+ * @NL80211_CMD_TDLS_CHANNEL_SWITCH: Start channel-switching with a TDLS peer,
+ *	identified by the %NL80211_ATTR_MAC parameter. A target channel is
+ *	provided via %NL80211_ATTR_WIPHY_FREQ and other attributes determining
+ *	channel width/type. The target operating class is given via
+ *	%NL80211_ATTR_OPER_CLASS.
+ *	The driver is responsible for continually initiating channel-switching
+ *	operations and returning to the base channel for communication with the
+ *	AP.
+ * @NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH: Stop channel-switching with a TDLS
+ *	peer given by %NL80211_ATTR_MAC. Both peers must be on the base channel
+ *	when this command completes.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -912,6 +948,16 @@
 	NL80211_CMD_ADD_TX_TS,
 	NL80211_CMD_DEL_TX_TS,
 
+	NL80211_CMD_GET_MPP,
+
+	NL80211_CMD_JOIN_OCB,
+	NL80211_CMD_LEAVE_OCB,
+
+	NL80211_CMD_CH_SWITCH_STARTED_NOTIFY,
+
+	NL80211_CMD_TDLS_CHANNEL_SWITCH,
+	NL80211_CMD_TDLS_CANCEL_CHANNEL_SWITCH,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -1606,9 +1652,9 @@
  * @NL80211_ATTR_TDLS_PEER_CAPABILITY: flags for TDLS peer capabilities, u32.
  *	As specified in the &enum nl80211_tdls_peer_capability.
  *
- * @NL80211_ATTR_IFACE_SOCKET_OWNER: flag attribute, if set during interface
+ * @NL80211_ATTR_SOCKET_OWNER: Flag attribute, if set during interface
  *	creation then the new interface will be owned by the netlink socket
- *	that created it and will be destroyed when the socket is closed
+ *	that created it and will be destroyed when the socket is closed.
  *
  * @NL80211_ATTR_TDLS_INITIATOR: flag attribute indicating the current end is
  *	the TDLS link initiator.
@@ -1638,6 +1684,11 @@
  * @NL80211_ATTR_SMPS_MODE: SMPS mode to use (ap mode). see
  *	&enum nl80211_smps_mode.
  *
+ * @NL80211_ATTR_OPER_CLASS: operating class
+ *
+ * @NL80211_ATTR_MAC_MASK: MAC address mask
+ *
+ * @NUM_NL80211_ATTR: total number of nl80211_attrs available
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1973,7 +2024,7 @@
 
 	NL80211_ATTR_TDLS_PEER_CAPABILITY,
 
-	NL80211_ATTR_IFACE_SOCKET_OWNER,
+	NL80211_ATTR_SOCKET_OWNER,
 
 	NL80211_ATTR_CSA_C_OFFSETS_TX,
 	NL80211_ATTR_MAX_CSA_COUNTERS,
@@ -1990,15 +2041,21 @@
 
 	NL80211_ATTR_SMPS_MODE,
 
+	NL80211_ATTR_OPER_CLASS,
+
+	NL80211_ATTR_MAC_MASK,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
+	NUM_NL80211_ATTR = __NL80211_ATTR_AFTER_LAST,
 	NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
 };
 
 /* source-level API compatibility */
 #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
 #define	NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
+#define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER
 
 /*
  * Allow user space programs to use #ifdef on new attributes by defining them
@@ -2064,6 +2121,8 @@
  *	and therefore can't be created in the normal ways, use the
  *	%NL80211_CMD_START_P2P_DEVICE and %NL80211_CMD_STOP_P2P_DEVICE
  *	commands to create and destroy one
+ * @NL80211_IF_TYPE_OCB: Outside Context of a BSS
+ *	This mode corresponds to the MIB variable dot11OCBActivated=true
  * @NL80211_IFTYPE_MAX: highest interface type number currently defined
  * @NUM_NL80211_IFTYPES: number of defined interface types
  *
@@ -2083,6 +2142,7 @@
 	NL80211_IFTYPE_P2P_CLIENT,
 	NL80211_IFTYPE_P2P_GO,
 	NL80211_IFTYPE_P2P_DEVICE,
+	NL80211_IFTYPE_OCB,
 
 	/* keep last */
 	NUM_NL80211_IFTYPES,
@@ -2631,6 +2691,11 @@
  * @NL80211_RRF_AUTO_BW: maximum available bandwidth should be calculated
  *	base on contiguous rules and wider channels will be allowed to cross
  *	multiple contiguous/overlapping frequency ranges.
+ * @NL80211_RRF_GO_CONCURRENT: See &NL80211_FREQUENCY_ATTR_GO_CONCURRENT
+ * @NL80211_RRF_NO_HT40MINUS: channels can't be used in HT40- operation
+ * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation
+ * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed
+ * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed
  */
 enum nl80211_reg_rule_flags {
 	NL80211_RRF_NO_OFDM		= 1<<0,
@@ -2643,11 +2708,18 @@
 	NL80211_RRF_NO_IR		= 1<<7,
 	__NL80211_RRF_NO_IBSS		= 1<<8,
 	NL80211_RRF_AUTO_BW		= 1<<11,
+	NL80211_RRF_GO_CONCURRENT	= 1<<12,
+	NL80211_RRF_NO_HT40MINUS	= 1<<13,
+	NL80211_RRF_NO_HT40PLUS		= 1<<14,
+	NL80211_RRF_NO_80MHZ		= 1<<15,
+	NL80211_RRF_NO_160MHZ		= 1<<16,
 };
 
 #define NL80211_RRF_PASSIVE_SCAN	NL80211_RRF_NO_IR
 #define NL80211_RRF_NO_IBSS		NL80211_RRF_NO_IR
 #define NL80211_RRF_NO_IR		NL80211_RRF_NO_IR
+#define NL80211_RRF_NO_HT40		(NL80211_RRF_NO_HT40MINUS |\
+					 NL80211_RRF_NO_HT40PLUS)
 
 /* For backport compatibility with older userspace */
 #define NL80211_RRF_NO_IR_ALL		(NL80211_RRF_NO_IR | __NL80211_RRF_NO_IBSS)
@@ -3379,6 +3451,8 @@
  *	interval in which %NL80211_ATTR_CQM_TXE_PKTS and
  *	%NL80211_ATTR_CQM_TXE_RATE must be satisfied before generating an
  *	%NL80211_CMD_NOTIFY_CQM. Set to 0 to turn off TX error reporting.
+ * @NL80211_ATTR_CQM_BEACON_LOSS_EVENT: flag attribute that's set in a beacon
+ *	loss event
  * @__NL80211_ATTR_CQM_AFTER_LAST: internal
  * @NL80211_ATTR_CQM_MAX: highest key attribute
  */
@@ -3391,6 +3465,7 @@
 	NL80211_ATTR_CQM_TXE_RATE,
 	NL80211_ATTR_CQM_TXE_PKTS,
 	NL80211_ATTR_CQM_TXE_INTVL,
+	NL80211_ATTR_CQM_BEACON_LOSS_EVENT,
 
 	/* keep last */
 	__NL80211_ATTR_CQM_AFTER_LAST,
@@ -3403,9 +3478,7 @@
  *      configured threshold
  * @NL80211_CQM_RSSI_THRESHOLD_EVENT_HIGH: The RSSI is higher than the
  *      configured threshold
- * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: The device experienced beacon loss.
- *	(Note that deauth/disassoc will still follow if the AP is not
- *	available. This event might get used as roaming event, etc.)
+ * @NL80211_CQM_RSSI_BEACON_LOSS_EVENT: (reserved, never sent)
  */
 enum nl80211_cqm_rssi_threshold_event {
 	NL80211_CQM_RSSI_THRESHOLD_EVENT_LOW,
@@ -3545,6 +3618,25 @@
  * @NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS: For wakeup reporting only,
  *	the TCP connection ran out of tokens to use for data to send to the
  *	service
+ * @NL80211_WOWLAN_TRIG_NET_DETECT: wake up when a configured network
+ *	is detected.  This is a nested attribute that contains the
+ *	same attributes used with @NL80211_CMD_START_SCHED_SCAN.  It
+ *	specifies how the scan is performed (e.g. the interval and the
+ *	channels to scan) as well as the scan results that will
+ *	trigger a wake (i.e. the matchsets).
+ * @NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS: nested attribute
+ *	containing an array with information about what triggered the
+ *	wake up.  If no elements are present in the array, it means
+ *	that the information is not available.  If more than one
+ *	element is present, it means that more than one match
+ *	occurred.
+ *	Each element in the array is a nested attribute that contains
+ *	one optional %NL80211_ATTR_SSID attribute and one optional
+ *	%NL80211_ATTR_SCAN_FREQUENCIES attribute.  At least one of
+ *	these attributes must be present.  If
+ *	%NL80211_ATTR_SCAN_FREQUENCIES contains more than one
+ *	frequency, it means that the match occurred in more than one
+ *	channel.
  * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
  * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
  *
@@ -3570,6 +3662,8 @@
 	NL80211_WOWLAN_TRIG_WAKEUP_TCP_MATCH,
 	NL80211_WOWLAN_TRIG_WAKEUP_TCP_CONNLOST,
 	NL80211_WOWLAN_TRIG_WAKEUP_TCP_NOMORETOKENS,
+	NL80211_WOWLAN_TRIG_NET_DETECT,
+	NL80211_WOWLAN_TRIG_NET_DETECT_RESULTS,
 
 	/* keep last */
 	NUM_NL80211_WOWLAN_TRIG,
@@ -4042,6 +4136,27 @@
  *	multiplexing powersave, ie. can turn off all but one chain
  *	and then wake the rest up as required after, for example,
  *	rts/cts handshake.
+ * @NL80211_FEATURE_SUPPORTS_WMM_ADMISSION: the device supports setting up WMM
+ *	TSPEC sessions (TID aka TSID 0-7) with the %NL80211_CMD_ADD_TX_TS
+ *	command. Standard IEEE 802.11 TSPEC setup is not yet supported, it
+ *	needs to be able to handle Block-Ack agreements and other things.
+ * @NL80211_FEATURE_MAC_ON_CREATE: Device supports configuring
+ *	the vif's MAC address upon creation.
+ *	See 'macaddr' field in the vif_params (cfg80211.h).
+ * @NL80211_FEATURE_TDLS_CHANNEL_SWITCH: Driver supports channel switching when
+ *	operating as a TDLS peer.
+ * @NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR: This device/driver supports using a
+ *	random MAC address during scan (if the device is unassociated); the
+ *	%NL80211_SCAN_FLAG_RANDOM_ADDR flag may be set for scans and the MAC
+ *	address mask/value will be used.
+ * @NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR: This device/driver supports
+ *	using a random MAC address for every scan iteration during scheduled
+ *	scan (while not associated), the %NL80211_SCAN_FLAG_RANDOM_ADDR may
+ *	be set for scheduled scan and the MAC address mask/value will be used.
+ * @NL80211_FEATURE_ND_RANDOM_MAC_ADDR: This device/driver supports using a
+ *	random MAC address for every scan iteration during "net detect", i.e.
+ *	scan in unassociated WoWLAN, the %NL80211_SCAN_FLAG_RANDOM_ADDR may
+ *	be set for scheduled scan and the MAC address mask/value will be used.
  */
 enum nl80211_feature_flags {
 	NL80211_FEATURE_SK_TX_STATUS			= 1 << 0,
@@ -4070,6 +4185,12 @@
 	NL80211_FEATURE_ACKTO_ESTIMATION		= 1 << 23,
 	NL80211_FEATURE_STATIC_SMPS			= 1 << 24,
 	NL80211_FEATURE_DYNAMIC_SMPS			= 1 << 25,
+	NL80211_FEATURE_SUPPORTS_WMM_ADMISSION		= 1 << 26,
+	NL80211_FEATURE_MAC_ON_CREATE			= 1 << 27,
+	NL80211_FEATURE_TDLS_CHANNEL_SWITCH		= 1 << 28,
+	NL80211_FEATURE_SCAN_RANDOM_MAC_ADDR		= 1 << 29,
+	NL80211_FEATURE_SCHED_SCAN_RANDOM_MAC_ADDR	= 1 << 30,
+	NL80211_FEATURE_ND_RANDOM_MAC_ADDR		= 1 << 31,
 };
 
 /**
@@ -4118,11 +4239,21 @@
  *	dangerous because will destroy stations performance as a lot of frames
  *	will be lost while scanning off-channel, therefore it must be used only
  *	when really needed
+ * @NL80211_SCAN_FLAG_RANDOM_ADDR: use a random MAC address for this scan (or
+ *	for scheduled scan: a different one for every scan iteration). When the
+ *	flag is set, depending on device capabilities the @NL80211_ATTR_MAC and
+ *	@NL80211_ATTR_MAC_MASK attributes may also be given in which case only
+ *	the masked bits will be preserved from the MAC address and the remainder
+ *	randomised. If the attributes are not given full randomisation (46 bits,
+ *	locally administered 1, multicast 0) is assumed.
+ *	This flag must not be requested when the feature isn't supported, check
+ *	the nl80211 feature flags for the device.
  */
 enum nl80211_scan_flags {
 	NL80211_SCAN_FLAG_LOW_PRIORITY			= 1<<0,
 	NL80211_SCAN_FLAG_FLUSH				= 1<<1,
 	NL80211_SCAN_FLAG_AP				= 1<<2,
+	NL80211_SCAN_FLAG_RANDOM_ADDR			= 1<<3,
 };
 
 /**
diff --git a/src/drivers/priv_netlink.h b/src/drivers/priv_netlink.h
index 6232088..d3f091c 100644
--- a/src/drivers/priv_netlink.h
+++ b/src/drivers/priv_netlink.h
@@ -68,6 +68,7 @@
 ((attrlen) -= RTA_ALIGN((rta)->rta_len), \
 (struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
 #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
 #define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0)))
 #define RTA_PAYLOAD(rta) ((int) ((rta)->rta_len) - RTA_LENGTH(0))
 
diff --git a/src/eap_common/eap_common.c b/src/eap_common/eap_common.c
index 7b077cb..1de1328 100644
--- a/src/eap_common/eap_common.c
+++ b/src/eap_common/eap_common.c
@@ -1,6 +1,6 @@
 /*
  * EAP common peer/server definitions
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -203,3 +203,86 @@
 
 	return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)];
 }
+
+
+#ifdef CONFIG_ERP
+int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs,
+		   int stop_at_keyname)
+{
+	os_memset(tlvs, 0, sizeof(*tlvs));
+
+	while (pos < end) {
+		u8 tlv_type, tlv_len;
+
+		tlv_type = *pos++;
+		switch (tlv_type) {
+		case EAP_ERP_TV_RRK_LIFETIME:
+		case EAP_ERP_TV_RMSK_LIFETIME:
+			/* 4-octet TV */
+			if (pos + 4 > end) {
+				wpa_printf(MSG_DEBUG, "EAP: Too short TV");
+				return -1;
+			}
+			pos += 4;
+			break;
+		case EAP_ERP_TLV_DOMAIN_NAME:
+		case EAP_ERP_TLV_KEYNAME_NAI:
+		case EAP_ERP_TLV_CRYPTOSUITES:
+		case EAP_ERP_TLV_AUTHORIZATION_INDICATION:
+		case EAP_ERP_TLV_CALLED_STATION_ID:
+		case EAP_ERP_TLV_CALLING_STATION_ID:
+		case EAP_ERP_TLV_NAS_IDENTIFIER:
+		case EAP_ERP_TLV_NAS_IP_ADDRESS:
+		case EAP_ERP_TLV_NAS_IPV6_ADDRESS:
+			if (pos >= end) {
+				wpa_printf(MSG_DEBUG, "EAP: Too short TLV");
+				return -1;
+			}
+			tlv_len = *pos++;
+			if (tlv_len > (unsigned) (end - pos)) {
+				wpa_printf(MSG_DEBUG, "EAP: Truncated TLV");
+				return -1;
+			}
+			if (tlv_type == EAP_ERP_TLV_KEYNAME_NAI) {
+				if (tlvs->keyname) {
+					wpa_printf(MSG_DEBUG,
+						   "EAP: More than one keyName-NAI");
+					return -1;
+				}
+				tlvs->keyname = pos;
+				tlvs->keyname_len = tlv_len;
+				if (stop_at_keyname)
+					return 0;
+			} else if (tlv_type == EAP_ERP_TLV_DOMAIN_NAME) {
+				tlvs->domain = pos;
+				tlvs->domain_len = tlv_len;
+			}
+			pos += tlv_len;
+			break;
+		default:
+			if (tlv_type >= 128 && tlv_type <= 191) {
+				/* Undefined TLV */
+				if (pos >= end) {
+					wpa_printf(MSG_DEBUG,
+						   "EAP: Too short TLV");
+					return -1;
+				}
+				tlv_len = *pos++;
+				if (tlv_len > (unsigned) (end - pos)) {
+					wpa_printf(MSG_DEBUG,
+						   "EAP: Truncated TLV");
+					return -1;
+				}
+				pos += tlv_len;
+				break;
+			}
+			wpa_printf(MSG_DEBUG, "EAP: Unknown TV/TLV type %u",
+				   tlv_type);
+			pos = end;
+			break;
+		}
+	}
+
+	return 0;
+}
+#endif /* CONFIG_ERP */
diff --git a/src/eap_common/eap_common.h b/src/eap_common/eap_common.h
index 8850c1f..e62f167 100644
--- a/src/eap_common/eap_common.h
+++ b/src/eap_common/eap_common.h
@@ -1,6 +1,6 @@
 /*
  * EAP common peer/server definitions
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -11,6 +11,14 @@
 
 #include "wpabuf.h"
 
+struct erp_tlvs {
+	const u8 *keyname;
+	const u8 *domain;
+
+	u8 keyname_len;
+	u8 domain_len;
+};
+
 int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
 const u8 * eap_hdr_validate(int vendor, EapType eap_type,
 			    const struct wpabuf *msg, size_t *plen);
@@ -19,5 +27,7 @@
 void eap_update_len(struct wpabuf *msg);
 u8 eap_get_id(const struct wpabuf *msg);
 EapType eap_get_type(const struct wpabuf *msg);
+int erp_parse_tlvs(const u8 *pos, const u8 *end, struct erp_tlvs *tlvs,
+		   int stop_at_keyname);
 
 #endif /* EAP_COMMON_H */
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index 4f14a01..54f26ca 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -1,6 +1,6 @@
 /*
  * EAP server/peer: Shared EAP definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -27,11 +27,39 @@
 #endif /* _MSC_VER */
 
 enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
-       EAP_CODE_FAILURE = 4 };
+       EAP_CODE_FAILURE = 4, EAP_CODE_INITIATE = 5, EAP_CODE_FINISH = 6 };
 
 /* EAP Request and Response data begins with one octet Type. Success and
  * Failure do not have additional data. */
 
+/* Type field in EAP-Initiate and EAP-Finish messages */
+enum eap_erp_type {
+	EAP_ERP_TYPE_REAUTH_START = 1,
+	EAP_ERP_TYPE_REAUTH = 2,
+};
+
+/* ERP TV/TLV types */
+enum eap_erp_tlv_type {
+	EAP_ERP_TLV_KEYNAME_NAI = 1,
+	EAP_ERP_TV_RRK_LIFETIME = 2,
+	EAP_ERP_TV_RMSK_LIFETIME = 3,
+	EAP_ERP_TLV_DOMAIN_NAME = 4,
+	EAP_ERP_TLV_CRYPTOSUITES = 5,
+	EAP_ERP_TLV_AUTHORIZATION_INDICATION = 6,
+	EAP_ERP_TLV_CALLED_STATION_ID = 128,
+	EAP_ERP_TLV_CALLING_STATION_ID = 129,
+	EAP_ERP_TLV_NAS_IDENTIFIER = 130,
+	EAP_ERP_TLV_NAS_IP_ADDRESS = 131,
+	EAP_ERP_TLV_NAS_IPV6_ADDRESS = 132,
+};
+
+/* ERP Cryptosuite */
+enum eap_erp_cryptosuite {
+	EAP_ERP_CS_HMAC_SHA256_64 = 1,
+	EAP_ERP_CS_HMAC_SHA256_128 = 2,
+	EAP_ERP_CS_HMAC_SHA256_256 = 3,
+};
+
 /*
  * EAP Method Types as allocated by IANA:
  * http://www.iana.org/assignments/eap-numbers
@@ -84,5 +112,7 @@
 
 #define EAP_MSK_LEN 64
 #define EAP_EMSK_LEN 64
+#define EAP_EMSK_NAME_LEN 8
+#define ERP_MAX_KEY_LEN 64
 
 #endif /* EAP_DEFS_H */
diff --git a/src/eap_common/eap_pax_common.c b/src/eap_common/eap_pax_common.c
index b3bbacc..0e80ef5 100644
--- a/src/eap_common/eap_pax_common.c
+++ b/src/eap_common/eap_pax_common.c
@@ -121,10 +121,11 @@
  * @mk: Buffer for the derived Master Key
  * @ck: Buffer for the derived Confirmation Key
  * @ick: Buffer for the derived Integrity Check Key
+ * @mid: Buffer for the derived Method ID
  * Returns: 0 on success, -1 on failure
  */
 int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
-				   u8 *mk, u8 *ck, u8 *ick)
+				   u8 *mk, u8 *ck, u8 *ick, u8 *mid)
 {
 	wpa_printf(MSG_DEBUG, "EAP-PAX: initial key derivation");
 	if (eap_pax_kdf(mac_id, ak, EAP_PAX_AK_LEN, "Master Key",
@@ -132,13 +133,16 @@
 	    eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Confirmation Key",
 			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_CK_LEN, ck) ||
 	    eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Integrity Check Key",
-			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick))
+			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_ICK_LEN, ick) ||
+	    eap_pax_kdf(mac_id, mk, EAP_PAX_MK_LEN, "Method ID",
+			e, 2 * EAP_PAX_RAND_LEN, EAP_PAX_MID_LEN, mid))
 		return -1;
 
 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: AK", ak, EAP_PAX_AK_LEN);
 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MK", mk, EAP_PAX_MK_LEN);
 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: CK", ck, EAP_PAX_CK_LEN);
 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: ICK", ick, EAP_PAX_ICK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "EAP-PAX: MID", mid, EAP_PAX_MID_LEN);
 
 	return 0;
 }
diff --git a/src/eap_common/eap_pax_common.h b/src/eap_common/eap_pax_common.h
index fb03df2..e6cdf4d 100644
--- a/src/eap_common/eap_pax_common.h
+++ b/src/eap_common/eap_pax_common.h
@@ -74,6 +74,7 @@
 #define EAP_PAX_MK_LEN 16
 #define EAP_PAX_CK_LEN 16
 #define EAP_PAX_ICK_LEN 16
+#define EAP_PAX_MID_LEN 16
 
 
 int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
@@ -86,6 +87,6 @@
 		const u8 *data3, size_t data3_len,
 		u8 *mac);
 int eap_pax_initial_key_derivation(u8 mac_id, const u8 *ak, const u8 *e,
-				   u8 *mk, u8 *ck, u8 *ick);
+				   u8 *mk, u8 *ck, u8 *ick, u8 *mid);
 
 #endif /* EAP_PAX_COMMON_H */
diff --git a/src/eap_common/ikev2_common.c b/src/eap_common/ikev2_common.c
index 3d4fb6f..4f9e64e 100644
--- a/src/eap_common/ikev2_common.c
+++ b/src/eap_common/ikev2_common.c
@@ -251,25 +251,29 @@
 	os_memset(payloads, 0, sizeof(*payloads));
 
 	while (next_payload != IKEV2_PAYLOAD_NO_NEXT_PAYLOAD) {
-		int plen, pdatalen;
+		unsigned int plen, pdatalen, left;
 		const u8 *pdata;
 		wpa_printf(MSG_DEBUG, "IKEV2: Processing payload %u",
 			   next_payload);
-		if (end - pos < (int) sizeof(*phdr)) {
+		if (end < pos)
+			return -1;
+		left = end - pos;
+		if (left < sizeof(*phdr)) {
 			wpa_printf(MSG_INFO, "IKEV2:   Too short message for "
 				   "payload header (left=%ld)",
 				   (long) (end - pos));
+			return -1;
 		}
 		phdr = (const struct ikev2_payload_hdr *) pos;
 		plen = WPA_GET_BE16(phdr->payload_length);
-		if (plen < (int) sizeof(*phdr) || pos + plen > end) {
+		if (plen < sizeof(*phdr) || plen > left) {
 			wpa_printf(MSG_INFO, "IKEV2:   Invalid payload header "
 				   "length %d", plen);
 			return -1;
 		}
 
 		wpa_printf(MSG_DEBUG, "IKEV2:   Next Payload: %u  Flags: 0x%x"
-			   "  Payload Length: %d",
+			   "  Payload Length: %u",
 			   phdr->next_payload, phdr->flags, plen);
 
 		pdata = (const u8 *) (phdr + 1);
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index 9880d3b..31c1a29 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -23,6 +23,7 @@
 #include "ext_password.h"
 #include "crypto/crypto.h"
 #include "crypto/tls.h"
+#include "crypto/sha256.h"
 #include "common/wpa_ctrl.h"
 #include "eap_common/eap_wsc_common.h"
 #include "eap_i.h"
@@ -190,6 +191,8 @@
 	sm->num_rounds = 0;
 	sm->prev_failure = 0;
 	sm->expected_failure = 0;
+	sm->reauthInit = FALSE;
+	sm->erp_seq = (u32) -1;
 }
 
 
@@ -353,6 +356,267 @@
 }
 
 
+#ifdef CONFIG_ERP
+
+static char * eap_home_realm(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	char *realm;
+	size_t i, realm_len;
+
+	if (!config)
+		return NULL;
+
+	if (config->identity) {
+		for (i = 0; i < config->identity_len; i++) {
+			if (config->identity[i] == '@')
+				break;
+		}
+		if (i < config->identity_len) {
+			realm_len = config->identity_len - i - 1;
+			realm = os_malloc(realm_len + 1);
+			if (realm == NULL)
+				return NULL;
+			os_memcpy(realm, &config->identity[i + 1], realm_len);
+			realm[realm_len] = '\0';
+			return realm;
+		}
+	}
+
+	if (config->anonymous_identity) {
+		for (i = 0; i < config->anonymous_identity_len; i++) {
+			if (config->anonymous_identity[i] == '@')
+				break;
+		}
+		if (i < config->anonymous_identity_len) {
+			realm_len = config->anonymous_identity_len - i - 1;
+			realm = os_malloc(realm_len + 1);
+			if (realm == NULL)
+				return NULL;
+			os_memcpy(realm, &config->anonymous_identity[i + 1],
+				  realm_len);
+			realm[realm_len] = '\0';
+			return realm;
+		}
+	}
+
+	return os_strdup("");
+}
+
+
+static struct eap_erp_key *
+eap_erp_get_key(struct eap_sm *sm, const char *realm)
+{
+	struct eap_erp_key *erp;
+
+	dl_list_for_each(erp, &sm->erp_keys, struct eap_erp_key, list) {
+		char *pos;
+
+		pos = os_strchr(erp->keyname_nai, '@');
+		if (!pos)
+			continue;
+		pos++;
+		if (os_strcmp(pos, realm) == 0)
+			return erp;
+	}
+
+	return NULL;
+}
+
+
+static struct eap_erp_key *
+eap_erp_get_key_nai(struct eap_sm *sm, const char *nai)
+{
+	struct eap_erp_key *erp;
+
+	dl_list_for_each(erp, &sm->erp_keys, struct eap_erp_key, list) {
+		if (os_strcmp(erp->keyname_nai, nai) == 0)
+			return erp;
+	}
+
+	return NULL;
+}
+
+
+static void eap_peer_erp_free_key(struct eap_erp_key *erp)
+{
+	dl_list_del(&erp->list);
+	bin_clear_free(erp, sizeof(*erp));
+}
+
+
+static void eap_erp_remove_keys_realm(struct eap_sm *sm, const char *realm)
+{
+	struct eap_erp_key *erp;
+
+	while ((erp = eap_erp_get_key(sm, realm)) != NULL) {
+		wpa_printf(MSG_DEBUG, "EAP: Delete old ERP key %s",
+			   erp->keyname_nai);
+		eap_peer_erp_free_key(erp);
+	}
+}
+
+#endif /* CONFIG_ERP */
+
+
+void eap_peer_erp_free_keys(struct eap_sm *sm)
+{
+#ifdef CONFIG_ERP
+	struct eap_erp_key *erp, *tmp;
+
+	dl_list_for_each_safe(erp, tmp, &sm->erp_keys, struct eap_erp_key, list)
+		eap_peer_erp_free_key(erp);
+#endif /* CONFIG_ERP */
+}
+
+
+static void eap_peer_erp_init(struct eap_sm *sm)
+{
+#ifdef CONFIG_ERP
+	u8 *emsk = NULL;
+	size_t emsk_len = 0;
+	u8 EMSKname[EAP_EMSK_NAME_LEN];
+	u8 len[2];
+	char *realm;
+	size_t realm_len, nai_buf_len;
+	struct eap_erp_key *erp = NULL;
+	int pos;
+
+	realm = eap_home_realm(sm);
+	if (!realm)
+		return;
+	realm_len = os_strlen(realm);
+	wpa_printf(MSG_DEBUG, "EAP: Realm for ERP keyName-NAI: %s", realm);
+	eap_erp_remove_keys_realm(sm, realm);
+
+	nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + realm_len;
+	if (nai_buf_len > 253) {
+		/*
+		 * keyName-NAI has a maximum length of 253 octet to fit in
+		 * RADIUS attributes.
+		 */
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Too long realm for ERP keyName-NAI maximum length");
+		goto fail;
+	}
+	nai_buf_len++; /* null termination */
+	erp = os_zalloc(sizeof(*erp) + nai_buf_len);
+	if (erp == NULL)
+		goto fail;
+
+	emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
+	if (!emsk || emsk_len == 0 || emsk_len > ERP_MAX_KEY_LEN) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: No suitable EMSK available for ERP");
+		goto fail;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
+
+	WPA_PUT_BE16(len, 8);
+	if (hmac_sha256_kdf(sm->eapSessionId, sm->eapSessionIdLen, "EMSK",
+			    len, sizeof(len),
+			    EMSKname, EAP_EMSK_NAME_LEN) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
+		goto fail;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
+
+	pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
+			       EMSKname, EAP_EMSK_NAME_LEN);
+	erp->keyname_nai[pos] = '@';
+	os_memcpy(&erp->keyname_nai[pos + 1], realm, realm_len);
+
+	WPA_PUT_BE16(len, emsk_len);
+	if (hmac_sha256_kdf(emsk, emsk_len,
+			    "EAP Re-authentication Root Key@ietf.org",
+			    len, sizeof(len), erp->rRK, emsk_len) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP");
+		goto fail;
+	}
+	erp->rRK_len = emsk_len;
+	wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
+
+	if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+			    "EAP Re-authentication Integrity Key@ietf.org",
+			    len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
+		goto fail;
+	}
+	erp->rIK_len = erp->rRK_len;
+	wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
+
+	wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s", erp->keyname_nai);
+	dl_list_add(&sm->erp_keys, &erp->list);
+	erp = NULL;
+fail:
+	bin_clear_free(emsk, emsk_len);
+	bin_clear_free(erp, sizeof(*erp));
+	os_free(realm);
+#endif /* CONFIG_ERP */
+}
+
+
+#ifdef CONFIG_ERP
+static int eap_peer_erp_reauth_start(struct eap_sm *sm,
+				     const struct eap_hdr *hdr, size_t len)
+{
+	char *realm;
+	struct eap_erp_key *erp;
+	struct wpabuf *msg;
+	u8 hash[SHA256_MAC_LEN];
+
+	realm = eap_home_realm(sm);
+	if (!realm)
+		return -1;
+
+	erp = eap_erp_get_key(sm, realm);
+	os_free(realm);
+	realm = NULL;
+	if (!erp)
+		return -1;
+
+	if (erp->next_seq >= 65536)
+		return -1; /* SEQ has range of 0..65535 */
+
+	/* TODO: check rRK lifetime expiration */
+
+	wpa_printf(MSG_DEBUG, "EAP: Valid ERP key found %s (SEQ=%u)",
+		   erp->keyname_nai, erp->next_seq);
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH,
+			    1 + 2 + 2 + os_strlen(erp->keyname_nai) + 1 + 16,
+			    EAP_CODE_INITIATE, hdr->identifier);
+	if (msg == NULL)
+		return -1;
+
+	wpabuf_put_u8(msg, 0x20); /* Flags: R=0 B=0 L=1 */
+	wpabuf_put_be16(msg, erp->next_seq);
+
+	wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
+	wpabuf_put_u8(msg, os_strlen(erp->keyname_nai));
+	wpabuf_put_str(msg, erp->keyname_nai);
+
+	wpabuf_put_u8(msg, EAP_ERP_CS_HMAC_SHA256_128); /* Cryptosuite */
+
+	if (hmac_sha256(erp->rIK, erp->rIK_len,
+			wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
+		wpabuf_free(msg);
+		return -1;
+	}
+	wpabuf_put_data(msg, hash, 16);
+
+	wpa_printf(MSG_DEBUG, "EAP: Sending EAP-Initiate/Re-auth");
+	sm->erp_seq = erp->next_seq;
+	erp->next_seq++;
+	wpabuf_free(sm->eapRespData);
+	sm->eapRespData = msg;
+	sm->reauthInit = TRUE;
+	return 0;
+}
+#endif /* CONFIG_ERP */
+
+
 /*
  * The method processing happens here. The request from the authenticator is
  * processed, and an appropriate response packet is built.
@@ -414,6 +678,8 @@
 
 	if (sm->m->isKeyAvailable && sm->m->getKey &&
 	    sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
+		struct eap_peer_config *config = eap_get_config(sm);
+
 		eap_sm_free_key(sm);
 		sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
 					       &sm->eapKeyDataLen);
@@ -426,6 +692,8 @@
 			wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
 				    sm->eapSessionId, sm->eapSessionIdLen);
 		}
+		if (config->erp && sm->m->get_emsk && sm->eapSessionId)
+			eap_peer_erp_init(sm);
 	}
 }
 
@@ -450,6 +718,7 @@
 	}
 	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
 	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
+	sm->reauthInit = FALSE;
 }
 
 
@@ -709,6 +978,8 @@
 	else if (sm->selectedMethod == EAP_TYPE_LEAP &&
 		 (sm->rxSuccess || sm->rxResp))
 		SM_ENTER(EAP, METHOD);
+	else if (sm->reauthInit)
+		SM_ENTER(EAP, SEND_RESPONSE);
 	else
 		SM_ENTER(EAP, DISCARD);
 }
@@ -1231,6 +1502,219 @@
 }
 
 
+static void eap_peer_initiate(struct eap_sm *sm, const struct eap_hdr *hdr,
+			      size_t len)
+{
+#ifdef CONFIG_ERP
+	const u8 *pos = (const u8 *) (hdr + 1);
+	const u8 *end = ((const u8 *) hdr) + len;
+	struct erp_tlvs parse;
+
+	if (len < sizeof(*hdr) + 1) {
+		wpa_printf(MSG_DEBUG, "EAP: Ignored too short EAP-Initiate");
+		return;
+	}
+
+	if (*pos != EAP_ERP_TYPE_REAUTH_START) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Ignored unexpected EAP-Initiate Type=%u",
+			   *pos);
+		return;
+	}
+
+	pos++;
+	if (pos >= end) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Too short EAP-Initiate/Re-auth-Start");
+		return;
+	}
+	pos++; /* Reserved */
+	wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth-Start TVs/TLVs",
+		    pos, end - pos);
+
+	if (erp_parse_tlvs(pos, end, &parse, 0) < 0)
+		goto invalid;
+
+	if (parse.domain) {
+		wpa_hexdump_ascii(MSG_DEBUG,
+				  "EAP: EAP-Initiate/Re-auth-Start - Domain name",
+				  parse.domain, parse.domain_len);
+		/* TODO: Derivation of domain specific keys for local ER */
+	}
+
+	if (eap_peer_erp_reauth_start(sm, hdr, len) == 0)
+		return;
+
+invalid:
+#endif /* CONFIG_ERP */
+	wpa_printf(MSG_DEBUG,
+		   "EAP: EAP-Initiate/Re-auth-Start - No suitable ERP keys available - try to start full EAP authentication");
+	eapol_set_bool(sm, EAPOL_eapTriggerStart, TRUE);
+}
+
+
+static void eap_peer_finish(struct eap_sm *sm, const struct eap_hdr *hdr,
+			    size_t len)
+{
+#ifdef CONFIG_ERP
+	const u8 *pos = (const u8 *) (hdr + 1);
+	const u8 *end = ((const u8 *) hdr) + len;
+	const u8 *start;
+	struct erp_tlvs parse;
+	u8 flags;
+	u16 seq;
+	u8 hash[SHA256_MAC_LEN];
+	size_t hash_len;
+	struct eap_erp_key *erp;
+	int max_len;
+	char nai[254];
+	u8 seed[4];
+	int auth_tag_ok = 0;
+
+	if (len < sizeof(*hdr) + 1) {
+		wpa_printf(MSG_DEBUG, "EAP: Ignored too short EAP-Finish");
+		return;
+	}
+
+	if (*pos != EAP_ERP_TYPE_REAUTH) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Ignored unexpected EAP-Finish Type=%u", *pos);
+		return;
+	}
+
+	if (len < sizeof(*hdr) + 4) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Ignored too short EAP-Finish/Re-auth");
+		return;
+	}
+
+	pos++;
+	flags = *pos++;
+	seq = WPA_GET_BE16(pos);
+	pos += 2;
+	wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
+
+	if (seq != sm->erp_seq) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Unexpected EAP-Finish/Re-auth SEQ=%u", seq);
+		return;
+	}
+
+	/*
+	 * Parse TVs/TLVs. Since we do not yet know the length of the
+	 * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
+	 * just try to find the keyName-NAI first so that we can check the
+	 * Authentication Tag.
+	 */
+	if (erp_parse_tlvs(pos, end, &parse, 1) < 0)
+		return;
+
+	if (!parse.keyname) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: No keyName-NAI in EAP-Finish/Re-auth Packet");
+		return;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Finish/Re-auth - keyName-NAI",
+			  parse.keyname, parse.keyname_len);
+	if (parse.keyname_len > 253) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Too long keyName-NAI in EAP-Finish/Re-auth");
+		return;
+	}
+	os_memcpy(nai, parse.keyname, parse.keyname_len);
+	nai[parse.keyname_len] = '\0';
+
+	erp = eap_erp_get_key_nai(sm, nai);
+	if (!erp) {
+		wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s",
+			   nai);
+		return;
+	}
+
+	/* Is there enough room for Cryptosuite and Authentication Tag? */
+	start = parse.keyname + parse.keyname_len;
+	max_len = end - start;
+	hash_len = 16;
+	if (max_len < 1 + (int) hash_len) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Not enough room for Authentication Tag");
+		if (flags & 0x80)
+			goto no_auth_tag;
+		return;
+	}
+	if (end[-17] != EAP_ERP_CS_HMAC_SHA256_128) {
+		wpa_printf(MSG_DEBUG, "EAP: Different Cryptosuite used");
+		if (flags & 0x80)
+			goto no_auth_tag;
+		return;
+	}
+
+	if (hmac_sha256(erp->rIK, erp->rIK_len, (const u8 *) hdr,
+			end - ((const u8 *) hdr) - hash_len, hash) < 0)
+		return;
+	if (os_memcmp(end - hash_len, hash, hash_len) != 0) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Authentication Tag mismatch");
+		return;
+	}
+	auth_tag_ok = 1;
+	end -= 1 + hash_len;
+
+no_auth_tag:
+	/*
+	 * Parse TVs/TLVs again now that we know the exact part of the buffer
+	 * that contains them.
+	 */
+	wpa_hexdump(MSG_DEBUG, "EAP: EAP-Finish/Re-Auth TVs/TLVs",
+		    pos, end - pos);
+	if (erp_parse_tlvs(pos, end, &parse, 0) < 0)
+		return;
+
+	if (flags & 0x80 || !auth_tag_ok) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: EAP-Finish/Re-auth indicated failure");
+		eapol_set_bool(sm, EAPOL_eapFail, TRUE);
+		eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+		eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+			"EAP authentication failed");
+		sm->prev_failure = 1;
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Drop ERP key to try full authentication on next attempt");
+		eap_peer_erp_free_key(erp);
+		return;
+	}
+
+	eap_sm_free_key(sm);
+	sm->eapKeyDataLen = 0;
+	sm->eapKeyData = os_malloc(erp->rRK_len);
+	if (!sm->eapKeyData)
+		return;
+	sm->eapKeyDataLen = erp->rRK_len;
+
+	WPA_PUT_BE16(seed, seq);
+	WPA_PUT_BE16(&seed[2], erp->rRK_len);
+	if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+			    "Re-authentication Master Session Key@ietf.org",
+			    seed, sizeof(seed),
+			    sm->eapKeyData, erp->rRK_len) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP");
+		eap_sm_free_key(sm);
+		return;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
+			sm->eapKeyData, sm->eapKeyDataLen);
+	sm->eapKeyAvailable = TRUE;
+	eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+		"EAP re-authentication completed successfully");
+#endif /* CONFIG_ERP */
+}
+
+
 static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
 {
 	const struct eap_hdr *hdr;
@@ -1322,6 +1806,12 @@
 		eap_notify_status(sm, "completion", "failure");
 		sm->rxFailure = TRUE;
 		break;
+	case EAP_CODE_INITIATE:
+		eap_peer_initiate(sm, hdr, plen);
+		break;
+	case EAP_CODE_FINISH:
+		eap_peer_finish(sm, hdr, plen);
+		break;
 	default:
 		wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
 			   "code %d", hdr->code);
@@ -1413,11 +1903,13 @@
 	sm->msg_ctx = msg_ctx;
 	sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
 	sm->wps = conf->wps;
+	dl_list_init(&sm->erp_keys);
 
 	os_memset(&tlsconf, 0, sizeof(tlsconf));
 	tlsconf.opensc_engine_path = conf->opensc_engine_path;
 	tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
 	tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
+	tlsconf.openssl_ciphers = conf->openssl_ciphers;
 #ifdef CONFIG_FIPS
 	tlsconf.fips_mode = 1;
 #endif /* CONFIG_FIPS */
@@ -1459,6 +1951,7 @@
 	if (sm->ssl_ctx2)
 		tls_deinit(sm->ssl_ctx2);
 	tls_deinit(sm->ssl_ctx);
+	eap_peer_erp_free_keys(sm);
 	os_free(sm);
 }
 
@@ -1607,7 +2100,7 @@
 	len = os_snprintf(buf, buflen,
 			  "EAP state=%s\n",
 			  eap_sm_state_txt(sm->EAP_state));
-	if (len < 0 || (size_t) len >= buflen)
+	if (os_snprintf_error(buflen, len))
 		return 0;
 
 	if (sm->selectedMethod != EAP_TYPE_NONE) {
@@ -1626,7 +2119,7 @@
 		ret = os_snprintf(buf + len, buflen - len,
 				  "selectedMethod=%d (EAP-%s)\n",
 				  sm->selectedMethod, name);
-		if (ret < 0 || (size_t) ret >= buflen - len)
+		if (os_snprintf_error(buflen - len, ret))
 			return len;
 		len += ret;
 
@@ -1647,7 +2140,7 @@
 				  eap_sm_method_state_txt(sm->methodState),
 				  eap_sm_decision_txt(sm->decision),
 				  sm->ClientTimeout);
-		if (ret < 0 || (size_t) ret >= buflen - len)
+		if (os_snprintf_error(buflen - len, ret))
 			return len;
 		len += ret;
 	}
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 712e929..bc207e7 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -94,7 +94,14 @@
 	 *
 	 * EAP state machines reads this value.
 	 */
-	EAPOL_altReject
+	EAPOL_altReject,
+
+	/**
+	 * EAPOL_eapTriggerStart - EAP-based trigger to send EAPOL-Start
+	 *
+	 * EAP state machine writes this value.
+	 */
+	EAPOL_eapTriggerStart
 };
 
 /**
@@ -268,6 +275,14 @@
 	 */
 	const char *pkcs11_module_path;
 	/**
+	 * openssl_ciphers - OpenSSL cipher string
+	 *
+	 * This is an OpenSSL specific configuration option for configuring the
+	 * default ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the
+	 * default.
+	 */
+	const char *openssl_ciphers;
+	/**
 	 * wps - WPS context data
 	 *
 	 * This is only used by EAP-WSC and can be left %NULL if not available.
@@ -321,6 +336,7 @@
 void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
 void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
 int eap_peer_was_failure_expected(struct eap_sm *sm);
+void eap_peer_erp_free_keys(struct eap_sm *sm);
 
 #endif /* IEEE8021X_EAPOL */
 
diff --git a/src/eap_peer/eap_config.h b/src/eap_peer/eap_config.h
index 2591e11..3584bdb 100644
--- a/src/eap_peer/eap_config.h
+++ b/src/eap_peer/eap_config.h
@@ -686,6 +686,20 @@
 	 * has more than one.
 	 */
 	int sim_num;
+
+	/**
+	 * openssl_ciphers - OpenSSL cipher string
+	 *
+	 * This is an OpenSSL specific configuration option for configuring the
+	 * ciphers for this connection. If not set, the default cipher suite
+	 * list is used.
+	 */
+	char *openssl_ciphers;
+
+	/**
+	 * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+	 */
+	int erp;
 };
 
 
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 0739187..68d7fba 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -1666,7 +1666,7 @@
 		ret = os_snprintf(buf + len, buflen - len,
 				  "EAP-FAST Phase2 method=%s\n",
 				  data->phase2_method->name);
-		if (ret < 0 || (size_t) ret >= buflen - len)
+		if (os_snprintf_error(buflen - len, ret))
 			return len;
 		len += ret;
 	}
diff --git a/src/eap_peer/eap_fast_pac.c b/src/eap_peer/eap_fast_pac.c
index 21d6098..89e604e 100644
--- a/src/eap_peer/eap_fast_pac.c
+++ b/src/eap_peer/eap_fast_pac.c
@@ -504,28 +504,28 @@
 	end = *buf + *buf_len;
 
 	ret = os_snprintf(*pos, end - *pos, "%s=", field);
-	if (ret < 0 || ret >= end - *pos)
+	if (os_snprintf_error(end - *pos, ret))
 		return;
 	*pos += ret;
 	*pos += wpa_snprintf_hex(*pos, end - *pos, data, len);
 	ret = os_snprintf(*pos, end - *pos, "\n");
-	if (ret < 0 || ret >= end - *pos)
+	if (os_snprintf_error(end - *pos, ret))
 		return;
 	*pos += ret;
 
 	if (txt) {
 		ret = os_snprintf(*pos, end - *pos, "%s-txt=", field);
-		if (ret < 0 || ret >= end - *pos)
+		if (os_snprintf_error(end - *pos, ret))
 			return;
 		*pos += ret;
 		for (i = 0; i < len; i++) {
 			ret = os_snprintf(*pos, end - *pos, "%c", data[i]);
-			if (ret < 0 || ret >= end - *pos)
+			if (os_snprintf_error(end - *pos, ret))
 				return;
 			*pos += ret;
 		}
 		ret = os_snprintf(*pos, end - *pos, "\n");
-		if (ret < 0 || ret >= end - *pos)
+		if (os_snprintf_error(end - *pos, ret))
 			return;
 		*pos += ret;
 	}
@@ -578,7 +578,7 @@
 
 	ret = os_snprintf(*pos, *buf + *buf_len - *pos,
 			  "START\nPAC-Type=%d\n", pac->pac_type);
-	if (ret < 0 || ret >= *buf + *buf_len - *pos)
+	if (os_snprintf_error(*buf + *buf_len - *pos, ret))
 		return -1;
 
 	*pos += ret;
@@ -600,7 +600,7 @@
 		return -1;
 	}
 	ret = os_snprintf(*pos, *buf + *buf_len - *pos, "END\n");
-	if (ret < 0 || ret >= *buf + *buf_len - *pos)
+	if (os_snprintf_error(*buf + *buf_len - *pos, ret))
 		return -1;
 	*pos += ret;
 
@@ -632,7 +632,7 @@
 		return -1;
 
 	ret = os_snprintf(pos, buf + buf_len - pos, "%s\n", pac_file_hdr);
-	if (ret < 0 || ret >= buf + buf_len - pos) {
+	if (os_snprintf_error(buf + buf_len - pos, ret)) {
 		os_free(buf);
 		return -1;
 	}
@@ -714,7 +714,7 @@
 		pos += 2;
 		len = WPA_GET_BE16(pos);
 		pos += 2;
-		if (pos + len > end)
+		if (len > (unsigned int) (end - pos))
 			break;
 
 		if (type == PAC_TYPE_A_ID) {
@@ -799,7 +799,9 @@
 	pos = buf + 6;
 	end = buf + len;
 	while (pos < end) {
-		if (end - pos < 2 + 32 + 2 + 2)
+		u16 val;
+
+		if (end - pos < 2 + EAP_FAST_PAC_KEY_LEN + 2 + 2)
 			goto parse_fail;
 
 		pac = os_zalloc(sizeof(*pac));
@@ -810,19 +812,23 @@
 		pos += 2;
 		os_memcpy(pac->pac_key, pos, EAP_FAST_PAC_KEY_LEN);
 		pos += EAP_FAST_PAC_KEY_LEN;
-		pac->pac_opaque_len = WPA_GET_BE16(pos);
+		val = WPA_GET_BE16(pos);
 		pos += 2;
-		if (pos + pac->pac_opaque_len + 2 > end)
+		if (val > end - pos)
 			goto parse_fail;
+		pac->pac_opaque_len = val;
 		pac->pac_opaque = os_malloc(pac->pac_opaque_len);
 		if (pac->pac_opaque == NULL)
 			goto parse_fail;
 		os_memcpy(pac->pac_opaque, pos, pac->pac_opaque_len);
 		pos += pac->pac_opaque_len;
-		pac->pac_info_len = WPA_GET_BE16(pos);
-		pos += 2;
-		if (pos + pac->pac_info_len > end)
+		if (2 > end - pos)
 			goto parse_fail;
+		val = WPA_GET_BE16(pos);
+		pos += 2;
+		if (val > end - pos)
+			goto parse_fail;
+		pac->pac_info_len = val;
 		pac->pac_info = os_malloc(pac->pac_info_len);
 		if (pac->pac_info == NULL)
 			goto parse_fail;
diff --git a/src/eap_peer/eap_i.h b/src/eap_peer/eap_i.h
index fde809c..2d7fdea 100644
--- a/src/eap_peer/eap_i.h
+++ b/src/eap_peer/eap_i.h
@@ -1,6 +1,6 @@
 /*
  * EAP peer state machines internal structures (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,7 @@
 #define EAP_I_H
 
 #include "wpabuf.h"
+#include "utils/list.h"
 #include "eap_peer/eap.h"
 #include "eap_common/eap_common.h"
 
@@ -277,6 +278,16 @@
 };
 
 
+struct eap_erp_key {
+	struct dl_list list;
+	size_t rRK_len;
+	size_t rIK_len;
+	u8 rRK[ERP_MAX_KEY_LEN];
+	u8 rIK[ERP_MAX_KEY_LEN];
+	u32 next_seq;
+	char keyname_nai[];
+};
+
 /**
  * struct eap_sm - EAP state machine data
  */
@@ -321,6 +332,8 @@
 	void *eap_method_priv;
 	int init_phase2;
 	int fast_reauth;
+	Boolean reauthInit; /* send EAP-Identity/Re-auth */
+	u32 erp_seq;
 
 	Boolean rxResp /* LEAP only */;
 	Boolean leap_done;
@@ -353,6 +366,8 @@
 	int external_sim;
 
 	unsigned int expected_failure:1;
+
+	struct dl_list erp_keys; /* struct eap_erp_key */
 };
 
 const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
diff --git a/src/eap_peer/eap_ikev2.c b/src/eap_peer/eap_ikev2.c
index c12b519..b5ef71b 100644
--- a/src/eap_peer/eap_ikev2.c
+++ b/src/eap_peer/eap_ikev2.c
@@ -301,6 +301,13 @@
 
 	if (data->in_buf == NULL) {
 		/* First fragment of the message */
+		if (message_length > 50000) {
+			/* Limit maximum memory allocation */
+			wpa_printf(MSG_DEBUG,
+				   "EAP-IKEV2: Ignore too long message");
+			ret->ignore = TRUE;
+			return NULL;
+		}
 		data->in_buf = wpabuf_alloc(message_length);
 		if (data->in_buf == NULL) {
 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
@@ -315,6 +322,7 @@
 			   (unsigned long) wpabuf_tailroom(data->in_buf));
 	}
 
+	ret->ignore = FALSE;
 	return eap_ikev2_build_frag_ack(id, EAP_CODE_RESPONSE);
 }
 
diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c
index 83a1457..1bdd81e 100644
--- a/src/eap_peer/eap_methods.c
+++ b/src/eap_peer/eap_methods.c
@@ -103,7 +103,7 @@
 	for (m = eap_methods; m; m = m->next) {
 		ret = os_snprintf(pos, end - pos, "%s%s",
 				  m == eap_methods ? "" : " ", m->name);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			break;
 		pos += ret;
 	}
@@ -133,7 +133,7 @@
 	for (m = eap_methods; m; m = m->next)
 		array_len++;
 
-	array = os_zalloc(sizeof(char *) * (array_len + 1));
+	array = os_calloc(array_len + 1, sizeof(char *));
 	if (array == NULL)
 		return NULL;
 
diff --git a/src/eap_peer/eap_pax.c b/src/eap_peer/eap_pax.c
index 1c111c2..6d1ff20 100644
--- a/src/eap_peer/eap_pax.c
+++ b/src/eap_peer/eap_pax.c
@@ -38,6 +38,7 @@
 	u8 mk[EAP_PAX_MK_LEN];
 	u8 ck[EAP_PAX_CK_LEN];
 	u8 ick[EAP_PAX_ICK_LEN];
+	u8 mid[EAP_PAX_MID_LEN];
 };
 
 
@@ -178,8 +179,8 @@
 		    data->rand.r.y, EAP_PAX_RAND_LEN);
 
 	if (eap_pax_initial_key_derivation(req->mac_id, data->ak, data->rand.e,
-					   data->mk, data->ck, data->ick) < 0)
-	{
+					   data->mk, data->ck, data->ick,
+					   data->mid) < 0) {
 		ret->ignore = TRUE;
 		return NULL;
 	}
@@ -501,6 +502,26 @@
 }
 
 
+static u8 * eap_pax_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pax_data *data = priv;
+	u8 *sid;
+
+	if (data->state != PAX_DONE)
+		return NULL;
+
+	sid = os_malloc(1 + EAP_PAX_MID_LEN);
+	if (sid == NULL)
+		return NULL;
+
+	*len = 1 + EAP_PAX_MID_LEN;
+	sid[0] = EAP_TYPE_PAX;
+	os_memcpy(sid + 1, data->mid, EAP_PAX_MID_LEN);
+
+	return sid;
+}
+
+
 int eap_peer_pax_register(void)
 {
 	struct eap_method *eap;
@@ -517,6 +538,7 @@
 	eap->isKeyAvailable = eap_pax_isKeyAvailable;
 	eap->getKey = eap_pax_getKey;
 	eap->get_emsk = eap_pax_get_emsk;
+	eap->getSessionId = eap_pax_get_session_id;
 
 	ret = eap_peer_method_register(eap);
 	if (ret)
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 472e861..86a18bb 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -1156,7 +1156,7 @@
 				  "EAP-PEAPv%d Phase2 method=%s\n",
 				  data->peap_version,
 				  data->phase2_method->name);
-		if (ret < 0 || (size_t) ret >= buflen - len)
+		if (os_snprintf_error(buflen - len, ret))
 			return len;
 		len += ret;
 	}
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index 1c915ed..059bbee 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -952,7 +952,6 @@
 	struct eap_method *eap;
 	int ret;
 
-	EVP_add_digest(EVP_sha256());
 	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
 				    EAP_VENDOR_IETF, EAP_TYPE_PWD, "PWD");
 	if (eap == NULL)
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index fe9bfe0..3641a2c 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -147,6 +147,8 @@
 	} else {
 		wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
 		eap_tls_params_from_conf1(params, config);
+		if (data->eap_type == EAP_TYPE_FAST)
+			params->flags |= TLS_CONN_EAP_FAST;
 	}
 
 	/*
@@ -167,6 +169,8 @@
 		return -1;
 	}
 
+	params->openssl_ciphers = config->openssl_ciphers;
+
 	return 0;
 }
 
@@ -377,15 +381,10 @@
 	struct tls_keys keys;
 	u8 *out;
 
-	/*
-	 * TLS library did not support session ID generation,
-	 * so get the needed TLS session parameters
-	 */
 	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
 		return NULL;
 
-	if (keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.master_key == NULL)
+	if (keys.client_random == NULL || keys.server_random == NULL)
 		return NULL;
 
 	*len = 1 + keys.client_random_len + keys.server_random_len;
@@ -397,7 +396,7 @@
 	out[0] = eap_type;
 	os_memcpy(out + 1, keys.client_random, keys.client_random_len);
 	os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
-	          keys.server_random_len);
+		  keys.server_random_len);
 
 	return out;
 }
@@ -795,8 +794,11 @@
 	if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0)
 	{
 		ret = os_snprintf(buf + len, buflen - len,
-				  "EAP TLS cipher=%s\n", name);
-		if (ret < 0 || (size_t) ret >= buflen - len)
+				  "EAP TLS cipher=%s\n"
+				  "tls_session_reused=%d\n",
+				  name, tls_connection_resumed(data->ssl_ctx,
+							       data->conn));
+		if (os_snprintf_error(buflen - len, ret))
 			return len;
 		len += ret;
 	}
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index 771da58..6fbc27b 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -136,7 +136,7 @@
 static void eap_ttls_free_key(struct eap_ttls_data *data)
 {
 	if (data->key_data) {
-		bin_clear_free(data->key_data, EAP_TLS_KEY_LEN);
+		bin_clear_free(data->key_data, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
 		data->key_data = NULL;
 	}
 }
@@ -225,7 +225,8 @@
 	eap_ttls_free_key(data);
 	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
 						 "ttls keying material",
-						 EAP_TLS_KEY_LEN);
+						 EAP_TLS_KEY_LEN +
+						 EAP_EMSK_LEN);
 	if (!data->key_data) {
 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key");
 		return -1;
@@ -233,6 +234,9 @@
 
 	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
 			data->key_data, EAP_TLS_KEY_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived EMSK",
+			data->key_data + EAP_TLS_KEY_LEN,
+			EAP_EMSK_LEN);
 
 	os_free(data->session_id);
 	data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
@@ -1567,7 +1571,7 @@
 	ret = os_snprintf(buf + len, buflen - len,
 			  "EAP-TTLSv%d Phase2 method=",
 			  data->ttls_version);
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 	switch (data->phase2_type) {
@@ -1592,7 +1596,7 @@
 		ret = 0;
 		break;
 	}
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -1645,6 +1649,25 @@
 }
 
 
+static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_ttls_data *data = priv;
+	u8 *key;
+
+	if (data->key_data == NULL)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_EMSK_LEN;
+	os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
+
+	return key;
+}
+
+
 int eap_peer_ttls_register(void)
 {
 	struct eap_method *eap;
@@ -1665,6 +1688,7 @@
 	eap->has_reauth_data = eap_ttls_has_reauth_data;
 	eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
 	eap->init_for_reauth = eap_ttls_init_for_reauth;
+	eap->get_emsk = eap_ttls_get_emsk;
 
 	ret = eap_peer_method_register(eap);
 	if (ret)
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index 23e9823..7ce0a53 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -462,7 +462,7 @@
 		message_length = WPA_GET_BE16(pos);
 		pos += 2;
 
-		if (message_length < end - pos) {
+		if (message_length < end - pos || message_length > 50000) {
 			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
 				   "Length");
 			ret->ignore = TRUE;
diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c
index 8186afb..55ab72a 100644
--- a/src/eap_peer/ikev2.c
+++ b/src/eap_peer/ikev2.c
@@ -213,7 +213,7 @@
 
 	p = (const struct ikev2_proposal *) pos;
 	proposal_len = WPA_GET_BE16(p->proposal_length);
-	if (proposal_len < (int) sizeof(*p) || pos + proposal_len > end) {
+	if (proposal_len < (int) sizeof(*p) || proposal_len > end - pos) {
 		wpa_printf(MSG_INFO, "IKEV2: Invalid proposal length %d",
 			   proposal_len);
 		return -1;
@@ -369,7 +369,7 @@
 	}
 
 	if (kei_len < 4 + 96) {
-		wpa_printf(MSG_INFO, "IKEV2: Too show Key Exchange Payload");
+		wpa_printf(MSG_INFO, "IKEV2: Too short Key Exchange Payload");
 		return -1;
 	}
 
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index 1253bd6..9de6cb6 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP Full Authenticator state machine (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,7 @@
 #define EAP_H
 
 #include "common/defs.h"
+#include "utils/list.h"
 #include "eap_common/eap_defs.h"
 #include "eap_server/eap_methods.h"
 #include "wpabuf.h"
@@ -58,6 +59,8 @@
 	struct wpabuf *eapReqData;
 	u8 *eapKeyData;
 	size_t eapKeyDataLen;
+	u8 *eapSessionId;
+	size_t eapSessionIdLen;
 	Boolean eapKeyAvailable; /* called keyAvailable in IEEE 802.1X-2004 */
 
 	/* AAA interface to full authenticator variables */
@@ -78,11 +81,27 @@
 	Boolean aaaTimeout;
 };
 
+struct eap_server_erp_key {
+	struct dl_list list;
+	size_t rRK_len;
+	size_t rIK_len;
+	u8 rRK[ERP_MAX_KEY_LEN];
+	u8 rIK[ERP_MAX_KEY_LEN];
+	u32 recv_seq;
+	u8 cryptosuite;
+	char keyname_nai[];
+};
+
 struct eapol_callbacks {
 	int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
 			    int phase2, struct eap_user *user);
 	const char * (*get_eap_req_id_text)(void *ctx, size_t *len);
 	void (*log_msg)(void *ctx, const char *msg);
+	int (*get_erp_send_reauth_start)(void *ctx);
+	const char * (*get_erp_domain)(void *ctx);
+	struct eap_server_erp_key * (*erp_get_key)(void *ctx,
+						   const char *keyname);
+	int (*erp_add_key)(void *ctx, struct eap_server_erp_key *erp);
 };
 
 struct eap_config {
@@ -111,6 +130,7 @@
 
 	const u8 *server_id;
 	size_t server_id_len;
+	int erp;
 
 #ifdef CONFIG_TESTING_OPTIONS
 	u32 tls_test_flags;
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 3a6802b..7d72309 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -88,6 +88,19 @@
 	 * private data or this function may derive the key.
 	 */
 	u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
+
+	/**
+	 * getSessionId - Get EAP method specific Session-Id
+	 * @sm: Pointer to EAP state machine allocated with eap_server_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 * @len: Pointer to a variable to store Session-Id length
+	 * Returns: Session-Id or %NULL if not available
+	 *
+	 * This function can be used to get the Session-Id from the EAP method.
+	 * The Session-Id may already be stored in the method-specific private
+	 * data or this function may derive the Session-Id.
+	 */
+	u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
 };
 
 /**
@@ -103,7 +116,8 @@
 		EAP_INITIALIZE_PASSTHROUGH, EAP_IDLE2, EAP_RETRANSMIT2,
 		EAP_RECEIVED2, EAP_DISCARD2, EAP_SEND_REQUEST2,
 		EAP_AAA_REQUEST, EAP_AAA_RESPONSE, EAP_AAA_IDLE,
-		EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2
+		EAP_TIMEOUT_FAILURE2, EAP_FAILURE2, EAP_SUCCESS2,
+		EAP_INITIATE_REAUTH_START, EAP_INITIATE_RECEIVED
 	} EAP_state;
 
 	/* Constants */
@@ -125,6 +139,7 @@
 
 	/* Short-term (not maintained between packets) */
 	Boolean rxResp;
+	Boolean rxInitiate;
 	int respId;
 	EapType respMethod;
 	int respVendor;
@@ -132,7 +147,7 @@
 	Boolean ignore;
 	enum {
 		DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE,
-		DECISION_PASSTHROUGH
+		DECISION_PASSTHROUGH, DECISION_INITIATE_REAUTH_START
 	} decision;
 
 	/* Miscellaneous variables */
@@ -192,6 +207,10 @@
 	const u8 *server_id;
 	size_t server_id_len;
 
+	Boolean initiate_reauth_start_sent;
+	Boolean try_initiate_reauth;
+	int erp;
+
 #ifdef CONFIG_TESTING_OPTIONS
 	u32 tls_test_flags;
 #endif /* CONFIG_TESTING_OPTIONS */
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index c1bb6b8..bd919e5 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP Full Authenticator state machine (RFC 4137)
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -15,6 +15,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/sha256.h"
 #include "eap_i.h"
 #include "state_machine.h"
 #include "common/wpa_ctrl.h"
@@ -44,6 +45,73 @@
 static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
 
 
+static int eap_get_erp_send_reauth_start(struct eap_sm *sm)
+{
+	if (sm->eapol_cb->get_erp_send_reauth_start)
+		return sm->eapol_cb->get_erp_send_reauth_start(sm->eapol_ctx);
+	return 0;
+}
+
+
+static const char * eap_get_erp_domain(struct eap_sm *sm)
+{
+	if (sm->eapol_cb->get_erp_domain)
+		return sm->eapol_cb->get_erp_domain(sm->eapol_ctx);
+	return NULL;
+}
+
+
+#ifdef CONFIG_ERP
+
+static struct eap_server_erp_key * eap_erp_get_key(struct eap_sm *sm,
+						   const char *keyname)
+{
+	if (sm->eapol_cb->erp_get_key)
+		return sm->eapol_cb->erp_get_key(sm->eapol_ctx, keyname);
+	return NULL;
+}
+
+
+static int eap_erp_add_key(struct eap_sm *sm, struct eap_server_erp_key *erp)
+{
+	if (sm->eapol_cb->erp_add_key)
+		return sm->eapol_cb->erp_add_key(sm->eapol_ctx, erp);
+	return -1;
+}
+
+#endif /* CONFIG_ERP */
+
+
+static struct wpabuf * eap_sm_buildInitiateReauthStart(struct eap_sm *sm,
+						       u8 id)
+{
+	const char *domain;
+	size_t plen = 1;
+	struct wpabuf *msg;
+	size_t domain_len = 0;
+
+	domain = eap_get_erp_domain(sm);
+	if (domain) {
+		domain_len = os_strlen(domain);
+		plen += 2 + domain_len;
+	}
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH_START, plen,
+			    EAP_CODE_INITIATE, id);
+	if (msg == NULL)
+		return NULL;
+	wpabuf_put_u8(msg, 0); /* Reserved */
+	if (domain) {
+		/* Domain name TLV */
+		wpabuf_put_u8(msg, EAP_ERP_TLV_DOMAIN_NAME);
+		wpabuf_put_u8(msg, domain_len);
+		wpabuf_put_data(msg, domain, domain_len);
+	}
+
+	return msg;
+}
+
+
 static int eap_copy_buf(struct wpabuf **dst, const struct wpabuf *src)
 {
 	if (src == NULL)
@@ -164,6 +232,7 @@
 		eap_server_clear_identity(sm);
 	}
 
+	sm->try_initiate_reauth = FALSE;
 	sm->currentId = -1;
 	sm->eap_if.eapSuccess = FALSE;
 	sm->eap_if.eapFail = FALSE;
@@ -171,6 +240,9 @@
 	bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
 	sm->eap_if.eapKeyData = NULL;
 	sm->eap_if.eapKeyDataLen = 0;
+	os_free(sm->eap_if.eapSessionId);
+	sm->eap_if.eapSessionId = NULL;
+	sm->eap_if.eapSessionIdLen = 0;
 	sm->eap_if.eapKeyAvailable = FALSE;
 	sm->eap_if.eapRestart = FALSE;
 
@@ -336,6 +408,95 @@
 }
 
 
+static void eap_server_erp_init(struct eap_sm *sm)
+{
+#ifdef CONFIG_ERP
+	u8 *emsk = NULL;
+	size_t emsk_len = 0;
+	u8 EMSKname[EAP_EMSK_NAME_LEN];
+	u8 len[2];
+	const char *domain;
+	size_t domain_len, nai_buf_len;
+	struct eap_server_erp_key *erp = NULL;
+	int pos;
+
+	domain = eap_get_erp_domain(sm);
+	if (!domain)
+		return;
+
+	domain_len = os_strlen(domain);
+
+	nai_buf_len = 2 * EAP_EMSK_NAME_LEN + 1 + domain_len;
+	if (nai_buf_len > 253) {
+		/*
+		 * keyName-NAI has a maximum length of 253 octet to fit in
+		 * RADIUS attributes.
+		 */
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Too long realm for ERP keyName-NAI maximum length");
+		return;
+	}
+	nai_buf_len++; /* null termination */
+	erp = os_zalloc(sizeof(*erp) + nai_buf_len);
+	if (erp == NULL)
+		goto fail;
+	erp->recv_seq = (u32) -1;
+
+	emsk = sm->m->get_emsk(sm, sm->eap_method_priv, &emsk_len);
+	if (!emsk || emsk_len == 0 || emsk_len > ERP_MAX_KEY_LEN) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: No suitable EMSK available for ERP");
+		goto fail;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP: EMSK", emsk, emsk_len);
+
+	WPA_PUT_BE16(len, 8);
+	if (hmac_sha256_kdf(sm->eap_if.eapSessionId, sm->eap_if.eapSessionIdLen,
+			    "EMSK", len, sizeof(len),
+			    EMSKname, EAP_EMSK_NAME_LEN) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP: Could not derive EMSKname");
+		goto fail;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP: EMSKname", EMSKname, EAP_EMSK_NAME_LEN);
+
+	pos = wpa_snprintf_hex(erp->keyname_nai, nai_buf_len,
+			       EMSKname, EAP_EMSK_NAME_LEN);
+	erp->keyname_nai[pos] = '@';
+	os_memcpy(&erp->keyname_nai[pos + 1], domain, domain_len);
+
+	WPA_PUT_BE16(len, emsk_len);
+	if (hmac_sha256_kdf(emsk, emsk_len,
+			    "EAP Re-authentication Root Key@ietf.org",
+			    len, sizeof(len), erp->rRK, emsk_len) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP: Could not derive rRK for ERP");
+		goto fail;
+	}
+	erp->rRK_len = emsk_len;
+	wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rRK", erp->rRK, erp->rRK_len);
+
+	if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+			    "EAP Re-authentication Integrity Key@ietf.org",
+			    len, sizeof(len), erp->rIK, erp->rRK_len) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP: Could not derive rIK for ERP");
+		goto fail;
+	}
+	erp->rIK_len = erp->rRK_len;
+	wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rIK", erp->rIK, erp->rIK_len);
+
+	if (eap_erp_add_key(sm, erp) == 0) {
+		wpa_printf(MSG_DEBUG, "EAP: Stored ERP keys %s",
+			   erp->keyname_nai);
+		erp = NULL;
+	}
+
+fail:
+	bin_clear_free(emsk, emsk_len);
+	bin_clear_free(erp, sizeof(*erp));
+#endif /* CONFIG_ERP */
+}
+
+
 SM_STATE(EAP, METHOD_RESPONSE)
 {
 	SM_ENTRY(EAP, METHOD_RESPONSE);
@@ -355,6 +516,18 @@
 			sm->eap_if.eapKeyData = NULL;
 			sm->eap_if.eapKeyDataLen = 0;
 		}
+		os_free(sm->eap_if.eapSessionId);
+		sm->eap_if.eapSessionId = NULL;
+		if (sm->m->getSessionId) {
+			sm->eap_if.eapSessionId = sm->m->getSessionId(
+				sm, sm->eap_method_priv,
+				&sm->eap_if.eapSessionIdLen);
+			wpa_hexdump(MSG_DEBUG, "EAP: Session-Id",
+				    sm->eap_if.eapSessionId,
+				    sm->eap_if.eapSessionIdLen);
+		}
+		if (sm->erp && sm->m->get_emsk && sm->eap_if.eapSessionId)
+			eap_server_erp_init(sm);
 		sm->methodState = METHOD_END;
 	} else {
 		sm->methodState = METHOD_CONTINUE;
@@ -369,6 +542,7 @@
 
 	SM_ENTRY(EAP, PROPOSE_METHOD);
 
+	sm->try_initiate_reauth = FALSE;
 try_another_method:
 	type = eap_sm_Policy_getNextMethod(sm, &vendor);
 	if (vendor == EAP_VENDOR_IETF)
@@ -492,12 +666,326 @@
 }
 
 
+SM_STATE(EAP, INITIATE_REAUTH_START)
+{
+	SM_ENTRY(EAP, INITIATE_REAUTH_START);
+
+	sm->initiate_reauth_start_sent = TRUE;
+	sm->try_initiate_reauth = TRUE;
+	sm->currentId = eap_sm_nextId(sm, sm->currentId);
+	wpa_printf(MSG_DEBUG,
+		   "EAP: building EAP-Initiate-Re-auth-Start: Identifier %d",
+		   sm->currentId);
+	sm->lastId = sm->currentId;
+	wpabuf_free(sm->eap_if.eapReqData);
+	sm->eap_if.eapReqData = eap_sm_buildInitiateReauthStart(sm,
+								sm->currentId);
+	wpabuf_free(sm->lastReqData);
+	sm->lastReqData = NULL;
+}
+
+
+#ifdef CONFIG_ERP
+
+static void erp_send_finish_reauth(struct eap_sm *sm,
+				   struct eap_server_erp_key *erp, u8 id,
+				   u8 flags, u16 seq, const char *nai)
+{
+	size_t plen;
+	struct wpabuf *msg;
+	u8 hash[SHA256_MAC_LEN];
+	size_t hash_len;
+	u8 seed[4];
+
+	if (erp) {
+		switch (erp->cryptosuite) {
+		case EAP_ERP_CS_HMAC_SHA256_256:
+			hash_len = 32;
+			break;
+		case EAP_ERP_CS_HMAC_SHA256_128:
+			hash_len = 16;
+			break;
+		default:
+			return;
+		}
+	} else
+		hash_len = 0;
+
+	plen = 1 + 2 + 2 + os_strlen(nai);
+	if (hash_len)
+		plen += 1 + hash_len;
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH, plen,
+			    EAP_CODE_FINISH, id);
+	if (msg == NULL)
+		return;
+	wpabuf_put_u8(msg, flags);
+	wpabuf_put_be16(msg, seq);
+
+	wpabuf_put_u8(msg, EAP_ERP_TLV_KEYNAME_NAI);
+	wpabuf_put_u8(msg, os_strlen(nai));
+	wpabuf_put_str(msg, nai);
+
+	if (erp) {
+		wpabuf_put_u8(msg, erp->cryptosuite);
+		if (hmac_sha256(erp->rIK, erp->rIK_len,
+				wpabuf_head(msg), wpabuf_len(msg), hash) < 0) {
+			wpabuf_free(msg);
+			return;
+		}
+		wpabuf_put_data(msg, hash, hash_len);
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP: Send EAP-Finish/Re-auth (%s)",
+		   flags & 0x80 ? "failure" : "success");
+
+	sm->lastId = sm->currentId;
+	sm->currentId = id;
+	wpabuf_free(sm->eap_if.eapReqData);
+	sm->eap_if.eapReqData = msg;
+	wpabuf_free(sm->lastReqData);
+	sm->lastReqData = NULL;
+
+	if (flags & 0x80) {
+		sm->eap_if.eapFail = TRUE;
+		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+			MACSTR, MAC2STR(sm->peer_addr));
+		return;
+	}
+
+	bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+	sm->eap_if.eapKeyDataLen = 0;
+	sm->eap_if.eapKeyData = os_malloc(erp->rRK_len);
+	if (!sm->eap_if.eapKeyData)
+		return;
+
+	WPA_PUT_BE16(seed, seq);
+	WPA_PUT_BE16(&seed[2], erp->rRK_len);
+	if (hmac_sha256_kdf(erp->rRK, erp->rRK_len,
+			    "Re-authentication Master Session Key@ietf.org",
+			    seed, sizeof(seed),
+			    sm->eap_if.eapKeyData, erp->rRK_len) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP: Could not derive rMSK for ERP");
+		bin_clear_free(sm->eap_if.eapKeyData, erp->rRK_len);
+		sm->eap_if.eapKeyData = NULL;
+		return;
+	}
+	sm->eap_if.eapKeyDataLen = erp->rRK_len;
+	sm->eap_if.eapKeyAvailable = TRUE;
+	wpa_hexdump_key(MSG_DEBUG, "EAP: ERP rMSK",
+			sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+	sm->eap_if.eapSuccess = TRUE;
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+		MACSTR, MAC2STR(sm->peer_addr));
+}
+
+
+SM_STATE(EAP, INITIATE_RECEIVED)
+{
+	const u8 *pos, *end, *start, *tlvs, *hdr;
+	const struct eap_hdr *ehdr;
+	size_t len;
+	u8 flags;
+	u16 seq;
+	char nai[254];
+	struct eap_server_erp_key *erp;
+	int max_len;
+	u8 hash[SHA256_MAC_LEN];
+	size_t hash_len;
+	struct erp_tlvs parse;
+	u8 resp_flags = 0x80; /* default to failure; cleared on success */
+
+	SM_ENTRY(EAP, INITIATE_RECEIVED);
+
+	sm->rxInitiate = FALSE;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_ERP_TYPE_REAUTH,
+			       sm->eap_if.eapRespData, &len);
+	if (pos == NULL) {
+		wpa_printf(MSG_INFO, "EAP-Initiate: Invalid frame");
+		goto fail;
+	}
+	hdr = wpabuf_head(sm->eap_if.eapRespData);
+	ehdr = wpabuf_head(sm->eap_if.eapRespData);
+
+	wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth", pos, len);
+	if (len < 4) {
+		wpa_printf(MSG_INFO, "EAP: Too short EAP-Initiate/Re-auth");
+		goto fail;
+	}
+	end = pos + len;
+
+	flags = *pos++;
+	seq = WPA_GET_BE16(pos);
+	pos += 2;
+	wpa_printf(MSG_DEBUG, "EAP: Flags=0x%x SEQ=%u", flags, seq);
+	tlvs = pos;
+
+	/*
+	 * Parse TVs/TLVs. Since we do not yet know the length of the
+	 * Authentication Tag, stop parsing if an unknown TV/TLV is seen and
+	 * just try to find the keyName-NAI first so that we can check the
+	 * Authentication Tag.
+	 */
+	if (erp_parse_tlvs(tlvs, end, &parse, 1) < 0)
+		goto fail;
+
+	if (!parse.keyname) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: No keyName-NAI in EAP-Initiate/Re-auth Packet");
+		goto fail;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Initiate/Re-auth - keyName-NAI",
+			  parse.keyname, parse.keyname_len);
+	if (parse.keyname_len > 253) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Too long keyName-NAI in EAP-Initiate/Re-auth");
+		goto fail;
+	}
+	os_memcpy(nai, parse.keyname, parse.keyname_len);
+	nai[parse.keyname_len] = '\0';
+
+	if (!sm->eap_server) {
+		/*
+		 * In passthrough case, EAP-Initiate/Re-auth replaces
+		 * EAP Identity exchange. Use keyName-NAI as the user identity
+		 * and forward EAP-Initiate/Re-auth to the backend
+		 * authentication server.
+		 */
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Use keyName-NAI as user identity for backend authentication");
+		eap_server_clear_identity(sm);
+		sm->identity = (u8 *) dup_binstr(parse.keyname,
+						 parse.keyname_len);
+		if (!sm->identity)
+			goto fail;
+		sm->identity_len = parse.keyname_len;
+		return;
+	}
+
+	erp = eap_erp_get_key(sm, nai);
+	if (!erp) {
+		wpa_printf(MSG_DEBUG, "EAP: No matching ERP key found for %s",
+			   nai);
+		goto report_error;
+	}
+
+	if (erp->recv_seq != (u32) -1 && erp->recv_seq >= seq) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: SEQ=%u replayed (already received SEQ=%u)",
+			   seq, erp->recv_seq);
+		goto fail;
+	}
+
+	/* Is there enough room for Cryptosuite and Authentication Tag? */
+	start = parse.keyname + parse.keyname_len;
+	max_len = end - start;
+	if (max_len <
+	    1 + (erp->cryptosuite == EAP_ERP_CS_HMAC_SHA256_256 ? 32 : 16)) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: Not enough room for Authentication Tag");
+		goto fail;
+	}
+
+	switch (erp->cryptosuite) {
+	case EAP_ERP_CS_HMAC_SHA256_256:
+		if (end[-33] != erp->cryptosuite) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP: Different Cryptosuite used");
+			goto fail;
+		}
+		hash_len = 32;
+		break;
+	case EAP_ERP_CS_HMAC_SHA256_128:
+		if (end[-17] != erp->cryptosuite) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP: Different Cryptosuite used");
+			goto fail;
+		}
+		hash_len = 16;
+		break;
+	default:
+		hash_len = 0;
+		break;
+	}
+
+	if (hash_len) {
+		if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+				end - hdr - hash_len, hash) < 0)
+			goto fail;
+		if (os_memcmp(end - hash_len, hash, hash_len) != 0) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP: Authentication Tag mismatch");
+			goto fail;
+		}
+	}
+
+	/* Check if any supported CS results in matching tag */
+	if (!hash_len && max_len >= 1 + 32 &&
+	    end[-33] == EAP_ERP_CS_HMAC_SHA256_256) {
+		if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+				end - hdr - 32, hash) < 0)
+			goto fail;
+		if (os_memcmp(end - 32, hash, 32) == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP: Authentication Tag match using HMAC-SHA256-256");
+			hash_len = 32;
+			erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_256;
+		}
+	}
+
+	if (!hash_len && end[-17] == EAP_ERP_CS_HMAC_SHA256_128) {
+		if (hmac_sha256(erp->rIK, erp->rIK_len, hdr,
+				end - hdr - 16, hash) < 0)
+			goto fail;
+		if (os_memcmp(end - 16, hash, 16) == 0) {
+			wpa_printf(MSG_DEBUG,
+				   "EAP: Authentication Tag match using HMAC-SHA256-128");
+			hash_len = 16;
+			erp->cryptosuite = EAP_ERP_CS_HMAC_SHA256_128;
+		}
+	}
+
+	if (!hash_len) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: No supported cryptosuite matched Authentication Tag");
+		goto fail;
+	}
+	end -= 1 + hash_len;
+
+	/*
+	 * Parse TVs/TLVs again now that we know the exact part of the buffer
+	 * that contains them.
+	 */
+	wpa_hexdump(MSG_DEBUG, "EAP: EAP-Initiate/Re-Auth TVs/TLVs",
+		    tlvs, end - tlvs);
+	if (erp_parse_tlvs(tlvs, end, &parse, 0) < 0)
+		goto fail;
+
+	wpa_printf(MSG_DEBUG, "EAP: ERP key %s SEQ updated to %u",
+		   erp->keyname_nai, seq);
+	erp->recv_seq = seq;
+	resp_flags &= ~0x80; /* R=0 - success */
+
+report_error:
+	erp_send_finish_reauth(sm, erp, ehdr->identifier, resp_flags, seq, nai);
+	return;
+
+fail:
+	sm->ignore = TRUE;
+}
+
+#endif /* CONFIG_ERP */
+
+
 SM_STATE(EAP, INITIALIZE_PASSTHROUGH)
 {
 	SM_ENTRY(EAP, INITIALIZE_PASSTHROUGH);
 
 	wpabuf_free(sm->eap_if.aaaEapRespData);
 	sm->eap_if.aaaEapRespData = NULL;
+	sm->try_initiate_reauth = FALSE;
 }
 
 
@@ -691,9 +1179,14 @@
 			SM_ENTER(EAP, INITIALIZE);
 		break;
 	case EAP_IDLE:
-		if (sm->eap_if.retransWhile == 0)
-			SM_ENTER(EAP, RETRANSMIT);
-		else if (sm->eap_if.eapResp)
+		if (sm->eap_if.retransWhile == 0) {
+			if (sm->try_initiate_reauth) {
+				sm->try_initiate_reauth = FALSE;
+				SM_ENTER(EAP, SELECT_ACTION);
+			} else {
+				SM_ENTER(EAP, RETRANSMIT);
+			}
+		} else if (sm->eap_if.eapResp)
 			SM_ENTER(EAP, RECEIVED);
 		break;
 	case EAP_RETRANSMIT:
@@ -716,6 +1209,10 @@
 			   sm->respVendor == EAP_VENDOR_IETF &&
 			   sm->respVendorMethod == sm->currentMethod)))
 			SM_ENTER(EAP, INTEGRITY_CHECK);
+#ifdef CONFIG_ERP
+		else if (sm->rxInitiate)
+			SM_ENTER(EAP, INITIATE_RECEIVED);
+#endif /* CONFIG_ERP */
 		else {
 			wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
 				   "rxResp=%d respId=%d currentId=%d "
@@ -804,9 +1301,22 @@
 			SM_ENTER(EAP, SUCCESS);
 		else if (sm->decision == DECISION_PASSTHROUGH)
 			SM_ENTER(EAP, INITIALIZE_PASSTHROUGH);
+		else if (sm->decision == DECISION_INITIATE_REAUTH_START)
+			SM_ENTER(EAP, INITIATE_REAUTH_START);
+#ifdef CONFIG_ERP
+		else if (sm->eap_server && sm->erp && sm->rxInitiate)
+			SM_ENTER(EAP, INITIATE_RECEIVED);
+#endif /* CONFIG_ERP */
 		else
 			SM_ENTER(EAP, PROPOSE_METHOD);
 		break;
+	case EAP_INITIATE_REAUTH_START:
+		SM_ENTER(EAP, SEND_REQUEST);
+		break;
+	case EAP_INITIATE_RECEIVED:
+		if (!sm->eap_server)
+			SM_ENTER(EAP, SELECT_ACTION);
+		break;
 	case EAP_TIMEOUT_FAILURE:
 		break;
 	case EAP_FAILURE:
@@ -876,6 +1386,12 @@
 {
 	int rto, i;
 
+	if (sm->try_initiate_reauth) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: retransmit timeout 1 second for EAP-Initiate-Re-auth-Start");
+		return 1;
+	}
+
 	if (methodTimeout) {
 		/*
 		 * EAP method (either internal or through AAA server, provided
@@ -929,6 +1445,7 @@
 
 	/* parse rxResp, respId, respMethod */
 	sm->rxResp = FALSE;
+	sm->rxInitiate = FALSE;
 	sm->respId = -1;
 	sm->respMethod = EAP_TYPE_NONE;
 	sm->respVendor = EAP_VENDOR_IETF;
@@ -955,6 +1472,8 @@
 
 	if (hdr->code == EAP_CODE_RESPONSE)
 		sm->rxResp = TRUE;
+	else if (hdr->code == EAP_CODE_INITIATE)
+		sm->rxInitiate = TRUE;
 
 	if (plen > sizeof(*hdr)) {
 		u8 *pos = (u8 *) (hdr + 1);
@@ -972,10 +1491,10 @@
 		}
 	}
 
-	wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
-		   "respMethod=%u respVendor=%u respVendorMethod=%u",
-		   sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
-		   sm->respVendorMethod);
+	wpa_printf(MSG_DEBUG,
+		   "EAP: parseEapResp: rxResp=%d rxInitiate=%d respId=%d respMethod=%u respVendor=%u respVendorMethod=%u",
+		   sm->rxResp, sm->rxInitiate, sm->respId, sm->respMethod,
+		   sm->respVendor, sm->respVendorMethod);
 }
 
 
@@ -1216,6 +1735,13 @@
 		return DECISION_CONTINUE;
 	}
 
+	if (!sm->identity && eap_get_erp_send_reauth_start(sm) &&
+	    !sm->initiate_reauth_start_sent) {
+		wpa_printf(MSG_DEBUG,
+			   "EAP: getDecision: send EAP-Initiate/Re-auth-Start");
+		return DECISION_INITIATE_REAUTH_START;
+	}
+
 	if (sm->identity == NULL || sm->currentId == -1) {
 		wpa_printf(MSG_DEBUG, "EAP: getDecision: no identity known "
 			   "yet -> CONTINUE");
@@ -1326,6 +1852,7 @@
 	sm->pbc_in_m1 = conf->pbc_in_m1;
 	sm->server_id = conf->server_id;
 	sm->server_id_len = conf->server_id_len;
+	sm->erp = conf->erp;
 
 #ifdef CONFIG_TESTING_OPTIONS
 	sm->tls_test_flags = conf->tls_test_flags;
@@ -1353,6 +1880,7 @@
 		sm->m->reset(sm, sm->eap_method_priv);
 	wpabuf_free(sm->eap_if.eapReqData);
 	bin_clear_free(sm->eap_if.eapKeyData, sm->eap_if.eapKeyDataLen);
+	os_free(sm->eap_if.eapSessionId);
 	wpabuf_free(sm->lastReqData);
 	wpabuf_free(sm->eap_if.eapRespData);
 	os_free(sm->identity);
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 09b976e..db9b6aa 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -1294,6 +1294,28 @@
 }
 
 
+static u8 * eap_aka_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_aka_data *data = priv;
+	u8 *id;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	*len = 1 + EAP_AKA_RAND_LEN + EAP_AKA_AUTN_LEN;
+	id = os_malloc(*len);
+	if (id == NULL)
+		return NULL;
+
+	id[0] = data->eap_method;
+	os_memcpy(id + 1, data->rand, EAP_AKA_RAND_LEN);
+	os_memcpy(id + 1 + EAP_AKA_RAND_LEN, data->autn, EAP_AKA_AUTN_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-AKA: Derived Session-Id", id, *len);
+
+	return id;
+}
+
+
 int eap_server_aka_register(void)
 {
 	struct eap_method *eap;
@@ -1313,6 +1335,7 @@
 	eap->getKey = eap_aka_getKey;
 	eap->isSuccess = eap_aka_isSuccess;
 	eap->get_emsk = eap_aka_get_emsk;
+	eap->getSessionId = eap_aka_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
@@ -1342,6 +1365,7 @@
 	eap->getKey = eap_aka_getKey;
 	eap->isSuccess = eap_aka_isSuccess;
 	eap->get_emsk = eap_aka_get_emsk;
+	eap->getSessionId = eap_aka_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_fast.c b/src/eap_server/eap_server_fast.c
index 2692bce..56ac7f4 100644
--- a/src/eap_server/eap_server_fast.c
+++ b/src/eap_server/eap_server_fast.c
@@ -186,7 +186,6 @@
 
 		switch (*pos) {
 		case PAC_OPAQUE_TYPE_PAD:
-			pos = end;
 			goto done;
 		case PAC_OPAQUE_TYPE_KEY:
 			if (pos[1] != EAP_FAST_PAC_KEY_LEN) {
@@ -1017,7 +1016,7 @@
 	if (m->check(sm, priv, &buf)) {
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Phase2 check() asked to "
 			   "ignore the packet");
-		next_type = eap_fast_req_failure(sm, data);
+		eap_fast_req_failure(sm, data);
 		return;
 	}
 
@@ -1590,6 +1589,18 @@
 }
 
 
+static u8 * eap_fast_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_fast_data *data = priv;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_FAST,
+						len);
+}
+
+
 int eap_server_fast_register(void)
 {
 	struct eap_method *eap;
@@ -1609,6 +1620,7 @@
 	eap->getKey = eap_fast_getKey;
 	eap->get_emsk = eap_fast_get_emsk;
 	eap->isSuccess = eap_fast_isSuccess;
+	eap->getSessionId = eap_fast_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_gpsk.c b/src/eap_server/eap_server_gpsk.c
index cb369e4..50f15c3 100644
--- a/src/eap_server/eap_server_gpsk.c
+++ b/src/eap_server/eap_server_gpsk.c
@@ -24,6 +24,8 @@
 	size_t sk_len;
 	u8 pk[EAP_GPSK_MAX_PK_LEN];
 	size_t pk_len;
+	u8 session_id[128];
+	size_t id_len;
 	u8 *id_peer;
 	size_t id_peer_len;
 #define MAX_NUM_CSUITES 2
@@ -417,6 +419,21 @@
 		return;
 	}
 
+	if (eap_gpsk_derive_session_id(sm->user->password,
+				       sm->user->password_len,
+				       data->vendor, data->specifier,
+				       data->rand_peer, data->rand_server,
+				       data->id_peer, data->id_peer_len,
+				       sm->server_id, sm->server_id_len,
+				       EAP_TYPE_GPSK,
+				       data->session_id, &data->id_len) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive Session-Id");
+		eap_gpsk_state(data, FAILURE);
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Derived Session-Id",
+		    data->session_id, data->id_len);
+
 	miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
 	if (end - pos < (int) miclen) {
 		wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
@@ -593,6 +610,24 @@
 }
 
 
+static u8 * eap_gpsk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_gpsk_data *data = priv;
+	u8 *sid;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	sid = os_malloc(data->id_len);
+	if (sid == NULL)
+		return NULL;
+	os_memcpy(sid, data->session_id, data->id_len);
+	*len = data->id_len;
+
+	return sid;
+}
+
+
 int eap_server_gpsk_register(void)
 {
 	struct eap_method *eap;
@@ -612,6 +647,7 @@
 	eap->getKey = eap_gpsk_getKey;
 	eap->isSuccess = eap_gpsk_isSuccess;
 	eap->get_emsk = eap_gpsk_get_emsk;
+	eap->getSessionId = eap_gpsk_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_ikev2.c b/src/eap_server/eap_server_ikev2.c
index 65b2ef6..16e6276 100644
--- a/src/eap_server/eap_server_ikev2.c
+++ b/src/eap_server/eap_server_ikev2.c
@@ -309,6 +309,12 @@
 
 	if (data->in_buf == NULL) {
 		/* First fragment of the message */
+		if (message_length > 50000) {
+			/* Limit maximum memory allocation */
+			wpa_printf(MSG_DEBUG,
+				   "EAP-IKEV2: Ignore too long message");
+			return -1;
+		}
 		data->in_buf = wpabuf_alloc(message_length);
 		if (data->in_buf == NULL) {
 			wpa_printf(MSG_DEBUG, "EAP-IKEV2: No memory for "
@@ -511,6 +517,36 @@
 }
 
 
+static u8 * eap_ikev2_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_ikev2_data *data = priv;
+	u8 *sid;
+	size_t sid_len;
+	size_t offset;
+
+	if (data->state != DONE || !data->keymat_ok)
+		return NULL;
+
+	sid_len = 1 + data->ikev2.i_nonce_len + data->ikev2.r_nonce_len;
+	sid = os_malloc(sid_len);
+	if (sid) {
+		offset = 0;
+		sid[offset] = EAP_TYPE_IKEV2;
+		offset++;
+		os_memcpy(sid + offset, data->ikev2.i_nonce,
+			  data->ikev2.i_nonce_len);
+		offset += data->ikev2.i_nonce_len;
+		os_memcpy(sid + offset, data->ikev2.r_nonce,
+			  data->ikev2.r_nonce_len);
+		*len = sid_len;
+		wpa_hexdump(MSG_DEBUG, "EAP-IKEV2: Derived Session-Id",
+			    sid, sid_len);
+	}
+
+	return sid;
+}
+
+
 int eap_server_ikev2_register(void)
 {
 	struct eap_method *eap;
@@ -531,6 +567,7 @@
 	eap->getKey = eap_ikev2_getKey;
 	eap->isSuccess = eap_ikev2_isSuccess;
 	eap->get_emsk = eap_ikev2_get_emsk;
+	eap->getSessionId = eap_ikev2_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index f7a753d..05848d2 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -414,13 +414,16 @@
 			}
 			pw_hash = pw_hash_buf;
 		}
-		generate_authenticator_response_pwhash(
-			pw_hash, peer_challenge, data->auth_challenge,
-			username, username_len, nt_response,
-			data->auth_response);
-
-		hash_nt_password_hash(pw_hash, pw_hash_hash);
-		get_master_key(pw_hash_hash, nt_response, data->master_key);
+		if (generate_authenticator_response_pwhash(
+			    pw_hash, peer_challenge, data->auth_challenge,
+			    username, username_len, nt_response,
+			    data->auth_response) < 0 ||
+		    hash_nt_password_hash(pw_hash, pw_hash_hash) < 0 ||
+		    get_master_key(pw_hash_hash, nt_response,
+				   data->master_key)) {
+			data->state = FAILURE;
+			return;
+		}
 		data->master_key_valid = 1;
 		wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key",
 				data->master_key, MSCHAPV2_KEY_LEN);
diff --git a/src/eap_server/eap_server_pax.c b/src/eap_server/eap_server_pax.c
index d9d4375..0e6b4a0 100644
--- a/src/eap_server/eap_server_pax.c
+++ b/src/eap_server/eap_server_pax.c
@@ -36,6 +36,7 @@
 	u8 mk[EAP_PAX_MK_LEN];
 	u8 ck[EAP_PAX_CK_LEN];
 	u8 ick[EAP_PAX_ICK_LEN];
+	u8 mid[EAP_PAX_MID_LEN];
 	int keys_set;
 	char *cid;
 	size_t cid_len;
@@ -148,7 +149,6 @@
 		    (u8 *) data->cid, data->cid_len, NULL, 0, pos);
 	wpa_hexdump(MSG_MSGDUMP, "EAP-PAX: MAC_CK(B, CID)",
 		    pos, EAP_PAX_MAC_LEN);
-	pos += EAP_PAX_MAC_LEN;
 
 	/* Optional ADE could be added here, if needed */
 
@@ -388,7 +388,7 @@
 
 	if (eap_pax_initial_key_derivation(data->mac_id, data->ak,
 					   data->rand.e, data->mk, data->ck,
-					   data->ick) < 0) {
+					   data->ick, data->mid) < 0) {
 		wpa_printf(MSG_INFO, "EAP-PAX: Failed to complete initial "
 			   "key derivation");
 		data->state = FAILURE;
@@ -542,6 +542,26 @@
 }
 
 
+static u8 * eap_pax_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pax_data *data = priv;
+	u8 *sid;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	sid = os_malloc(1 + EAP_PAX_MID_LEN);
+	if (sid == NULL)
+		return NULL;
+
+	*len = 1 + EAP_PAX_MID_LEN;
+	sid[0] = EAP_TYPE_PAX;
+	os_memcpy(sid + 1, data->mid, EAP_PAX_MID_LEN);
+
+	return sid;
+}
+
+
 int eap_server_pax_register(void)
 {
 	struct eap_method *eap;
@@ -561,6 +581,7 @@
 	eap->getKey = eap_pax_getKey;
 	eap->isSuccess = eap_pax_isSuccess;
 	eap->get_emsk = eap_pax_get_emsk;
+	eap->getSessionId = eap_pax_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 594e02d..98d608b 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -1229,6 +1229,18 @@
 }
 
 
+static u8 * eap_peap_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_peap_data *data = priv;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_PEAP,
+						len);
+}
+
+
 int eap_server_peap_register(void)
 {
 	struct eap_method *eap;
@@ -1247,6 +1259,7 @@
 	eap->isDone = eap_peap_isDone;
 	eap->getKey = eap_peap_getKey;
 	eap->isSuccess = eap_peap_isSuccess;
+	eap->getSessionId = eap_peap_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index db394e9..12b5d25 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -485,6 +485,28 @@
 }
 
 
+static u8 * eap_psk_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_psk_data *data = priv;
+	u8 *id;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	*len = 1 + 2 * EAP_PSK_RAND_LEN;
+	id = os_malloc(*len);
+	if (id == NULL)
+		return NULL;
+
+	id[0] = EAP_TYPE_PSK;
+	os_memcpy(id + 1, data->rand_p, EAP_PSK_RAND_LEN);
+	os_memcpy(id + 1 + EAP_PSK_RAND_LEN, data->rand_s, EAP_PSK_RAND_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-PSK: Derived Session-Id", id, *len);
+
+	return id;
+}
+
+
 int eap_server_psk_register(void)
 {
 	struct eap_method *eap;
@@ -504,6 +526,7 @@
 	eap->getKey = eap_psk_getKey;
 	eap->isSuccess = eap_psk_isSuccess;
 	eap->get_emsk = eap_psk_get_emsk;
+	eap->getSessionId = eap_psk_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index 7e1278d..943af0d 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -1020,6 +1020,25 @@
 }
 
 
+static u8 * eap_pwd_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_pwd_data *data = priv;
+	u8 *id;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	id = os_malloc(1 + SHA256_MAC_LEN);
+	if (id == NULL)
+		return NULL;
+
+	os_memcpy(id, data->session_id, 1 + SHA256_MAC_LEN);
+	*len = 1 + SHA256_MAC_LEN;
+
+	return id;
+}
+
+
 int eap_server_pwd_register(void)
 {
 	struct eap_method *eap;
@@ -1028,8 +1047,6 @@
 	struct timezone tz;
 	u32 sr;
 
-	EVP_add_digest(EVP_sha256());
-
 	sr = 0xdeaddada;
 	(void) gettimeofday(&tp, &tz);
 	sr ^= (tp.tv_sec ^ tp.tv_usec);
@@ -1050,6 +1067,7 @@
 	eap->getKey = eap_pwd_getkey;
 	eap->get_emsk = eap_pwd_get_emsk;
 	eap->isSuccess = eap_pwd_is_success;
+	eap->getSessionId = eap_pwd_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_sake.c b/src/eap_server/eap_server_sake.c
index 1937621..de70777 100644
--- a/src/eap_server/eap_server_sake.c
+++ b/src/eap_server/eap_server_sake.c
@@ -495,6 +495,28 @@
 }
 
 
+static u8 * eap_sake_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sake_data *data = priv;
+	u8 *id;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	*len = 1 + 2 * EAP_SAKE_RAND_LEN;
+	id = os_malloc(*len);
+	if (id == NULL)
+		return NULL;
+
+	id[0] = EAP_TYPE_SAKE;
+	os_memcpy(id + 1, data->rand_s, EAP_SAKE_RAND_LEN);
+	os_memcpy(id + 1 + EAP_SAKE_RAND_LEN, data->rand_s, EAP_SAKE_RAND_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Derived Session-Id", id, *len);
+
+	return id;
+}
+
+
 int eap_server_sake_register(void)
 {
 	struct eap_method *eap;
@@ -514,6 +536,7 @@
 	eap->getKey = eap_sake_getKey;
 	eap->isSuccess = eap_sake_isSuccess;
 	eap->get_emsk = eap_sake_get_emsk;
+	eap->getSessionId = eap_sake_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_sim.c b/src/eap_server/eap_server_sim.c
index 23ee2b6..ddfb71c 100644
--- a/src/eap_server/eap_server_sim.c
+++ b/src/eap_server/eap_server_sim.c
@@ -820,6 +820,29 @@
 }
 
 
+static u8 * eap_sim_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_sim_data *data = priv;
+	u8 *id;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	*len = 1 + data->num_chal * GSM_RAND_LEN + EAP_SIM_NONCE_MT_LEN;
+	id = os_malloc(*len);
+	if (id == NULL)
+		return NULL;
+
+	id[0] = EAP_TYPE_SIM;
+	os_memcpy(id + 1, data->rand, data->num_chal * GSM_RAND_LEN);
+	os_memcpy(id + 1 + data->num_chal * GSM_RAND_LEN, data->nonce_mt,
+		  EAP_SIM_NONCE_MT_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-SIM: Derived Session-Id", id, *len);
+
+	return id;
+}
+
+
 int eap_server_sim_register(void)
 {
 	struct eap_method *eap;
@@ -839,6 +862,7 @@
 	eap->getKey = eap_sim_getKey;
 	eap->isSuccess = eap_sim_isSuccess;
 	eap->get_emsk = eap_sim_get_emsk;
+	eap->getSessionId = eap_sim_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_tls.c b/src/eap_server/eap_server_tls.c
index 6bed62f..58cfe8a 100644
--- a/src/eap_server/eap_server_tls.c
+++ b/src/eap_server/eap_server_tls.c
@@ -287,7 +287,7 @@
 		if (emsk)
 			os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
 				  EAP_EMSK_LEN);
-		os_free(eapKeyData);
+		bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
 	} else
 		emsk = NULL;
 
@@ -310,6 +310,18 @@
 }
 
 
+static u8 * eap_tls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_tls_data *data = priv;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TLS,
+						len);
+}
+
+
 int eap_server_tls_register(void)
 {
 	struct eap_method *eap;
@@ -329,6 +341,7 @@
 	eap->getKey = eap_tls_getKey;
 	eap->isSuccess = eap_tls_isSuccess;
 	eap->get_emsk = eap_tls_get_emsk;
+	eap->getSessionId = eap_tls_get_session_id;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index 01853e6..56916c4 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -140,6 +140,47 @@
 }
 
 
+/**
+ * eap_server_tls_derive_session_id - Derive a Session-Id based on TLS data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ * @len: Pointer to length of the session ID generated
+ * Returns: Pointer to allocated Session-Id on success or %NULL on failure
+ *
+ * This function derive the Session-Id based on the TLS session data
+ * (client/server random and method type).
+ *
+ * The caller is responsible for freeing the returned buffer.
+ */
+u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
+				      struct eap_ssl_data *data, u8 eap_type,
+				      size_t *len)
+{
+	struct tls_keys keys;
+	u8 *out;
+
+	if (tls_connection_get_keys(sm->ssl_ctx, data->conn, &keys))
+		return NULL;
+
+	if (keys.client_random == NULL || keys.server_random == NULL)
+		return NULL;
+
+	*len = 1 + keys.client_random_len + keys.server_random_len;
+	out = os_malloc(*len);
+	if (out == NULL)
+		return NULL;
+
+	/* Session-Id = EAP type || client.random || server.random */
+	out[0] = eap_type;
+	os_memcpy(out + 1, keys.client_random, keys.client_random_len);
+	os_memcpy(out + 1 + keys.client_random_len, keys.server_random,
+		  keys.server_random_len);
+
+	return out;
+}
+
+
 struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
 					 int eap_type, int version, u8 id)
 {
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 31e3871..12a31b0 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -409,7 +409,7 @@
 				       RADIUS_VENDOR_ID_MICROSOFT, 1, 43);
 		*pos++ = data->mschapv2_ident;
 		ret = os_snprintf((char *) pos, end - pos, "S=");
-		if (ret >= 0 && ret < end - pos)
+		if (!os_snprintf_error(end - pos, ret))
 			pos += ret;
 		pos += wpa_snprintf_hex_uppercase(
 			(char *) pos, end - pos, data->mschapv2_auth_response,
@@ -1181,6 +1181,50 @@
 }
 
 
+static u8 * eap_ttls_get_session_id(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_ttls_data *data = priv;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	return eap_server_tls_derive_session_id(sm, &data->ssl, EAP_TYPE_TTLS,
+						len);
+}
+
+
+static u8 * eap_ttls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_ttls_data *data = priv;
+	u8 *eapKeyData, *emsk;
+
+	if (data->state != SUCCESS)
+		return NULL;
+
+	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+					       "ttls keying material",
+					       EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+	if (eapKeyData) {
+		emsk = os_malloc(EAP_EMSK_LEN);
+		if (emsk)
+			os_memcpy(emsk, eapKeyData + EAP_TLS_KEY_LEN,
+				  EAP_EMSK_LEN);
+		bin_clear_free(eapKeyData, EAP_TLS_KEY_LEN + EAP_EMSK_LEN);
+	} else
+		emsk = NULL;
+
+	if (emsk) {
+		*len = EAP_EMSK_LEN;
+		wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Derived EMSK",
+			    emsk, EAP_EMSK_LEN);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive EMSK");
+	}
+
+	return emsk;
+}
+
+
 int eap_server_ttls_register(void)
 {
 	struct eap_method *eap;
@@ -1199,6 +1243,8 @@
 	eap->isDone = eap_ttls_isDone;
 	eap->getKey = eap_ttls_getKey;
 	eap->isSuccess = eap_ttls_isSuccess;
+	eap->getSessionId = eap_ttls_get_session_id;
+	eap->get_emsk = eap_ttls_get_emsk;
 
 	ret = eap_server_method_register(eap);
 	if (ret)
diff --git a/src/eap_server/eap_server_wsc.c b/src/eap_server/eap_server_wsc.c
index 97ec0c0..9d9c28d 100644
--- a/src/eap_server/eap_server_wsc.c
+++ b/src/eap_server/eap_server_wsc.c
@@ -380,7 +380,7 @@
 		message_length = WPA_GET_BE16(pos);
 		pos += 2;
 
-		if (message_length < end - pos) {
+		if (message_length < end - pos || message_length > 50000) {
 			wpa_printf(MSG_DEBUG, "EAP-WSC: Invalid Message "
 				   "Length");
 			return;
diff --git a/src/eap_server/eap_sim_db.c b/src/eap_server/eap_sim_db.c
index bc2cbe5..acf5435 100644
--- a/src/eap_server/eap_sim_db.c
+++ b/src/eap_server/eap_sim_db.c
@@ -573,16 +573,14 @@
 	char buf[1000], *pos, *cmd, *imsi;
 	int res;
 
-	res = recv(sock, buf, sizeof(buf), 0);
+	res = recv(sock, buf, sizeof(buf) - 1, 0);
 	if (res < 0)
 		return;
+	buf[res] = '\0';
 	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
 			      "external source", (u8 *) buf, res);
 	if (res == 0)
 		return;
-	if (res >= (int) sizeof(buf))
-		res = sizeof(buf) - 1;
-	buf[res] = '\0';
 
 	if (data->get_complete_cb == NULL) {
 		wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
@@ -924,12 +922,13 @@
 
 	imsi_len = os_strlen(imsi);
 	len = os_snprintf(msg, sizeof(msg), "SIM-REQ-AUTH ");
-	if (len < 0 || len + imsi_len >= sizeof(msg))
+	if (os_snprintf_error(sizeof(msg), len) ||
+	    len + imsi_len >= sizeof(msg))
 		return EAP_SIM_DB_FAILURE;
 	os_memcpy(msg + len, imsi, imsi_len);
 	len += imsi_len;
 	ret = os_snprintf(msg + len, sizeof(msg) - len, " %d", max_chal);
-	if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+	if (os_snprintf_error(sizeof(msg) - len, ret))
 		return EAP_SIM_DB_FAILURE;
 	len += ret;
 
@@ -966,7 +965,7 @@
 	pos = id;
 	end = id + sizeof(buf) * 2 + 2;
 	*pos++ = prefix;
-	pos += wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
+	wpa_snprintf_hex(pos, end - pos, buf, sizeof(buf));
 	
 	return id;
 }
@@ -1387,7 +1386,8 @@
 
 	imsi_len = os_strlen(imsi);
 	len = os_snprintf(msg, sizeof(msg), "AKA-REQ-AUTH ");
-	if (len < 0 || len + imsi_len >= sizeof(msg))
+	if (os_snprintf_error(sizeof(msg), len) ||
+	    len + imsi_len >= sizeof(msg))
 		return EAP_SIM_DB_FAILURE;
 	os_memcpy(msg + len, imsi, imsi_len);
 	len += imsi_len;
@@ -1451,19 +1451,20 @@
 
 		imsi_len = os_strlen(imsi);
 		len = os_snprintf(msg, sizeof(msg), "AKA-AUTS ");
-		if (len < 0 || len + imsi_len >= sizeof(msg))
+		if (os_snprintf_error(sizeof(msg), len) ||
+		    len + imsi_len >= sizeof(msg))
 			return -1;
 		os_memcpy(msg + len, imsi, imsi_len);
 		len += imsi_len;
 
 		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
-		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+		if (os_snprintf_error(sizeof(msg) - len, ret))
 			return -1;
 		len += ret;
 		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
 					auts, EAP_AKA_AUTS_LEN);
 		ret = os_snprintf(msg + len, sizeof(msg) - len, " ");
-		if (ret < 0 || (size_t) ret >= sizeof(msg) - len)
+		if (os_snprintf_error(sizeof(msg) - len, ret))
 			return -1;
 		len += ret;
 		len += wpa_snprintf_hex(msg + len, sizeof(msg) - len,
diff --git a/src/eap_server/eap_tls_common.h b/src/eap_server/eap_tls_common.h
index 91449af..ddf90b8 100644
--- a/src/eap_server/eap_tls_common.h
+++ b/src/eap_server/eap_tls_common.h
@@ -74,6 +74,9 @@
 void eap_server_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
 u8 * eap_server_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
 			       char *label, size_t len);
+u8 * eap_server_tls_derive_session_id(struct eap_sm *sm,
+				      struct eap_ssl_data *data, u8 eap_type,
+				      size_t *len);
 struct wpabuf * eap_server_tls_build_msg(struct eap_ssl_data *data,
 					 int eap_type, int version, u8 id);
 struct wpabuf * eap_server_tls_build_ack(u8 id, int eap_type, int version);
diff --git a/src/eapol_auth/eapol_auth_dump.c b/src/eapol_auth/eapol_auth_dump.c
index 6c6969b..5579582 100644
--- a/src/eapol_auth/eapol_auth_dump.c
+++ b/src/eapol_auth/eapol_auth_dump.c
@@ -130,7 +130,7 @@
 	ret = os_snprintf(pos, end - pos, "aWhile=%d\nquietWhile=%d\n"
 			  "reAuthWhen=%d\n",
 			  sm->aWhile, sm->quietWhile, sm->reAuthWhen);
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -173,7 +173,7 @@
 			  _SB(sm->eap_if->portEnabled),
 			  _SB(sm->portValid),
 			  _SB(sm->reAuthenticate));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -215,7 +215,7 @@
 			  sm->authAuthReauthsWhileAuthenticated,
 			  sm->authAuthEapStartsWhileAuthenticated,
 			  sm->authAuthEapLogoffWhileAuthenticated);
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -240,7 +240,7 @@
 			  sm->backendOtherRequestsToSupplicant,
 			  sm->backendAuthSuccesses,
 			  sm->backendAuthFails);
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -251,14 +251,14 @@
 			  reauth_timer_state_txt(sm->reauth_timer_state),
 			  sm->reAuthPeriod,
 			  _SB(sm->reAuthEnabled));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
 	ret = os_snprintf(pos, end - pos,
 			  "auth_key_tx_state=%s\n",
 			  auth_key_tx_state_txt(sm->auth_key_tx_state));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -267,7 +267,7 @@
 			  "rxKey=%s\n",
 			  key_rx_state_txt(sm->key_rx_state),
 			  _SB(sm->rxKey));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -280,7 +280,7 @@
 			  ctrl_dir_txt(sm->adminControlledDirections),
 			  ctrl_dir_txt(sm->operControlledDirections),
 			  _SB(sm->operEdge));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 #undef _SB
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index a76fa13..0df6eb5 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -1,6 +1,6 @@
 /*
  * IEEE 802.1X-2004 Authenticator - EAPOL state machine
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -43,6 +43,7 @@
 static void eapol_sm_step_run(struct eapol_state_machine *sm);
 static void eapol_sm_step_cb(void *eloop_ctx, void *timeout_ctx);
 static void eapol_auth_initialize(struct eapol_state_machine *sm);
+static void eapol_auth_conf_free(struct eapol_auth_config *conf);
 
 
 static void eapol_auth_logger(struct eapol_authenticator *eapol,
@@ -833,6 +834,7 @@
 	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;
+	eap_conf.erp = eapol->conf.erp;
 	sm->eap = eap_server_sm_init(sm, &eapol_cb, &eap_conf);
 	if (sm->eap == NULL) {
 		eapol_auth_free(sm);
@@ -851,6 +853,11 @@
 		sm->radius_cui = wpabuf_alloc_copy(radius_cui,
 						   os_strlen(radius_cui));
 
+	sm->acct_multi_session_id_lo = eapol->acct_multi_session_id_lo++;
+	if (eapol->acct_multi_session_id_lo == 0)
+		eapol->acct_multi_session_id_hi++;
+	sm->acct_multi_session_id_hi = eapol->acct_multi_session_id_hi;
+
 	return sm;
 }
 
@@ -1020,11 +1027,44 @@
 }
 
 
+static int eapol_sm_get_erp_send_reauth_start(void *ctx)
+{
+	struct eapol_state_machine *sm = ctx;
+	return sm->eapol->conf.erp_send_reauth_start;
+}
+
+
+static const char * eapol_sm_get_erp_domain(void *ctx)
+{
+	struct eapol_state_machine *sm = ctx;
+	return sm->eapol->conf.erp_domain;
+}
+
+
+static struct eap_server_erp_key * eapol_sm_erp_get_key(void *ctx,
+							const char *keyname)
+{
+	struct eapol_state_machine *sm = ctx;
+	return sm->eapol->cb.erp_get_key(sm->eapol->conf.ctx, keyname);
+}
+
+
+static int eapol_sm_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
+{
+	struct eapol_state_machine *sm = ctx;
+	return sm->eapol->cb.erp_add_key(sm->eapol->conf.ctx, erp);
+}
+
+
 static struct eapol_callbacks eapol_cb =
 {
 	eapol_sm_get_eap_user,
 	eapol_sm_get_eap_req_id_text,
-	NULL
+	NULL,
+	eapol_sm_get_erp_send_reauth_start,
+	eapol_sm_get_erp_domain,
+	eapol_sm_erp_get_key,
+	eapol_sm_erp_add_key,
 };
 
 
@@ -1069,21 +1109,16 @@
 	}
 	if (src->pac_opaque_encr_key) {
 		dst->pac_opaque_encr_key = os_malloc(16);
-		if (dst->pac_opaque_encr_key == NULL) {
-			os_free(dst->eap_req_id_text);
-			return -1;
-		}
+		if (dst->pac_opaque_encr_key == NULL)
+			goto fail;
 		os_memcpy(dst->pac_opaque_encr_key, src->pac_opaque_encr_key,
 			  16);
 	} else
 		dst->pac_opaque_encr_key = NULL;
 	if (src->eap_fast_a_id) {
 		dst->eap_fast_a_id = os_malloc(src->eap_fast_a_id_len);
-		if (dst->eap_fast_a_id == NULL) {
-			os_free(dst->eap_req_id_text);
-			os_free(dst->pac_opaque_encr_key);
-			return -1;
-		}
+		if (dst->eap_fast_a_id == NULL)
+			goto fail;
 		os_memcpy(dst->eap_fast_a_id, src->eap_fast_a_id,
 			  src->eap_fast_a_id_len);
 		dst->eap_fast_a_id_len = src->eap_fast_a_id_len;
@@ -1091,12 +1126,8 @@
 		dst->eap_fast_a_id = NULL;
 	if (src->eap_fast_a_id_info) {
 		dst->eap_fast_a_id_info = os_strdup(src->eap_fast_a_id_info);
-		if (dst->eap_fast_a_id_info == NULL) {
-			os_free(dst->eap_req_id_text);
-			os_free(dst->pac_opaque_encr_key);
-			os_free(dst->eap_fast_a_id);
-			return -1;
-		}
+		if (dst->eap_fast_a_id_info == NULL)
+			goto fail;
 	} else
 		dst->eap_fast_a_id_info = NULL;
 	dst->eap_fast_prov = src->eap_fast_prov;
@@ -1106,7 +1137,23 @@
 	dst->tnc = src->tnc;
 	dst->wps = src->wps;
 	dst->fragment_size = src->fragment_size;
+
+	os_free(dst->erp_domain);
+	if (src->erp_domain) {
+		dst->erp_domain = os_strdup(src->erp_domain);
+		if (dst->erp_domain == NULL)
+			goto fail;
+	} else {
+		dst->erp_domain = NULL;
+	}
+	dst->erp_send_reauth_start = src->erp_send_reauth_start;
+	dst->erp = src->erp;
+
 	return 0;
+
+fail:
+	eapol_auth_conf_free(dst);
+	return -1;
 }
 
 
@@ -1120,6 +1167,8 @@
 	conf->eap_fast_a_id = NULL;
 	os_free(conf->eap_fast_a_id_info);
 	conf->eap_fast_a_id_info = NULL;
+	os_free(conf->erp_domain);
+	conf->erp_domain = NULL;
 }
 
 
@@ -1127,6 +1176,7 @@
 					     struct eapol_auth_cb *cb)
 {
 	struct eapol_authenticator *eapol;
+	struct os_time now;
 
 	eapol = os_zalloc(sizeof(*eapol));
 	if (eapol == NULL)
@@ -1152,6 +1202,14 @@
 	eapol->cb.abort_auth = cb->abort_auth;
 	eapol->cb.tx_key = cb->tx_key;
 	eapol->cb.eapol_event = cb->eapol_event;
+	eapol->cb.erp_get_key = cb->erp_get_key;
+	eapol->cb.erp_add_key = cb->erp_add_key;
+
+	/* Acct-Multi-Session-Id should be unique over reboots. If reliable
+	 * clock is not available, this could be replaced with reboot counter,
+	 * etc. */
+	os_get_time(&now);
+	eapol->acct_multi_session_id_hi = now.sec;
 
 	return eapol;
 }
diff --git a/src/eapol_auth/eapol_auth_sm.h b/src/eapol_auth/eapol_auth_sm.h
index 320a0ad..ebed19a 100644
--- a/src/eapol_auth/eapol_auth_sm.h
+++ b/src/eapol_auth/eapol_auth_sm.h
@@ -24,6 +24,9 @@
 	void *eap_sim_db_priv;
 	char *eap_req_id_text; /* a copy of this will be allocated */
 	size_t eap_req_id_text_len;
+	int erp_send_reauth_start;
+	char *erp_domain; /* a copy of this will be allocated */
+	int erp; /* Whether ERP is enabled on authentication server */
 	u8 *pac_opaque_encr_key;
 	u8 *eap_fast_a_id;
 	size_t eap_fast_a_id_len;
@@ -45,6 +48,7 @@
 };
 
 struct eap_user;
+struct eap_server_erp_key;
 
 typedef enum {
 	EAPOL_LOGGER_DEBUG, EAPOL_LOGGER_INFO, EAPOL_LOGGER_WARNING
@@ -71,6 +75,9 @@
 	void (*abort_auth)(void *ctx, void *sta_ctx);
 	void (*tx_key)(void *ctx, void *sta_ctx);
 	void (*eapol_event)(void *ctx, void *sta_ctx, enum eapol_event type);
+	struct eap_server_erp_key * (*erp_get_key)(void *ctx,
+						   const char *keyname);
+	int (*erp_add_key)(void *ctx, struct eap_server_erp_key *erp);
 };
 
 
diff --git a/src/eapol_auth/eapol_auth_sm_i.h b/src/eapol_auth/eapol_auth_sm_i.h
index 25baddb..a29b49c 100644
--- a/src/eapol_auth/eapol_auth_sm_i.h
+++ b/src/eapol_auth/eapol_auth_sm_i.h
@@ -30,6 +30,9 @@
 
 	u8 *default_wep_key;
 	u8 default_wep_key_idx;
+
+	u32 acct_multi_session_id_hi;
+	u32 acct_multi_session_id_lo;
 };
 
 
@@ -175,6 +178,9 @@
 	void *sta; /* station context pointer to use in callbacks */
 
 	int remediation;
+
+	u32 acct_multi_session_id_hi;
+	u32 acct_multi_session_id_lo;
 };
 
 #endif /* EAPOL_AUTH_SM_I_H */
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index 70258be..941a269 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -128,6 +128,7 @@
 	struct wpabuf *eapReqData; /* for EAP */
 	Boolean altAccept; /* for EAP */
 	Boolean altReject; /* for EAP */
+	Boolean eapTriggerStart;
 	Boolean replay_counter_valid;
 	u8 last_replay_counter[16];
 	struct eapol_config conf;
@@ -222,6 +223,7 @@
 	SM_ENTRY(SUPP_PAE, DISCONNECTED);
 	sm->sPortMode = Auto;
 	sm->startCount = 0;
+	sm->eapTriggerStart = FALSE;
 	sm->logoffSent = FALSE;
 	eapol_sm_set_port_unauthorized(sm);
 	sm->suppAbort = TRUE;
@@ -244,6 +246,11 @@
 {
 	int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
 	SM_ENTRY(SUPP_PAE, CONNECTING);
+
+	if (sm->eapTriggerStart)
+		send_start = 1;
+	sm->eapTriggerStart = FALSE;
+
 	if (send_start) {
 		sm->startWhen = sm->startPeriod;
 		sm->startCount++;
@@ -255,7 +262,7 @@
 		 * delay authentication. Use a short timeout to send the first
 		 * EAPOL-Start if Authenticator does not start authentication.
 		 */
-		if (sm->conf.wps) {
+		if (sm->conf.wps && !(sm->conf.wps & EAPOL_PEER_IS_WPS20_AP)) {
 			/* Reduce latency on starting WPS negotiation. */
 			wpa_printf(MSG_DEBUG,
 				   "EAPOL: Using shorter startWhen for WPS");
@@ -386,6 +393,8 @@
 			SM_ENTER(SUPP_PAE, HELD);
 		else if (sm->suppTimeout)
 			SM_ENTER(SUPP_PAE, CONNECTING);
+		else if (sm->eapTriggerStart)
+			SM_ENTER(SUPP_PAE, CONNECTING);
 		break;
 	case SUPP_PAE_HELD:
 		if (sm->heldWhile == 0)
@@ -1099,7 +1108,7 @@
 			  "suppPortStatus=%s\n",
 			  eapol_supp_pae_state(sm->SUPP_PAE_state),
 			  eapol_port_status(sm->suppPortStatus));
-	if (len < 0 || (size_t) len >= buflen)
+	if (os_snprintf_error(buflen, len))
 		return 0;
 
 	if (verbose) {
@@ -1116,7 +1125,7 @@
 				  sm->maxStart,
 				  eapol_port_control(sm->portControl),
 				  eapol_supp_be_state(sm->SUPP_BE_state));
-		if (ret < 0 || (size_t) ret >= buflen - len)
+		if (os_snprintf_error(buflen - len, ret))
 			return len;
 		len += ret;
 	}
@@ -1170,7 +1179,7 @@
 			  "Authorized" : "Unauthorized",
 			  sm->SUPP_BE_state);
 
-	if (ret < 0 || (size_t) ret >= buflen)
+	if (os_snprintf_error(buflen, ret))
 		return 0;
 	len = ret;
 
@@ -1198,7 +1207,7 @@
 			  sm->dot1xSuppLastEapolFrameVersion,
 			  MAC2STR(sm->dot1xSuppLastEapolFrameSource));
 
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
@@ -1822,6 +1831,8 @@
 		return sm->altAccept;
 	case EAPOL_altReject:
 		return sm->altReject;
+	case EAPOL_eapTriggerStart:
+		return sm->eapTriggerStart;
 	}
 	return FALSE;
 }
@@ -1861,6 +1872,9 @@
 	case EAPOL_altReject:
 		sm->altReject = value;
 		break;
+	case EAPOL_eapTriggerStart:
+		sm->eapTriggerStart = value;
+		break;
 	}
 }
 
@@ -2026,6 +2040,7 @@
 	conf.opensc_engine_path = ctx->opensc_engine_path;
 	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
 	conf.pkcs11_module_path = ctx->pkcs11_module_path;
+	conf.openssl_ciphers = ctx->openssl_ciphers;
 	conf.wps = ctx->wps;
 	conf.cert_in_cb = ctx->cert_in_cb;
 
@@ -2106,3 +2121,10 @@
 	return -1;
 #endif /* CONFIG_EAP_PROXY */
 }
+
+
+void eapol_sm_erp_flush(struct eapol_sm *sm)
+{
+	if (sm)
+		eap_peer_erp_free_keys(sm->eap);
+}
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 5b37314..e089e88 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -59,6 +59,8 @@
 	 */
 	int external_sim;
 
+#define EAPOL_LOCAL_WPS_IN_USE BIT(0)
+#define EAPOL_PEER_IS_WPS20_AP BIT(1)
 	/**
 	 * wps - Whether this connection is used for WPS
 	 */
@@ -210,6 +212,15 @@
 	const char *pkcs11_module_path;
 
 	/**
+	 * openssl_ciphers - OpenSSL cipher string
+	 *
+	 * This is an OpenSSL specific configuration option for configuring the
+	 * default ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the
+	 * default.
+	 */
+	const char *openssl_ciphers;
+
+	/**
 	 * wps - WPS context data
 	 *
 	 * This is only used by EAP-WSC and can be left %NULL if not available.
@@ -305,6 +316,7 @@
 void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
 			     struct ext_password_data *ext);
 int eapol_sm_failed(struct eapol_sm *sm);
+void eapol_sm_erp_flush(struct eapol_sm *sm);
 int eapol_sm_get_eap_proxy_imsi(struct eapol_sm *sm, char *imsi, size_t *len);
 #else /* IEEE8021X_EAPOL */
 static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
@@ -405,6 +417,9 @@
 {
 	return 0;
 }
+static inline void eapol_sm_erp_flush(struct eapol_sm *sm)
+{
+}
 #endif /* IEEE8021X_EAPOL */
 
 #endif /* EAPOL_SUPP_SM_H */
diff --git a/src/l2_packet/l2_packet.h b/src/l2_packet/l2_packet.h
index dd825b5..7537f93 100644
--- a/src/l2_packet/l2_packet.h
+++ b/src/l2_packet/l2_packet.h
@@ -39,6 +39,11 @@
 #pragma pack(pop)
 #endif /* _MSC_VER */
 
+enum l2_packet_filter_type {
+	L2_PACKET_FILTER_DHCP,
+	L2_PACKET_FILTER_NDISC,
+};
+
 /**
  * l2_packet_init - Initialize l2_packet interface
  * @ifname: Interface name
@@ -121,4 +126,16 @@
  */
 void l2_packet_notify_auth_start(struct l2_packet_data *l2);
 
+/**
+ * l2_packet_set_packet_filter - Set socket filter for l2_packet
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @type: enum l2_packet_filter_type, type of filter
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to set the socket filter for l2_packet socket.
+ *
+ */
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+				enum l2_packet_filter_type type);
+
 #endif /* L2_PACKET_H */
diff --git a/src/l2_packet/l2_packet_freebsd.c b/src/l2_packet/l2_packet_freebsd.c
index 2e9a04c..d87c32b 100644
--- a/src/l2_packet/l2_packet_freebsd.c
+++ b/src/l2_packet/l2_packet_freebsd.c
@@ -308,3 +308,10 @@
 void l2_packet_notify_auth_start(struct l2_packet_data *l2)
 {
 }
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+				enum l2_packet_filter_type type)
+{
+	return -1;
+}
diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c
index 1419830..89ff7db 100644
--- a/src/l2_packet/l2_packet_linux.c
+++ b/src/l2_packet/l2_packet_linux.c
@@ -10,6 +10,7 @@
 #include <sys/ioctl.h>
 #include <netpacket/packet.h>
 #include <net/if.h>
+#include <linux/filter.h>
 
 #include "common.h"
 #include "eloop.h"
@@ -28,6 +29,50 @@
 		     * buffers */
 };
 
+/* Generated by 'sudo tcpdump -s 3000 -dd greater 278 and ip and udp and
+ * src port bootps and dst port bootpc'
+ */
+static struct sock_filter dhcp_sock_filter_insns[] = {
+	{ 0x80, 0, 0, 0x00000000 },
+	{ 0x35, 0, 12, 0x00000116 },
+	{ 0x28, 0, 0, 0x0000000c },
+	{ 0x15, 0, 10, 0x00000800 },
+	{ 0x30, 0, 0, 0x00000017 },
+	{ 0x15, 0, 8, 0x00000011 },
+	{ 0x28, 0, 0, 0x00000014 },
+	{ 0x45, 6, 0, 0x00001fff },
+	{ 0xb1, 0, 0, 0x0000000e },
+	{ 0x48, 0, 0, 0x0000000e },
+	{ 0x15, 0, 3, 0x00000043 },
+	{ 0x48, 0, 0, 0x00000010 },
+	{ 0x15, 0, 1, 0x00000044 },
+	{ 0x6, 0, 0, 0x00000bb8 },
+	{ 0x6, 0, 0, 0x00000000 },
+};
+
+static const struct sock_fprog dhcp_sock_filter = {
+	.len = ARRAY_SIZE(dhcp_sock_filter_insns),
+	.filter = dhcp_sock_filter_insns,
+};
+
+
+/* Generated by 'sudo tcpdump -dd -s 1500 multicast and ip6[6]=58' */
+static struct sock_filter ndisc_sock_filter_insns[] = {
+	{ 0x30, 0, 0, 0x00000000 },
+	{ 0x45, 0, 5, 0x00000001 },
+	{ 0x28, 0, 0, 0x0000000c },
+	{ 0x15, 0, 3, 0x000086dd },
+	{ 0x30, 0, 0, 0x00000014 },
+	{ 0x15, 0, 1, 0x0000003a },
+	{ 0x6, 0, 0, 0x000005dc },
+	{ 0x6, 0, 0, 0x00000000 },
+};
+
+static const struct sock_fprog ndisc_sock_filter = {
+	.len = ARRAY_SIZE(ndisc_sock_filter_insns),
+	.filter = ndisc_sock_filter_insns,
+};
+
 
 int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
 {
@@ -202,3 +247,31 @@
 void l2_packet_notify_auth_start(struct l2_packet_data *l2)
 {
 }
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+				enum l2_packet_filter_type type)
+{
+	const struct sock_fprog *sock_filter;
+
+	switch (type) {
+	case L2_PACKET_FILTER_DHCP:
+		sock_filter = &dhcp_sock_filter;
+		break;
+	case L2_PACKET_FILTER_NDISC:
+		sock_filter = &ndisc_sock_filter;
+		break;
+	default:
+		return -1;
+	}
+
+	if (setsockopt(l2->fd, SOL_SOCKET, SO_ATTACH_FILTER,
+		       sock_filter, sizeof(struct sock_fprog))) {
+		wpa_printf(MSG_ERROR,
+			   "l2_packet_linux: setsockopt(SO_ATTACH_FILTER) failed: %s",
+			   strerror(errno));
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/src/l2_packet/l2_packet_ndis.c b/src/l2_packet/l2_packet_ndis.c
index 23b8ddc..39a62a0 100644
--- a/src/l2_packet/l2_packet_ndis.c
+++ b/src/l2_packet/l2_packet_ndis.c
@@ -514,3 +514,10 @@
 void l2_packet_notify_auth_start(struct l2_packet_data *l2)
 {
 }
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+				enum l2_packet_filter_type type)
+{
+	return -1;
+}
diff --git a/src/l2_packet/l2_packet_none.c b/src/l2_packet/l2_packet_none.c
index 6896c4e..0501925 100644
--- a/src/l2_packet/l2_packet_none.c
+++ b/src/l2_packet/l2_packet_none.c
@@ -116,3 +116,10 @@
 {
 	/* This function can be left empty */
 }
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+				enum l2_packet_filter_type type)
+{
+	return -1;
+}
diff --git a/src/l2_packet/l2_packet_pcap.c b/src/l2_packet/l2_packet_pcap.c
index 45aef56..bb4f4a3 100644
--- a/src/l2_packet/l2_packet_pcap.c
+++ b/src/l2_packet/l2_packet_pcap.c
@@ -54,15 +54,16 @@
 
 	l2->eth = eth_open(l2->ifname);
 	if (!l2->eth) {
-		printf("Failed to open interface '%s'.\n", l2->ifname);
-		perror("eth_open");
+		wpa_printf(MSG_ERROR,
+			   "Failed to open interface '%s' - eth_open: %s",
+			   l2->ifname, strerror(errno));
 		return -1;
 	}
 
 	if (eth_get(l2->eth, &own_addr) < 0) {
-		printf("Failed to get own hw address from interface '%s'.\n",
-		       l2->ifname);
-		perror("eth_get");
+		wpa_printf(MSG_ERROR,
+			   "Failed to get own hw address from interface '%s' - eth_get: %s",
+			   l2->ifname, strerror(errno));
 		eth_close(l2->eth);
 		l2->eth = NULL;
 		return -1;
@@ -378,3 +379,10 @@
 			       l2, l2->pcap);
 #endif /* CONFIG_WINPCAP */
 }
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+				enum l2_packet_filter_type type)
+{
+	return -1;
+}
diff --git a/src/l2_packet/l2_packet_privsep.c b/src/l2_packet/l2_packet_privsep.c
index 6b117ca..76dcccc 100644
--- a/src/l2_packet/l2_packet_privsep.c
+++ b/src/l2_packet/l2_packet_privsep.c
@@ -44,7 +44,7 @@
 	msg.msg_namelen = sizeof(l2->priv_addr);
 
 	if (sendmsg(l2->fd, &msg, 0) < 0) {
-		perror("L2: sendmsg(cmd)");
+		wpa_printf(MSG_ERROR, "L2: sendmsg(cmd): %s", strerror(errno));
 		return -1;
 	}
 
@@ -82,7 +82,8 @@
 	msg.msg_namelen = sizeof(l2->priv_addr);
 
 	if (sendmsg(l2->fd, &msg, 0) < 0) {
-		perror("L2: sendmsg(packet_send)");
+		wpa_printf(MSG_ERROR, "L2: sendmsg(packet_send): %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -102,7 +103,8 @@
 	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
 		       &fromlen);
 	if (res < 0) {
-		perror("l2_packet_receive - recvfrom");
+		wpa_printf(MSG_ERROR, "l2_packet_receive - recvfrom: %s",
+			   strerror(errno));
 		return;
 	}
 	if (res < ETH_ALEN) {
@@ -162,7 +164,7 @@
 
 	l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (l2->fd < 0) {
-		perror("socket(PF_UNIX)");
+		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
 		os_free(l2->own_socket_path);
 		l2->own_socket_path = NULL;
 		os_free(l2);
@@ -173,7 +175,8 @@
 	addr.sun_family = AF_UNIX;
 	os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
 	if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("l2-pkt-privsep: bind(PF_UNIX)");
+		wpa_printf(MSG_ERROR, "l2-pkt-privsep: bind(PF_UNIX): %s",
+			   strerror(errno));
 		goto fail;
 	}
 
@@ -191,14 +194,14 @@
 	tv.tv_usec = 0;
 	res = select(l2->fd + 1, &rfds, NULL, NULL, &tv);
 	if (res < 0 && errno != EINTR) {
-		perror("select");
+		wpa_printf(MSG_ERROR, "select: %s", strerror(errno));
 		goto fail;
 	}
 
 	if (FD_ISSET(l2->fd, &rfds)) {
 		res = recv(l2->fd, reply, sizeof(reply), 0);
 		if (res < 0) {
-			perror("recv");
+			wpa_printf(MSG_ERROR, "recv: %s", strerror(errno));
 			goto fail;
 		}
 	} else {
@@ -259,3 +262,10 @@
 {
 	wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0);
 }
+
+
+int l2_packet_set_packet_filter(struct l2_packet_data *l2,
+				enum l2_packet_filter_type type)
+{
+	return -1;
+}
diff --git a/src/lib.rules b/src/lib.rules
index b260d25..0c79d99 100644
--- a/src/lib.rules
+++ b/src/lib.rules
@@ -15,6 +15,10 @@
 Q=
 E=true
 endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
 
 %.o: %.c
 	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
index 7d4a03c..fc61081 100644
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -211,29 +211,35 @@
 }
 
 
-void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
-		       int status)
+void p2p_go_neg_failed(struct p2p_data *p2p, int status)
 {
 	struct p2p_go_neg_results res;
-	p2p_clear_timeout(p2p);
-	p2p_set_state(p2p, P2P_IDLE);
-	if (p2p->go_neg_peer) {
-		p2p->go_neg_peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
-		p2p->go_neg_peer->wps_method = WPS_NOT_READY;
-		p2p->go_neg_peer->oob_pw_id = 0;
+	struct p2p_device *peer = p2p->go_neg_peer;
+
+	if (!peer)
+		return;
+
+	eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
+	if (p2p->state != P2P_SEARCH) {
+		/*
+		 * Clear timeouts related to GO Negotiation if no new p2p_find
+		 * has been started.
+		 */
+		p2p_clear_timeout(p2p);
+		p2p_set_state(p2p, P2P_IDLE);
 	}
+
+	peer->flags &= ~P2P_DEV_PEER_WAITING_RESPONSE;
+	peer->wps_method = WPS_NOT_READY;
+	peer->oob_pw_id = 0;
+	wpabuf_free(peer->go_neg_conf);
+	peer->go_neg_conf = NULL;
 	p2p->go_neg_peer = NULL;
 
 	os_memset(&res, 0, sizeof(res));
 	res.status = status;
-	if (peer) {
-		wpabuf_free(peer->go_neg_conf);
-		peer->go_neg_conf = NULL;
-		os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr,
-			  ETH_ALEN);
-		os_memcpy(res.peer_interface_addr, peer->intended_addr,
-			  ETH_ALEN);
-	}
+	os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
+	os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
 	p2p->cfg->go_neg_completed(p2p->cfg->cb_ctx, &res);
 }
 
@@ -348,8 +354,10 @@
 static void p2p_device_clear_reported(struct p2p_data *p2p)
 {
 	struct p2p_device *dev;
-	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list)
+	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
 		dev->flags &= ~P2P_DEV_REPORTED;
+		dev->sd_reqs = 0;
+	}
 }
 
 
@@ -650,6 +658,24 @@
 }
 
 
+static int p2p_compare_wfd_info(struct p2p_device *dev,
+			      const struct p2p_message *msg)
+{
+	if (dev->info.wfd_subelems && msg->wfd_subelems) {
+		if (dev->info.wfd_subelems->used != msg->wfd_subelems->used)
+			return 1;
+
+		return os_memcmp(dev->info.wfd_subelems->buf,
+				 msg->wfd_subelems->buf,
+				 dev->info.wfd_subelems->used);
+	}
+	if (dev->info.wfd_subelems || msg->wfd_subelems)
+		return 1;
+
+	return 0;
+}
+
+
 /**
  * p2p_add_device - Add peer entries based on scan results or P2P frames
  * @p2p: P2P module context from p2p_init()
@@ -675,6 +701,7 @@
 	struct p2p_device *dev;
 	struct p2p_message msg;
 	const u8 *p2p_dev_addr;
+	int wfd_changed;
 	int i;
 	struct os_reltime time_now;
 
@@ -786,6 +813,8 @@
 			break;
 	}
 
+	wfd_changed = p2p_compare_wfd_info(dev, &msg);
+
 	if (msg.wfd_subelems) {
 		wpabuf_free(dev->info.wfd_subelems);
 		dev->info.wfd_subelems = wpabuf_dup(msg.wfd_subelems);
@@ -800,7 +829,7 @@
 
 	p2p_update_peer_vendor_elems(dev, ies, ies_len);
 
-	if (dev->flags & P2P_DEV_REPORTED)
+	if (dev->flags & P2P_DEV_REPORTED && !wfd_changed)
 		return 0;
 
 	p2p_dbg(p2p, "Peer found with Listen frequency %d MHz (rx_time=%u.%06u)",
@@ -848,8 +877,7 @@
 		/*
 		 * If GO Negotiation is in progress, report that it has failed.
 		 */
-		p2p_go_neg_failed(p2p, dev, -1);
-		p2p->go_neg_peer = NULL;
+		p2p_go_neg_failed(p2p, -1);
 	}
 	if (p2p->invite_peer == dev)
 		p2p->invite_peer = NULL;
@@ -956,14 +984,8 @@
 				 p2p->num_req_dev_types, p2p->req_dev_types,
 				 p2p->find_dev_id, pw_id);
 	if (res < 0) {
-		p2p_dbg(p2p, "Scan request failed");
+		p2p_dbg(p2p, "Scan request schedule failed");
 		p2p_continue_find(p2p);
-	} else {
-		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);
 	}
 }
 
@@ -976,6 +998,22 @@
 }
 
 
+void p2p_notify_scan_trigger_status(struct p2p_data *p2p, int status)
+{
+	if (status != 0) {
+		p2p_dbg(p2p, "Scan request failed");
+		/* Do continue find even for the first p2p_find_scan */
+		p2p_continue_find(p2p);
+	} else {
+		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);
+	}
+}
+
+
 static int p2p_run_after_scan(struct p2p_data *p2p)
 {
 	struct p2p_device *dev;
@@ -1106,17 +1144,11 @@
 		return -1;
 	}
 
-	if (res == 0) {
-		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 (p2p->p2p_scan_running) {
+	if (res != 0 && p2p->p2p_scan_running) {
 		p2p_dbg(p2p, "Failed to start p2p_scan - another p2p_scan was already running");
 		/* wait for the previous p2p_scan to complete */
 		res = 0; /* do not report failure */
-	} else {
+	} else if (res != 0) {
 		p2p_dbg(p2p, "Failed to start p2p_scan");
 		p2p_set_state(p2p, P2P_IDLE);
 		eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
@@ -1334,8 +1366,8 @@
 	if (go)
 		p2p_channels_remove_freqs(&p2p->channels, &p2p->no_go_freq);
 	else if (!force_freq)
-		p2p_channels_union(&p2p->channels, &p2p->cfg->cli_channels,
-				   &p2p->channels);
+		p2p_channels_union_inplace(&p2p->channels,
+					   &p2p->cfg->cli_channels);
 	p2p_channels_dump(p2p, "after go/cli filter/add", &p2p->channels);
 
 	p2p_dbg(p2p, "Own preference for operation channel: Operating Class %u Channel %u%s",
@@ -1616,8 +1648,6 @@
 	struct p2p_go_neg_results res;
 	int go = peer->go_state == LOCAL_GO;
 	struct p2p_channels intersection;
-	int freqs;
-	size_t i, j;
 
 	p2p_dbg(p2p, "GO Negotiation with " MACSTR " completed (%s will be GO)",
 		MAC2STR(peer->info.p2p_device_addr), go ? "local end" : "peer");
@@ -1658,21 +1688,9 @@
 		p2p_channels_dump(p2p, "intersection after no-GO removal",
 				  &intersection);
 	}
-	freqs = 0;
-	for (i = 0; i < intersection.reg_classes; i++) {
-		struct p2p_reg_class *c = &intersection.reg_class[i];
-		if (freqs + 1 == P2P_MAX_CHANNELS)
-			break;
-		for (j = 0; j < c->channels; j++) {
-			int freq;
-			if (freqs + 1 == P2P_MAX_CHANNELS)
-				break;
-			freq = p2p_channel_to_freq(c->reg_class, c->channel[j]);
-			if (freq < 0)
-				continue;
-			res.freq_list[freqs++] = freq;
-		}
-	}
+
+	p2p_channels_to_freqs(&intersection, res.freq_list,
+			      P2P_MAX_CHANNELS);
 
 	res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
 
@@ -1713,7 +1731,6 @@
 					   rx_freq);
 		break;
 	case P2P_INVITATION_RESP:
-		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		p2p_process_invitation_resp(p2p, sa, data + 1, len - 1);
 		break;
 	case P2P_PROV_DISC_REQ:
@@ -1992,11 +2009,12 @@
 				attr.num_req_dev_type))
 		return 1; /* Own Primary Device Type matches */
 
-	for (i = 0; i < p2p->cfg->num_sec_dev_types; i++)
+	for (i = 0; i < p2p->cfg->num_sec_dev_types; i++) {
 		if (dev_type_list_match(p2p->cfg->sec_dev_type[i],
 					attr.req_dev_type,
 					attr.num_req_dev_type))
-		return 1; /* Own Secondary Device Type matches */
+			return 1; /* Own Secondary Device Type matches */
+	}
 
 	/* No matching device type found */
 	return 0;
@@ -2541,6 +2559,7 @@
 	eloop_cancel_timeout(p2p_ext_listen_timeout, p2p, NULL);
 	eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
 	eloop_cancel_timeout(p2p_go_neg_start, p2p, NULL);
+	eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
 	p2p_flush(p2p);
 	p2p_free_req_dev_types(p2p);
 	os_free(p2p->cfg->dev_name);
@@ -2583,8 +2602,10 @@
 
 	p2p_dbg(p2p, "Unauthorizing " MACSTR, MAC2STR(addr));
 
-	if (p2p->go_neg_peer == dev)
+	if (p2p->go_neg_peer == dev) {
+		eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
 		p2p->go_neg_peer = NULL;
+	}
 
 	dev->wps_method = WPS_NOT_READY;
 	dev->oob_pw_id = 0;
@@ -2742,28 +2763,64 @@
 }
 
 
+static int p2p_pre_find_operation(struct p2p_data *p2p, struct p2p_device *dev)
+{
+	if (dev->sd_pending_bcast_queries == 0) {
+		/* Initialize with total number of registered broadcast
+		 * SD queries. */
+		dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries;
+	}
+
+	if (p2p_start_sd(p2p, dev) == 0)
+		return 1;
+
+	if (dev->req_config_methods &&
+	    !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
+		p2p_dbg(p2p, "Send pending Provision Discovery Request to "
+			MACSTR " (config methods 0x%x)",
+			MAC2STR(dev->info.p2p_device_addr),
+			dev->req_config_methods);
+		if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
 void p2p_continue_find(struct p2p_data *p2p)
 {
 	struct p2p_device *dev;
-	p2p_set_state(p2p, P2P_SEARCH);
-	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
-		if (dev->sd_pending_bcast_queries == 0) {
-			/* Initialize with total number of registered broadcast
-			 * SD queries. */
-			dev->sd_pending_bcast_queries = p2p->num_p2p_sd_queries;
-		}
+	int found;
 
-		if (p2p_start_sd(p2p, dev) == 0)
-			return;
-		if (dev->req_config_methods &&
-		    !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
-			p2p_dbg(p2p, "Send pending Provision Discovery Request to "
-				MACSTR " (config methods 0x%x)",
-				MAC2STR(dev->info.p2p_device_addr),
-				dev->req_config_methods);
-			if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
-				return;
+	p2p_set_state(p2p, P2P_SEARCH);
+
+	/* Continue from the device following the last iteration */
+	found = 0;
+	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+		if (dev == p2p->last_p2p_find_oper) {
+			found = 1;
+			continue;
 		}
+		if (!found)
+			continue;
+		if (p2p_pre_find_operation(p2p, dev) > 0) {
+			p2p->last_p2p_find_oper = dev;
+			return;
+		}
+	}
+
+	/*
+	 * Wrap around to the beginning of the list and continue until the last
+	 * iteration device.
+	 */
+	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+		if (p2p_pre_find_operation(p2p, dev) > 0) {
+			p2p->last_p2p_find_oper = dev;
+			return;
+		}
+		if (dev == p2p->last_p2p_find_oper)
+			break;
 	}
 
 	p2p_listen_in_find(p2p, 1);
@@ -2777,6 +2834,8 @@
 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 
 	if (!success) {
+		if (p2p->sd_peer)
+			p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		p2p->sd_peer = NULL;
 		p2p_continue_find(p2p);
 		return;
@@ -3057,8 +3116,7 @@
 {
 	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);
+		p2p_go_neg_failed(p2p, p2p->go_neg_peer->status);
 	} else if (success) {
 		struct p2p_device *dev;
 		dev = p2p_get_device(p2p, addr);
@@ -3086,7 +3144,7 @@
 	p2p_dbg(p2p, "GO Negotiation Confirm TX callback: result=%d", result);
 	if (result == P2P_SEND_ACTION_FAILED) {
 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
-		p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+		p2p_go_neg_failed(p2p, -1);
 		return;
 	}
 
@@ -3257,7 +3315,7 @@
 	if (p2p->state == P2P_CONNECT_LISTEN && p2p->go_neg_peer) {
 		if (p2p->go_neg_peer->connect_reqs >= 120) {
 			p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
-			p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+			p2p_go_neg_failed(p2p, -1);
 			return 0;
 		}
 
@@ -3308,7 +3366,7 @@
 	if (p2p->go_neg_peer &&
 	    (p2p->go_neg_peer->flags & P2P_DEV_WAIT_GO_NEG_CONFIRM)) {
 		p2p_dbg(p2p, "Wait for GO Negotiation Confirm timed out - assume GO Negotiation failed");
-		p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+		p2p_go_neg_failed(p2p, -1);
 		return;
 	}
 	if (p2p->go_neg_peer &&
@@ -3339,7 +3397,7 @@
 
 		if (p2p->go_neg_peer->connect_reqs >= 120) {
 			p2p_dbg(p2p, "Timeout on sending GO Negotiation Request without getting response");
-			p2p_go_neg_failed(p2p, p2p->go_neg_peer, -1);
+			p2p_go_neg_failed(p2p, -1);
 			return;
 		}
 
@@ -3365,20 +3423,12 @@
 static void p2p_timeout_wait_peer_idle(struct p2p_data *p2p)
 {
 	struct p2p_device *dev = p2p->go_neg_peer;
-	struct os_reltime now;
 
 	if (dev == NULL) {
 		p2p_dbg(p2p, "Unknown GO Neg peer - stop GO Neg wait");
 		return;
 	}
 
-	os_get_reltime(&now);
-	if (os_reltime_expired(&now, &dev->go_neg_wait_started, 120)) {
-		p2p_dbg(p2p, "Timeout on waiting peer to become ready for GO Negotiation");
-		p2p_go_neg_failed(p2p, dev, -1);
-		return;
-	}
-
 	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);
@@ -3489,6 +3539,10 @@
 	p2p_dbg(p2p, "Timeout (state=%s)", p2p_state_txt(p2p->state));
 
 	p2p->in_listen = 0;
+	if (p2p->drv_in_listen) {
+		p2p_dbg(p2p, "Driver is still in listen state - stop it");
+		p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+	}
 
 	switch (p2p->state) {
 	case P2P_IDLE:
@@ -3704,7 +3758,7 @@
 			  "[PD_FOR_JOIN]" : "",
 			  dev->status,
 			  dev->invitation_reqs);
-	if (res < 0 || res >= end - pos)
+	if (os_snprintf_error(end - pos, res))
 		return pos - buf;
 	pos += res;
 
@@ -3714,7 +3768,7 @@
 				  "ext_listen_interval=%u\n",
 				  dev->ext_listen_period,
 				  dev->ext_listen_interval);
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
 	}
@@ -3724,7 +3778,7 @@
 				  "oper_ssid=%s\n",
 				  wpa_ssid_txt(dev->oper_ssid,
 					       dev->oper_ssid_len));
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
 	}
@@ -3732,7 +3786,7 @@
 #ifdef CONFIG_WIFI_DISPLAY
 	if (dev->info.wfd_subelems) {
 		res = os_snprintf(pos, end - pos, "wfd_subelems=");
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
 
@@ -3741,7 +3795,7 @@
 					wpabuf_len(dev->info.wfd_subelems));
 
 		res = os_snprintf(pos, end - pos, "\n");
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
 	}
@@ -4859,3 +4913,13 @@
 {
 	p2p->vendor_elem = vendor_elem;
 }
+
+
+void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct p2p_data *p2p = eloop_ctx;
+
+	p2p_dbg(p2p,
+		"Timeout on waiting peer to become ready for GO Negotiation");
+	p2p_go_neg_failed(p2p, -1);
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 076a2ac..fa886f7 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -949,6 +949,13 @@
 	     const u8 *dev_id, unsigned int search_delay);
 
 /**
+ * p2p_notify_scan_trigger_status - Indicate scan trigger status
+ * @p2p: P2P module context from p2p_init()
+ * @status: 0 on success, -1 on failure
+ */
+void p2p_notify_scan_trigger_status(struct p2p_data *p2p, int status);
+
+/**
  * p2p_stop_find - Stop P2P Find (Device Discovery)
  * @p2p: P2P module context from p2p_init()
  */
@@ -1738,6 +1745,9 @@
 int p2p_channels_includes_freq(const struct p2p_channels *channels,
 			       unsigned int freq);
 
+int p2p_channels_to_freqs(const struct p2p_channels *channels,
+			  int *freq_list, unsigned int max_len);
+
 /**
  * p2p_supported_freq - Check whether channel is supported for P2P
  * @p2p: P2P module context from p2p_init()
@@ -1912,7 +1922,8 @@
 /**
  * p2p_in_progress - Check whether a P2P operation is progress
  * @p2p: P2P module context from p2p_init()
- * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ * Returns: 0 if P2P module is idle, 1 if an operation is in progress but not
+ * in search state, or 2 if search state operation is in progress
  */
 int p2p_in_progress(struct p2p_data *p2p);
 
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 21fae3f..c654c5a 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
 #include "wps/wps_defs.h"
@@ -240,6 +241,7 @@
 	p2p_set_state(p2p, P2P_CONNECT);
 	p2p->pending_action_state = P2P_PENDING_GO_NEG_REQUEST;
 	p2p->go_neg_peer = dev;
+	eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
 	dev->flags |= P2P_DEV_WAIT_GO_NEG_RESPONSE;
 	dev->connect_reqs++;
 	if (p2p_send_action(p2p, freq, dev->info.p2p_device_addr,
@@ -621,7 +623,7 @@
 			 * Request frame.
 			 */
 			p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
-			p2p_go_neg_failed(p2p, dev, *msg.status);
+			p2p_go_neg_failed(p2p, *msg.status);
 			p2p_parse_free(&msg);
 			return;
 		}
@@ -645,6 +647,9 @@
 		p2p_add_dev_info(p2p, sa, dev, &msg);
 	}
 
+	if (p2p->go_neg_peer && p2p->go_neg_peer == dev)
+		eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
+
 	if (dev && dev->flags & P2P_DEV_USER_REJECTED) {
 		p2p_dbg(p2p, "User has rejected this peer");
 		status = P2P_SC_FAIL_REJECTED_BY_USER;
@@ -789,6 +794,7 @@
 		dev->dialog_token = msg.dialog_token;
 		os_memcpy(dev->intended_addr, msg.intended_addr, ETH_ALEN);
 		p2p->go_neg_peer = dev;
+		eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p, NULL);
 		status = P2P_SC_SUCCESS;
 	}
 
@@ -957,7 +963,10 @@
 		if (*msg.status == P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) {
 			p2p_dbg(p2p, "Wait for the peer to become ready for GO Negotiation");
 			dev->flags |= P2P_DEV_NOT_YET_READY;
-			os_get_reltime(&dev->go_neg_wait_started);
+			eloop_cancel_timeout(p2p_go_neg_wait_timeout, p2p,
+					     NULL);
+			eloop_register_timeout(120, 0, p2p_go_neg_wait_timeout,
+					       p2p, NULL);
 			if (p2p->state == P2P_CONNECT_LISTEN)
 				p2p_set_state(p2p, P2P_WAIT_PEER_CONNECT);
 			else
@@ -965,7 +974,7 @@
 			p2p_set_timeout(p2p, 0, 0);
 		} else {
 			p2p_dbg(p2p, "Stop GO Negotiation attempt");
-			p2p_go_neg_failed(p2p, dev, *msg.status);
+			p2p_go_neg_failed(p2p, *msg.status);
 		}
 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		p2p_parse_free(&msg);
@@ -1147,13 +1156,13 @@
 			    wpabuf_head(dev->go_neg_conf),
 			    wpabuf_len(dev->go_neg_conf), 200) < 0) {
 		p2p_dbg(p2p, "Failed to send Action frame");
-		p2p_go_neg_failed(p2p, dev, -1);
+		p2p_go_neg_failed(p2p, -1);
 		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 	} else
 		dev->go_neg_conf_sent++;
 	if (status != P2P_SC_SUCCESS) {
 		p2p_dbg(p2p, "GO Negotiation failed");
-		p2p_go_neg_failed(p2p, dev, status);
+		p2p_go_neg_failed(p2p, status);
 	}
 }
 
@@ -1204,7 +1213,7 @@
 	}
 	if (*msg.status) {
 		p2p_dbg(p2p, "GO Negotiation rejected: status %d", *msg.status);
-		p2p_go_neg_failed(p2p, dev, *msg.status);
+		p2p_go_neg_failed(p2p, *msg.status);
 		p2p_parse_free(&msg);
 		return;
 	}
@@ -1216,7 +1225,7 @@
 	} else if (dev->go_state == REMOTE_GO) {
 		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_go_neg_failed(p2p, P2P_SC_FAIL_INVALID_PARAMS);
 		p2p_parse_free(&msg);
 		return;
 	}
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index 3b60582..62711e7 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -101,10 +101,10 @@
 	unsigned int flags;
 
 	int status; /* enum p2p_status_code */
-	struct os_reltime go_neg_wait_started;
 	unsigned int wait_count;
 	unsigned int connect_reqs;
 	unsigned int invitation_reqs;
+	unsigned int sd_reqs;
 
 	u16 ext_listen_period;
 	u16 ext_listen_interval;
@@ -260,10 +260,18 @@
 	 */
 	struct p2p_device *invite_peer;
 
+	/**
+	 * last_p2p_find_oper - Pointer to last pre-find operation peer
+	 */
+	struct p2p_device *last_p2p_find_oper;
+
 	const u8 *invite_go_dev_addr;
 	u8 invite_go_dev_addr_buf[ETH_ALEN];
 	int invite_dev_pw_id;
 
+	unsigned int retry_invite_req:1;
+	unsigned int retry_invite_req_sent:1;
+
 	/**
 	 * sd_peer - Pointer to Service Discovery peer
 	 */
@@ -606,6 +614,8 @@
 void p2p_channels_intersect(const struct p2p_channels *a,
 			    const struct p2p_channels *b,
 			    struct p2p_channels *res);
+void p2p_channels_union_inplace(struct p2p_channels *res,
+				const struct p2p_channels *b);
 void p2p_channels_union(const struct p2p_channels *a,
 			const struct p2p_channels *b,
 			struct p2p_channels *res);
@@ -768,8 +778,7 @@
 struct p2p_device * p2p_get_device(struct p2p_data *p2p, const u8 *addr);
 struct p2p_device * p2p_get_device_interface(struct p2p_data *p2p,
 					     const u8 *addr);
-void p2p_go_neg_failed(struct p2p_data *p2p, struct p2p_device *peer,
-		       int status);
+void p2p_go_neg_failed(struct p2p_data *p2p, int status);
 void p2p_go_complete(struct p2p_data *p2p, struct p2p_device *peer);
 int p2p_match_dev_type(struct p2p_data *p2p, struct wpabuf *wps);
 int dev_type_list_match(const u8 *dev_type, const u8 *req_dev_type[],
@@ -783,6 +792,7 @@
 int p2p_prepare_channel(struct p2p_data *p2p, struct p2p_device *dev,
 			unsigned int force_freq, unsigned int pref_freq,
 			int go);
+void p2p_go_neg_wait_timeout(void *eloop_ctx, void *timeout_ctx);
 void p2p_dbg(struct p2p_data *p2p, const char *fmt, ...)
 PRINTF_FORMAT(2, 3);
 void p2p_info(struct p2p_data *p2p, const char *fmt, ...)
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index ef01a66..558c6dd 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -174,7 +174,7 @@
 	u8 group_bssid[ETH_ALEN], *bssid;
 	int op_freq = 0;
 	u8 reg_class = 0, channel = 0;
-	struct p2p_channels intersection, *channels = NULL;
+	struct p2p_channels all_channels, intersection, *channels = NULL;
 	int persistent;
 
 	os_memset(group_bssid, 0, sizeof(group_bssid));
@@ -226,7 +226,10 @@
 		persistent = 1;
 	}
 
-	if (p2p_peer_channels_check(p2p, &p2p->cfg->channels, dev,
+	p2p_channels_union(&p2p->cfg->channels, &p2p->cfg->cli_channels,
+			   &all_channels);
+
+	if (p2p_peer_channels_check(p2p, &all_channels, dev,
 				    msg.channel_list, msg.channel_list_len) <
 	    0) {
 		p2p_dbg(p2p, "No common channels found");
@@ -235,8 +238,9 @@
 	}
 
 	p2p_channels_dump(p2p, "own channels", &p2p->cfg->channels);
+	p2p_channels_dump(p2p, "own client channels", &all_channels);
 	p2p_channels_dump(p2p, "peer channels", &dev->channels);
-	p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+	p2p_channels_intersect(&all_channels, &dev->channels,
 			       &intersection);
 	p2p_channels_dump(p2p, "intersection", &intersection);
 
@@ -248,6 +252,17 @@
 			msg.dev_password_id_present ? msg.dev_password_id : -1);
 	}
 
+	if (go) {
+		p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+				       &intersection);
+		p2p_channels_dump(p2p, "intersection(GO)", &intersection);
+		if (intersection.reg_classes == 0) {
+			p2p_dbg(p2p, "No common channels found (GO)");
+			status = P2P_SC_FAIL_NO_COMMON_CHANNELS;
+			goto fail;
+		}
+	}
+
 	if (op_freq) {
 		p2p_dbg(p2p, "Invitation processing forced frequency %d MHz",
 			op_freq);
@@ -412,25 +427,68 @@
 	if (dev == NULL) {
 		p2p_dbg(p2p, "Ignore Invitation Response from unknown peer "
 			MACSTR, MAC2STR(sa));
+		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		return;
 	}
 
 	if (dev != p2p->invite_peer) {
 		p2p_dbg(p2p, "Ignore unexpected Invitation Response from peer "
 			MACSTR, MAC2STR(sa));
+		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		return;
 	}
 
-	if (p2p_parse(data, len, &msg))
+	if (p2p_parse(data, len, &msg)) {
+		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		return;
+	}
 
 	if (!msg.status) {
 		p2p_dbg(p2p, "Mandatory Status attribute missing in Invitation Response from "
 			MACSTR, MAC2STR(sa));
 		p2p_parse_free(&msg);
+		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
 		return;
 	}
 
+	/*
+	 * We should not really receive a replayed response twice since
+	 * duplicate frames are supposed to be dropped. However, not all drivers
+	 * do that for pre-association frames. We did not use to verify dialog
+	 * token matches for invitation response frames, but that check can be
+	 * safely used to drop a replayed response to the previous Invitation
+	 * Request in case the suggested operating channel was changed. This
+	 * allows a duplicated reject frame to be dropped with the assumption
+	 * that the real response follows after it.
+	 */
+	if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
+	    p2p->retry_invite_req_sent &&
+	    msg.dialog_token != dev->dialog_token) {
+		p2p_dbg(p2p, "Unexpected Dialog Token %u (expected %u)",
+			msg.dialog_token, dev->dialog_token);
+		p2p_parse_free(&msg);
+		return;
+	}
+
+	if (*msg.status == P2P_SC_FAIL_NO_COMMON_CHANNELS &&
+	    p2p->retry_invite_req &&
+	    p2p_channel_random_social(&p2p->cfg->channels, &p2p->op_reg_class,
+				      &p2p->op_channel) == 0) {
+		p2p->retry_invite_req = 0;
+		p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+		p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
+		p2p_set_state(p2p, P2P_INVITE);
+		p2p_dbg(p2p, "Resend Invitation Request setting op_class %u channel %u as operating channel",
+			p2p->op_reg_class, p2p->op_channel);
+		p2p->retry_invite_req_sent = 1;
+		p2p_invite_send(p2p, p2p->invite_peer, p2p->invite_go_dev_addr,
+				p2p->invite_dev_pw_id);
+		p2p_parse_free(&msg);
+		return;
+	}
+	p2p->cfg->send_action_done(p2p->cfg->cb_ctx);
+	p2p->retry_invite_req = 0;
+
 	if (!msg.channel_list && *msg.status == P2P_SC_SUCCESS) {
 		p2p_dbg(p2p, "Mandatory Channel List attribute missing in Invitation Response from "
 			MACSTR, MAC2STR(sa));
@@ -592,6 +650,9 @@
 			dev_pw_id);
 	}
 	p2p->invite_dev_pw_id = dev_pw_id;
+	p2p->retry_invite_req = role == P2P_INVITE_ROLE_GO &&
+		persistent_group && !force_freq;
+	p2p->retry_invite_req_sent = 0;
 
 	dev = p2p_get_device(p2p, peer);
 	if (dev == NULL || (dev->listen_freq <= 0 && dev->oper_freq <= 0 &&
diff --git a/src/p2p/p2p_parse.c b/src/p2p/p2p_parse.c
index d6144a0..52ba19e 100644
--- a/src/p2p/p2p_parse.c
+++ b/src/p2p/p2p_parse.c
@@ -309,23 +309,27 @@
 
 	while (pos < end) {
 		u16 attr_len;
-		if (pos + 2 >= end) {
+		u8 id;
+
+		if (end - pos < 3) {
 			wpa_printf(MSG_DEBUG, "P2P: Invalid P2P attribute");
 			return -1;
 		}
-		attr_len = WPA_GET_LE16(pos + 1);
+		id = *pos++;
+		attr_len = WPA_GET_LE16(pos);
+		pos += 2;
 		wpa_printf(MSG_DEBUG, "P2P: Attribute %d length %u",
-			   pos[0], attr_len);
-		if (pos + 3 + attr_len > end) {
+			   id, attr_len);
+		if (attr_len > end - pos) {
 			wpa_printf(MSG_DEBUG, "P2P: Attribute underflow "
 				   "(len=%u left=%d)",
-				   attr_len, (int) (end - pos - 3));
+				   attr_len, (int) (end - pos));
 			wpa_hexdump(MSG_MSGDUMP, "P2P: Data", pos, end - pos);
 			return -1;
 		}
-		if (p2p_parse_attribute(pos[0], pos + 3, attr_len, msg))
+		if (p2p_parse_attribute(id, pos, attr_len, msg))
 			return -1;
-		pos += 3 + attr_len;
+		pos += attr_len;
 	}
 
 	return 0;
@@ -603,7 +607,7 @@
 				  "dev=" MACSTR " iface=" MACSTR,
 				  MAC2STR(cli->p2p_device_addr),
 				  MAC2STR(cli->p2p_interface_addr));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 
@@ -614,7 +618,7 @@
 				  wps_dev_type_bin2str(cli->pri_dev_type,
 						       devtype,
 						       sizeof(devtype)));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 
@@ -623,7 +627,7 @@
 					  wps_dev_type_bin2str(
 						  &cli->sec_dev_types[s * 8],
 						  devtype, sizeof(devtype)));
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
@@ -638,7 +642,7 @@
 		}
 
 		ret = os_snprintf(pos, end - pos, " dev_name='%s'\n", name);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -672,7 +676,7 @@
 				  "p2p_dev_capab=0x%x\n"
 				  "p2p_group_capab=0x%x\n",
 				  msg.capability[0], msg.capability[1]);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -684,14 +688,14 @@
 				  wps_dev_type_bin2str(msg.pri_dev_type,
 						       devtype,
 						       sizeof(devtype)));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
 
 	ret = os_snprintf(pos, end - pos, "p2p_device_name=%s\n",
 			  msg.device_name);
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -699,14 +703,14 @@
 		ret = os_snprintf(pos, end - pos, "p2p_device_addr=" MACSTR
 				  "\n",
 				  MAC2STR(msg.p2p_device_addr));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
 
 	ret = os_snprintf(pos, end - pos, "p2p_config_methods=0x%x\n",
 			  msg.config_methods);
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 13119c2..1a2af04 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -75,16 +75,25 @@
 				return NULL;
 			/* query number that needs to be send to the device */
 			if (count == dev->sd_pending_bcast_queries - 1)
-				return q;
+				goto found;
 			count++;
 		}
 		if (!q->for_all_peers &&
 		    os_memcmp(q->peer, dev->info.p2p_device_addr, ETH_ALEN) ==
 		    0)
-			return q;
+			goto found;
 	}
 
 	return NULL;
+
+found:
+	if (dev->sd_reqs > 100) {
+		p2p_dbg(p2p, "Too many SD request attempts to " MACSTR
+			" - skip remaining queries",
+			MAC2STR(dev->info.p2p_device_addr));
+		return NULL;
+	}
+	return q;
 }
 
 
@@ -287,6 +296,7 @@
 	if (req == NULL)
 		return -1;
 
+	dev->sd_reqs++;
 	p2p->sd_peer = dev;
 	p2p->sd_query = query;
 	p2p->pending_action_state = P2P_PENDING_SD;
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index 23acce7..f32751d 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "common/ieee802_11_common.h"
 #include "p2p_i.h"
 
 
@@ -54,56 +55,7 @@
  */
 int p2p_channel_to_freq(int op_class, int channel)
 {
-	/* 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)
-			return -1;
-		return 2407 + 5 * channel;
-	case 82:
-		/* channel 14 */
-		if (channel != 14)
-			return -1;
-		return 2414 + 5 * channel;
-	case 83: /* channels 1..9; 40 MHz */
-	case 84: /* channels 5..13; 40 MHz */
-		if (channel < 1 || channel > 13)
-			return -1;
-		return 2407 + 5 * channel;
-	case 115: /* channels 36,40,44,48; indoor only */
-	case 118: /* channels 52,56,60,64; dfs */
-		if (channel < 36 || channel > 64)
-			return -1;
-		return 5000 + 5 * channel;
-	case 124: /* channels 149,153,157,161 */
-	case 125: /* channels 149,153,157,161,165,169 */
-		if (channel < 149 || channel > 161)
-			return -1;
-		return 5000 + 5 * channel;
-	case 116: /* channels 36,44; 40 MHz; indoor only */
-	case 117: /* channels 40,48; 40 MHz; indoor only */
-	case 119: /* channels 52,60; 40 MHz; dfs */
-	case 120: /* channels 56,64; 40 MHz; dfs */
-		if (channel < 36 || channel > 64)
-			return -1;
-		return 5000 + 5 * channel;
-	case 126: /* channels 149,157; 40 MHz */
-	case 127: /* channels 153,161; 40 MHz */
-		if (channel < 149 || channel > 161)
-			return -1;
-		return 5000 + 5 * channel;
-	case 128: /* center freqs 42, 58, 106, 122, 138, 155; 80 MHz */
-		if (channel < 36 || channel > 161)
-			return -1;
-		return 5000 + 5 * channel;
-	case 180: /* 60 GHz band, channels 1..4 */
-		if (channel < 1 || channel > 4)
-			return -1;
-		return 56160 + 2160 * channel;
-	}
-	return -1;
+	return ieee80211_chan_to_freq(NULL, op_class, channel);
 }
 
 
@@ -241,20 +193,15 @@
 
 
 /**
- * p2p_channels_union - Union of channel lists
- * @a: First set of channels
+ * p2p_channels_union_inplace - Inplace union of channel lists
+ * @res: Input data and place for returning union of the channel sets
  * @b: Second set of channels
- * @res: Data structure for returning the union of channels
  */
-void p2p_channels_union(const struct p2p_channels *a,
-			const struct p2p_channels *b,
-			struct p2p_channels *res)
+void p2p_channels_union_inplace(struct p2p_channels *res,
+				const struct p2p_channels *b)
 {
 	size_t i, j;
 
-	if (a != res)
-		os_memcpy(res, a, sizeof(*res));
-
 	for (i = 0; i < res->reg_classes; i++) {
 		struct p2p_reg_class *cl = &res->reg_class[i];
 		for (j = 0; j < b->reg_classes; j++) {
@@ -284,6 +231,21 @@
 }
 
 
+/**
+ * p2p_channels_union - Union of channel lists
+ * @a: First set of channels
+ * @b: Second set of channels
+ * @res: Data structure for returning the union of channels
+ */
+void p2p_channels_union(const struct p2p_channels *a,
+			const struct p2p_channels *b,
+			struct p2p_channels *res)
+{
+	os_memcpy(res, a, sizeof(*res));
+	p2p_channels_union_inplace(res, b);
+}
+
+
 void p2p_channels_remove_freqs(struct p2p_channels *chan,
 			       const struct wpa_freq_range_list *list)
 {
@@ -428,7 +390,7 @@
 		const struct p2p_reg_class *c;
 		c = &chan->reg_class[i];
 		ret = os_snprintf(pos, end - pos, " %u:", c->reg_class);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			break;
 		pos += ret;
 
@@ -436,7 +398,7 @@
 			ret = os_snprintf(pos, end - pos, "%s%u",
 					  j == 0 ? "" : ",",
 					  c->channel[j]);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				break;
 			pos += ret;
 		}
@@ -517,3 +479,35 @@
 
 	return 0;
 }
+
+
+int p2p_channels_to_freqs(const struct p2p_channels *channels, int *freq_list,
+			  unsigned int max_len)
+{
+	unsigned int i, idx;
+
+	if (!channels || max_len == 0)
+		return 0;
+
+	for (i = 0, idx = 0; i < channels->reg_classes; i++) {
+		const struct p2p_reg_class *c = &channels->reg_class[i];
+		unsigned int j;
+
+		if (idx + 1 == max_len)
+			break;
+		for (j = 0; j < c->channels; j++) {
+			int freq;
+			if (idx + 1 == max_len)
+				break;
+			freq = p2p_channel_to_freq(c->reg_class,
+						   c->channel[j]);
+			if (freq < 0)
+				continue;
+			freq_list[idx++] = freq;
+		}
+	}
+
+	freq_list[idx] = 0;
+
+	return idx;
+}
diff --git a/src/pae/ieee802_1x_kay.c b/src/pae/ieee802_1x_kay.c
index b1cf32d..ef74430 100644
--- a/src/pae/ieee802_1x_kay.c
+++ b/src/pae/ieee802_1x_kay.c
@@ -729,7 +729,8 @@
 
 	/* If the peer's MI is my MI, I will choose new MI */
 	if (os_memcmp(body->actor_mi, participant->mi, MI_LEN) == 0) {
-		os_get_random(participant->mi, sizeof(participant->mi));
+		if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+			return NULL;
 		participant->mn = 0;
 	}
 
@@ -1003,8 +1004,10 @@
 		if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
 			/* My message id is used by other participant */
 			if (peer_mn > participant->mn) {
-				os_get_random(participant->mi,
-					      sizeof(participant->mi));
+				if (os_get_random(participant->mi,
+						  sizeof(participant->mi)) < 0)
+					wpa_printf(MSG_DEBUG,
+						   "KaY: Could not update mi");
 				participant->mn = 0;
 			}
 			continue;
@@ -1054,8 +1057,10 @@
 		if (os_memcmp(peer_mi, participant->mi, MI_LEN) == 0) {
 			/* My message id is used by other participant */
 			if (peer_mn > participant->mn) {
-				os_get_random(participant->mi,
-					      sizeof(participant->mi));
+				if (os_get_random(participant->mi,
+						  sizeof(participant->mi)) < 0)
+					wpa_printf(MSG_DEBUG,
+						   "KaY: Could not update mi");
 				participant->mn = 0;
 			}
 			continue;
@@ -1998,7 +2003,12 @@
 		return -1;
 	}
 	ctx_offset = 0;
-	os_get_random(context + ctx_offset, conf->key_len);
+	if (os_get_random(context + ctx_offset, conf->key_len) < 0) {
+		os_free(context);
+		os_free(conf->key);
+		os_free(conf);
+		return -1;
+	}
 	ctx_offset += conf->key_len;
 	dl_list_for_each(peer, &participant->live_peers,
 			 struct ieee802_1x_kay_peer, list) {
@@ -3159,7 +3169,7 @@
 		kay->macsec_capable = MACSEC_CAP_NOT_IMPLEMENTED;
 		kay->macsec_desired = FALSE;
 		kay->macsec_protect = FALSE;
-		kay->macsec_validate = FALSE;
+		kay->macsec_validate = Disabled;
 		kay->macsec_replay_protect = FALSE;
 		kay->macsec_replay_window = 0;
 		kay->macsec_confidentiality = CONFIDENTIALITY_NONE;
@@ -3167,7 +3177,7 @@
 		kay->macsec_capable = MACSEC_CAP_INTEG_AND_CONF_0_30_50;
 		kay->macsec_desired = TRUE;
 		kay->macsec_protect = TRUE;
-		kay->macsec_validate = TRUE;
+		kay->macsec_validate = Strict;
 		kay->macsec_replay_protect = FALSE;
 		kay->macsec_replay_window = 0;
 		kay->macsec_confidentiality = CONFIDENTIALITY_OFFSET_0;
@@ -3325,7 +3335,8 @@
 	participant->retry_count = 0;
 	participant->kay = kay;
 
-	os_get_random(participant->mi, sizeof(participant->mi));
+	if (os_get_random(participant->mi, sizeof(participant->mi)) < 0)
+		goto fail;
 	participant->mn = 0;
 
 	participant->lrx = FALSE;
@@ -3340,6 +3351,9 @@
 	dl_list_init(&participant->rxsc_list);
 	participant->txsc = ieee802_1x_kay_init_transmit_sc(&kay->actor_sci,
 							    kay->sc_ch);
+	secy_cp_control_protect_frames(kay, kay->macsec_protect);
+	secy_cp_control_replay(kay, kay->macsec_replay_protect,
+			       kay->macsec_replay_window);
 	secy_create_transmit_sc(kay, participant->txsc);
 
 	/* to derive KEK from CAK and CKN */
diff --git a/src/radius/radius.c b/src/radius/radius.c
index f3b645d..6eba2eb 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -233,6 +233,17 @@
 	{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },
 	{ RADIUS_ATTR_ERROR_CAUSE, "Error-Cause", RADIUS_ATTR_INT32 },
 	{ RADIUS_ATTR_EAP_KEY_NAME, "EAP-Key-Name", RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_OPERATOR_NAME, "Operator-Name", RADIUS_ATTR_TEXT },
+	{ RADIUS_ATTR_LOCATION_INFO, "Location-Information",
+	  RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_LOCATION_DATA, "Location-Data", RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_BASIC_LOCATION_POLICY_RULES,
+	  "Basic-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES,
+	  "Extended-Location-Policy-Rules", RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_LOCATION_CAPABLE, "Location-Capable", RADIUS_ATTR_INT32 },
+	{ RADIUS_ATTR_REQUESTED_LOCATION_INFO, "Requested-Location-Info",
+	  RADIUS_ATTR_INT32 },
 	{ RADIUS_ATTR_MOBILITY_DOMAIN_ID, "Mobility-Domain-Id",
 	  RADIUS_ATTR_INT32 },
 	{ RADIUS_ATTR_WLAN_HESSID, "WLAN-HESSID", RADIUS_ATTR_TEXT },
@@ -945,7 +956,6 @@
 			vhdr = (struct radius_attr_vendor *) pos;
 			if (vhdr->vendor_length > left ||
 			    vhdr->vendor_length < sizeof(*vhdr)) {
-				left = 0;
 				break;
 			}
 			if (vhdr->vendor_type != subtype) {
diff --git a/src/radius/radius.h b/src/radius/radius.h
index 62faae1..5977339 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -92,6 +92,13 @@
        RADIUS_ATTR_NAS_IPV6_ADDRESS = 95,
        RADIUS_ATTR_ERROR_CAUSE = 101,
        RADIUS_ATTR_EAP_KEY_NAME = 102,
+       RADIUS_ATTR_OPERATOR_NAME = 126,
+       RADIUS_ATTR_LOCATION_INFO = 127,
+       RADIUS_ATTR_LOCATION_DATA = 128,
+       RADIUS_ATTR_BASIC_LOCATION_POLICY_RULES = 129,
+       RADIUS_ATTR_EXTENDED_LOCATION_POLICY_RULES = 130,
+       RADIUS_ATTR_LOCATION_CAPABLE = 131,
+       RADIUS_ATTR_REQUESTED_LOCATION_INFO = 132,
        RADIUS_ATTR_MOBILITY_DOMAIN_ID = 177,
        RADIUS_ATTR_WLAN_HESSID = 181,
        RADIUS_ATTR_WLAN_PAIRWISE_CIPHER = 186,
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index e2766e2..1382c53 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -1039,6 +1039,13 @@
 		return -1;
 	}
 
+	if (sel_sock < 0) {
+		wpa_printf(MSG_INFO,
+			   "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d",
+			   nserv->addr.af, sock, sock6, auth);
+		return -1;
+	}
+
 	if (conf->force_client_addr) {
 		switch (conf->client_addr.af) {
 		case AF_INET:
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 00394b4..85a485e 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -252,6 +252,20 @@
 	const char *server_id;
 
 	/**
+	 * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+	 *
+	 * This controls whether the authentication server derives ERP key
+	 * hierarchy (rRK and rIK) from full EAP authentication and allows
+	 * these keys to be used to perform ERP to derive rMSK instead of full
+	 * EAP authentication to derive MSK.
+	 */
+	int erp;
+
+	const char *erp_domain;
+
+	struct dl_list erp_keys; /* struct eap_server_erp_key */
+
+	/**
 	 * wps - Wi-Fi Protected Setup context
 	 *
 	 * If WPS is used with an external RADIUS server (which is quite
@@ -673,6 +687,7 @@
 	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);
+	eap_conf.erp = data->erp;
 	radius_server_testing_options(sess, &eap_conf);
 	sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
 				       &eap_conf);
@@ -1687,6 +1702,7 @@
 	if (data == NULL)
 		return NULL;
 
+	dl_list_init(&data->erp_keys);
 	os_get_reltime(&data->start_time);
 	data->conf_ctx = conf->conf_ctx;
 	data->eap_sim_db_priv = conf->eap_sim_db_priv;
@@ -1725,6 +1741,8 @@
 			data->eap_req_id_text_len = conf->eap_req_id_text_len;
 		}
 	}
+	data->erp = conf->erp;
+	data->erp_domain = conf->erp_domain;
 
 	if (conf->subscr_remediation_url) {
 		data->subscr_remediation_url =
@@ -1802,6 +1820,24 @@
 
 
 /**
+ * radius_server_erp_flush - Flush all ERP keys
+ * @data: RADIUS server context from radius_server_init()
+ */
+void radius_server_erp_flush(struct radius_server_data *data)
+{
+	struct eap_server_erp_key *erp;
+
+	if (data == NULL)
+		return;
+	while ((erp = dl_list_first(&data->erp_keys, struct eap_server_erp_key,
+				    list)) != NULL) {
+		dl_list_del(&erp->list);
+		bin_clear_free(erp, sizeof(*erp));
+	}
+}
+
+
+/**
  * radius_server_deinit - Deinitialize RADIUS server
  * @data: RADIUS server context from radius_server_init()
  */
@@ -1836,6 +1872,8 @@
 		sqlite3_close(data->db);
 #endif /* CONFIG_SQLITE */
 
+	radius_server_erp_flush(data);
+
 	os_free(data);
 }
 
@@ -1874,7 +1912,7 @@
 			  "radiusAuthServResetTime=0\n"
 			  "radiusAuthServConfigReset=4\n",
 			  uptime);
-	if (ret < 0 || ret >= end - pos) {
+	if (os_snprintf_error(end - pos, ret)) {
 		*pos = '\0';
 		return pos - buf;
 	}
@@ -1913,7 +1951,7 @@
 			  data->counters.malformed_acct_requests,
 			  data->counters.acct_bad_authenticators,
 			  data->counters.unknown_acct_types);
-	if (ret < 0 || ret >= end - pos) {
+	if (os_snprintf_error(end - pos, ret)) {
 		*pos = '\0';
 		return pos - buf;
 	}
@@ -1971,7 +2009,7 @@
 				  cli->counters.malformed_acct_requests,
 				  cli->counters.acct_bad_authenticators,
 				  cli->counters.unknown_acct_types);
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			*pos = '\0';
 			return pos - buf;
 		}
@@ -2017,11 +2055,57 @@
 }
 
 
+#ifdef CONFIG_ERP
+
+static const char * radius_server_get_erp_domain(void *ctx)
+{
+	struct radius_session *sess = ctx;
+	struct radius_server_data *data = sess->server;
+
+	return data->erp_domain;
+}
+
+
+static struct eap_server_erp_key *
+radius_server_erp_get_key(void *ctx, const char *keyname)
+{
+	struct radius_session *sess = ctx;
+	struct radius_server_data *data = sess->server;
+	struct eap_server_erp_key *erp;
+
+	dl_list_for_each(erp, &data->erp_keys, struct eap_server_erp_key,
+			 list) {
+		if (os_strcmp(erp->keyname_nai, keyname) == 0)
+			return erp;
+	}
+
+	return NULL;
+}
+
+
+static int radius_server_erp_add_key(void *ctx, struct eap_server_erp_key *erp)
+{
+	struct radius_session *sess = ctx;
+	struct radius_server_data *data = sess->server;
+
+	dl_list_add(&data->erp_keys, &erp->list);
+	return 0;
+}
+
+#endif /* CONFIG_ERP */
+
+
 static struct eapol_callbacks radius_server_eapol_cb =
 {
 	.get_eap_user = radius_server_get_eap_user,
 	.get_eap_req_id_text = radius_server_get_eap_req_id_text,
 	.log_msg = radius_server_log_msg,
+#ifdef CONFIG_ERP
+	.get_erp_send_reauth_start = NULL,
+	.get_erp_domain = radius_server_get_erp_domain,
+	.erp_get_key = radius_server_erp_get_key,
+	.erp_add_key = radius_server_erp_add_key,
+#endif /* CONFIG_ERP */
 };
 
 
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 46ac312..ca4e38c 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -159,6 +159,18 @@
 	const char *server_id;
 
 	/**
+	 * erp - Whether EAP Re-authentication Protocol (ERP) is enabled
+	 *
+	 * This controls whether the authentication server derives ERP key
+	 * hierarchy (rRK and rIK) from full EAP authentication and allows
+	 * these keys to be used to perform ERP to derive rMSK instead of full
+	 * EAP authentication to derive MSK.
+	 */
+	int erp;
+
+	const char *erp_domain;
+
+	/**
 	 * wps - Wi-Fi Protected Setup context
 	 *
 	 * If WPS is used with an external RADIUS server (which is quite
@@ -223,6 +235,7 @@
 struct radius_server_data *
 radius_server_init(struct radius_server_conf *conf);
 
+void radius_server_erp_flush(struct radius_server_data *data);
 void radius_server_deinit(struct radius_server_data *data);
 
 int radius_server_get_mib(struct radius_server_data *data, char *buf,
diff --git a/src/rsn_supp/peerkey.c b/src/rsn_supp/peerkey.c
index aab8b7e..aca8f54 100644
--- a/src/rsn_supp/peerkey.c
+++ b/src/rsn_supp/peerkey.c
@@ -242,7 +242,8 @@
 	peerkey->cipher = cipher;
 #ifdef CONFIG_IEEE80211W
 	if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
-			   WPA_KEY_MGMT_PSK_SHA256))
+			   WPA_KEY_MGMT_PSK_SHA256 |
+			   WPA_KEY_MGMT_IEEE8021X_SUITE_B))
 		peerkey->use_sha256 = 1;
 #endif /* CONFIG_IEEE80211W */
 
@@ -927,8 +928,8 @@
 	os_memcpy(mic, key->key_mic, 16);
 	if (peerkey->tstk_set) {
 		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
-				  key->key_mic);
+		wpa_eapol_key_mic(peerkey->tstk.kck, sm->key_mgmt, ver, buf,
+				  len, key->key_mic);
 		if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
 			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
 				   "when using TSTK - ignoring TSTK");
@@ -943,7 +944,7 @@
 
 	if (!ok && peerkey->stk_set) {
 		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
+		wpa_eapol_key_mic(peerkey->stk.kck, sm->key_mgmt, ver, buf, len,
 				  key->key_mic);
 		if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
 			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index 885291a..8af04d0 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -109,6 +109,8 @@
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  * @pmk: The new pairwise master key
  * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @kck: Key confirmation key or %NULL if not yet derived
+ * @kck_len: KCK length in bytes
  * @aa: Authenticator address
  * @spa: Supplicant address
  * @network_ctx: Network configuration context for this PMK
@@ -122,6 +124,7 @@
  */
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+		const u8 *kck, size_t kck_len,
 		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
 {
 	struct rsn_pmksa_cache_entry *entry, *pos, *prev;
@@ -130,13 +133,19 @@
 	if (pmk_len > PMK_LEN)
 		return NULL;
 
+	if (wpa_key_mgmt_suite_b(akmp) && !kck)
+		return NULL;
+
 	entry = os_zalloc(sizeof(*entry));
 	if (entry == NULL)
 		return NULL;
 	os_memcpy(entry->pmk, pmk, pmk_len);
 	entry->pmk_len = pmk_len;
-	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
-		  wpa_key_mgmt_sha256(akmp));
+	if (wpa_key_mgmt_suite_b(akmp))
+		rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
+	else
+		rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+			  wpa_key_mgmt_sha256(akmp));
 	os_get_reltime(&now);
 	entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
 	entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
@@ -333,6 +342,7 @@
 	struct rsn_pmksa_cache_entry *new_entry;
 
 	new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
+				    NULL, 0,
 				    aa, pmksa->sm->own_addr,
 				    old_entry->network_ctx, old_entry->akmp);
 	if (new_entry == NULL)
@@ -472,7 +482,7 @@
 	ret = os_snprintf(pos, buf + len - pos,
 			  "Index / AA / PMKID / expiration (in seconds) / "
 			  "opportunistic\n");
-	if (ret < 0 || ret >= buf + len - pos)
+	if (os_snprintf_error(buf + len - pos, ret))
 		return pos - buf;
 	pos += ret;
 	i = 0;
@@ -481,7 +491,7 @@
 		i++;
 		ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
 				  i, MAC2STR(entry->aa));
-		if (ret < 0 || ret >= buf + len - pos)
+		if (os_snprintf_error(buf + len - pos, ret))
 			return pos - buf;
 		pos += ret;
 		pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
@@ -489,7 +499,7 @@
 		ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
 				  (int) (entry->expiration - now.sec),
 				  entry->opportunistic);
-		if (ret < 0 || ret >= buf + len - pos)
+		if (os_snprintf_error(buf + len - pos, ret))
 			return pos - buf;
 		pos += ret;
 		entry = entry->next;
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index 6cbf89a..f8e040e 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -57,6 +57,7 @@
 int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+		const u8 *kck, size_t kck_len,
 		const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
 struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
 void pmksa_cache_clear_current(struct wpa_sm *sm);
@@ -104,6 +105,7 @@
 
 static inline struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+		const u8 *kck, size_t kck_len,
 		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
 {
 	return NULL;
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index 915f85e..af0e108 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -94,6 +94,7 @@
 					pmk, pmk_len);
 			sm->pmk_len = pmk_len;
 			pmksa_cache_add(sm->pmksa, pmk, pmk_len,
+					NULL, 0,
 					sm->preauth_bssid, sm->own_addr,
 					sm->network_ctx,
 					WPA_KEY_MGMT_IEEE8021X);
@@ -298,7 +299,8 @@
 	    sm->proto != WPA_PROTO_RSN ||
 	    wpa_sm_get_state(sm) != WPA_COMPLETED ||
 	    (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
-	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256 &&
+	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SUITE_B)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
 			"state for new pre-authentication");
 		return; /* invalid state for new pre-auth */
@@ -391,6 +393,18 @@
 	dl_list_for_each(pos, &sm->pmksa_candidates,
 			 struct rsn_pmksa_candidate, list) {
 		if (cand->priority <= pos->priority) {
+			if (!pos->list.prev) {
+				/*
+				 * This cannot really happen in pracrice since
+				 * pos was fetched from the list and the prev
+				 * pointer must be set. It looks like clang
+				 * static analyzer gets confused with the
+				 * dl_list_del(&cand->list) call above and ends
+				 * up assuming pos->list.prev could be NULL.
+				 */
+				os_free(cand);
+				return;
+			}
 			dl_list_add(pos->list.prev, &cand->list);
 			cand = NULL;
 			break;
@@ -487,7 +501,7 @@
 	if (sm->preauth_eapol) {
 		ret = os_snprintf(pos, end - pos, "Pre-authentication "
 				  "EAPOL state machines:\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 		res = eapol_sm_get_status(sm->preauth_eapol,
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 8cb19a2..4baeb3b 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -148,6 +148,9 @@
 	size_t supp_oper_classes_len;
 
 	u8 wmm_capable;
+
+	/* channel switch currently enabled */
+	int chan_switch_enabled;
 };
 
 
@@ -687,6 +690,7 @@
 	peer->qos_info = 0;
 	peer->wmm_capable = 0;
 	peer->tpk_set = peer->tpk_success = 0;
+	peer->chan_switch_enabled = 0;
 	os_memset(&peer->tpk, 0, sizeof(peer->tpk));
 	os_memset(peer->inonce, 0, WPA_NONCE_LEN);
 	os_memset(peer->rnonce, 0, WPA_NONCE_LEN);
@@ -742,6 +746,13 @@
 		return 0;
 	}
 
+	/* Cancel active channel switch before teardown */
+	if (peer->chan_switch_enabled) {
+		wpa_printf(MSG_DEBUG, "TDLS: First returning link with " MACSTR
+			   " to base channel", MAC2STR(addr));
+		wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+	}
+
 	dialog_token = peer->dtoken;
 
 	wpa_printf(MSG_DEBUG, "TDLS: TDLS Teardown for " MACSTR,
@@ -858,9 +869,11 @@
 
 	if (wpa_tdls_is_external_setup(sm)) {
 		/*
-		 * Disable the link, send a teardown packet through the
-		 * AP, and then reset link data.
+		 * Get us on the base channel, disable the link, send a
+		 * teardown packet through the AP, and then reset link data.
 		 */
+		if (peer->chan_switch_enabled)
+			wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
 		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
 		wpa_tdls_send_teardown(sm, addr,
 				       WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE);
@@ -2742,7 +2755,8 @@
 	 * are assumed to perform everything internally
 	 */
 	if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported,
-				 &sm->tdls_external_setup) < 0) {
+				 &sm->tdls_external_setup,
+				 &sm->tdls_chan_switch) < 0) {
 		sm->tdls_supported = 1;
 		sm->tdls_external_setup = 0;
 	}
@@ -2751,6 +2765,8 @@
 		   "driver", sm->tdls_supported ? "" : " not");
 	wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup",
 		   sm->tdls_external_setup ? "external" : "internal");
+	wpa_printf(MSG_DEBUG, "TDLS: Driver %s TDLS channel switching",
+		   sm->tdls_chan_switch ? "supports" : "does not support");
 
 	return 0;
 }
@@ -2830,39 +2846,61 @@
 }
 
 
-static int wpa_tdls_prohibited(const u8 *ies, size_t len)
+static int wpa_tdls_prohibited(struct wpa_eapol_ie_parse *elems)
 {
-	struct wpa_eapol_ie_parse elems;
+	/* bit 38 - TDLS Prohibited */
+	return !!(elems->ext_capab[2 + 4] & 0x40);
+}
 
-	if (ies == NULL)
-		return 0;
 
-	if (wpa_supplicant_parse_ies(ies, len, &elems) < 0)
-		return 0;
-
-	if (elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
-		return 0;
-
-	 /* bit 38 - TDLS Prohibited */
-	return !!(elems.ext_capab[2 + 4] & 0x40);
+static int wpa_tdls_chan_switch_prohibited(struct wpa_eapol_ie_parse *elems)
+{
+	/* bit 39 - TDLS Channel Switch Prohibited */
+	return !!(elems->ext_capab[2 + 4] & 0x80);
 }
 
 
 void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
 {
-	sm->tdls_prohibited = wpa_tdls_prohibited(ies, len);
+	struct wpa_eapol_ie_parse elems;
+
+	sm->tdls_prohibited = 0;
+	sm->tdls_chan_switch_prohibited = 0;
+
+	if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 ||
+	    elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+		return;
+
+	sm->tdls_prohibited = wpa_tdls_prohibited(&elems);
 	wpa_printf(MSG_DEBUG, "TDLS: TDLS is %s in the target BSS",
 		   sm->tdls_prohibited ? "prohibited" : "allowed");
+	sm->tdls_chan_switch_prohibited =
+		wpa_tdls_chan_switch_prohibited(&elems);
+	wpa_printf(MSG_DEBUG, "TDLS: TDLS channel switch %s in the target BSS",
+		   sm->tdls_chan_switch_prohibited ? "prohibited" : "allowed");
 }
 
 
 void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len)
 {
-	if (!sm->tdls_prohibited && wpa_tdls_prohibited(ies, len)) {
+	struct wpa_eapol_ie_parse elems;
+
+	if (ies == NULL || wpa_supplicant_parse_ies(ies, len, &elems) < 0 ||
+	    elems.ext_capab == NULL || elems.ext_capab_len < 2 + 5)
+		return;
+
+	if (!sm->tdls_prohibited && wpa_tdls_prohibited(&elems)) {
 		wpa_printf(MSG_DEBUG, "TDLS: TDLS prohibited based on "
 			   "(Re)Association Response IEs");
 		sm->tdls_prohibited = 1;
 	}
+
+	if (!sm->tdls_chan_switch_prohibited &&
+	    wpa_tdls_chan_switch_prohibited(&elems)) {
+		wpa_printf(MSG_DEBUG,
+			   "TDLS: TDLS channel switch prohibited based on (Re)Association Response IEs");
+		sm->tdls_chan_switch_prohibited = 1;
+	}
 }
 
 
@@ -2877,3 +2915,78 @@
 {
 	return sm->tdls_external_setup;
 }
+
+
+int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
+				u8 oper_class,
+				struct hostapd_freq_params *freq_params)
+{
+	struct wpa_tdls_peer *peer;
+	int ret;
+
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+	if (!sm->tdls_chan_switch) {
+		wpa_printf(MSG_DEBUG,
+			   "TDLS: Channel switching not supported by the driver");
+		return -1;
+	}
+
+	if (sm->tdls_chan_switch_prohibited) {
+		wpa_printf(MSG_DEBUG,
+			   "TDLS: Channel switching is prohibited in this BSS - reject request to switch channel");
+		return -1;
+	}
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer == NULL || !peer->tpk_success) {
+		wpa_printf(MSG_ERROR, "TDLS: Peer " MACSTR
+			   " not found for channel switching", MAC2STR(addr));
+		return -1;
+	}
+
+	if (peer->chan_switch_enabled) {
+		wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+			   " already has channel switching enabled",
+			   MAC2STR(addr));
+		return 0;
+	}
+
+	ret = wpa_sm_tdls_enable_channel_switch(sm, peer->addr,
+						oper_class, freq_params);
+	if (!ret)
+		peer->chan_switch_enabled = 1;
+
+	return ret;
+}
+
+
+int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (!peer || !peer->chan_switch_enabled) {
+		wpa_printf(MSG_ERROR, "TDLS: Channel switching not enabled for "
+			   MACSTR, MAC2STR(addr));
+		return -1;
+	}
+
+	/* ignore the return value */
+	wpa_sm_tdls_disable_channel_switch(sm, peer->addr);
+
+	peer->chan_switch_enabled = 0;
+	return 0;
+}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 8f561b9..8ea54bb 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -56,10 +56,10 @@
 		}
 	}
 	if (key_mic &&
-	    wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) {
+	    wpa_eapol_key_mic(kck, sm->key_mgmt, ver, msg, msg_len, key_mic)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
-			"WPA: Failed to generate EAPOL-Key "
-			"version %d MIC", ver);
+			"WPA: Failed to generate EAPOL-Key version %d key_mgmt 0x%x MIC",
+			ver, sm->key_mgmt);
 		goto out;
 	}
 	wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16);
@@ -89,7 +89,8 @@
 	int key_info, ver;
 	u8 bssid[ETH_ALEN], *rbuf;
 
-	if (sm->key_mgmt == WPA_KEY_MGMT_OSEN)
+	if (sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+	    wpa_key_mgmt_suite_b(sm->key_mgmt))
 		ver = WPA_KEY_INFO_TYPE_AKM_DEFINED;
 	else if (wpa_key_mgmt_ft(sm->key_mgmt) ||
 		 wpa_key_mgmt_sha256(sm->key_mgmt))
@@ -138,6 +139,24 @@
 }
 
 
+static void wpa_supplicant_key_mgmt_set_pmk(struct wpa_sm *sm)
+{
+#ifdef CONFIG_IEEE80211R
+	if (sm->key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+		if (wpa_sm_key_mgmt_set_pmk(sm, sm->xxkey, sm->xxkey_len))
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"RSN: Cannot set low order 256 bits of MSK for key management offload");
+	} else {
+#endif /* CONFIG_IEEE80211R */
+		if (wpa_sm_key_mgmt_set_pmk(sm, sm->pmk, sm->pmk_len))
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"RSN: Cannot set PMK for key management offload");
+#ifdef CONFIG_IEEE80211R
+	}
+#endif /* CONFIG_IEEE80211R */
+}
+
+
 static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
 				  const unsigned char *src_addr,
 				  const u8 *pmkid)
@@ -198,10 +217,13 @@
 			wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
 					"machines", sm->pmk, pmk_len);
 			sm->pmk_len = pmk_len;
+			wpa_supplicant_key_mgmt_set_pmk(sm);
 			if (sm->proto == WPA_PROTO_RSN &&
+			    !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
 			    !wpa_key_mgmt_ft(sm->key_mgmt)) {
 				sa = pmksa_cache_add(sm->pmksa,
 						     sm->pmk, pmk_len,
+						     NULL, 0,
 						     src_addr, sm->own_addr,
 						     sm->network_ctx,
 						     sm->key_mgmt);
@@ -235,6 +257,7 @@
 	}
 
 	if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
+	    !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
 	    !wpa_key_mgmt_ft(sm->key_mgmt) && sm->key_mgmt != WPA_KEY_MGMT_OSEN)
 	{
 		/* Send EAPOL-Start to trigger full EAP authentication. */
@@ -586,6 +609,10 @@
 		return -1;
 	}
 
+	/* TK is not needed anymore in supplicant */
+	os_memset(sm->ptk.tk1, 0, sizeof(sm->ptk.tk1));
+	os_memset(sm->ptk.u.tk2, 0, sizeof(sm->ptk.u.tk2));
+
 	if (sm->wpa_ptk_rekey) {
 		eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
 		eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
@@ -1178,6 +1205,17 @@
 	if (ie.gtk)
 		wpa_sm_set_rekey_offload(sm);
 
+	if (sm->proto == WPA_PROTO_RSN && wpa_key_mgmt_suite_b(sm->key_mgmt)) {
+		struct rsn_pmksa_cache_entry *sa;
+
+		sa = pmksa_cache_add(sm->pmksa, sm->pmk, sm->pmk_len,
+				     sm->ptk.kck, sizeof(sm->ptk.kck),
+				     sm->bssid, sm->own_addr,
+				     sm->network_ctx, sm->key_mgmt);
+		if (!sm->cur_pmksa)
+			sm->cur_pmksa = sa;
+	}
+
 	return;
 
 failed:
@@ -1242,8 +1280,9 @@
 					     u16 ver, struct wpa_gtk_data *gd)
 {
 	size_t maxkeylen;
+	u16 gtk_len;
 
-	gd->gtk_len = WPA_GET_BE16(key->key_length);
+	gtk_len = WPA_GET_BE16(key->key_length);
 	maxkeylen = key_data_len;
 	if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 		if (maxkeylen < 8) {
@@ -1255,11 +1294,13 @@
 		maxkeylen -= 8;
 	}
 
-	if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
-					      gd->gtk_len, maxkeylen,
+	if (gtk_len > maxkeylen ||
+	    wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+					      gtk_len, maxkeylen,
 					      &gd->key_rsc_len, &gd->alg))
 		return -1;
 
+	gd->gtk_len = gtk_len;
 	gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
 		WPA_KEY_INFO_KEY_INDEX_SHIFT;
 	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
@@ -1385,6 +1426,7 @@
 	if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
 	    wpa_supplicant_send_2_of_2(sm, key, ver, key_info))
 		goto failed;
+	os_memset(&gd, 0, sizeof(gd));
 
 	if (rekey) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying "
@@ -1403,6 +1445,7 @@
 	return;
 
 failed:
+	os_memset(&gd, 0, sizeof(gd));
 	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
 }
 
@@ -1418,7 +1461,7 @@
 	os_memcpy(mic, key->key_mic, 16);
 	if (sm->tptk_set) {
 		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
+		wpa_eapol_key_mic(sm->tptk.kck, sm->key_mgmt, ver, buf, len,
 				  key->key_mic);
 		if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1435,7 +1478,7 @@
 
 	if (!ok && sm->ptk_set) {
 		os_memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
+		wpa_eapol_key_mic(sm->ptk.kck, sm->key_mgmt, ver, buf, len,
 				  key->key_mic);
 		if (os_memcmp_const(mic, key->key_mic, 16) != 0) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1489,7 +1532,8 @@
 		os_memset(ek, 0, sizeof(ek));
 	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
 		   ver == WPA_KEY_INFO_TYPE_AES_128_CMAC ||
-		   sm->key_mgmt == WPA_KEY_MGMT_OSEN) {
+		   sm->key_mgmt == WPA_KEY_MGMT_OSEN ||
+		   wpa_key_mgmt_suite_b(sm->key_mgmt)) {
 		u8 *buf;
 		if (*key_data_len < 8 || *key_data_len % 8) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
@@ -1687,6 +1731,7 @@
 	    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
 #endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
 	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES &&
+	    !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
 	    sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"WPA: Unsupported EAPOL-Key descriptor version %d",
@@ -1702,6 +1747,14 @@
 		goto out;
 	}
 
+	if (wpa_key_mgmt_suite_b(sm->key_mgmt) &&
+	    ver != WPA_KEY_INFO_TYPE_AKM_DEFINED) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: Unsupported EAPOL-Key descriptor version %d (expected AKM defined = 0)",
+			ver);
+		goto out;
+	}
+
 #ifdef CONFIG_IEEE80211R
 	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
 		/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
@@ -1715,7 +1768,8 @@
 #ifdef CONFIG_IEEE80211W
 	if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
 		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
-		    sm->key_mgmt != WPA_KEY_MGMT_OSEN) {
+		    sm->key_mgmt != WPA_KEY_MGMT_OSEN &&
+		    !wpa_key_mgmt_suite_b(sm->key_mgmt)) {
 			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 				"WPA: AP did not use the "
 				"negotiated AES-128-CMAC");
@@ -1724,6 +1778,7 @@
 	} else
 #endif /* CONFIG_IEEE80211W */
 	if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+	    !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
 	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"WPA: CCMP is used, but EAPOL-Key "
@@ -1743,6 +1798,7 @@
 		} else
 			goto out;
 	} else if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+		   !wpa_key_mgmt_suite_b(sm->key_mgmt) &&
 		   ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
 			"WPA: GCMP is used, but EAPOL-Key "
@@ -1870,7 +1926,7 @@
 	ret = 1;
 
 out:
-	os_free(tmp);
+	bin_clear_free(tmp, data_len);
 	return ret;
 }
 
@@ -1906,6 +1962,8 @@
 			WPA_AUTH_KEY_MGMT_CCKM);
 	case WPA_KEY_MGMT_WPA_NONE:
 		return WPA_AUTH_KEY_MGMT_NONE;
+	case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
+		return RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
 	default:
 		return 0;
 	}
@@ -1963,7 +2021,7 @@
 			  sm->dot11RSNAConfigPMKLifetime,
 			  sm->dot11RSNAConfigPMKReauthThreshold,
 			  sm->dot11RSNAConfigSATimeout);
-	if (ret < 0 || (size_t) ret >= buflen)
+	if (os_snprintf_error(buflen, ret))
 		return 0;
 	len = ret;
 
@@ -1990,7 +2048,7 @@
 		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
 						  sm->group_cipher)),
 		sm->dot11RSNA4WayHandshakeFailures);
-	if (ret >= 0 && (size_t) ret < buflen)
+	if (!os_snprintf_error(buflen - len, ret))
 		len += ret;
 
 	return (int) len;
@@ -2088,6 +2146,7 @@
 	os_free(sm->assoc_wpa_ie);
 	os_free(sm->ap_wpa_ie);
 	os_free(sm->ap_rsn_ie);
+	wpa_sm_drop_sa(sm);
 	os_free(sm->ctx);
 	peerkey_deinit(sm);
 #ifdef CONFIG_IEEE80211R
@@ -2176,6 +2235,9 @@
 #ifdef CONFIG_TDLS
 	wpa_tdls_disassoc(sm);
 #endif /* CONFIG_TDLS */
+
+	/* Keys are not needed in the WPA state machine anymore */
+	wpa_sm_drop_sa(sm);
 }
 
 
@@ -2184,10 +2246,12 @@
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
  * @pmk: The new PMK
  * @pmk_len: The length of the new PMK in bytes
+ * @bssid: AA to add into PMKSA cache or %NULL to not cache the PMK
  *
  * Configure the PMK for WPA state machine.
  */
-void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+		    const u8 *bssid)
 {
 	if (sm == NULL)
 		return;
@@ -2200,6 +2264,12 @@
 	sm->xxkey_len = pmk_len;
 	os_memcpy(sm->xxkey, pmk, pmk_len);
 #endif /* CONFIG_IEEE80211R */
+
+	if (bssid) {
+		pmksa_cache_add(sm->pmksa, pmk, pmk_len, NULL, 0,
+				bssid, sm->own_addr,
+				sm->network_ctx, sm->key_mgmt);
+	}
 }
 
 
@@ -2424,7 +2494,7 @@
 			  wpa_cipher_txt(sm->pairwise_cipher),
 			  wpa_cipher_txt(sm->group_cipher),
 			  wpa_key_mgmt_txt(sm->key_mgmt, sm->proto));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -2437,7 +2507,7 @@
 			ret = os_snprintf(pos, end - pos, "pmf=%d\n",
 					  (rsn.capabilities &
 					   WPA_CAPABILITY_MFPR) ? 2 : 1);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
@@ -2640,7 +2710,6 @@
 }
 
 
-#ifdef CONFIG_TESTING_OPTIONS
 void wpa_sm_drop_sa(struct wpa_sm *sm)
 {
 	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
@@ -2649,8 +2718,12 @@
 	os_memset(sm->pmk, 0, sizeof(sm->pmk));
 	os_memset(&sm->ptk, 0, sizeof(sm->ptk));
 	os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+#ifdef CONFIG_IEEE80211R
+	os_memset(sm->xxkey, 0, sizeof(sm->xxkey));
+	os_memset(sm->pmk_r0, 0, sizeof(sm->pmk_r0));
+	os_memset(sm->pmk_r1, 0, sizeof(sm->pmk_r1));
+#endif /* CONFIG_IEEE80211R */
 }
-#endif /* CONFIG_TESTING_OPTIONS */
 
 
 int wpa_sm_has_ptk(struct wpa_sm *sm)
@@ -2783,3 +2856,30 @@
 }
 
 #endif /* CONFIG_P2P */
+
+
+void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter)
+{
+	if (rx_replay_counter == NULL)
+		return;
+
+	os_memcpy(sm->rx_replay_counter, rx_replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	sm->rx_replay_counter_set = 1;
+	wpa_printf(MSG_DEBUG, "Updated key replay counter");
+}
+
+
+void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
+			    const u8 *ptk_kek)
+{
+	if (ptk_kck) {
+		os_memcpy(sm->ptk.kck, ptk_kck, 16);
+		wpa_printf(MSG_DEBUG, "Updated PTK KCK");
+	}
+	if (ptk_kek) {
+		os_memcpy(sm->ptk.kek, ptk_kek, 16);
+		wpa_printf(MSG_DEBUG, "Updated PTK KEK");
+	}
+	sm->ptk_set = 1;
+}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 63032b0..cc12893 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -17,6 +17,7 @@
 struct wpa_sm;
 struct eapol_sm;
 struct wpa_config_blob;
+struct hostapd_freq_params;
 
 struct wpa_sm_ctx {
 	void *ctx; /* pointer to arbitrary upper level context */
@@ -51,7 +52,7 @@
 	int (*mark_authenticated)(void *ctx, const u8 *target_ap);
 #ifdef CONFIG_TDLS
 	int (*tdls_get_capa)(void *ctx, int *tdls_supported,
-			     int *tdls_ext_setup);
+			     int *tdls_ext_setup, int *tdls_chan_switch);
 	int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
 			      u8 action_code, u8 dialog_token,
 			      u16 status_code, u32 peer_capab,
@@ -67,9 +68,14 @@
 				size_t supp_channels_len,
 				const u8 *supp_oper_classes,
 				size_t supp_oper_classes_len);
+	int (*tdls_enable_channel_switch)(
+		void *ctx, const u8 *addr, u8 oper_class,
+		const struct hostapd_freq_params *params);
+	int (*tdls_disable_channel_switch)(void *ctx, const u8 *addr);
 #endif /* CONFIG_TDLS */
 	void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
 				  const u8 *replay_ctr);
+	int (*key_mgmt_set_pmk)(void *ctx, const u8 *pmk, size_t pmk_len);
 };
 
 
@@ -105,7 +111,8 @@
 void wpa_sm_deinit(struct wpa_sm *sm);
 void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
 void wpa_sm_notify_disassoc(struct wpa_sm *sm);
-void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len);
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len,
+		    const u8 *bssid);
 void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
 void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth);
 void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);
@@ -147,6 +154,10 @@
 
 int wpa_sm_get_p2p_ip_addr(struct wpa_sm *sm, u8 *buf);
 
+void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm, const u8 *rx_replay_counter);
+void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
+			    const u8 *ptk_kek);
+
 #else /* CONFIG_NO_WPA */
 
 static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -301,6 +312,16 @@
 {
 }
 
+static inline void wpa_sm_set_rx_replay_ctr(struct wpa_sm *sm,
+					    const u8 *rx_replay_counter)
+{
+}
+
+static inline void wpa_sm_set_ptk_kck_kek(struct wpa_sm *sm, const u8 *ptk_kck,
+					  const u8 *ptk_kek)
+{
+}
+
 #endif /* CONFIG_NO_WPA */
 
 #ifdef CONFIG_PEERKEY
@@ -388,6 +409,10 @@
 void wpa_tdls_disable_unreachable_link(struct wpa_sm *sm, const u8 *addr);
 const char * wpa_tdls_get_link_status(struct wpa_sm *sm, const u8 *addr);
 int wpa_tdls_is_external_setup(struct wpa_sm *sm);
+int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
+				u8 oper_class,
+				struct hostapd_freq_params *freq_params);
+int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr);
 
 int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
 
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 839b545..07f3692 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -92,6 +92,7 @@
 #ifdef CONFIG_TDLS
 	struct wpa_tdls_peer *tdls;
 	int tdls_prohibited;
+	int tdls_chan_switch_prohibited;
 	int tdls_disabled;
 
 	/* The driver supports TDLS */
@@ -102,6 +103,9 @@
 	 * to it via tdls_mgmt.
 	 */
 	int tdls_external_setup;
+
+	/* The driver supports TDLS channel switching */
+	int tdls_chan_switch;
 #endif /* CONFIG_TDLS */
 
 #ifdef CONFIG_IEEE80211R
@@ -257,11 +261,12 @@
 #ifdef CONFIG_TDLS
 static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
 				       int *tdls_supported,
-				       int *tdls_ext_setup)
+				       int *tdls_ext_setup,
+				       int *tdls_chan_switch)
 {
 	if (sm->ctx->tdls_get_capa)
 		return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported,
-					      tdls_ext_setup);
+					      tdls_ext_setup, tdls_chan_switch);
 	return -1;
 }
 
@@ -310,8 +315,38 @@
 						 supp_oper_classes_len);
 	return -1;
 }
+
+static inline int
+wpa_sm_tdls_enable_channel_switch(struct wpa_sm *sm, const u8 *addr,
+				  u8 oper_class,
+				  const struct hostapd_freq_params *freq_params)
+{
+	if (sm->ctx->tdls_enable_channel_switch)
+		return sm->ctx->tdls_enable_channel_switch(sm->ctx->ctx, addr,
+							   oper_class,
+							   freq_params);
+	return -1;
+}
+
+static inline int
+wpa_sm_tdls_disable_channel_switch(struct wpa_sm *sm, const u8 *addr)
+{
+	if (sm->ctx->tdls_disable_channel_switch)
+		return sm->ctx->tdls_disable_channel_switch(sm->ctx->ctx, addr);
+	return -1;
+}
 #endif /* CONFIG_TDLS */
 
+static inline int wpa_sm_key_mgmt_set_pmk(struct wpa_sm *sm,
+					  const u8 *pmk, size_t pmk_len)
+{
+	if (!sm->proactive_key_caching)
+		return 0;
+	if (!sm->ctx->key_mgmt_set_pmk)
+		return -1;
+	return sm->ctx->key_mgmt_set_pmk(sm->ctx->ctx, pmk, pmk_len);
+}
+
 void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
 			int ver, const u8 *dest, u16 proto,
 			u8 *msg, size_t msg_len, u8 *key_mic);
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 93e8cf6..51876ed 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -173,6 +173,8 @@
 	} else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
 		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
 #endif /* CONFIG_SAE */
+	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B);
 	} else {
 		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
 			   key_mgmt);
diff --git a/src/tls/asn1.c b/src/tls/asn1.c
index 97462fa..cec1092 100644
--- a/src/tls/asn1.c
+++ b/src/tls/asn1.c
@@ -166,7 +166,7 @@
 		ret = os_snprintf(pos, buf + len - pos,
 				  "%s%lu",
 				  i == 0 ? "" : ".", oid->oid[i]);
-		if (ret < 0 || ret >= buf + len - pos)
+		if (os_snprintf_error(buf + len - pos, ret))
 			break;
 		pos += ret;
 	}
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 4a4f0b6..facdd65 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -570,8 +570,26 @@
 	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
 		cipher = "DES-CBC3-SHA";
 		break;
-	case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
-		cipher = "ADH-AES-128-SHA256";
+	case TLS_DHE_RSA_WITH_DES_CBC_SHA:
+		cipher = "DHE-RSA-DES-CBC-SHA";
+		break;
+	case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+		cipher = "DHE-RSA-DES-CBC3-SHA";
+		break;
+	case TLS_DH_anon_WITH_RC4_128_MD5:
+		cipher = "ADH-RC4-MD5";
+		break;
+	case TLS_DH_anon_WITH_DES_CBC_SHA:
+		cipher = "ADH-DES-SHA";
+		break;
+	case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+		cipher = "ADH-DES-CBC3-SHA";
+		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA:
+		cipher = "AES-128-SHA";
+		break;
+	case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+		cipher = "DHE-RSA-AES-128-SHA";
 		break;
 	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
 		cipher = "ADH-AES-128-SHA";
@@ -579,15 +597,30 @@
 	case TLS_RSA_WITH_AES_256_CBC_SHA:
 		cipher = "AES-256-SHA";
 		break;
-	case TLS_RSA_WITH_AES_256_CBC_SHA256:
-		cipher = "AES-256-SHA256";
+	case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+		cipher = "DHE-RSA-AES-256-SHA";
 		break;
-	case TLS_RSA_WITH_AES_128_CBC_SHA:
-		cipher = "AES-128-SHA";
+	case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+		cipher = "ADH-AES-256-SHA";
 		break;
 	case TLS_RSA_WITH_AES_128_CBC_SHA256:
 		cipher = "AES-128-SHA256";
 		break;
+	case TLS_RSA_WITH_AES_256_CBC_SHA256:
+		cipher = "AES-256-SHA256";
+		break;
+	case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+		cipher = "DHE-RSA-AES-128-SHA256";
+		break;
+	case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+		cipher = "DHE-RSA-AES-256-SHA256";
+		break;
+	case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+		cipher = "ADH-AES-128-SHA256";
+		break;
+	case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+		cipher = "ADH-AES-256-SHA256";
+		break;
 	default:
 		return -1;
 	}
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index 4f08e0f..9ce9680 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -440,6 +440,7 @@
 	const u8 *pos, *end, *server_params, *server_params_end;
 	u8 alert;
 	unsigned int bits;
+	u16 val;
 
 	tlsv1_client_free_dh(conn);
 
@@ -449,13 +450,13 @@
 	if (end - pos < 3)
 		goto fail;
 	server_params = pos;
-	conn->dh_p_len = WPA_GET_BE16(pos);
+	val = WPA_GET_BE16(pos);
 	pos += 2;
-	if (conn->dh_p_len == 0 || end - pos < (int) conn->dh_p_len) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %lu",
-			   (unsigned long) conn->dh_p_len);
+	if (val == 0 || val > (size_t) (end - pos)) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid dh_p length %u", val);
 		goto fail;
 	}
+	conn->dh_p_len = val;
 	bits = count_bits(pos, conn->dh_p_len);
 	if (bits < 768) {
 		wpa_printf(MSG_INFO, "TLSv1: Reject under 768-bit DH prime (insecure; only %u bits)",
@@ -474,10 +475,11 @@
 
 	if (end - pos < 3)
 		goto fail;
-	conn->dh_g_len = WPA_GET_BE16(pos);
+	val = WPA_GET_BE16(pos);
 	pos += 2;
-	if (conn->dh_g_len == 0 || end - pos < (int) conn->dh_g_len)
+	if (val == 0 || val > (size_t) (end - pos))
 		goto fail;
+	conn->dh_g_len = val;
 	conn->dh_g = os_malloc(conn->dh_g_len);
 	if (conn->dh_g == NULL)
 		goto fail;
@@ -490,10 +492,11 @@
 
 	if (end - pos < 3)
 		goto fail;
-	conn->dh_ys_len = WPA_GET_BE16(pos);
+	val = WPA_GET_BE16(pos);
 	pos += 2;
-	if (conn->dh_ys_len == 0 || end - pos < (int) conn->dh_ys_len)
+	if (val == 0 || val > (size_t) (end - pos))
 		goto fail;
+	conn->dh_ys_len = val;
 	conn->dh_ys = os_malloc(conn->dh_ys_len);
 	if (conn->dh_ys == NULL)
 		goto fail;
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 23d0b81..93ae488 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -516,14 +516,56 @@
 	case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
 		cipher = "DES-CBC3-SHA";
 		break;
+	case TLS_DHE_RSA_WITH_DES_CBC_SHA:
+		cipher = "DHE-RSA-DES-CBC-SHA";
+		break;
+	case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+		cipher = "DHE-RSA-DES-CBC3-SHA";
+		break;
+	case TLS_DH_anon_WITH_RC4_128_MD5:
+		cipher = "ADH-RC4-MD5";
+		break;
+	case TLS_DH_anon_WITH_DES_CBC_SHA:
+		cipher = "ADH-DES-SHA";
+		break;
+	case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+		cipher = "ADH-DES-CBC3-SHA";
+		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA:
+		cipher = "AES-128-SHA";
+		break;
+	case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+		cipher = "DHE-RSA-AES-128-SHA";
+		break;
 	case TLS_DH_anon_WITH_AES_128_CBC_SHA:
 		cipher = "ADH-AES-128-SHA";
 		break;
 	case TLS_RSA_WITH_AES_256_CBC_SHA:
 		cipher = "AES-256-SHA";
 		break;
-	case TLS_RSA_WITH_AES_128_CBC_SHA:
-		cipher = "AES-128-SHA";
+	case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+		cipher = "DHE-RSA-AES-256-SHA";
+		break;
+	case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+		cipher = "ADH-AES-256-SHA";
+		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA256:
+		cipher = "AES-128-SHA256";
+		break;
+	case TLS_RSA_WITH_AES_256_CBC_SHA256:
+		cipher = "AES-256-SHA256";
+		break;
+	case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+		cipher = "DHE-RSA-AES-128-SHA256";
+		break;
+	case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+		cipher = "DHE-RSA-AES-256-SHA256";
+		break;
+	case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+		cipher = "ADH-AES-128-SHA256";
+		break;
+	case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+		cipher = "ADH-AES-256-SHA256";
 		break;
 	default:
 		return -1;
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 728e137..310966c 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -626,7 +626,7 @@
 	dh_yc_len = WPA_GET_BE16(pos);
 	dh_yc = pos + 2;
 
-	if (dh_yc + dh_yc_len > end) {
+	if (dh_yc_len > end - dh_yc) {
 		tlsv1_server_log(conn, "Client public value overflow (length %d)",
 				 dh_yc_len);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
diff --git a/src/tls/x509v3.c b/src/tls/x509v3.c
index e1e4df8..742af32 100644
--- a/src/tls/x509v3.c
+++ b/src/tls/x509v3.c
@@ -512,7 +512,7 @@
 		ret = os_snprintf(pos, end - pos, "%s=%s, ",
 				  x509_name_attr_str(name->attr[i].type),
 				  name->attr[i].value);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			goto done;
 		pos += ret;
 	}
@@ -527,7 +527,7 @@
 	if (name->email) {
 		ret = os_snprintf(pos, end - pos, "/emailAddress=%s",
 				  name->email);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			goto done;
 		pos += ret;
 	}
diff --git a/src/utils/base64.c b/src/utils/base64.c
index af1307f..d44f290 100644
--- a/src/utils/base64.c
+++ b/src/utils/base64.c
@@ -48,9 +48,11 @@
 	pos = out;
 	line_len = 0;
 	while (end - in >= 3) {
-		*pos++ = base64_table[in[0] >> 2];
-		*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
-		*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
+		*pos++ = base64_table[(in[0] >> 2) & 0x3f];
+		*pos++ = base64_table[(((in[0] & 0x03) << 4) |
+				       (in[1] >> 4)) & 0x3f];
+		*pos++ = base64_table[(((in[1] & 0x0f) << 2) |
+				       (in[2] >> 6)) & 0x3f];
 		*pos++ = base64_table[in[2] & 0x3f];
 		in += 3;
 		line_len += 4;
@@ -61,14 +63,14 @@
 	}
 
 	if (end - in) {
-		*pos++ = base64_table[in[0] >> 2];
+		*pos++ = base64_table[(in[0] >> 2) & 0x3f];
 		if (end - in == 1) {
-			*pos++ = base64_table[(in[0] & 0x03) << 4];
+			*pos++ = base64_table[((in[0] & 0x03) << 4) & 0x3f];
 			*pos++ = '=';
 		} else {
-			*pos++ = base64_table[((in[0] & 0x03) << 4) |
-					      (in[1] >> 4)];
-			*pos++ = base64_table[(in[1] & 0x0f) << 2];
+			*pos++ = base64_table[(((in[0] & 0x03) << 4) |
+					       (in[1] >> 4)) & 0x3f];
+			*pos++ = base64_table[((in[1] & 0x0f) << 2) & 0x3f];
 		}
 		*pos++ = '=';
 		line_len += 4;
diff --git a/src/utils/browser-android.c b/src/utils/browser-android.c
index d5ff5b5..9ce1a5c 100644
--- a/src/utils/browser-android.c
+++ b/src/utils/browser-android.c
@@ -64,24 +64,15 @@
 
 int hs20_web_browser(const char *url)
 {
-	char cmd[2000];
-	int ret;
 	struct http_server *http;
 	struct in_addr addr;
 	struct browser_data data;
+	pid_t pid;
 
 	wpa_printf(MSG_INFO, "Launching Android browser to %s", url);
 
 	os_memset(&data, 0, sizeof(data));
 
-	ret = os_snprintf(cmd, sizeof(cmd),
-			  "start -a android.intent.action.VIEW -d %s "
-			  "-n com.android.browser/.BrowserActivity", url);
-	if (ret < 0 || (size_t) ret >= sizeof(cmd)) {
-		wpa_printf(MSG_ERROR, "Too long URL");
-		return -1;
-	}
-
 	if (eloop_init() < 0) {
 		wpa_printf(MSG_ERROR, "eloop_init failed");
 		return -1;
@@ -94,14 +85,34 @@
 		return -1;
 	}
 
-	if (os_exec("/system/bin/am", cmd, 1) != 0) {
-		wpa_printf(MSG_INFO, "Failed to launch Android browser");
-		eloop_cancel_timeout(browser_timeout, NULL, NULL);
+	pid = fork();
+	if (pid < 0) {
+		wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
 		http_server_deinit(http);
 		eloop_destroy();
 		return -1;
 	}
 
+	if (pid == 0) {
+		/* run the external command in the child process */
+		char *argv[9];
+
+		argv[0] = "browser-android";
+		argv[1] = "start";
+		argv[2] = "-a";
+		argv[3] = "android.intent.action.VIEW";
+		argv[4] = "-d";
+		argv[5] = (void *) url;
+		argv[6] = "-n";
+		argv[7] = "com.android.browser/.BrowserActivity";
+		argv[8] = NULL;
+
+		execv("/system/bin/am", argv);
+		wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+		exit(0);
+		return -1;
+	}
+
 	eloop_register_timeout(30, 0, browser_timeout, &data, NULL);
 	eloop_run();
 	eloop_cancel_timeout(browser_timeout, &data, NULL);
@@ -109,7 +120,7 @@
 	eloop_destroy();
 
 	wpa_printf(MSG_INFO, "Closing Android browser");
-	if (os_exec("/system/bin/input", "keyevent 3", 1) != 0) {
+	if (system("/system/bin/input keyevent KEYCODE_HOME") != 0) {
 		wpa_printf(MSG_INFO, "Failed to inject keyevent");
 	}
 
diff --git a/src/utils/browser-system.c b/src/utils/browser-system.c
index a080e2c..aed3970 100644
--- a/src/utils/browser-system.c
+++ b/src/utils/browser-system.c
@@ -64,22 +64,15 @@
 
 int hs20_web_browser(const char *url)
 {
-	char cmd[2000];
-	int ret;
 	struct http_server *http;
 	struct in_addr addr;
 	struct browser_data data;
+	pid_t pid;
 
-	wpa_printf(MSG_INFO, "Launching Android browser to %s", url);
+	wpa_printf(MSG_INFO, "Launching system browser to %s", url);
 
 	os_memset(&data, 0, sizeof(data));
 
-	ret = os_snprintf(cmd, sizeof(cmd), "x-www-browser '%s' &", url);
-	if (ret < 0 || (size_t) ret >= sizeof(cmd)) {
-		wpa_printf(MSG_ERROR, "Too long URL");
-		return -1;
-	}
-
 	if (eloop_init() < 0) {
 		wpa_printf(MSG_ERROR, "eloop_init failed");
 		return -1;
@@ -92,14 +85,28 @@
 		return -1;
 	}
 
-	if (os_exec("/usr/bin/x-www-browser", url, 0) != 0) {
-		wpa_printf(MSG_INFO, "Failed to launch browser");
-		eloop_cancel_timeout(browser_timeout, NULL, NULL);
+	pid = fork();
+	if (pid < 0) {
+		wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
 		http_server_deinit(http);
 		eloop_destroy();
 		return -1;
 	}
 
+	if (pid == 0) {
+		/* run the external command in the child process */
+		char *argv[3];
+
+		argv[0] = "browser-system";
+		argv[1] = (void *) url;
+		argv[2] = NULL;
+
+		execv("/usr/bin/x-www-browser", argv);
+		wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+		exit(0);
+		return -1;
+	}
+
 	eloop_register_timeout(120, 0, browser_timeout, &data, NULL);
 	eloop_run();
 	eloop_cancel_timeout(browser_timeout, &data, NULL);
diff --git a/src/utils/browser-wpadebug.c b/src/utils/browser-wpadebug.c
index ce3054b..5fc40fa 100644
--- a/src/utils/browser-wpadebug.c
+++ b/src/utils/browser-wpadebug.c
@@ -65,26 +65,15 @@
 
 int hs20_web_browser(const char *url)
 {
-	char cmd[2000];
-	int ret;
 	struct http_server *http;
 	struct in_addr addr;
 	struct browser_data data;
+	pid_t pid;
 
 	wpa_printf(MSG_INFO, "Launching wpadebug browser to %s", url);
 
 	os_memset(&data, 0, sizeof(data));
 
-	ret = os_snprintf(cmd, sizeof(cmd),
-			  "start -a android.action.MAIN "
-			  "-c android.intent.category.LAUNCHER "
-			  "-n w1.fi.wpadebug/.WpaWebViewActivity "
-			  "-e w1.fi.wpadebug.URL '%s'", url);
-	if (ret < 0 || (size_t) ret >= sizeof(cmd)) {
-		wpa_printf(MSG_ERROR, "Too long URL");
-		return -1;
-	}
-
 	if (eloop_init() < 0) {
 		wpa_printf(MSG_ERROR, "eloop_init failed");
 		return -1;
@@ -97,14 +86,37 @@
 		return -1;
 	}
 
-	if (os_exec("/system/bin/am", cmd, 1) != 0) {
-		wpa_printf(MSG_INFO, "Failed to launch wpadebug browser");
-		eloop_cancel_timeout(browser_timeout, NULL, NULL);
+	pid = fork();
+	if (pid < 0) {
+		wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
 		http_server_deinit(http);
 		eloop_destroy();
 		return -1;
 	}
 
+	if (pid == 0) {
+		/* run the external command in the child process */
+		char *argv[12];
+
+		argv[0] = "browser-wpadebug";
+		argv[1] = "start";
+		argv[2] = "-a";
+		argv[3] = "android.action.MAIN";
+		argv[4] = "-c";
+		argv[5] = "android.intent.category.LAUNCHER";
+		argv[6] = "-n";
+		argv[7] = "w1.fi.wpadebug/.WpaWebViewActivity";
+		argv[8] = "-e";
+		argv[9] = "w1.fi.wpadebug.URL";
+		argv[10] = (void *) url;
+		argv[11] = NULL;
+
+		execv("/system/bin/am", argv);
+		wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+		exit(0);
+		return -1;
+	}
+
 	eloop_register_timeout(300, 0, browser_timeout, &data, NULL);
 	eloop_run();
 	eloop_cancel_timeout(browser_timeout, &data, NULL);
diff --git a/src/utils/common.c b/src/utils/common.c
index 9902004..182c6a8 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -183,6 +183,35 @@
 	os_memcpy(buf + 4, (u8 *) &tmp, 4);
 }
 
+/**
+ * wpa_scnprintf - Simpler-to-use snprintf function
+ * @buf: Output buffer
+ * @size: Buffer size
+ * @fmt: format
+ *
+ * Simpler snprintf version that doesn't require further error checks - the
+ * return value only indicates how many bytes were actually written, excluding
+ * the NULL byte (i.e., 0 on error, size-1 if buffer is not big enough).
+ */
+int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...)
+{
+	va_list ap;
+	int ret;
+
+	if (!size)
+		return 0;
+
+	va_start(ap, fmt);
+	ret = vsnprintf(buf, size, fmt, ap);
+	va_end(ap);
+
+	if (ret < 0)
+		return 0;
+	if ((size_t) ret >= size)
+		return size - 1;
+
+	return ret;
+}
 
 static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
 				    size_t len, int uppercase)
@@ -195,7 +224,7 @@
 	for (i = 0; i < len; i++) {
 		ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
 				  data[i]);
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return pos - buf;
 		}
@@ -578,21 +607,6 @@
 }
 
 
-int find_first_bit(u32 value)
-{
-	int pos = 0;
-
-	while (value) {
-		if (value & 0x1)
-			return pos;
-		value >>= 1;
-		pos++;
-	}
-
-	return -1;
-}
-
-
 size_t merge_byte_arrays(u8 *res, size_t res_len,
 			 const u8 *src1, size_t src1_len,
 			 const u8 *src2, size_t src2_len)
@@ -726,7 +740,7 @@
 			res = os_snprintf(pos, end - pos, "%s%u-%u",
 					  i == 0 ? "" : ",",
 					  range->min, range->max);
-		if (res < 0 || res > end - pos) {
+		if (os_snprintf_error(end - pos, res)) {
 			os_free(buf);
 			return NULL;
 		}
@@ -866,3 +880,35 @@
 	addr[0] |= 0x02; /* locally administered */
 	return 0;
 }
+
+
+/**
+ * str_token - Get next token from a string
+ * @buf: String to tokenize. Note that the string might be modified.
+ * @delim: String of delimiters
+ * @context: Pointer to save our context. Should be initialized with
+ *	NULL on the first call, and passed for any further call.
+ * Returns: The next token, NULL if there are no more valid tokens.
+ */
+char * str_token(char *str, const char *delim, char **context)
+{
+	char *end, *pos = str;
+
+	if (*context)
+		pos = *context;
+
+	while (*pos && os_strchr(delim, *pos))
+		pos++;
+	if (!*pos)
+		return NULL;
+
+	end = pos + 1;
+	while (*end && !os_strchr(delim, *end))
+		end++;
+
+	if (*end)
+		*end++ = '\0';
+
+	*context = end;
+	return pos;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index 14d9ad1..7eca409 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -329,6 +329,9 @@
 #ifndef ETH_ALEN
 #define ETH_ALEN 6
 #endif
+#ifndef ETH_HLEN
+#define ETH_HLEN 14
+#endif
 #ifndef IFNAMSIZ
 #define IFNAMSIZ 16
 #endif
@@ -474,6 +477,7 @@
 int hexstr2bin(const char *hex, u8 *buf, size_t len);
 void inc_byte_array(u8 *counter, size_t len);
 void wpa_get_ntp_timestamp(u8 *buf);
+int wpa_scnprintf(char *buf, size_t size, const char *fmt, ...);
 int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
 int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
 			       size_t len);
@@ -493,7 +497,6 @@
 
 char * wpa_config_parse_string(const char *value, size_t *len);
 int is_hex(const u8 *data, size_t len);
-int find_first_bit(u32 value);
 size_t merge_byte_arrays(u8 *res, size_t res_len,
 			 const u8 *src1, size_t src1_len,
 			 const u8 *src2, size_t src2_len);
@@ -534,13 +537,14 @@
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
 
-
 void str_clear_free(char *str);
 void bin_clear_free(void *bin, size_t len);
 
 int random_mac_addr(u8 *addr);
 int random_mac_addr_keep_oui(u8 *addr);
 
+char * str_token(char *str, const char *delim, char **context);
+
 
 /*
  * gcc 4.4 ends up generating strict-aliasing warnings about some very common
diff --git a/src/utils/os.h b/src/utils/os.h
index b9247d8..77250d6 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -549,6 +549,12 @@
 #endif /* OS_NO_C_LIB_DEFINES */
 
 
+static inline int os_snprintf_error(size_t size, int res)
+{
+	return res < 0 || (unsigned int) res >= size;
+}
+
+
 static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
 {
 	if (size && nmemb > (~(size_t) 0) / size)
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index 90b6688..77733ad 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -17,9 +17,11 @@
  */
 
 #include "includes.h"
+#include <time.h>
+#include <sys/wait.h>
 
 #undef OS_REJECT_C_LIB_FUNCTIONS
-#include "os.h"
+#include "common.h"
 
 void os_sleep(os_time_t sec, os_time_t usec)
 {
@@ -96,7 +98,7 @@
 int os_daemonize(const char *pid_file)
 {
 	if (daemon(0, 0)) {
-		perror("daemon");
+		wpa_printf(MSG_ERROR, "daemon: %s", strerror(errno));
 		return -1;
 	}
 
@@ -167,8 +169,8 @@
 		}
 	}
 
-	cwd_len = strlen(cwd);
-	rel_len = strlen(rel_path);
+	cwd_len = os_strlen(cwd);
+	rel_len = os_strlen(rel_path);
 	ret_len = cwd_len + 1 + rel_len + 1;
 	ret = os_malloc(ret_len);
 	if (ret) {
@@ -506,3 +508,57 @@
 		str[size - 1] = '\0';
 	return ret;
 }
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+	pid_t pid;
+	int pid_status;
+
+	pid = fork();
+	if (pid < 0) {
+		wpa_printf(MSG_ERROR, "fork: %s", strerror(errno));
+		return -1;
+	}
+
+	if (pid == 0) {
+		/* run the external command in the child process */
+		const int MAX_ARG = 30;
+		char *_program, *_arg, *pos;
+		char *argv[MAX_ARG + 1];
+		int i;
+
+		_program = os_strdup(program);
+		_arg = os_strdup(arg);
+
+		argv[0] = _program;
+
+		i = 1;
+		pos = _arg;
+		while (i < MAX_ARG && pos && *pos) {
+			while (*pos == ' ')
+				pos++;
+			if (*pos == '\0')
+				break;
+			argv[i++] = pos;
+			pos = os_strchr(pos, ' ');
+			if (pos)
+				*pos++ = '\0';
+		}
+		argv[i] = NULL;
+
+		execv(program, argv);
+		wpa_printf(MSG_ERROR, "execv: %s", strerror(errno));
+		os_free(_program);
+		os_free(_arg);
+		exit(0);
+		return -1;
+	}
+
+	if (wait_completion) {
+		/* wait for the child process to complete in the parent */
+		waitpid(pid, &pid_status, 0);
+	}
+
+	return 0;
+}
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
index 2649111..83fe025 100644
--- a/src/utils/os_none.c
+++ b/src/utils/os_none.c
@@ -234,3 +234,9 @@
 	return 0;
 }
 #endif /* OS_NO_C_LIB_DEFINES */
+
+
+int os_exec(const char *program, const char *arg, int wait_completion)
+{
+	return -1;
+}
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
index d955dc4..6f5ea93 100644
--- a/src/utils/pcsc_funcs.c
+++ b/src/utils/pcsc_funcs.c
@@ -281,77 +281,82 @@
 	wpa_hexdump(MSG_DEBUG, "SCARD: file header FSP template",
 		    pos, end - pos);
 
-	while (pos + 1 < end) {
+	while (end - pos >= 2) {
+		unsigned char type, len;
+
+		type = pos[0];
+		len = pos[1];
 		wpa_printf(MSG_MSGDUMP, "SCARD: file header TLV 0x%02x len=%d",
-			   pos[0], pos[1]);
-		if (pos + 2 + pos[1] > end)
+			   type, len);
+		pos += 2;
+
+		if (len > (unsigned int) (end - pos))
 			break;
 
-		switch (pos[0]) {
+		switch (type) {
 		case USIM_TLV_FILE_DESC:
 			wpa_hexdump(MSG_MSGDUMP, "SCARD: File Descriptor TLV",
-				    pos + 2, pos[1]);
+				    pos, len);
 			break;
 		case USIM_TLV_FILE_ID:
 			wpa_hexdump(MSG_MSGDUMP, "SCARD: File Identifier TLV",
-				    pos + 2, pos[1]);
+				    pos, len);
 			break;
 		case USIM_TLV_DF_NAME:
 			wpa_hexdump(MSG_MSGDUMP, "SCARD: DF name (AID) TLV",
-				    pos + 2, pos[1]);
+				    pos, len);
 			break;
 		case USIM_TLV_PROPR_INFO:
 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Proprietary "
-				    "information TLV", pos + 2, pos[1]);
+				    "information TLV", pos, len);
 			break;
 		case USIM_TLV_LIFE_CYCLE_STATUS:
 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Life Cycle Status "
-				    "Integer TLV", pos + 2, pos[1]);
+				    "Integer TLV", pos, len);
 			break;
 		case USIM_TLV_FILE_SIZE:
 			wpa_hexdump(MSG_MSGDUMP, "SCARD: File size TLV",
-				    pos + 2, pos[1]);
-			if ((pos[1] == 1 || pos[1] == 2) && file_len) {
-				if (pos[1] == 1)
-					*file_len = (int) pos[2];
+				    pos, len);
+			if ((len == 1 || len == 2) && file_len) {
+				if (len == 1)
+					*file_len = (int) pos[0];
 				else
-					*file_len = ((int) pos[2] << 8) |
-						(int) pos[3];
+					*file_len = WPA_GET_BE16(pos);
 				wpa_printf(MSG_DEBUG, "SCARD: file_size=%d",
 					   *file_len);
 			}
 			break;
 		case USIM_TLV_TOTAL_FILE_SIZE:
 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Total file size TLV",
-				    pos + 2, pos[1]);
+				    pos, len);
 			break;
 		case USIM_TLV_PIN_STATUS_TEMPLATE:
 			wpa_hexdump(MSG_MSGDUMP, "SCARD: PIN Status Template "
-				    "DO TLV", pos + 2, pos[1]);
-			if (pos[1] >= 2 && pos[2] == USIM_PS_DO_TAG &&
-			    pos[3] >= 1 && ps_do) {
+				    "DO TLV", pos, len);
+			if (len >= 2 && pos[0] == USIM_PS_DO_TAG &&
+			    pos[1] >= 1 && ps_do) {
 				wpa_printf(MSG_DEBUG, "SCARD: PS_DO=0x%02x",
-					   pos[4]);
-				*ps_do = (int) pos[4];
+					   pos[2]);
+				*ps_do = (int) pos[2];
 			}
 			break;
 		case USIM_TLV_SHORT_FILE_ID:
 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Short File "
-				    "Identifier (SFI) TLV", pos + 2, pos[1]);
+				    "Identifier (SFI) TLV", pos, len);
 			break;
 		case USIM_TLV_SECURITY_ATTR_8B:
 		case USIM_TLV_SECURITY_ATTR_8C:
 		case USIM_TLV_SECURITY_ATTR_AB:
 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Security attribute "
-				    "TLV", pos + 2, pos[1]);
+				    "TLV", pos, len);
 			break;
 		default:
 			wpa_hexdump(MSG_MSGDUMP, "SCARD: Unrecognized TLV",
-				    pos, 2 + pos[1]);
+				    pos, len);
 			break;
 		}
 
-		pos += 2 + pos[1];
+		pos += len;
 
 		if (pos == end)
 			return 0;
@@ -397,10 +402,12 @@
 		unsigned char rid[5];
 		unsigned char appl_code[2]; /* 0x1002 for 3G USIM */
 	} *efdir;
-	unsigned char buf[127];
+	unsigned char buf[127], *aid_pos;
 	size_t blen;
+	unsigned int aid_len = 0;
 
 	efdir = (struct efdir *) buf;
+	aid_pos = &buf[4];
 	blen = sizeof(buf);
 	if (scard_select_file(scard, SCARD_FILE_EF_DIR, buf, &blen)) {
 		wpa_printf(MSG_DEBUG, "SCARD: Failed to read EF_DIR");
@@ -449,14 +456,15 @@
 			continue;
 		}
 
-		if (efdir->aid_len < 1 || efdir->aid_len > 16) {
-			wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %d",
-				   efdir->aid_len);
+		aid_len = efdir->aid_len;
+		if (aid_len < 1 || aid_len > 16) {
+			wpa_printf(MSG_DEBUG, "SCARD: Invalid AID length %u",
+				   aid_len);
 			continue;
 		}
 
 		wpa_hexdump(MSG_DEBUG, "SCARD: AID from EF_DIR record",
-			    efdir->rid, efdir->aid_len);
+			    aid_pos, aid_len);
 
 		if (efdir->appl_code[0] == 0x10 &&
 		    efdir->appl_code[1] == 0x02) {
@@ -472,14 +480,14 @@
 		return -1;
 	}
 
-	if (efdir->aid_len > maxlen) {
+	if (aid_len > maxlen) {
 		wpa_printf(MSG_DEBUG, "SCARD: Too long AID");
 		return -1;
 	}
 
-	os_memcpy(aid, efdir->rid, efdir->aid_len);
+	os_memcpy(aid, aid_pos, aid_len);
 
-	return efdir->aid_len;
+	return aid_len;
 }
 
 
@@ -1096,7 +1104,7 @@
 	}
 
 	if (scard->sim_type == SCARD_GSM_SIM) {
-		blen = (buf[2] << 8) | buf[3];
+		blen = WPA_GET_BE16(&buf[2]);
 	} else {
 		int file_size;
 		if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
@@ -1170,7 +1178,7 @@
 	}
 
 	if (scard->sim_type == SCARD_GSM_SIM) {
-		file_size = (buf[2] << 8) | buf[3];
+		file_size = WPA_GET_BE16(&buf[2]);
 	} else {
 		if (scard_parse_fsp_templ(buf, blen, NULL, &file_size))
 			return -3;
diff --git a/src/utils/radiotap.c b/src/utils/radiotap.c
index 197a4af..f8f815a 100644
--- a/src/utils/radiotap.c
+++ b/src/utils/radiotap.c
@@ -109,6 +109,7 @@
 	iterator->_arg_index = 0;
 	iterator->_bitmap_shifter = get_unaligned_le32(&radiotap_header->it_present);
 	iterator->_arg = (uint8_t *)radiotap_header + sizeof(*radiotap_header);
+	iterator->_next_ns_data = NULL;
 	iterator->_reset_on_ext = 0;
 	iterator->_next_bitmap = &radiotap_header->it_present;
 	iterator->_next_bitmap++;
@@ -154,6 +155,8 @@
 	}
 
 	iterator->this_arg = iterator->_arg;
+	iterator->this_arg_index = 0;
+	iterator->this_arg_size = 0;
 
 	/* we are all initialized happily */
 
diff --git a/src/utils/trace.c b/src/utils/trace.c
index 6044f5f..7403c08 100644
--- a/src/utils/trace.c
+++ b/src/utils/trace.c
@@ -33,7 +33,7 @@
 	os_snprintf(exe, sizeof(exe) - 1, "/proc/%u/exe", getpid());
 	len = readlink(exe, fname, sizeof(fname) - 1);
 	if (len < 0 || len >= (int) sizeof(fname)) {
-		perror("readlink");
+		wpa_printf(MSG_ERROR, "readlink: %s", strerror(errno));
 		return;
 	}
 	fname[len] = '\0';
diff --git a/src/utils/uuid.c b/src/utils/uuid.c
index 2aa4bcb..0f224f9 100644
--- a/src/utils/uuid.c
+++ b/src/utils/uuid.c
@@ -55,7 +55,7 @@
 			  bin[4], bin[5], bin[6], bin[7],
 			  bin[8], bin[9], bin[10], bin[11],
 			  bin[12], bin[13], bin[14], bin[15]);
-	if (len < 0 || (size_t) len >= max_len)
+	if (os_snprintf_error(max_len, len))
 		return -1;
 	return 0;
 }
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 68cbace..0d11905 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -555,6 +555,8 @@
 #ifndef _WIN32
 	setvbuf(out_file, NULL, _IOLBF, 0);
 #endif /* _WIN32 */
+#else /* CONFIG_DEBUG_FILE */
+	(void)path;
 #endif /* CONFIG_DEBUG_FILE */
 	return 0;
 }
@@ -572,6 +574,14 @@
 #endif /* CONFIG_DEBUG_FILE */
 }
 
+
+void wpa_debug_setup_stdout(void)
+{
+#ifndef _WIN32
+	setvbuf(stdout, NULL, _IOLBF, 0);
+#endif /* _WIN32 */
+}
+
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
 
@@ -617,7 +627,7 @@
 		if (ifname) {
 			int res = os_snprintf(prefix, sizeof(prefix), "%s: ",
 					      ifname);
-			if (res < 0 || res >= (int) sizeof(prefix))
+			if (os_snprintf_error(sizeof(prefix), res))
 				prefix[0] = '\0';
 		}
 	}
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 391f197..400bea9 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -34,6 +34,7 @@
 #define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
 #define wpa_debug_open_file(p) do { } while (0)
 #define wpa_debug_close_file() do { } while (0)
+#define wpa_debug_setup_stdout() do { } while (0)
 #define wpa_dbg(args...) do { } while (0)
 
 static inline int wpa_debug_reopen_file(void)
@@ -46,6 +47,7 @@
 int wpa_debug_open_file(const char *path);
 int wpa_debug_reopen_file(void);
 void wpa_debug_close_file(void);
+void wpa_debug_setup_stdout(void);
 
 /**
  * wpa_debug_printf_timestamp - Print timestamp for debug output
diff --git a/src/wps/wps.c b/src/wps/wps.c
index b0f6887..2c68be8 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -560,7 +560,7 @@
 					  "wps_state=configured\n");
 		else
 			ret = 0;
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -568,7 +568,7 @@
 	if (attr.ap_setup_locked && *attr.ap_setup_locked) {
 		ret = os_snprintf(pos, end - pos,
 				  "wps_ap_setup_locked=1\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -576,7 +576,7 @@
 	if (attr.selected_registrar && *attr.selected_registrar) {
 		ret = os_snprintf(pos, end - pos,
 				  "wps_selected_registrar=1\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -585,7 +585,7 @@
 		ret = os_snprintf(pos, end - pos,
 				  "wps_device_password_id=%u\n",
 				  WPA_GET_BE16(attr.dev_password_id));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -595,7 +595,7 @@
 				  "wps_selected_registrar_config_methods="
 				  "0x%04x\n",
 				  WPA_GET_BE16(attr.sel_reg_config_methods));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -607,7 +607,7 @@
 				  wps_dev_type_bin2str(attr.primary_dev_type,
 						       devtype,
 						       sizeof(devtype)));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -626,7 +626,7 @@
 		str[i] = '\0';
 		ret = os_snprintf(pos, end - pos, "wps_device_name=%s\n", str);
 		os_free(str);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -635,7 +635,7 @@
 		ret = os_snprintf(pos, end - pos,
 				  "wps_config_methods=0x%04x\n",
 				  WPA_GET_BE16(attr.config_methods));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 192d283..0a7f65d 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -819,6 +819,7 @@
 int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
 					 const u8 *oob_dev_pw,
 					 size_t oob_dev_pw_len);
+void wps_registrar_flush(struct wps_registrar *reg);
 
 int wps_build_credential_wrap(struct wpabuf *msg,
 			      const struct wps_credential *cred);
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index a282348..222d485 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -489,7 +489,7 @@
 	ret = os_snprintf(buf, buf_len, "%u-%08X-%u",
 			  WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
 			  WPA_GET_BE16(&dev_type[6]));
-	if (ret < 0 || (unsigned int) ret >= buf_len)
+	if (os_snprintf_error(buf_len, ret))
 		return NULL;
 
 	return buf;
diff --git a/src/wps/wps_defs.h b/src/wps/wps_defs.h
index f483e2e..da005a4 100644
--- a/src/wps/wps_defs.h
+++ b/src/wps/wps_defs.h
@@ -279,30 +279,71 @@
 	WPS_DEV_DISPLAY = 7,
 	WPS_DEV_MULTIMEDIA = 8,
 	WPS_DEV_GAMING = 9,
-	WPS_DEV_PHONE = 10
+	WPS_DEV_PHONE = 10,
+	WPS_DEV_AUDIO = 11,
 };
 
 enum wps_dev_subcateg {
 	WPS_DEV_COMPUTER_PC = 1,
 	WPS_DEV_COMPUTER_SERVER = 2,
 	WPS_DEV_COMPUTER_MEDIA_CENTER = 3,
+	WPS_DEV_COMPUTER_ULTRA_MOBILE = 4,
+	WPS_DEV_COMPUTER_NOTEBOOK = 5,
+	WPS_DEV_COMPUTER_DESKTOP = 6,
+	WPS_DEV_COMPUTER_MID = 7,
+	WPS_DEV_COMPUTER_NETBOOK = 8,
+	WPS_DEV_COMPUTER_TABLET = 9,
+	WPS_DEV_INPUT_KEYBOARD = 1,
+	WPS_DEV_INPUT_MOUSE = 2,
+	WPS_DEV_INPUT_JOYSTICK = 3,
+	WPS_DEV_INPUT_TRACKBALL = 4,
+	WPS_DEV_INPUT_GAMING = 5,
+	WPS_DEV_INPUT_REMOTE = 6,
+	WPS_DEV_INPUT_TOUCHSCREEN = 7,
+	WPS_DEV_INPUT_BIOMETRIC_READER = 8,
+	WPS_DEV_INPUT_BARCODE_READER = 9,
 	WPS_DEV_PRINTER_PRINTER = 1,
 	WPS_DEV_PRINTER_SCANNER = 2,
+	WPS_DEV_PRINTER_FAX = 3,
+	WPS_DEV_PRINTER_COPIER = 4,
+	WPS_DEV_PRINTER_ALL_IN_ONE = 5,
 	WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA = 1,
+	WPS_DEV_CAMERA_VIDEO = 2,
+	WPS_DEV_CAMERA_WEB = 3,
+	WPS_DEV_CAMERA_SECURITY = 4,
 	WPS_DEV_STORAGE_NAS = 1,
 	WPS_DEV_NETWORK_INFRA_AP = 1,
 	WPS_DEV_NETWORK_INFRA_ROUTER = 2,
 	WPS_DEV_NETWORK_INFRA_SWITCH = 3,
+	WPS_DEV_NETWORK_INFRA_GATEWAY = 4,
+	WPS_DEV_NETWORK_INFRA_BRIDGE = 5,
 	WPS_DEV_DISPLAY_TV = 1,
 	WPS_DEV_DISPLAY_PICTURE_FRAME = 2,
 	WPS_DEV_DISPLAY_PROJECTOR = 3,
+	WPS_DEV_DISPLAY_MONITOR = 4,
 	WPS_DEV_MULTIMEDIA_DAR = 1,
 	WPS_DEV_MULTIMEDIA_PVR = 2,
 	WPS_DEV_MULTIMEDIA_MCX = 3,
+	WPS_DEV_MULTIMEDIA_SET_TOP_BOX = 4,
+	WPS_DEV_MULTIMEDIA_MEDIA_SERVER = 5,
+	WPS_DEV_MULTIMEDIA_PORTABLE_VIDEO_PLAYER = 6,
 	WPS_DEV_GAMING_XBOX = 1,
 	WPS_DEV_GAMING_XBOX360 = 2,
 	WPS_DEV_GAMING_PLAYSTATION = 3,
-	WPS_DEV_PHONE_WINDOWS_MOBILE = 1
+	WPS_DEV_GAMING_GAME_CONSOLE = 4,
+	WPS_DEV_GAMING_PORTABLE_DEVICE = 5,
+	WPS_DEV_PHONE_WINDOWS_MOBILE = 1,
+	WPS_DEV_PHONE_SINGLE_MODE = 2,
+	WPS_DEV_PHONE_DUAL_MODE = 3,
+	WPS_DEV_PHONE_SP_SINGLE_MODE = 4,
+	WPS_DEV_PHONE_SP_DUAL_MODE = 5,
+	WPS_DEV_AUDIO_TUNER_RECV = 1,
+	WPS_DEV_AUDIO_SPEAKERS = 2,
+	WPS_DEV_AUDIO_PMP = 3,
+	WPS_DEV_AUDIO_HEADSET = 4,
+	WPS_DEV_AUDIO_HEADPHONES = 5,
+	WPS_DEV_AUDIO_MICROPHONE = 6,
+	WPS_DEV_AUDIO_HOME_THEATRE = 7,
 };
 
 
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index b90cc25..8ee1ea9 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -676,6 +676,22 @@
 }
 
 
+void wps_registrar_flush(struct wps_registrar *reg)
+{
+	if (reg == NULL)
+		return;
+	wps_free_pins(&reg->pins);
+	wps_free_nfc_pw_tokens(&reg->nfc_pw_tokens, 0);
+	wps_free_pbc_sessions(reg->pbc_sessions);
+	reg->pbc_sessions = NULL;
+	wps_free_devices(reg->devices);
+	reg->devices = NULL;
+#ifdef WPS_WORKAROUNDS
+	reg->pbc_ignore_start.sec = 0;
+#endif /* WPS_WORKAROUNDS */
+}
+
+
 /**
  * wps_registrar_deinit - Deinitialize WPS Registrar data
  * @reg: Registrar data from wps_registrar_init()
@@ -686,11 +702,8 @@
 		return;
 	eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL);
 	eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
-	wps_free_pins(&reg->pins);
-	wps_free_nfc_pw_tokens(&reg->nfc_pw_tokens, 0);
-	wps_free_pbc_sessions(reg->pbc_sessions);
+	wps_registrar_flush(reg);
 	wpabuf_free(reg->extra_cred);
-	wps_free_devices(reg->devices);
 	os_free(reg);
 }
 
@@ -3495,7 +3508,7 @@
 			  d->dev.model_name ? d->dev.model_name : "",
 			  d->dev.model_number ? d->dev.model_number : "",
 			  d->dev.serial_number ? d->dev.serial_number : "");
-	if (ret < 0 || (size_t) ret >= buflen - len)
+	if (os_snprintf_error(buflen - len, ret))
 		return len;
 	len += ret;
 
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index ae94a9f..933d734 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -251,13 +251,16 @@
  * use for constructing UUIDs for subscriptions. Presumably any method from
  * rfc4122 is good enough; I've chosen random number method.
  */
-static void uuid_make(u8 uuid[UUID_LEN])
+static int uuid_make(u8 uuid[UUID_LEN])
 {
-	os_get_random(uuid, UUID_LEN);
+	if (os_get_random(uuid, UUID_LEN) < 0)
+		return -1;
 
 	/* Replace certain bits as specified in rfc4122 or X.667 */
 	uuid[6] &= 0x0f; uuid[6] |= (4 << 4);   /* version 4 == random gen */
 	uuid[8] &= 0x3f; uuid[8] |= 0x80;
+
+	return 0;
 }
 
 
@@ -700,10 +703,12 @@
 	if (dl_list_len(&sm->subscriptions) >= MAX_SUBSCRIPTIONS) {
 		s = dl_list_first(&sm->subscriptions, struct subscription,
 				  list);
-		wpa_printf(MSG_INFO, "WPS UPnP: Too many subscriptions, "
-			   "trashing oldest");
-		dl_list_del(&s->list);
-		subscription_destroy(s);
+		if (s) {
+			wpa_printf(MSG_INFO,
+				   "WPS UPnP: Too many subscriptions, trashing oldest");
+			dl_list_del(&s->list);
+			subscription_destroy(s);
+		}
 	}
 
 	s = os_zalloc(sizeof(*s));
@@ -714,7 +719,10 @@
 
 	s->sm = sm;
 	s->timeout_time = expire;
-	uuid_make(s->uuid);
+	if (uuid_make(s->uuid) < 0) {
+		subscription_destroy(s);
+		return NULL;
+	}
 	subscr_addr_list_create(s, callback_urls);
 	if (dl_list_empty(&s->addr_list)) {
 		wpa_printf(MSG_DEBUG, "WPS UPnP: No valid callback URLs in "
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index 098571c..26a740d 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -317,7 +317,8 @@
 			 * (see notes above)
 			 */
 			next_timeout_msec = 0;
-			os_get_random((void *) &r, sizeof(r));
+			if (os_get_random((void *) &r, sizeof(r)) < 0)
+				r = 32768;
 			next_timeout_sec = UPNP_CACHE_SEC / 4 +
 				(((UPNP_CACHE_SEC / 4) * r) >> 16);
 			sm->advertise_count++;
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index 43c3eed..7d7f1b6 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -10,8 +10,6 @@
 
 ifneq ($(BOARD_WPA_SUPPLICANT_DRIVER),)
   CONFIG_DRIVER_$(BOARD_WPA_SUPPLICANT_DRIVER) := y
-else
-  CONFIG_DRIVER_TEST := y
 endif
 
 include $(LOCAL_PATH)/android.config
@@ -85,6 +83,7 @@
 OBJS += src/utils/common.c
 OBJS += src/utils/wpa_debug.c
 OBJS += src/utils/wpabuf.c
+OBJS += wmm_ac.c
 OBJS_p = wpa_passphrase.c
 OBJS_p += src/utils/common.c
 OBJS_p += src/utils/wpa_debug.c
@@ -184,6 +183,12 @@
 L_CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
 endif
 
+ifdef CONFIG_SUITEB
+L_CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
 ifdef CONFIG_IEEE80211W
 L_CFLAGS += -DCONFIG_IEEE80211W
 NEED_SHA256=y
@@ -193,11 +198,24 @@
 ifdef CONFIG_IEEE80211R
 L_CFLAGS += -DCONFIG_IEEE80211R
 OBJS += src/rsn_supp/wpa_ft.c
-NEED_80211_COMMON=y
 NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_MESH
+NEED_80211_COMMON=y
+NEED_SHA256=y
+NEED_AES_SIV=y
+NEED_AES_OMAC1=y
+NEED_AES_CTR=y
+CONFIG_SAE=y
+CONFIG_AP=y
+L_CFLAGS += -DCONFIG_MESH
+OBJS += mesh.c
+OBJS += mesh_mpm.c
+OBJS += mesh_rsn.c
+endif
+
 ifdef CONFIG_SAE
 L_CFLAGS += -DCONFIG_SAE
 OBJS += src/common/sae.c
@@ -263,7 +281,6 @@
 L_CFLAGS += -DCONFIG_P2P
 NEED_GAS=y
 NEED_OFFCHANNEL=y
-NEED_80211_COMMON=y
 CONFIG_WPS=y
 CONFIG_AP=y
 ifdef CONFIG_P2P_STRICT
@@ -329,6 +346,12 @@
 LIBS += -lpcap
 endif
 
+ifdef CONFIG_ERP
+L_CFLAGS += -DCONFIG_ERP
+NEED_SHA256=y
+NEED_HMAC_SHA256_KDF=y
+endif
+
 ifdef CONFIG_EAP_TLS
 # EAP-TLS
 ifeq ($(CONFIG_EAP_TLS), dyn)
@@ -635,7 +658,6 @@
 NEED_DH_GROUPS=y
 NEED_SHA256=y
 NEED_BASE64=y
-NEED_80211_COMMON=y
 NEED_AES_CBC=y
 NEED_MODEXP=y
 
@@ -744,7 +766,6 @@
 endif
 
 ifdef CONFIG_AP
-NEED_80211_COMMON=y
 NEED_EAP_COMMON=y
 NEED_RSN_AUTHENTICATOR=y
 L_CFLAGS += -DCONFIG_AP
@@ -768,6 +789,7 @@
 OBJS += src/ap/drv_callbacks.c
 OBJS += src/ap/ap_drv_ops.c
 OBJS += src/ap/beacon.c
+OBJS += src/ap/bss_load.c
 OBJS += src/ap/eap_user_db.c
 ifdef CONFIG_IEEE80211N
 OBJS += src/ap/ieee802_11_ht.c
@@ -1149,6 +1171,9 @@
 AESOBJS += src/crypto/aes-internal-enc.c
 endif
 endif
+ifdef NEED_AES_SIV
+AESOBJS += src/crypto/aes-siv.c
+endif
 ifdef NEED_AES
 OBJS += $(AESOBJS)
 endif
@@ -1224,6 +1249,9 @@
 ifdef NEED_TLS_PRF_SHA256
 SHA256OBJS += src/crypto/sha256-tlsprf.c
 endif
+ifdef NEED_HMAC_SHA256_KDF
+SHA256OBJS += src/crypto/sha256-kdf.c
+endif
 OBJS += $(SHA256OBJS)
 endif
 
@@ -1368,14 +1396,11 @@
 endif
 
 ifdef NEED_SME
-NEED_80211_COMMON=y
 OBJS += sme.c
 L_CFLAGS += -DCONFIG_SME
 endif
 
-ifdef NEED_80211_COMMON
 OBJS += src/common/ieee802_11_common.c
-endif
 
 ifdef NEED_EAP_COMMON
 OBJS += src/eap_common/eap_common.c
@@ -1500,26 +1525,6 @@
 ifdef CONFIG_DRIVER_NL80211
 OBJS_priv += src/common/ieee802_11_common.c
 endif
-ifdef CONFIG_DRIVER_TEST
-OBJS_priv += $(SHA1OBJS)
-OBJS_priv += $(MD5OBJS)
-ifeq ($(CONFIG_TLS), openssl)
-OBJS_priv += src/crypto/crypto_openssl.c
-endif
-ifeq ($(CONFIG_TLS), gnutls)
-OBJS_priv += src/crypto/crypto_gnutls.c
-endif
-ifeq ($(CONFIG_TLS), nss)
-OBJS_priv += src/crypto/crypto_nss.c
-endif
-ifeq ($(CONFIG_TLS), internal)
-ifeq ($(CONFIG_CRYPTO), libtomcrypt)
-OBJS_priv += src/crypto/crypto_libtomcrypt.c
-else
-OBJS_priv += src/crypto/crypto_internal.c
-endif
-endif
-endif # CONFIG_DRIVER_TEST
 OBJS += src/l2_packet/l2_packet_privsep.c
 OBJS += src/drivers/driver_privsep.c
 EXTRA_progs += wpa_priv
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 8f7c23f..06ba18f 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -80,6 +80,7 @@
 OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
 OBJS_c += ../src/utils/wpa_debug.o
 OBJS_c += ../src/utils/common.o
+OBJS += wmm_ac.o
 
 ifndef CONFIG_OS
 ifdef CONFIG_NATIVE_WINDOWS
@@ -185,6 +186,12 @@
 CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
 endif
 
+ifdef CONFIG_SUITEB
+CFLAGS += -DCONFIG_SUITEB
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
 ifdef CONFIG_IEEE80211W
 CFLAGS += -DCONFIG_IEEE80211W
 NEED_SHA256=y
@@ -194,11 +201,24 @@
 ifdef CONFIG_IEEE80211R
 CFLAGS += -DCONFIG_IEEE80211R
 OBJS += ../src/rsn_supp/wpa_ft.o
-NEED_80211_COMMON=y
 NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_MESH
+NEED_80211_COMMON=y
+NEED_SHA256=y
+NEED_AES_SIV=y
+NEED_AES_OMAC1=y
+NEED_AES_CTR=y
+CONFIG_SAE=y
+CONFIG_AP=y
+CFLAGS += -DCONFIG_MESH
+OBJS += mesh.o
+OBJS += mesh_mpm.o
+OBJS += mesh_rsn.o
+endif
+
 ifdef CONFIG_SAE
 CFLAGS += -DCONFIG_SAE
 OBJS += ../src/common/sae.o
@@ -264,7 +284,6 @@
 CFLAGS += -DCONFIG_P2P
 NEED_GAS=y
 NEED_OFFCHANNEL=y
-NEED_80211_COMMON=y
 CONFIG_WPS=y
 CONFIG_AP=y
 ifdef CONFIG_P2P_STRICT
@@ -329,6 +348,12 @@
 LIBS += -lpcap
 endif
 
+ifdef CONFIG_ERP
+CFLAGS += -DCONFIG_ERP
+NEED_SHA256=y
+NEED_HMAC_SHA256_KDF=y
+endif
+
 ifdef CONFIG_EAP_TLS
 # EAP-TLS
 ifeq ($(CONFIG_EAP_TLS), dyn)
@@ -635,7 +660,6 @@
 NEED_DH_GROUPS=y
 NEED_SHA256=y
 NEED_BASE64=y
-NEED_80211_COMMON=y
 NEED_AES_CBC=y
 NEED_MODEXP=y
 
@@ -757,7 +781,6 @@
 endif
 
 ifdef CONFIG_AP
-NEED_80211_COMMON=y
 NEED_EAP_COMMON=y
 NEED_RSN_AUTHENTICATOR=y
 CFLAGS += -DCONFIG_AP
@@ -781,6 +804,7 @@
 OBJS += ../src/ap/drv_callbacks.o
 OBJS += ../src/ap/ap_drv_ops.o
 OBJS += ../src/ap/beacon.o
+OBJS += ../src/ap/bss_load.o
 OBJS += ../src/ap/eap_user_db.o
 ifdef CONFIG_IEEE80211N
 OBJS += ../src/ap/ieee802_11_ht.o
@@ -1149,6 +1173,9 @@
 AESOBJS += ../src/crypto/aes-omac1.o
 endif
 endif
+ifdef NEED_AES_SIV
+AESOBJS += ../src/crypto/aes-siv.o
+endif
 ifdef NEED_AES_WRAP
 NEED_AES_ENC=y
 AESOBJS += ../src/crypto/aes-wrap.o
@@ -1235,6 +1262,9 @@
 ifdef NEED_TLS_PRF_SHA256
 SHA256OBJS += ../src/crypto/sha256-tlsprf.o
 endif
+ifdef NEED_HMAC_SHA256_KDF
+OBJS += ../src/crypto/sha256-kdf.o
+endif
 OBJS += $(SHA256OBJS)
 endif
 
@@ -1386,14 +1416,11 @@
 endif
 
 ifdef NEED_SME
-NEED_80211_COMMON=y
 OBJS += sme.o
 CFLAGS += -DCONFIG_SME
 endif
 
-ifdef NEED_80211_COMMON
 OBJS += ../src/common/ieee802_11_common.o
-endif
 
 ifdef NEED_EAP_COMMON
 OBJS += ../src/eap_common/eap_common.o
@@ -1539,26 +1566,6 @@
 ifdef CONFIG_DRIVER_NL80211
 OBJS_priv += ../src/common/ieee802_11_common.o
 endif
-ifdef CONFIG_DRIVER_TEST
-OBJS_priv += $(SHA1OBJS)
-OBJS_priv += $(MD5OBJS)
-ifeq ($(CONFIG_TLS), openssl)
-OBJS_priv += ../src/crypto/crypto_openssl.o
-endif
-ifeq ($(CONFIG_TLS), gnutls)
-OBJS_priv += ../src/crypto/crypto_gnutls.o
-endif
-ifeq ($(CONFIG_TLS), nss)
-OBJS_priv += ../src/crypto/crypto_nss.o
-endif
-ifeq ($(CONFIG_TLS), internal)
-ifeq ($(CONFIG_CRYPTO), libtomcrypt)
-OBJS_priv += ../src/crypto/crypto_libtomcrypt.o
-else
-OBJS_priv += ../src/crypto/crypto_internal.o
-endif
-endif
-endif # CONFIG_DRIVER_TEST
 OBJS += ../src/l2_packet/l2_packet_privsep.o
 OBJS += ../src/drivers/driver_privsep.o
 EXTRA_progs += wpa_priv
@@ -1588,6 +1595,10 @@
 Q=
 E=true
 endif
+ifeq ($(QUIET), 1)
+Q=@
+E=true
+endif
 
 dynamic_eap_methods: $(EAPDYN)
 
@@ -1680,10 +1691,12 @@
 endif
 
 %.service: %.service.in
-	sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+	$(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+	@$(E) "  sed" $<
 
 %@.service: %.service.arg.in
-	sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+	$(Q)sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+	@$(E) "  sed" $<
 
 wpa_supplicant.exe: wpa_supplicant
 	mv -f $< $@
diff --git a/wpa_supplicant/android.config b/wpa_supplicant/android.config
index 3ed734d..8d27bb2 100644
--- a/wpa_supplicant/android.config
+++ b/wpa_supplicant/android.config
@@ -55,9 +55,6 @@
 # wpa_supplicant.
 # CONFIG_USE_NDISUIO=y
 
-# Driver interface for development testing
-#CONFIG_DRIVER_TEST=y
-
 # Driver interface for wired Ethernet drivers
 #CONFIG_DRIVER_WIRED=y
 
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 7c93498..2ebc7f6 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -75,24 +75,10 @@
 #endif /* CONFIG_IEEE80211N */
 
 
-static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
-				  struct wpa_ssid *ssid,
-				  struct hostapd_config *conf)
+void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+			       struct wpa_ssid *ssid,
+			       struct hostapd_config *conf)
 {
-	struct hostapd_bss_config *bss = conf->bss[0];
-
-	conf->driver = wpa_s->driver;
-
-	os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
-
-	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;
 	 * drop to 11b if driver does not support 11g */
 
@@ -155,6 +141,28 @@
 		}
 	}
 #endif /* CONFIG_IEEE80211N */
+}
+
+
+static int wpa_supplicant_conf_ap(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid,
+				  struct hostapd_config *conf)
+{
+	struct hostapd_bss_config *bss = conf->bss[0];
+
+	conf->driver = wpa_s->driver;
+
+	os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
+
+	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;
+	}
+
+	wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
 
 #ifdef CONFIG_P2P
 	if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G &&
@@ -217,7 +225,7 @@
 	bss->wpa_key_mgmt = ssid->key_mgmt;
 	bss->wpa_pairwise = ssid->pairwise_cipher;
 	if (ssid->psk_set) {
-		os_free(bss->ssid.wpa_psk);
+		bin_clear_free(bss->ssid.wpa_psk, sizeof(*bss->ssid.wpa_psk));
 		bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
 		if (bss->ssid.wpa_psk == NULL)
 			return -1;
@@ -317,7 +325,8 @@
 	    bss->ssid.security_policy != SECURITY_PLAINTEXT)
 		goto no_wps;
 	if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
-	    (!(bss->rsn_pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
+	    (!(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ||
+	     !(bss->wpa & 2)))
 		goto no_wps; /* WPS2 does not allow WPA/TKIP-only
 			      * configuration */
 	bss->eap_server = 1;
@@ -555,6 +564,7 @@
 		return -1;
 	hapd_iface->owner = wpa_s;
 	hapd_iface->drv_flags = wpa_s->drv_flags;
+	hapd_iface->smps_modes = wpa_s->drv_smps_modes;
 	hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
 	hapd_iface->extended_capa = wpa_s->extended_capa;
 	hapd_iface->extended_capa_mask = wpa_s->extended_capa_mask;
@@ -629,6 +639,10 @@
 #endif /* CONFIG_P2P */
 		hapd_iface->bss[i]->setup_complete_cb = wpas_ap_configured_cb;
 		hapd_iface->bss[i]->setup_complete_cb_ctx = wpa_s;
+#ifdef CONFIG_TESTING_OPTIONS
+		hapd_iface->bss[i]->ext_eapol_frame_io =
+			wpa_s->ext_eapol_frame_io;
+#endif /* CONFIG_TESTING_OPTIONS */
 	}
 
 	os_memcpy(hapd_iface->bss[0]->own_addr, wpa_s->own_addr, ETH_ALEN);
@@ -798,9 +812,14 @@
 	if (pin == NULL) {
 		unsigned int rpin = wps_generate_pin();
 		ret_len = os_snprintf(buf, buflen, "%08d", rpin);
+		if (os_snprintf_error(buflen, ret_len))
+			return -1;
 		pin = buf;
-	} else
+	} else if (buf) {
 		ret_len = os_snprintf(buf, buflen, "%s", pin);
+		if (os_snprintf_error(buflen, ret_len))
+			return -1;
+	}
 
 	ret = hostapd_wps_add_pin(wpa_s->ap_iface->bss[0], bssid, "any", pin,
 				  timeout);
@@ -890,7 +909,7 @@
 		return -1;
 	hapd = wpa_s->ap_iface->bss[0];
 	ret = os_snprintf(pin_txt, sizeof(pin_txt), "%s", pin);
-	if (ret < 0 || ret >= (int) sizeof(pin_txt))
+	if (os_snprintf_error(sizeof(pin_txt), ret))
 		return -1;
 	os_free(hapd->conf->ap_pin);
 	hapd->conf->ap_pin = os_strdup(pin_txt);
@@ -975,30 +994,45 @@
 int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
 			    char *buf, size_t buflen)
 {
-	if (wpa_s->ap_iface == NULL)
+	struct hostapd_data *hapd;
+
+	if (wpa_s->ap_iface)
+		hapd = wpa_s->ap_iface->bss[0];
+	else if (wpa_s->ifmsh)
+		hapd = wpa_s->ifmsh->bss[0];
+	else
 		return -1;
-	return hostapd_ctrl_iface_sta_first(wpa_s->ap_iface->bss[0],
-					    buf, buflen);
+	return hostapd_ctrl_iface_sta_first(hapd, buf, buflen);
 }
 
 
 int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
 		      char *buf, size_t buflen)
 {
-	if (wpa_s->ap_iface == NULL)
+	struct hostapd_data *hapd;
+
+	if (wpa_s->ap_iface)
+		hapd = wpa_s->ap_iface->bss[0];
+	else if (wpa_s->ifmsh)
+		hapd = wpa_s->ifmsh->bss[0];
+	else
 		return -1;
-	return hostapd_ctrl_iface_sta(wpa_s->ap_iface->bss[0], txtaddr,
-				      buf, buflen);
+	return hostapd_ctrl_iface_sta(hapd, txtaddr, buf, buflen);
 }
 
 
 int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
 			   char *buf, size_t buflen)
 {
-	if (wpa_s->ap_iface == NULL)
+	struct hostapd_data *hapd;
+
+	if (wpa_s->ap_iface)
+		hapd = wpa_s->ap_iface->bss[0];
+	else if (wpa_s->ifmsh)
+		hapd = wpa_s->ifmsh->bss[0];
+	else
 		return -1;
-	return hostapd_ctrl_iface_sta_next(wpa_s->ap_iface->bss[0], txtaddr,
-					   buf, buflen);
+	return hostapd_ctrl_iface_sta_next(hapd, txtaddr, buf, buflen);
 }
 
 
@@ -1044,7 +1078,7 @@
 			  wpa_cipher_txt(conf->wpa_group),
 			  wpa_key_mgmt_txt(conf->wpa_key_mgmt,
 					   conf->wpa));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 	return pos - buf;
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index 8aa5ffa..4d80c7a 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -75,4 +75,9 @@
 int wpas_ap_wps_add_nfc_pw(struct wpa_supplicant *wpa_s, u16 pw_id,
 			   const struct wpabuf *pw, const u8 *pubkey_hash);
 
+struct hostapd_config;
+void wpa_supplicant_conf_ap_ht(struct wpa_supplicant *wpa_s,
+			       struct wpa_ssid *ssid,
+			       struct hostapd_config *conf);
+
 #endif /* AP_H */
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index 6a92b73..a320cc4 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -294,7 +294,7 @@
 			int ret;
 			ret = os_snprintf(pos, msg + sizeof(msg) - pos, " %d",
 					  freqs[i]);
-			if (ret < 0 || ret >= msg + sizeof(msg) - pos)
+			if (os_snprintf_error(msg + sizeof(msg) - pos, ret))
 				break;
 			pos += ret;
 		}
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 1de51e5..1798439 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -306,8 +306,9 @@
 static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
 	return bss == wpa_s->current_bss ||
-		os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
-		os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
+		(!is_zero_ether_addr(bss->bssid) &&
+		 (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
+		  os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0));
 }
 
 
@@ -620,7 +621,7 @@
 			     struct wpa_scan_res *res,
 			     struct os_reltime *fetch_time)
 {
-	const u8 *ssid, *p2p;
+	const u8 *ssid, *p2p, *mesh;
 	struct wpa_bss *bss;
 
 	if (wpa_s->conf->ignore_old_scan_res) {
@@ -670,6 +671,11 @@
 
 	/* TODO: add option for ignoring BSSes we are not interested in
 	 * (to save memory) */
+
+	mesh = wpa_scan_get_ie(res, WLAN_EID_MESH_ID);
+	if (mesh && mesh[1] <= 32)
+		ssid = mesh;
+
 	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
 	if (bss == NULL)
 		bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res, fetch_time);
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index b7f259b..4ebf684 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -225,7 +225,7 @@
 	if (value == NULL)
 		return NULL;
 	res = os_snprintf(value, 20, "%d", *src);
-	if (res < 0 || res >= 20) {
+	if (os_snprintf_error(20, res)) {
 		os_free(value);
 		return NULL;
 	}
@@ -270,7 +270,7 @@
 	if (value == NULL)
 		return NULL;
 	res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
-	if (res < 0 || res >= 20) {
+	if (os_snprintf_error(20, res)) {
 		os_free(value);
 		return NULL;
 	}
@@ -358,9 +358,15 @@
 	if (ssid->ext_psk) {
 		size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
 		char *buf = os_malloc(len);
+		int res;
+
 		if (buf == NULL)
 			return NULL;
-		os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+		res = os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+		if (os_snprintf_error(len, res)) {
+			os_free(buf);
+			buf = NULL;
+		}
 		return buf;
 	}
 #endif /* CONFIG_EXT_PASSWORD */
@@ -446,7 +452,7 @@
 	if (ssid->proto & WPA_PROTO_WPA) {
 		ret = os_snprintf(pos, end - pos, "%sWPA",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return buf;
 		pos += ret;
 	}
@@ -454,7 +460,7 @@
 	if (ssid->proto & WPA_PROTO_RSN) {
 		ret = os_snprintf(pos, end - pos, "%sRSN",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return buf;
 		pos += ret;
 	}
@@ -462,7 +468,7 @@
 	if (ssid->proto & WPA_PROTO_OSEN) {
 		ret = os_snprintf(pos, end - pos, "%sOSEN",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return buf;
 		pos += ret;
 	}
@@ -535,6 +541,8 @@
 		else if (os_strcmp(start, "OSEN") == 0)
 			val |= WPA_KEY_MGMT_OSEN;
 #endif /* CONFIG_HS20 */
+		else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
 		else {
 			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
 				   line, start);
@@ -574,7 +582,7 @@
 	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
 		ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -584,7 +592,7 @@
 	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
 		ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -594,7 +602,7 @@
 	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
 		ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -604,7 +612,7 @@
 	if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
 		ret = os_snprintf(pos, end - pos, "%sNONE",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -614,7 +622,7 @@
 	if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
 		ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -625,7 +633,7 @@
 	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK) {
 		ret = os_snprintf(pos, end - pos, "%sFT-PSK",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -635,7 +643,7 @@
 	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
 		ret = os_snprintf(pos, end - pos, "%sFT-EAP",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -647,7 +655,7 @@
 	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
 		ret = os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -657,7 +665,7 @@
 	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
 		ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -669,7 +677,7 @@
 	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
 		ret = os_snprintf(pos, end - pos, "%sWPS",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -677,6 +685,50 @@
 	}
 #endif /* CONFIG_WPS */
 
+#ifdef CONFIG_SAE
+	if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+		ret = os_snprintf(pos, end - pos, "%sSAE",
+				  pos == buf ? "" : " ");
+		if (os_snprintf_error(end - pos, ret)) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+		ret = os_snprintf(pos, end - pos, "%sFT-SAE",
+				  pos == buf ? "" : " ");
+		if (os_snprintf_error(end - pos, ret)) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_HS20
+	if (ssid->key_mgmt & WPA_KEY_MGMT_OSEN) {
+		ret = os_snprintf(pos, end - pos, "%sOSEN",
+				  pos == buf ? "" : " ");
+		if (os_snprintf_error(end - pos, ret)) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+#endif /* CONFIG_HS20 */
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-EAP-SUITE-B",
+				  pos == buf ? "" : " ");
+		if (os_snprintf_error(end - pos, ret)) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
 	if (pos == buf) {
 		os_free(buf);
 		buf = NULL;
@@ -846,7 +898,7 @@
 	if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
 		ret = os_snprintf(pos, end - pos, "%sOPEN",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -856,7 +908,7 @@
 	if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
 		ret = os_snprintf(pos, end - pos, "%sSHARED",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -866,7 +918,7 @@
 	if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
 		ret = os_snprintf(pos, end - pos, "%sLEAP",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -987,7 +1039,7 @@
 	for (i = 0; freqs[i]; i++) {
 		ret = os_snprintf(pos, end - pos, "%s%u",
 				  i == 0 ? "" : " ", freqs[i]);
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			end[-1] = '\0';
 			return buf;
 		}
@@ -1110,7 +1162,7 @@
 		if (name) {
 			ret = os_snprintf(pos, end - pos, "%s%s",
 					  pos == buf ? "" : " ", name);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				break;
 			pos += ret;
 		}
@@ -1264,7 +1316,7 @@
 	os_memcpy(key, buf, *len);
 	str_clear_free(buf);
 	res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
-	if (res >= 0 && (size_t) res < sizeof(title))
+	if (!os_snprintf_error(sizeof(title), res))
 		wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
 	return 0;
 }
@@ -1387,7 +1439,7 @@
 	if (value == NULL)
 		return NULL;
 	res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->go_p2p_dev_addr));
-	if (res < 0 || res >= 20) {
+	if (os_snprintf_error(20, res)) {
 		os_free(value);
 		return NULL;
 	}
@@ -1472,7 +1524,7 @@
 		res = os_snprintf(pos, end - pos, MACSTR " ",
 				  MAC2STR(ssid->p2p_client_list +
 					  (i - 1) * ETH_ALEN));
-		if (res < 0 || res >= end - pos) {
+		if (os_snprintf_error(end - pos, res)) {
 			os_free(value);
 			return NULL;
 		}
@@ -1542,6 +1594,97 @@
 
 #endif /* CONFIG_P2P */
 
+
+#ifdef CONFIG_MESH
+
+static int wpa_config_parse_mesh_ht_mode(const struct parse_data *data,
+					 struct wpa_ssid *ssid, int line,
+					 const char *value)
+{
+	int htval = 0;
+
+	if (os_strcmp(value, "NOHT") == 0)
+		htval = CHAN_NO_HT;
+	else if (os_strcmp(value, "HT20") == 0)
+		htval = CHAN_HT20;
+	else if (os_strcmp(value, "HT40-") == 0)
+		htval = CHAN_HT40MINUS;
+	else if (os_strcmp(value, "HT40+") == 0)
+		htval = CHAN_HT40PLUS;
+	else {
+		wpa_printf(MSG_ERROR,
+			   "Line %d: no ht_mode configured.", line);
+		return -1;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "mesh_ht_mode: 0x%x", htval);
+	ssid->mesh_ht_mode = htval;
+	return 0;
+}
+
+
+static int wpa_config_parse_mesh_basic_rates(const struct parse_data *data,
+					     struct wpa_ssid *ssid, int line,
+					     const char *value)
+{
+	int *rates = wpa_config_parse_int_array(value);
+
+	if (rates == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid mesh_basic_rates '%s'",
+			   line, value);
+		return -1;
+	}
+	if (rates[0] == 0) {
+		os_free(rates);
+		rates = NULL;
+	}
+
+	os_free(ssid->mesh_basic_rates);
+	ssid->mesh_basic_rates = rates;
+
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+
+static char * wpa_config_write_mesh_ht_mode(const struct parse_data *data,
+					    struct wpa_ssid *ssid)
+{
+	char *val;
+
+	switch (ssid->mesh_ht_mode) {
+	default:
+		val = NULL;
+		break;
+	case CHAN_NO_HT:
+		val = "NOHT";
+		break;
+	case CHAN_HT20:
+		val = "HT20";
+		break;
+	case CHAN_HT40MINUS:
+		val = "HT40-";
+		break;
+	case CHAN_HT40PLUS:
+		val = "HT40+";
+		break;
+	}
+	return val ? os_strdup(val) : NULL;
+}
+
+
+static char * wpa_config_write_mesh_basic_rates(const struct parse_data *data,
+						struct wpa_ssid *ssid)
+{
+	return wpa_config_write_freqs(data, ssid->mesh_basic_rates);
+}
+
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_MESH */
+
+
 /* Helper macros for network block parser */
 
 #ifdef OFFSET
@@ -1682,6 +1825,8 @@
 	{ INTe(engine2) },
 	{ INT(eapol_flags) },
 	{ INTe(sim_num) },
+	{ STRe(openssl_ciphers) },
+	{ INTe(erp) },
 #endif /* IEEE8021X_EAPOL */
 	{ FUNC_KEY(wep_key0) },
 	{ FUNC_KEY(wep_key1) },
@@ -1695,7 +1840,12 @@
 	{ INTe(fragment_size) },
 	{ INTe(ocsp) },
 #endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+	{ INT_RANGE(mode, 0, 5) },
+	{ INT_RANGE(no_auto_peer, 0, 1) },
+#else /* CONFIG_MESH */
 	{ INT_RANGE(mode, 0, 4) },
+#endif /* CONFIG_MESH */
 	{ INT_RANGE(proactive_key_caching, 0, 1) },
 	{ INT_RANGE(disabled, 0, 2) },
 	{ STR(id_str) },
@@ -1705,6 +1855,14 @@
 	{ INT_RANGE(peerkey, 0, 1) },
 	{ INT_RANGE(mixed_cell, 0, 1) },
 	{ INT_RANGE(frequency, 0, 65000) },
+#ifdef CONFIG_MESH
+	{ FUNC(mesh_ht_mode) },
+	{ FUNC(mesh_basic_rates) },
+	{ INT(dot11MeshMaxRetries) },
+	{ INT(dot11MeshRetryTimeout) },
+	{ INT(dot11MeshConfirmTimeout) },
+	{ INT(dot11MeshHoldingTimeout) },
+#endif /* CONFIG_MESH */
 	{ INT(wpa_ptk_rekey) },
 	{ STR(bgscan) },
 	{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
@@ -1903,6 +2061,7 @@
 	os_free(eap->pac_file);
 	bin_clear_free(eap->new_password, eap->new_password_len);
 	str_clear_free(eap->external_sim_resp);
+	os_free(eap->openssl_ciphers);
 }
 #endif /* IEEE8021X_EAPOL */
 
@@ -1919,7 +2078,6 @@
 	struct psk_list_entry *psk;
 
 	os_free(ssid->ssid);
-	os_memset(ssid->psk, 0, sizeof(ssid->psk));
 	str_clear_free(ssid->passphrase);
 	os_free(ssid->ext_psk);
 #ifdef IEEE8021X_EAPOL
@@ -1933,12 +2091,15 @@
 #ifdef CONFIG_HT_OVERRIDES
 	os_free(ssid->ht_mcs);
 #endif /* CONFIG_HT_OVERRIDES */
+#ifdef CONFIG_MESH
+	os_free(ssid->mesh_basic_rates);
+#endif /* CONFIG_MESH */
 	while ((psk = dl_list_first(&ssid->psk_list, struct psk_list_entry,
 				    list))) {
 		dl_list_del(&psk->list);
-		os_free(psk);
+		bin_clear_free(psk, sizeof(*psk));
 	}
-	os_free(ssid);
+	bin_clear_free(ssid, sizeof(*ssid));
 }
 
 
@@ -2000,6 +2161,7 @@
 {
 	struct wpa_ssid *ssid, *prev = NULL;
 	struct wpa_cred *cred, *cprev;
+	int i;
 
 	ssid = config->ssid;
 	while (ssid) {
@@ -2018,11 +2180,14 @@
 	wpa_config_flush_blobs(config);
 
 	wpabuf_free(config->wps_vendor_ext_m1);
+	for (i = 0; i < MAX_WPS_VENDOR_EXT; i++)
+		wpabuf_free(config->wps_vendor_ext[i]);
 	os_free(config->ctrl_interface);
 	os_free(config->ctrl_interface_group);
 	os_free(config->opensc_engine_path);
 	os_free(config->pkcs11_engine_path);
 	os_free(config->pkcs11_module_path);
+	os_free(config->openssl_ciphers);
 	os_free(config->pcsc_reader);
 	str_clear_free(config->pcsc_pin);
 	os_free(config->driver_param);
@@ -2181,6 +2346,13 @@
 	ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
 	ssid->eap.sim_num = DEFAULT_USER_SELECTED_SIM;
 #endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_MESH
+	ssid->mesh_ht_mode = DEFAULT_MESH_HT_MODE;
+	ssid->dot11MeshMaxRetries = DEFAULT_MESH_MAX_RETRIES;
+	ssid->dot11MeshRetryTimeout = DEFAULT_MESH_RETRY_TIMEOUT;
+	ssid->dot11MeshConfirmTimeout = DEFAULT_MESH_CONFIRM_TIMEOUT;
+	ssid->dot11MeshHoldingTimeout = DEFAULT_MESH_HOLDING_TIMEOUT;
+#endif /* CONFIG_MESH */
 #ifdef CONFIG_HT_OVERRIDES
 	ssid->disable_ht = DEFAULT_DISABLE_HT;
 	ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
@@ -2831,12 +3003,18 @@
 
 static char * alloc_int_str(int val)
 {
+	const unsigned int bufsize = 20;
 	char *buf;
+	int res;
 
-	buf = os_malloc(20);
+	buf = os_malloc(bufsize);
 	if (buf == NULL)
 		return NULL;
-	os_snprintf(buf, 20, "%d", val);
+	res = os_snprintf(buf, bufsize, "%d", val);
+	if (os_snprintf_error(bufsize, res)) {
+		os_free(buf);
+		buf = NULL;
+	}
 	return buf;
 }
 
@@ -2907,7 +3085,7 @@
 			ret = os_snprintf(pos, end - pos, "%s%u",
 					  i > 0 ? "\n" : "",
 					  cred->req_conn_capab_proto[i]);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return buf;
 			pos += ret;
 
@@ -2919,7 +3097,7 @@
 							  "%s%d",
 							  j > 0 ? "," : ":",
 							  ports[j]);
-					if (ret < 0 || ret >= end - pos)
+					if (os_snprintf_error(end - pos, ret))
 						return buf;
 					pos += ret;
 				}
@@ -2988,7 +3166,7 @@
 		for (i = 0; i < cred->num_domain; i++) {
 			ret = os_snprintf(pos, end - pos, "%s%s",
 					  i > 0 ? "\n" : "", cred->domain[i]);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return buf;
 			pos += ret;
 		}
@@ -3053,7 +3231,7 @@
 			ret = os_snprintf(pos, end - pos, "%s%s",
 					  i > 0 ? "\n" : "",
 					  wpa_ssid_txt(e->ssid, e->ssid_len));
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return buf;
 			pos += ret;
 		}
@@ -3083,7 +3261,7 @@
 					  i > 0 ? "\n" : "",
 					  p->fqdn, p->exact_match, p->priority,
 					  p->country);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return buf;
 			pos += ret;
 		}
@@ -3273,6 +3451,8 @@
 		return NULL;
 	config->eapol_version = DEFAULT_EAPOL_VERSION;
 	config->ap_scan = DEFAULT_AP_SCAN;
+	config->user_mpm = DEFAULT_USER_MPM;
+	config->max_peer_links = DEFAULT_MAX_PEER_LINKS;
 	config->fast_reauth = DEFAULT_FAST_REAUTH;
 	config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
 	config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
@@ -3290,6 +3470,7 @@
 	config->wmm_ac_params[3] = ac_vo;
 	config->p2p_search_delay = DEFAULT_P2P_SEARCH_DELAY;
 	config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
+	config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
 
 	if (ctrl_interface)
 		config->ctrl_interface = os_strdup(ctrl_interface);
@@ -3818,11 +3999,16 @@
 #endif /* CONFIG_MACSEC */
 	{ INT(ap_scan), 0 },
 	{ FUNC(bgscan), 0 },
+#ifdef CONFIG_MESH
+	{ INT(user_mpm), 0 },
+	{ INT_RANGE(max_peer_links, 0, 255), 0 },
+#endif /* CONFIG_MESH */
 	{ INT(disable_scan_offload), 0 },
 	{ INT(fast_reauth), 0 },
 	{ STR(opensc_engine_path), 0 },
 	{ STR(pkcs11_engine_path), 0 },
 	{ STR(pkcs11_module_path), 0 },
+	{ STR(openssl_ciphers), 0 },
 	{ STR(pcsc_reader), 0 },
 	{ STR(pcsc_pin), 0 },
 	{ INT(external_sim), 0 },
@@ -3915,6 +4101,7 @@
 	{ INT(mac_addr), 0 },
 	{ INT(rand_addr_lifetime), 0 },
 	{ INT(preassoc_mac_addr), 0 },
+	{ INT(key_mgmt_offload), 0},
 };
 
 #undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 3fd4192..b3f7eef 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -15,6 +15,8 @@
 #else /* CONFIG_NO_SCAN_PROCESSING */
 #define DEFAULT_AP_SCAN 1
 #endif /* CONFIG_NO_SCAN_PROCESSING */
+#define DEFAULT_USER_MPM 1
+#define DEFAULT_MAX_PEER_LINKS 99
 #define DEFAULT_FAST_REAUTH 1
 #define DEFAULT_P2P_GO_INTENT 7
 #define DEFAULT_P2P_INTRA_BSS 1
@@ -28,6 +30,7 @@
 #define DEFAULT_SCAN_CUR_FREQ 0
 #define DEFAULT_P2P_SEARCH_DELAY 500
 #define DEFAULT_RAND_ADDR_LIFETIME 60
+#define DEFAULT_KEY_MGMT_OFFLOAD 1
 
 #include "config_ssid.h"
 #include "wps/wps.h"
@@ -517,6 +520,15 @@
 	char *pkcs11_module_path;
 
 	/**
+	 * openssl_ciphers - OpenSSL cipher string
+	 *
+	 * This is an OpenSSL specific configuration option for configuring the
+	 * default ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the
+	 * default.
+	 */
+	char *openssl_ciphers;
+
+	/**
 	 * pcsc_reader - PC/SC reader name prefix
 	 *
 	 * If not %NULL, PC/SC reader with a name that matches this prefix is
@@ -1079,6 +1091,34 @@
 	 * 2 = like 1, but maintain OUI (with local admin bit set)
 	 */
 	int preassoc_mac_addr;
+
+	/**
+	 * key_mgmt_offload - Use key management offload
+	 *
+	 * Key management offload should be used if the device supports it.
+	 * Key management offload is the capability of a device operating as
+	 * a station to do the exchange necessary to establish temporal keys
+	 * during initial RSN connection, after roaming, or during a PTK
+	 * rekeying operation.
+	 */
+	int key_mgmt_offload;
+
+	/**
+	 * user_mpm - MPM residency
+	 *
+	 * 0: MPM lives in driver.
+	 * 1: wpa_supplicant handles peering and station allocation.
+	 *
+	 * If AMPE or SAE is enabled, the MPM is always in userspace.
+	 */
+	int user_mpm;
+
+	/**
+	 * max_peer_links - Maximum number of peer links
+	 *
+	 * Maximum number of mesh peering currently maintained by the STA.
+	 */
+	int max_peer_links;
 };
 
 
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 5c8f045..5c8b24b 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -143,6 +143,15 @@
 		ssid->group_cipher &= ~WPA_CIPHER_CCMP;
 	}
 
+	if (ssid->mode == WPAS_MODE_MESH &&
+	    (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
+	    ssid->key_mgmt != WPA_KEY_MGMT_SAE)) {
+		wpa_printf(MSG_ERROR,
+			   "Line %d: key_mgmt for mesh network should be open or SAE",
+			   line);
+		errors++;
+	}
+
 	return errors;
 }
 
@@ -599,7 +608,7 @@
 	int res;
 
 	res = os_snprintf(field, sizeof(field), "wep_key%d", idx);
-	if (res < 0 || (size_t) res >= sizeof(field))
+	if (os_snprintf_error(sizeof(field), res))
 		return;
 	value = wpa_config_get(ssid, field);
 	if (value) {
@@ -707,6 +716,7 @@
 	INTe(engine);
 	INTe(engine2);
 	INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
+	INTe(erp);
 #endif /* IEEE8021X_EAPOL */
 	for (i = 0; i < 4; i++)
 		write_wep_key(f, i, ssid);
@@ -743,6 +753,14 @@
 	INT(update_identifier);
 #endif /* CONFIG_HS20 */
 	write_int(f, "mac_addr", ssid->mac_addr, -1);
+#ifdef CONFIG_MESH
+	STR(mesh_ht_mode);
+	STR(mesh_basic_rates);
+	INT_DEF(dot11MeshMaxRetries, DEFAULT_MESH_MAX_RETRIES);
+	INT_DEF(dot11MeshRetryTimeout, DEFAULT_MESH_RETRY_TIMEOUT);
+	INT_DEF(dot11MeshConfirmTimeout, DEFAULT_MESH_CONFIRM_TIMEOUT);
+	INT_DEF(dot11MeshHoldingTimeout, DEFAULT_MESH_HOLDING_TIMEOUT);
+#endif /* CONFIG_MESH */
 
 #undef STR
 #undef INT
@@ -938,6 +956,8 @@
 	if (config->pkcs11_module_path)
 		fprintf(f, "pkcs11_module_path=%s\n",
 			config->pkcs11_module_path);
+	if (config->openssl_ciphers)
+		fprintf(f, "openssl_ciphers=%s\n", config->openssl_ciphers);
 	if (config->pcsc_reader)
 		fprintf(f, "pcsc_reader=%s\n", config->pcsc_reader);
 	if (config->pcsc_pin)
@@ -1190,6 +1210,15 @@
 
 	if (config->preassoc_mac_addr)
 		fprintf(f, "preassoc_mac_addr=%d\n", config->preassoc_mac_addr);
+
+	if (config->key_mgmt_offload != DEFAULT_KEY_MGMT_OFFLOAD)
+		fprintf(f, "key_mgmt_offload=%u\n", config->key_mgmt_offload);
+
+	if (config->user_mpm != DEFAULT_USER_MPM)
+		fprintf(f, "user_mpm=%d\n", config->user_mpm);
+
+	if (config->max_peer_links != DEFAULT_MAX_PEER_LINKS)
+		fprintf(f, "max_peer_links=%d\n", config->max_peer_links);
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index f50b2d4..c5cd6e7 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -27,6 +27,11 @@
 #define DEFAULT_FRAGMENT_SIZE 1398
 
 #define DEFAULT_BG_SCAN_PERIOD -1
+#define DEFAULT_MESH_HT_MODE CHAN_UNDEFINED /* undefined */
+#define DEFAULT_MESH_MAX_RETRIES 2
+#define DEFAULT_MESH_RETRY_TIMEOUT 40
+#define DEFAULT_MESH_CONFIRM_TIMEOUT 40
+#define DEFAULT_MESH_HOLDING_TIMEOUT 40
 #define DEFAULT_DISABLE_HT 0
 #define DEFAULT_DISABLE_HT40 0
 #define DEFAULT_DISABLE_SGI 0
@@ -317,6 +322,8 @@
 	 * 4 = P2P Group Formation (used internally; not in configuration
 	 * files)
 	 *
+	 * 5 = Mesh
+	 *
 	 * Note: IBSS can only be used with key_mgmt NONE (plaintext and static
 	 * WEP) and WPA-PSK (with proto=RSN). In addition, key_mgmt=WPA-NONE
 	 * (fixed group key TKIP/CCMP) is available for backwards compatibility,
@@ -331,6 +338,7 @@
 		WPAS_MODE_AP = 2,
 		WPAS_MODE_P2P_GO = 3,
 		WPAS_MODE_P2P_GROUP_FORMATION = 4,
+		WPAS_MODE_MESH = 5,
 	} mode;
 
 	/**
@@ -400,6 +408,29 @@
 	 */
 	int frequency;
 
+	/**
+	 * mesh_ht_mode - definition of HT mode in mesh mode
+	 *
+	 * Use the given HT mode for mesh networks. The driver will
+	 * adapt to other stations if neccesary, but advertise the
+	 * configured HT mode (HT20/HT40-/HT40+/NOHT).
+	 */
+	int mesh_ht_mode;
+
+	/**
+	 * mesh_basic_rates - BSS Basic rate set for mesh network
+	 *
+	 */
+	int *mesh_basic_rates;
+
+	/**
+	 * Mesh network plink parameters
+	 */
+	int dot11MeshMaxRetries;
+	int dot11MeshRetryTimeout; /* msec */
+	int dot11MeshConfirmTimeout; /* msec */
+	int dot11MeshHoldingTimeout; /* msec */
+
 	int ht40;
 
 	int vht;
@@ -666,6 +697,14 @@
 	 * followed).
 	 */
 	int mac_addr;
+
+	/**
+	 * no_auto_peer - Do not automatically peer with compatible mesh peers
+	 *
+	 * When unset, the reception of a beacon from a another mesh peer in
+	 * this MBSS will trigger a peering attempt.
+	 */
+	int no_auto_peer;
 };
 
 #endif /* CONFIG_SSID_H */
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index a4c26e4..acdc90d 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -7,6 +7,10 @@
  */
 
 #include "utils/includes.h"
+#ifdef CONFIG_TESTING_OPTIONS
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#endif /* CONFIG_TESTING_OPTIONS */
 
 #include "utils/common.h"
 #include "utils/eloop.h"
@@ -15,6 +19,7 @@
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
+#include "ap/hostapd.h"
 #include "eap_peer/eap.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "rsn_supp/wpa.h"
@@ -42,6 +47,7 @@
 #include "wnm_sta.h"
 #include "offchannel.h"
 #include "drivers/driver.h"
+#include "mesh.h"
 
 static int wpa_supplicant_global_iface_list(struct wpa_global *global,
 					    char *buf, int len);
@@ -420,11 +426,30 @@
 #ifdef CONFIG_TESTING_OPTIONS
 	} else if (os_strcasecmp(cmd, "ext_mgmt_frame_handling") == 0) {
 		wpa_s->ext_mgmt_frame_handling = !!atoi(value);
+	} else if (os_strcasecmp(cmd, "ext_eapol_frame_io") == 0) {
+		wpa_s->ext_eapol_frame_io = !!atoi(value);
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface) {
+			wpa_s->ap_iface->bss[0]->ext_eapol_frame_io =
+				wpa_s->ext_eapol_frame_io;
+		}
+#endif /* CONFIG_AP */
+	} else if (os_strcasecmp(cmd, "extra_roc_dur") == 0) {
+		wpa_s->extra_roc_dur = atoi(value);
 #endif /* CONFIG_TESTING_OPTIONS */
 #ifndef CONFIG_NO_CONFIG_BLOBS
 	} else if (os_strcmp(cmd, "blob") == 0) {
 		ret = wpas_ctrl_set_blob(wpa_s, value);
 #endif /* CONFIG_NO_CONFIG_BLOBS */
+	} else if (os_strcasecmp(cmd, "setband") == 0) {
+		if (os_strcmp(value, "AUTO") == 0)
+			wpa_s->setband = WPA_SETBAND_AUTO;
+		else if (os_strcmp(value, "5G") == 0)
+			wpa_s->setband = WPA_SETBAND_5G;
+		else if (os_strcmp(value, "2G") == 0)
+			wpa_s->setband = WPA_SETBAND_2G;
+		else
+			ret = -1;
 	} else {
 		value[-1] = '=';
 		ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -459,9 +484,6 @@
 		else
 			enabled = wpa_s->global->wifi_display;
 		res = os_snprintf(buf, buflen, "%d", enabled);
-		if (res < 0 || (unsigned int) res >= buflen)
-			return -1;
-		return res;
 #endif /* CONFIG_WIFI_DISPLAY */
 #ifdef CONFIG_TESTING_GET_GTK
 	} else if (os_strcmp(cmd, "gtk") == 0) {
@@ -473,7 +495,7 @@
 #endif /* CONFIG_TESTING_GET_GTK */
 	}
 
-	if (res < 0 || (unsigned int) res >= buflen)
+	if (os_snprintf_error(buflen, res))
 		return -1;
 	return res;
 }
@@ -626,14 +648,162 @@
 			  (wpa_s->drv_flags &
 			   WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP ?
 			   "EXTERNAL" : "INTERNAL") : "UNSUPPORTED");
-	if (ret < 0 || (size_t) ret > buflen)
+	if (os_snprintf_error(buflen, ret))
 		return -1;
 	return ret;
 }
 
+
+static int wpa_supplicant_ctrl_iface_tdls_chan_switch(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 peer[ETH_ALEN];
+	struct hostapd_freq_params freq_params;
+	u8 oper_class;
+	char *pos, *end;
+
+	if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
+		wpa_printf(MSG_INFO,
+			   "tdls_chanswitch: Only supported with external setup");
+		return -1;
+	}
+
+	os_memset(&freq_params, 0, sizeof(freq_params));
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	oper_class = strtol(pos, &end, 10);
+	if (pos == end) {
+		wpa_printf(MSG_INFO,
+			   "tdls_chanswitch: Invalid op class provided");
+		return -1;
+	}
+
+	pos = end;
+	freq_params.freq = atoi(pos);
+	if (freq_params.freq == 0) {
+		wpa_printf(MSG_INFO, "tdls_chanswitch: Invalid freq provided");
+		return -1;
+	}
+
+#define SET_FREQ_SETTING(str) \
+	do { \
+		const char *pos2 = os_strstr(pos, " " #str "="); \
+		if (pos2) { \
+			pos2 += sizeof(" " #str "=") - 1; \
+			freq_params.str = atoi(pos2); \
+		} \
+	} while (0)
+
+	SET_FREQ_SETTING(center_freq1);
+	SET_FREQ_SETTING(center_freq2);
+	SET_FREQ_SETTING(bandwidth);
+	SET_FREQ_SETTING(sec_channel_offset);
+#undef SET_FREQ_SETTING
+
+	freq_params.ht_enabled = !!os_strstr(pos, " ht");
+	freq_params.vht_enabled = !!os_strstr(pos, " vht");
+
+	if (hwaddr_aton(cmd, peer)) {
+		wpa_printf(MSG_DEBUG,
+			   "CTRL_IFACE TDLS_CHAN_SWITCH: Invalid address '%s'",
+			   cmd);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CHAN_SWITCH " MACSTR
+		   " OP CLASS %d FREQ %d CENTER1 %d CENTER2 %d BW %d SEC_OFFSET %d%s%s",
+		   MAC2STR(peer), oper_class, freq_params.freq,
+		   freq_params.center_freq1, freq_params.center_freq2,
+		   freq_params.bandwidth, freq_params.sec_channel_offset,
+		   freq_params.ht_enabled ? " HT" : "",
+		   freq_params.vht_enabled ? " VHT" : "");
+
+	return wpa_tdls_enable_chan_switch(wpa_s->wpa, peer, oper_class,
+					   &freq_params);
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 peer[ETH_ALEN];
+
+	if (!wpa_tdls_is_external_setup(wpa_s->wpa)) {
+		wpa_printf(MSG_INFO,
+			   "tdls_chanswitch: Only supported with external setup");
+		return -1;
+	}
+
+	if (hwaddr_aton(cmd, peer)) {
+		wpa_printf(MSG_DEBUG,
+			   "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH: Invalid address '%s'",
+			   cmd);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_CANCEL_CHAN_SWITCH " MACSTR,
+		   MAC2STR(peer));
+
+	return wpa_tdls_disable_chan_switch(wpa_s->wpa, peer);
+}
+
 #endif /* CONFIG_TDLS */
 
 
+static int wmm_ac_ctrl_addts(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *token, *context = NULL;
+	struct wmm_ac_ts_setup_params params = {
+		.tsid = 0xff,
+		.direction = 0xff,
+	};
+
+	while ((token = str_token(cmd, " ", &context))) {
+		if (sscanf(token, "tsid=%i", &params.tsid) == 1 ||
+		    sscanf(token, "up=%i", &params.user_priority) == 1 ||
+		    sscanf(token, "nominal_msdu_size=%i",
+			   &params.nominal_msdu_size) == 1 ||
+		    sscanf(token, "mean_data_rate=%i",
+			   &params.mean_data_rate) == 1 ||
+		    sscanf(token, "min_phy_rate=%i",
+			   &params.minimum_phy_rate) == 1 ||
+		    sscanf(token, "sba=%i",
+			   &params.surplus_bandwidth_allowance) == 1)
+			continue;
+
+		if (os_strcasecmp(token, "downlink") == 0) {
+			params.direction = WMM_TSPEC_DIRECTION_DOWNLINK;
+		} else if (os_strcasecmp(token, "uplink") == 0) {
+			params.direction = WMM_TSPEC_DIRECTION_UPLINK;
+		} else if (os_strcasecmp(token, "bidi") == 0) {
+			params.direction = WMM_TSPEC_DIRECTION_BI_DIRECTIONAL;
+		} else if (os_strcasecmp(token, "fixed_nominal_msdu") == 0) {
+			params.fixed_nominal_msdu = 1;
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "CTRL: Invalid WMM_AC_ADDTS parameter: '%s'",
+				   token);
+			return -1;
+		}
+
+	}
+
+	return wpas_wmm_ac_addts(wpa_s, &params);
+}
+
+
+static int wmm_ac_ctrl_delts(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 tsid = atoi(cmd);
+
+	return wpas_wmm_ac_delts(wpa_s, tsid);
+}
+
+
 #ifdef CONFIG_IEEE80211R
 static int wpa_supplicant_ctrl_iface_ft_ds(
 	struct wpa_supplicant *wpa_s, char *addr)
@@ -747,7 +917,7 @@
 		if (ret < 0)
 			return -1;
 		ret = os_snprintf(buf, buflen, "%s", pin);
-		if (ret < 0 || (size_t) ret >= buflen)
+		if (os_snprintf_error(buflen, ret))
 			return -1;
 		return ret;
 	}
@@ -759,7 +929,7 @@
 done:
 	/* Return the generated PIN */
 	ret = os_snprintf(buf, buflen, "%08d", ret);
-	if (ret < 0 || (size_t) ret >= buflen)
+	if (os_snprintf_error(buflen, ret))
 		return -1;
 	return ret;
 }
@@ -796,14 +966,14 @@
 		if (!wps_pin_valid(pin_val)) {
 			wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
 			ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
-			if (ret < 0 || (size_t) ret >= buflen)
+			if (os_snprintf_error(buflen, ret))
 				return -1;
 			return ret;
 		}
 	}
 
 	ret = os_snprintf(buf, buflen, "%s", pin);
-	if (ret < 0 || (size_t) ret >= buflen)
+	if (os_snprintf_error(buflen, ret))
 		return -1;
 
 	return ret;
@@ -1537,12 +1707,12 @@
 		struct wpa_ssid *ssid = wpa_s->current_ssid;
 		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
 				  MAC2STR(wpa_s->bssid));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 		ret = os_snprintf(pos, end - pos, "freq=%u\n",
 				  wpa_s->assoc_freq);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 		if (ssid) {
@@ -1560,7 +1730,7 @@
 			ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
 					  wpa_ssid_txt(_ssid, ssid_len),
 					  ssid->id);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 
@@ -1571,7 +1741,7 @@
 				ret = os_snprintf(pos, end - pos,
 						  "passphrase=%s\n",
 						  ssid->passphrase);
-				if (ret < 0 || ret >= end - pos)
+				if (os_snprintf_error(end - pos, ret))
 					return pos - buf;
 				pos += ret;
 			}
@@ -1579,7 +1749,7 @@
 				ret = os_snprintf(pos, end - pos,
 						  "id_str=%s\n",
 						  ssid->id_str);
-				if (ret < 0 || ret >= end - pos)
+				if (os_snprintf_error(end - pos, ret))
 					return pos - buf;
 				pos += ret;
 			}
@@ -1610,7 +1780,7 @@
 				ret = 0;
 				break;
 			}
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
@@ -1632,21 +1802,21 @@
 	    wpa_s->sme.sae.state == SAE_ACCEPTED) {
 		ret = os_snprintf(pos, end - pos, "sae_group=%d\n",
 				  wpa_s->sme.sae.group);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
 #endif /* CONFIG_SAE */
 	ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
 			  wpa_supplicant_state_txt(wpa_s->wpa_state));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
 	if (wpa_s->l2 &&
 	    l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
 		ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -1655,7 +1825,7 @@
 	if (wpa_s->global->p2p) {
 		ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
 				  "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -1663,7 +1833,7 @@
 
 	ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
 			  MAC2STR(wpa_s->own_addr));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -1679,7 +1849,7 @@
 			release = rel_num + 1;
 		}
 		ret = os_snprintf(pos, end - pos, "hs20=%d\n", release);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -1698,7 +1868,7 @@
 				ret = os_snprintf(pos, end - pos,
 						  "provisioning_sp=%s\n",
 						  cred->provisioning_sp);
-				if (ret < 0 || ret >= end - pos)
+				if (os_snprintf_error(end - pos, ret))
 					return pos - buf;
 				pos += ret;
 			}
@@ -1721,7 +1891,7 @@
 			}
 			ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
 					  cred->domain[i]);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 
@@ -1741,7 +1911,7 @@
 				type = "unknown";
 
 			ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 
@@ -1767,7 +1937,7 @@
 		char uuid_str[100];
 		uuid_bin2str(wpa_s->wps->uuid, uuid_str, sizeof(uuid_str));
 		ret = os_snprintf(pos, end - pos, "uuid=%s\n", uuid_str);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -1855,7 +2025,7 @@
 		while (e) {
 			ret = os_snprintf(pos, end - pos, MACSTR "\n",
 					  MAC2STR(e->bssid));
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 			e = e->next;
@@ -1937,10 +2107,6 @@
 	char *pos, *end, *stamp;
 	int ret;
 
-	if (cmd == NULL) {
-		return -1;
-	}
-
 	/* cmd: "LOG_LEVEL [<level>]" */
 	if (*cmd == '\0') {
 		pos = buf;
@@ -1949,7 +2115,7 @@
 				  "Timestamp: %d\n",
 				  debug_level_str(wpa_debug_level),
 				  wpa_debug_timestamp);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			ret = 0;
 
 		return ret;
@@ -1992,7 +2158,7 @@
 	end = buf + buflen;
 	ret = os_snprintf(pos, end - pos,
 			  "network id / ssid / bssid / flags\n");
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -2013,7 +2179,7 @@
 		ret = os_snprintf(pos, end - pos, "%d\t%s",
 				  ssid->id,
 				  wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return prev - buf;
 		pos += ret;
 		if (ssid->bssid_set) {
@@ -2022,7 +2188,7 @@
 		} else {
 			ret = os_snprintf(pos, end - pos, "\tany");
 		}
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return prev - buf;
 		pos += ret;
 		ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
@@ -2033,11 +2199,11 @@
 				  "[TEMP-DISABLED]" : "",
 				  ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
 				  "");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return prev - buf;
 		pos += ret;
 		ret = os_snprintf(pos, end - pos, "\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return prev - buf;
 		pos += ret;
 
@@ -2052,7 +2218,7 @@
 {
 	int ret;
 	ret = os_snprintf(pos, end - pos, "-");
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos;
 	pos += ret;
 	ret = wpa_write_ciphers(pos, end, cipher, "+");
@@ -2071,13 +2237,13 @@
 	int ret;
 
 	ret = os_snprintf(pos, end - pos, "[%s-", proto);
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos;
 	pos += ret;
 
 	if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
 		ret = os_snprintf(pos, end - pos, "?]");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos;
 		pos += ret;
 		return pos;
@@ -2087,21 +2253,28 @@
 	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
 		ret = os_snprintf(pos, end - pos, "%sEAP",
 				  pos == start ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos;
 		pos += ret;
 	}
 	if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
 		ret = os_snprintf(pos, end - pos, "%sPSK",
 				  pos == start ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos;
 		pos += ret;
 	}
 	if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
 		ret = os_snprintf(pos, end - pos, "%sNone",
 				  pos == start ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
+			return pos;
+		pos += ret;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_SAE) {
+		ret = os_snprintf(pos, end - pos, "%sSAE",
+				  pos == start ? "" : "+");
+		if (os_snprintf_error(end - pos, ret))
 			return pos;
 		pos += ret;
 	}
@@ -2109,14 +2282,21 @@
 	if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
 		ret = os_snprintf(pos, end - pos, "%sFT/EAP",
 				  pos == start ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos;
 		pos += ret;
 	}
 	if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
 		ret = os_snprintf(pos, end - pos, "%sFT/PSK",
 				  pos == start ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
+			return pos;
+		pos += ret;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+		ret = os_snprintf(pos, end - pos, "%sFT/SAE",
+				  pos == start ? "" : "+");
+		if (os_snprintf_error(end - pos, ret))
 			return pos;
 		pos += ret;
 	}
@@ -2125,30 +2305,38 @@
 	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
 		ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
 				  pos == start ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos;
 		pos += ret;
 	}
 	if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
 		ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
 				  pos == start ? "" : "+");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos;
 		pos += ret;
 	}
 #endif /* CONFIG_IEEE80211W */
 
+	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+		ret = os_snprintf(pos, end - pos, "%sEAP-SUITE-B",
+				  pos == start ? "" : "+");
+		if (os_snprintf_error(end - pos, ret))
+			return pos;
+		pos += ret;
+	}
+
 	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
 
 	if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
 		ret = os_snprintf(pos, end - pos, "-preauth");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos;
 		pos += ret;
 	}
 
 	ret = os_snprintf(pos, end - pos, "]");
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos;
 	pos += ret;
 
@@ -2176,7 +2364,7 @@
 		txt = "[WPS]";
 
 	ret = os_snprintf(pos, end - pos, "%s", txt);
-	if (ret >= 0 && ret < end - pos)
+	if (!os_snprintf_error(end - pos, ret))
 		pos += ret;
 	wpabuf_free(wps_ie);
 	return pos;
@@ -2205,8 +2393,9 @@
 {
 	char *pos, *end;
 	int ret;
-	const u8 *ie, *ie2, *p2p;
+	const u8 *ie, *ie2, *p2p, *mesh;
 
+	mesh = wpa_bss_get_ie(bss, WLAN_EID_MESH_ID);
 	p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
 	if (!p2p)
 		p2p = wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE);
@@ -2220,26 +2409,34 @@
 
 	ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
 			  MAC2STR(bss->bssid), bss->freq, bss->level);
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return -1;
 	pos += ret;
 	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
 	if (ie)
 		pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
 	ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-	if (ie2)
-		pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
+	if (ie2) {
+		pos = wpa_supplicant_ie_txt(pos, end, mesh ? "RSN" : "WPA2",
+					    ie2, 2 + ie2[1]);
+	}
 	pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
 	if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
 		ret = os_snprintf(pos, end - pos, "[WEP]");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
+			return -1;
+		pos += ret;
+	}
+	if (mesh) {
+		ret = os_snprintf(pos, end - pos, "[MESH]");
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
 	if (bss_is_dmg(bss)) {
 		const char *s;
 		ret = os_snprintf(pos, end - pos, "[DMG]");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 		switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
@@ -2257,33 +2454,33 @@
 			break;
 		}
 		ret = os_snprintf(pos, end - pos, "%s", s);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	} else {
 		if (bss->caps & IEEE80211_CAP_IBSS) {
 			ret = os_snprintf(pos, end - pos, "[IBSS]");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return -1;
 			pos += ret;
 		}
 		if (bss->caps & IEEE80211_CAP_ESS) {
 			ret = os_snprintf(pos, end - pos, "[ESS]");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return -1;
 			pos += ret;
 		}
 	}
 	if (p2p) {
 		ret = os_snprintf(pos, end - pos, "[P2P]");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
 #ifdef CONFIG_HS20
 	if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
 		ret = os_snprintf(pos, end - pos, "[HS20]");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
@@ -2291,12 +2488,12 @@
 
 	ret = os_snprintf(pos, end - pos, "\t%s",
 			  wpa_ssid_txt(bss->ssid, bss->ssid_len));
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return -1;
 	pos += ret;
 
 	ret = os_snprintf(pos, end - pos, "\n");
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return -1;
 	pos += ret;
 
@@ -2315,7 +2512,7 @@
 	end = buf + buflen;
 	ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
 			  "flags / ssid\n");
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -2331,6 +2528,116 @@
 }
 
 
+#ifdef CONFIG_MESH
+
+static int wpa_supplicant_ctrl_iface_mesh_interface_add(
+	struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+	char *pos, ifname[IFNAMSIZ + 1];
+
+	ifname[0] = '\0';
+
+	pos = os_strstr(cmd, "ifname=");
+	if (pos) {
+		pos += 7;
+		os_strlcpy(ifname, pos, sizeof(ifname));
+	}
+
+	if (wpas_mesh_add_interface(wpa_s, ifname, sizeof(ifname)) < 0)
+		return -1;
+
+	os_strlcpy(reply, ifname, max_len);
+	return os_strlen(ifname);
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_group_add(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_ADD id=%d", id);
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG,
+			   "CTRL_IFACE: Could not find network id=%d", id);
+		return -1;
+	}
+	if (ssid->mode != WPAS_MODE_MESH) {
+		wpa_printf(MSG_DEBUG,
+			   "CTRL_IFACE: Cannot use MESH_GROUP_ADD on a non mesh network");
+		return -1;
+	}
+	if (ssid->key_mgmt != WPA_KEY_MGMT_NONE &&
+	    ssid->key_mgmt != WPA_KEY_MGMT_SAE) {
+		wpa_printf(MSG_ERROR,
+			   "CTRL_IFACE: key_mgmt for mesh network should be open or SAE");
+		return -1;
+	}
+
+	/*
+	 * TODO: If necessary write our own group_add function,
+	 * for now we can reuse select_network
+	 */
+	wpa_supplicant_select_network(wpa_s, ssid);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_mesh_group_remove(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	struct wpa_supplicant *orig;
+	struct wpa_global *global;
+	int found = 0;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s", cmd);
+
+	global = wpa_s->global;
+	orig = wpa_s;
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (os_strcmp(wpa_s->ifname, cmd) == 0) {
+			found = 1;
+			break;
+		}
+	}
+	if (!found) {
+		wpa_printf(MSG_ERROR,
+			   "CTRL_IFACE: MESH_GROUP_REMOVE ifname=%s not found",
+			   cmd);
+		return -1;
+	}
+	if (wpa_s->mesh_if_created && wpa_s == orig) {
+		wpa_printf(MSG_ERROR,
+			   "CTRL_IFACE: MESH_GROUP_REMOVE can't remove itself");
+		return -1;
+	}
+
+	wpa_s->reassociate = 0;
+	wpa_s->disconnected = 1;
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+	wpa_supplicant_cancel_scan(wpa_s);
+
+	/*
+	 * TODO: If necessary write our own group_remove function,
+	 * for now we can reuse deauthenticate
+	 */
+	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
+	if (wpa_s->mesh_if_created)
+		wpa_supplicant_remove_iface(global, wpa_s, 0);
+
+	return 0;
+}
+
+#endif /* CONFIG_MESH */
+
+
 static int wpa_supplicant_ctrl_iface_select_network(
 	struct wpa_supplicant *wpa_s, char *cmd)
 {
@@ -2463,7 +2770,7 @@
 	wpa_config_set_network_defaults(ssid);
 
 	ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
-	if (ret < 0 || (size_t) ret >= buflen)
+	if (os_snprintf_error(buflen, ret))
 		return -1;
 	return ret;
 }
@@ -2586,6 +2893,8 @@
 		wpa_config_update_psk(ssid);
 	else if (os_strcmp(name, "priority") == 0)
 		wpa_config_update_prio_list(wpa_s->conf);
+	else if (os_strcmp(name, "no_auto_peer") == 0)
+		ssid->no_auto_peer = atoi(value);
 
 	return 0;
 }
@@ -2712,7 +3021,7 @@
 	ssid_d = wpa_config_get_network(wpa_s->conf, id_d);
 	if (ssid_d == NULL) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
-			   "network id=%d", id_s);
+			   "network id=%d", id_d);
 		return -1;
 	}
 
@@ -2743,7 +3052,7 @@
 	end = buf + buflen;
 	ret = os_snprintf(pos, end - pos,
 			  "cred id / realm / username / domain / imsi\n");
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
@@ -2754,7 +3063,7 @@
 				  cred->username ? cred->username : "",
 				  cred->domain ? cred->domain[0] : "",
 				  cred->imsi ? cred->imsi : "");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 
@@ -2780,7 +3089,7 @@
 	wpa_msg(wpa_s, MSG_INFO, CRED_ADDED "%d", cred->id);
 
 	ret = os_snprintf(buf, buflen, "%d\n", cred->id);
-	if (ret < 0 || (size_t) ret >= buflen)
+	if (os_snprintf_error(buflen, ret))
 		return -1;
 	return ret;
 }
@@ -2810,9 +3119,13 @@
 	ssid = wpa_s->conf->ssid;
 	while (ssid) {
 		if (ssid->parent_cred == cred) {
+			int res;
+
 			wpa_printf(MSG_DEBUG, "Remove network id %d since it "
 				   "used the removed credential", ssid->id);
-			os_snprintf(str, sizeof(str), "%d", ssid->id);
+			res = os_snprintf(str, sizeof(str), "%d", ssid->id);
+			if (os_snprintf_error(sizeof(str), res))
+				str[sizeof(str) - 1] = '\0';
 			ssid = ssid->next;
 			wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
 		} else
@@ -3042,7 +3355,7 @@
 			ret = os_snprintf(pos, end - pos, "%s%s",
 					  pos == buf ? "" : " ",
 					  ciphers[i].name);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
@@ -3078,7 +3391,7 @@
 			ret = os_snprintf(pos, end - pos, "%s%s",
 					  pos == buf ? "" : " ",
 					  ciphers[i].name);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
@@ -3110,14 +3423,14 @@
 	}
 
 	ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 
 	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
 			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
 		ret = os_snprintf(pos, end - pos, " WPA-EAP");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -3125,14 +3438,14 @@
 	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
 			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
 		ret = os_snprintf(pos, end - pos, " WPA-PSK");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
 
 	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
 		ret = os_snprintf(pos, end - pos, " WPA-NONE");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -3165,7 +3478,7 @@
 			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
 		ret = os_snprintf(pos, end - pos, "%sRSN",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -3174,7 +3487,7 @@
 			      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
 		ret = os_snprintf(pos, end - pos, "%sWPA",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -3206,7 +3519,7 @@
 	if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
 		ret = os_snprintf(pos, end - pos, "%sOPEN",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -3214,7 +3527,7 @@
 	if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
 		ret = os_snprintf(pos, end - pos, "%sSHARED",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -3222,7 +3535,7 @@
 	if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
 		ret = os_snprintf(pos, end - pos, "%sLEAP",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -3254,7 +3567,7 @@
 	if (capa->flags & WPA_DRIVER_FLAGS_IBSS) {
 		ret = os_snprintf(pos, end - pos, "%sIBSS",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -3262,7 +3575,7 @@
 	if (capa->flags & WPA_DRIVER_FLAGS_AP) {
 		ret = os_snprintf(pos, end - pos, "%sAP",
 				  pos == buf ? "" : " ");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -3299,7 +3612,7 @@
 			continue;
 		}
 		ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 		chnl = wpa_s->hw.modes[j].channels;
@@ -3307,12 +3620,12 @@
 			if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
 				continue;
 			ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
 		ret = os_snprintf(pos, end - pos, "\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -3350,7 +3663,7 @@
 		}
 		ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:\n",
 				  hmode);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 		chnl = wpa_s->hw.modes[j].channels;
@@ -3359,17 +3672,17 @@
 				continue;
 			ret = os_snprintf(pos, end - pos, " %d = %d MHz%s%s\n",
 					  chnl[i].chan, chnl[i].freq,
-					  chnl[i].flag & HOSTAPD_CHAN_NO_IBSS ?
-					  " (NO_IBSS)" : "",
+					  chnl[i].flag & HOSTAPD_CHAN_NO_IR ?
+					  " (NO_IR)" : "",
 					  chnl[i].flag & HOSTAPD_CHAN_RADAR ?
 					  " (DFS)" : "");
 
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return pos - buf;
 			pos += ret;
 		}
 		ret = os_snprintf(pos, end - pos, "\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -3443,6 +3756,15 @@
 		return ctrl_iface_get_capability_tdls(wpa_s, buf, buflen);
 #endif /* CONFIG_TDLS */
 
+#ifdef CONFIG_ERP
+	if (os_strcmp(field, "erp") == 0) {
+		res = os_snprintf(buf, buflen, "ERP");
+		if (os_snprintf_error(buflen, res))
+			return -1;
+		return res;
+	}
+#endif /* CONFIG_EPR */
+
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
 		   field);
 
@@ -3463,20 +3785,20 @@
 		return start;
 
 	ret = os_snprintf(pos, end - pos, "%s=", title);
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return start;
 	pos += ret;
 
 	d = wpabuf_head_u8(data);
 	for (i = 0; i < wpabuf_len(data); i++) {
 		ret = os_snprintf(pos, end - pos, "%02x", *d++);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return start;
 		pos += ret;
 	}
 
 	ret = os_snprintf(pos, end - pos, "\n");
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return start;
 	pos += ret;
 
@@ -3498,7 +3820,7 @@
 
 	if (mask & WPA_BSS_MASK_ID) {
 		ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
@@ -3506,14 +3828,14 @@
 	if (mask & WPA_BSS_MASK_BSSID) {
 		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
 				  MAC2STR(bss->bssid));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
 
 	if (mask & WPA_BSS_MASK_FREQ) {
 		ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
@@ -3521,7 +3843,7 @@
 	if (mask & WPA_BSS_MASK_BEACON_INT) {
 		ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
 				  bss->beacon_int);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
@@ -3529,28 +3851,28 @@
 	if (mask & WPA_BSS_MASK_CAPABILITIES) {
 		ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
 				  bss->caps);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
 
 	if (mask & WPA_BSS_MASK_QUAL) {
 		ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
 
 	if (mask & WPA_BSS_MASK_NOISE) {
 		ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
 
 	if (mask & WPA_BSS_MASK_LEVEL) {
 		ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
@@ -3558,7 +3880,7 @@
 	if (mask & WPA_BSS_MASK_TSF) {
 		ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
 				  (unsigned long long) bss->tsf);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
@@ -3569,34 +3891,34 @@
 		os_get_reltime(&now);
 		ret = os_snprintf(pos, end - pos, "age=%d\n",
 				  (int) (now.sec - bss->last_update.sec));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
 
 	if (mask & WPA_BSS_MASK_IE) {
 		ret = os_snprintf(pos, end - pos, "ie=");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 
 		ie = (const u8 *) (bss + 1);
 		for (i = 0; i < bss->ie_len; i++) {
 			ret = os_snprintf(pos, end - pos, "%02x", *ie++);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return 0;
 			pos += ret;
 		}
 
 		ret = os_snprintf(pos, end - pos, "\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
 
 	if (mask & WPA_BSS_MASK_FLAGS) {
 		ret = os_snprintf(pos, end - pos, "flags=");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 
@@ -3611,14 +3933,14 @@
 		pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
 		if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
 			ret = os_snprintf(pos, end - pos, "[WEP]");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return 0;
 			pos += ret;
 		}
 		if (bss_is_dmg(bss)) {
 			const char *s;
 			ret = os_snprintf(pos, end - pos, "[DMG]");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return 0;
 			pos += ret;
 			switch (bss->caps & IEEE80211_CAP_DMG_MASK) {
@@ -3636,19 +3958,19 @@
 				break;
 			}
 			ret = os_snprintf(pos, end - pos, "%s", s);
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return 0;
 			pos += ret;
 		} else {
 			if (bss->caps & IEEE80211_CAP_IBSS) {
 				ret = os_snprintf(pos, end - pos, "[IBSS]");
-				if (ret < 0 || ret >= end - pos)
+				if (os_snprintf_error(end - pos, ret))
 					return 0;
 				pos += ret;
 			}
 			if (bss->caps & IEEE80211_CAP_ESS) {
 				ret = os_snprintf(pos, end - pos, "[ESS]");
-				if (ret < 0 || ret >= end - pos)
+				if (os_snprintf_error(end - pos, ret))
 					return 0;
 				pos += ret;
 			}
@@ -3656,21 +3978,21 @@
 		if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE) ||
 		    wpa_bss_get_vendor_ie_beacon(bss, P2P_IE_VENDOR_TYPE)) {
 			ret = os_snprintf(pos, end - pos, "[P2P]");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return 0;
 			pos += ret;
 		}
 #ifdef CONFIG_HS20
 		if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
 			ret = os_snprintf(pos, end - pos, "[HS20]");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return 0;
 			pos += ret;
 		}
 #endif /* CONFIG_HS20 */
 
 		ret = os_snprintf(pos, end - pos, "\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
@@ -3678,7 +4000,7 @@
 	if (mask & WPA_BSS_MASK_SSID) {
 		ret = os_snprintf(pos, end - pos, "ssid=%s\n",
 				  wpa_ssid_txt(bss->ssid, bss->ssid_len));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
@@ -3711,7 +4033,7 @@
 						  WFD_IE_VENDOR_TYPE);
 		if (wfd) {
 			ret = os_snprintf(pos, end - pos, "wfd_subelems=");
-			if (ret < 0 || ret >= end - pos) {
+			if (os_snprintf_error(end - pos, ret)) {
 				wpabuf_free(wfd);
 				return 0;
 			}
@@ -3723,7 +4045,7 @@
 			wpabuf_free(wfd);
 
 			ret = os_snprintf(pos, end - pos, "\n");
-			if (ret < 0 || ret >= end - pos)
+			if (os_snprintf_error(end - pos, ret))
 				return 0;
 			pos += ret;
 		}
@@ -3761,9 +4083,19 @@
 	}
 #endif /* CONFIG_INTERWORKING */
 
+#ifdef CONFIG_MESH
+	if (mask & WPA_BSS_MASK_MESH_SCAN) {
+		ie = (const u8 *) (bss + 1);
+		ret = wpas_mesh_scan_result_text(ie, bss->ie_len, pos, end);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+#endif /* CONFIG_MESH */
+
 	if (mask & WPA_BSS_MASK_DELIM) {
 		ret = os_snprintf(pos, end - pos, "====\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return 0;
 		pos += ret;
 	}
@@ -3783,7 +4115,7 @@
 	struct dl_list *next;
 	int ret = 0;
 	int len;
-	char *ctmp;
+	char *ctmp, *end = buf + buflen;
 	unsigned long mask = WPA_BSS_MASK_ALL;
 
 	if (os_strncmp(cmd, "RANGE=", 6) == 0) {
@@ -3892,8 +4224,16 @@
 		if (bss == bsslast) {
 			if ((mask & WPA_BSS_MASK_DELIM) && len &&
 			    (bss == dl_list_last(&wpa_s->bss_id,
-						 struct wpa_bss, list_id)))
-				os_snprintf(buf - 5, 5, "####\n");
+						 struct wpa_bss, list_id))) {
+				int res;
+
+				res = os_snprintf(buf - 5, end - buf + 5,
+						  "####\n");
+				if (os_snprintf_error(end - buf + 5, res)) {
+					wpa_printf(MSG_DEBUG,
+						   "Could not add end delim");
+				}
+			}
 			break;
 		}
 		next = bss->list_id.next;
@@ -3938,7 +4278,7 @@
 }
 
 
-static int wpa_supplicant_ctrl_iface_bss_flush(
+static void wpa_supplicant_ctrl_iface_bss_flush(
 	struct wpa_supplicant *wpa_s, char *cmd)
 {
 	int flush_age = atoi(cmd);
@@ -3947,7 +4287,6 @@
 		wpa_bss_flush(wpa_s);
 	else
 		wpa_bss_flush_by_age(wpa_s, flush_age);
-	return 0;
 }
 
 
@@ -4173,7 +4512,7 @@
 		return -1;
 	if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
 		ret = os_snprintf(buf, buflen, "%08d", new_pin);
-		if (ret < 0 || (size_t) ret >= buflen)
+		if (os_snprintf_error(buflen, ret))
 			return -1;
 		return ret;
 	}
@@ -4288,7 +4627,7 @@
 	if (ref == 0)
 		return -1;
 	res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
-	if (res < 0 || (unsigned) res >= buflen)
+	if (os_snprintf_error(buflen, res))
 		return -1;
 	return res;
 }
@@ -4724,7 +5063,7 @@
 			  info->dev_capab,
 			  info->group_capab,
 			  info->level);
-	if (res < 0 || res >= end - pos)
+	if (os_snprintf_error(end - pos, res))
 		return pos - buf;
 	pos += res;
 
@@ -4735,7 +5074,7 @@
 		res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
 				  wps_dev_type_bin2str(t, devtype,
 						       sizeof(devtype)));
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
 	}
@@ -4743,7 +5082,7 @@
 	ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
 	if (ssid) {
 		res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
 	}
@@ -4755,7 +5094,7 @@
 
 	if (info->vendor_elems) {
 		res = os_snprintf(pos, end - pos, "vendor_elems=");
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
 
@@ -4764,7 +5103,7 @@
 					wpabuf_len(info->vendor_elems));
 
 		res = os_snprintf(pos, end - pos, "\n");
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			return pos - buf;
 		pos += res;
 	}
@@ -5007,6 +5346,7 @@
 {
 	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
 	wpa_s->force_long_sd = 0;
+	wpas_p2p_stop_find(wpa_s);
 	if (wpa_s->global->p2p)
 		p2p_flush(wpa_s->global->p2p);
 }
@@ -5180,6 +5520,8 @@
 	if (used < 0)
 		return -1;
 	pos = dst + used;
+	if (*pos == ' ')
+		pos++;
 	while (num_id < MAX_ANQP_INFO_ID) {
 		if (os_strncmp(pos, "hs20:", 5) == 0) {
 #ifdef CONFIG_HS20
@@ -5359,6 +5701,8 @@
 	if (used < 0)
 		return -1;
 	pos = dst + used;
+	if (*pos == ' ')
+		pos++;
 	for (;;) {
 		int num = atoi(pos);
 		if (num <= 0 || num > 31)
@@ -5471,14 +5815,6 @@
 #endif /* CONFIG_HS20 */
 
 
-static int wpa_supplicant_ctrl_iface_sta_autoconnect(
-	struct wpa_supplicant *wpa_s, char *cmd)
-{
-	wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
-	return 0;
-}
-
-
 #ifdef CONFIG_AUTOSCAN
 
 static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
@@ -5594,14 +5930,14 @@
 			  "NOISE=%d\nFREQUENCY=%u\n",
 			  si.current_signal, si.current_txrate / 1000,
 			  si.current_noise, si.frequency);
-	if (ret < 0 || ret > end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return -1;
 	pos += ret;
 
 	if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
 		ret = os_snprintf(pos, end - pos, "WIDTH=%s\n",
 				  channel_width_to_string(si.chanwidth));
-		if (ret < 0 || ret > end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
@@ -5610,7 +5946,7 @@
 		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)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
@@ -5618,7 +5954,7 @@
 	if (si.avg_signal) {
 		ret = os_snprintf(pos, end - pos,
 				  "AVG_RSSI=%d\n", si.avg_signal);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return -1;
 		pos += ret;
 	}
@@ -5639,7 +5975,7 @@
 
 	ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
 			  sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
-	if (ret < 0 || (size_t) ret > buflen)
+	if (os_snprintf_error(buflen, ret))
 		return -1;
 	return ret;
 }
@@ -5664,6 +6000,8 @@
 			}
 		}
 		ret = os_snprintf(buf, buflen, "%s\n", "OK");
+		if (os_snprintf_error(buflen, ret))
+			ret = -1;
 	}
 	return ret;
 }
@@ -5753,6 +6091,7 @@
 #ifdef CONFIG_WPS
 	wpa_s->wps_fragment_size = 0;
 	wpas_wps_cancel(wpa_s);
+	wps_registrar_flush(wpa_s->wps->registrar);
 #endif /* CONFIG_WPS */
 	wpa_s->after_wps = 0;
 	wpa_s->known_wps_freq = 0;
@@ -5792,12 +6131,16 @@
 	wpa_s->conf->auto_interworking = 0;
 	wpa_s->conf->okc = 0;
 
+	wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+	rsn_preauth_deinit(wpa_s->wpa);
+
 	wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME, 43200);
 	wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD, 70);
 	wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, 60);
 	eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
 
 	radio_remove_works(wpa_s, NULL, 1);
+	wpa_s->ext_work_in_progress = 0;
 
 	wpa_s->next_ssid = NULL;
 
@@ -5806,6 +6149,14 @@
 #endif /* CONFIG_INTERWORKING */
 
 	wpa_s->ext_mgmt_frame_handling = 0;
+	wpa_s->ext_eapol_frame_io = 0;
+#ifdef CONFIG_TESTING_OPTIONS
+	wpa_s->extra_roc_dur = 0;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	wpa_s->disconnected = 0;
+	os_free(wpa_s->next_scan_freqs);
+	wpa_s->next_scan_freqs = NULL;
 }
 
 
@@ -5829,7 +6180,7 @@
 		ret = os_snprintf(pos, end - pos, "%s@%s:%u:%u:%ld.%06ld\n",
 				  work->type, work->wpa_s->ifname, work->freq,
 				  work->started, diff.sec, diff.usec);
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			break;
 		pos += ret;
 	}
@@ -5847,6 +6198,7 @@
 		"Timing out external radio work %u (%s)",
 		ework->id, work->type);
 	wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_TIMEOUT "%u", ework->id);
+	work->wpa_s->ext_work_in_progress = 0;
 	radio_work_done(work);
 	os_free(ework);
 }
@@ -5868,6 +6220,7 @@
 	wpa_dbg(work->wpa_s, MSG_DEBUG, "Starting external radio work %u (%s)",
 		ework->id, ework->type);
 	wpa_msg(work->wpa_s, MSG_INFO, EXT_RADIO_WORK_START "%u", ework->id);
+	work->wpa_s->ext_work_in_progress = 1;
 	if (!ework->timeout)
 		ework->timeout = 10;
 	eloop_register_timeout(ework->timeout, 0, wpas_ctrl_radio_work_timeout,
@@ -5923,7 +6276,7 @@
 	}
 
 	ret = os_snprintf(buf, buflen, "%u", ework->id);
-	if (ret < 0 || (size_t) ret >= buflen)
+	if (os_snprintf_error(buflen, ret))
 		return -1;
 	return ret;
 }
@@ -5947,6 +6300,7 @@
 			"Completed external radio work %u (%s)",
 			ework->id, ework->type);
 		eloop_cancel_timeout(wpas_ctrl_radio_work_timeout, work, NULL);
+		wpa_s->ext_work_in_progress = 0;
 		radio_work_done(work);
 		os_free(ework);
 		return 3; /* "OK\n" */
@@ -6003,31 +6357,17 @@
 }
 
 
-static int set_scan_freqs(struct wpa_supplicant *wpa_s, char *val)
-{
-	int *freqs = NULL;
-
-	freqs = freq_range_to_channel_list(wpa_s, val);
-	if (freqs == NULL)
-		return -1;
-
-	os_free(wpa_s->manual_scan_freqs);
-	wpa_s->manual_scan_freqs = freqs;
-
-	return 0;
-}
-
-
-static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value)
+static int scan_id_list_parse(struct wpa_supplicant *wpa_s, const char *value,
+			      unsigned int *scan_id_count, int scan_id[])
 {
 	const char *pos = value;
 
 	while (pos) {
 		if (*pos == ' ' || *pos == '\0')
 			break;
-		if (wpa_s->scan_id_count == MAX_SCAN_ID)
+		if (*scan_id_count == MAX_SCAN_ID)
 			return -1;
-		wpa_s->scan_id[wpa_s->scan_id_count++] = atoi(pos);
+		scan_id[(*scan_id_count)++] = atoi(pos);
 		pos = os_strchr(pos, ',');
 		if (pos)
 			pos++;
@@ -6041,54 +6381,82 @@
 			   char *reply, int reply_size, int *reply_len)
 {
 	char *pos;
+	unsigned int manual_scan_passive = 0;
+	unsigned int manual_scan_use_id = 0;
+	unsigned int manual_scan_only_new = 0;
+	unsigned int scan_only = 0;
+	unsigned int scan_id_count = 0;
+	int scan_id[MAX_SCAN_ID];
+	void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
+				 struct wpa_scan_results *scan_res);
+	int *manual_scan_freqs = NULL;
 
 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
 		*reply_len = -1;
 		return;
 	}
 
-	wpa_s->manual_scan_passive = 0;
-	wpa_s->manual_scan_use_id = 0;
-	wpa_s->manual_scan_only_new = 0;
-	wpa_s->scan_id_count = 0;
+	if (radio_work_pending(wpa_s, "scan")) {
+		wpa_printf(MSG_DEBUG,
+			   "Pending scan scheduled - reject new request");
+		*reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
+		return;
+	}
 
 	if (params) {
 		if (os_strncasecmp(params, "TYPE=ONLY", 9) == 0)
-			wpa_s->scan_res_handler = scan_only_handler;
+			scan_only = 1;
 
 		pos = os_strstr(params, "freq=");
-		if (pos && set_scan_freqs(wpa_s, pos + 5) < 0) {
-			*reply_len = -1;
-			return;
+		if (pos) {
+			manual_scan_freqs = freq_range_to_channel_list(wpa_s,
+								       pos + 5);
+			if (manual_scan_freqs == NULL) {
+				*reply_len = -1;
+				goto done;
+			}
 		}
 
 		pos = os_strstr(params, "passive=");
 		if (pos)
-			wpa_s->manual_scan_passive = !!atoi(pos + 8);
+			manual_scan_passive = !!atoi(pos + 8);
 
 		pos = os_strstr(params, "use_id=");
 		if (pos)
-			wpa_s->manual_scan_use_id = atoi(pos + 7);
+			manual_scan_use_id = atoi(pos + 7);
 
 		pos = os_strstr(params, "only_new=1");
 		if (pos)
-			wpa_s->manual_scan_only_new = 1;
+			manual_scan_only_new = 1;
 
 		pos = os_strstr(params, "scan_id=");
-		if (pos && scan_id_list_parse(wpa_s, pos + 8) < 0) {
+		if (pos && scan_id_list_parse(wpa_s, pos + 8, &scan_id_count,
+					      scan_id) < 0) {
 			*reply_len = -1;
-			return;
+			goto done;
 		}
-	} else {
-		os_free(wpa_s->manual_scan_freqs);
-		wpa_s->manual_scan_freqs = NULL;
-		if (wpa_s->scan_res_handler == scan_only_handler)
-			wpa_s->scan_res_handler = NULL;
 	}
 
+	if (scan_only)
+		scan_res_handler = scan_only_handler;
+	else if (wpa_s->scan_res_handler == scan_only_handler)
+		scan_res_handler = NULL;
+	else
+		scan_res_handler = wpa_s->scan_res_handler;
+
 	if (!wpa_s->sched_scanning && !wpa_s->scanning &&
 	    ((wpa_s->wpa_state <= WPA_SCANNING) ||
 	     (wpa_s->wpa_state == WPA_COMPLETED))) {
+		wpa_s->manual_scan_passive = manual_scan_passive;
+		wpa_s->manual_scan_use_id = manual_scan_use_id;
+		wpa_s->manual_scan_only_new = manual_scan_only_new;
+		wpa_s->scan_id_count = scan_id_count;
+		os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
+		wpa_s->scan_res_handler = scan_res_handler;
+		os_free(wpa_s->manual_scan_freqs);
+		wpa_s->manual_scan_freqs = manual_scan_freqs;
+		manual_scan_freqs = NULL;
+
 		wpa_s->normal_scans = 0;
 		wpa_s->scan_req = MANUAL_SCAN_REQ;
 		wpa_s->after_wps = 0;
@@ -6102,6 +6470,16 @@
 						 wpa_s->manual_scan_id);
 		}
 	} else if (wpa_s->sched_scanning) {
+		wpa_s->manual_scan_passive = manual_scan_passive;
+		wpa_s->manual_scan_use_id = manual_scan_use_id;
+		wpa_s->manual_scan_only_new = manual_scan_only_new;
+		wpa_s->scan_id_count = scan_id_count;
+		os_memcpy(wpa_s->scan_id, scan_id, scan_id_count * sizeof(int));
+		wpa_s->scan_res_handler = scan_res_handler;
+		os_free(wpa_s->manual_scan_freqs);
+		wpa_s->manual_scan_freqs = manual_scan_freqs;
+		manual_scan_freqs = NULL;
+
 		wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to allow requested full scan to proceed");
 		wpa_supplicant_cancel_sched_scan(wpa_s);
 		wpa_s->scan_req = MANUAL_SCAN_REQ;
@@ -6117,6 +6495,9 @@
 		wpa_printf(MSG_DEBUG, "Ongoing scan action - reject new request");
 		*reply_len = os_snprintf(reply, reply_size, "FAIL-BUSY\n");
 	}
+
+done:
+	os_free(manual_scan_freqs);
 }
 
 
@@ -6256,6 +6637,228 @@
 	return 0;
 }
 
+
+static int wpas_ctrl_iface_eapol_rx(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+	u8 src[ETH_ALEN], *buf;
+	int used;
+	size_t len;
+
+	wpa_printf(MSG_DEBUG, "External EAPOL RX: %s", cmd);
+
+	pos = cmd;
+	used = hwaddr_aton2(pos, src);
+	if (used < 0)
+		return -1;
+	pos += used;
+	while (*pos == ' ')
+		pos++;
+
+	len = os_strlen(pos);
+	if (len & 1)
+		return -1;
+	len /= 2;
+
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return -1;
+
+	if (hexstr2bin(pos, buf, len) < 0) {
+		os_free(buf);
+		return -1;
+	}
+
+	wpa_supplicant_rx_eapol(wpa_s, src, buf, len);
+	os_free(buf);
+
+	return 0;
+}
+
+
+static u16 ipv4_hdr_checksum(const void *buf, size_t len)
+{
+	size_t i;
+	u32 sum = 0;
+	const u16 *pos = buf;
+
+	for (i = 0; i < len / 2; i++)
+		sum += *pos++;
+
+	while (sum >> 16)
+		sum = (sum & 0xffff) + (sum >> 16);
+
+	return sum ^ 0xffff;
+}
+
+
+#define HWSIM_PACKETLEN 1500
+#define HWSIM_IP_LEN (HWSIM_PACKETLEN - sizeof(struct ether_header))
+
+void wpas_data_test_rx(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	const struct ether_header *eth;
+	const struct iphdr *ip;
+	const u8 *pos;
+	unsigned int i;
+
+	if (len != HWSIM_PACKETLEN)
+		return;
+
+	eth = (const struct ether_header *) buf;
+	ip = (const struct iphdr *) (eth + 1);
+	pos = (const u8 *) (ip + 1);
+
+	if (ip->ihl != 5 || ip->version != 4 ||
+	    ntohs(ip->tot_len) != HWSIM_IP_LEN)
+		return;
+
+	for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++) {
+		if (*pos != (u8) i)
+			return;
+		pos++;
+	}
+
+	wpa_msg(wpa_s, MSG_INFO, "DATA-TEST-RX " MACSTR " " MACSTR,
+		MAC2STR(eth->ether_dhost), MAC2STR(eth->ether_shost));
+}
+
+
+static int wpas_ctrl_iface_data_test_config(struct wpa_supplicant *wpa_s,
+					    char *cmd)
+{
+	int enabled = atoi(cmd);
+
+	if (!enabled) {
+		if (wpa_s->l2_test) {
+			l2_packet_deinit(wpa_s->l2_test);
+			wpa_s->l2_test = NULL;
+			wpa_dbg(wpa_s, MSG_DEBUG, "test data: Disabled");
+		}
+		return 0;
+	}
+
+	if (wpa_s->l2_test)
+		return 0;
+
+	wpa_s->l2_test = l2_packet_init(wpa_s->ifname, wpa_s->own_addr,
+					ETHERTYPE_IP, wpas_data_test_rx,
+					wpa_s, 1);
+	if (wpa_s->l2_test == NULL)
+		return -1;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "test data: Enabled");
+
+	return 0;
+}
+
+
+static int wpas_ctrl_iface_data_test_tx(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 dst[ETH_ALEN], src[ETH_ALEN];
+	char *pos;
+	int used;
+	long int val;
+	u8 tos;
+	u8 buf[HWSIM_PACKETLEN];
+	struct ether_header *eth;
+	struct iphdr *ip;
+	u8 *dpos;
+	unsigned int i;
+
+	if (wpa_s->l2_test == NULL)
+		return -1;
+
+	/* format: <dst> <src> <tos> */
+
+	pos = cmd;
+	used = hwaddr_aton2(pos, dst);
+	if (used < 0)
+		return -1;
+	pos += used;
+	while (*pos == ' ')
+		pos++;
+	used = hwaddr_aton2(pos, src);
+	if (used < 0)
+		return -1;
+	pos += used;
+
+	val = strtol(pos, NULL, 0);
+	if (val < 0 || val > 0xff)
+		return -1;
+	tos = val;
+
+	eth = (struct ether_header *) buf;
+	os_memcpy(eth->ether_dhost, dst, ETH_ALEN);
+	os_memcpy(eth->ether_shost, src, ETH_ALEN);
+	eth->ether_type = htons(ETHERTYPE_IP);
+	ip = (struct iphdr *) (eth + 1);
+	os_memset(ip, 0, sizeof(*ip));
+	ip->ihl = 5;
+	ip->version = 4;
+	ip->ttl = 64;
+	ip->tos = tos;
+	ip->tot_len = htons(HWSIM_IP_LEN);
+	ip->protocol = 1;
+	ip->saddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 1);
+	ip->daddr = htonl(192 << 24 | 168 << 16 | 1 << 8 | 2);
+	ip->check = ipv4_hdr_checksum(ip, sizeof(*ip));
+	dpos = (u8 *) (ip + 1);
+	for (i = 0; i < HWSIM_IP_LEN - sizeof(*ip); i++)
+		*dpos++ = i;
+
+	if (l2_packet_send(wpa_s->l2_test, dst, ETHERTYPE_IP, buf,
+			   HWSIM_PACKETLEN) < 0)
+		return -1;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX dst=" MACSTR " src=" MACSTR
+		" tos=0x%x", MAC2STR(dst), MAC2STR(src), tos);
+
+	return 0;
+}
+
+
+static int wpas_ctrl_iface_data_test_frame(struct wpa_supplicant *wpa_s,
+					   char *cmd)
+{
+	u8 *buf;
+	struct ether_header *eth;
+	struct l2_packet_data *l2 = NULL;
+	size_t len;
+	u16 ethertype;
+	int res = -1;
+
+	len = os_strlen(cmd);
+	if (len & 1 || len < ETH_HLEN * 2)
+		return -1;
+	len /= 2;
+
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return -1;
+
+	if (hexstr2bin(cmd, buf, len) < 0)
+		goto done;
+
+	eth = (struct ether_header *) buf;
+	ethertype = ntohs(eth->ether_type);
+
+	l2 = l2_packet_init(wpa_s->ifname, wpa_s->own_addr, ethertype,
+			    wpas_data_test_rx, wpa_s, 1);
+	if (l2 == NULL)
+		goto done;
+
+	res = l2_packet_send(l2, eth->ether_dhost, ethertype, buf, len);
+	wpa_dbg(wpa_s, MSG_DEBUG, "test data: TX frame res=%d", res);
+done:
+	if (l2)
+		l2_packet_deinit(l2);
+	os_free(buf);
+
+	return res < 0 ? -1 : 0;
+}
+
 #endif /* CONFIG_TESTING_OPTIONS */
 
 
@@ -6268,8 +6871,13 @@
 
 	for (i = 0; i < NUM_VENDOR_ELEM_FRAMES; i++) {
 		if (wpa_s->vendor_elem[i]) {
-			os_snprintf(buf, sizeof(buf), "frame[%u]", i);
-			wpa_hexdump_buf(MSG_DEBUG, buf, wpa_s->vendor_elem[i]);
+			int res;
+
+			res = os_snprintf(buf, sizeof(buf), "frame[%u]", i);
+			if (!os_snprintf_error(sizeof(buf), res)) {
+				wpa_hexdump_buf(MSG_DEBUG, buf,
+						wpa_s->vendor_elem[i]);
+			}
 		}
 	}
 
@@ -6463,6 +7071,171 @@
 }
 
 
+static void wpas_ctrl_neighbor_rep_cb(void *ctx, struct wpabuf *neighbor_rep)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	if (neighbor_rep) {
+		wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
+			     "length=%u",
+			     (unsigned int) wpabuf_len(neighbor_rep));
+		wpabuf_free(neighbor_rep);
+	} else {
+		wpa_msg_ctrl(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_FAILED);
+	}
+}
+
+
+static int wpas_ctrl_iface_send_neigbor_rep(struct wpa_supplicant *wpa_s,
+					    char *cmd)
+{
+	struct wpa_ssid ssid;
+	struct wpa_ssid *ssid_p = NULL;
+	int ret = 0;
+
+	if (os_strncmp(cmd, " ssid=", 6) == 0) {
+		ssid.ssid_len = os_strlen(cmd + 6);
+		if (ssid.ssid_len > 32)
+			return -1;
+		ssid.ssid = (u8 *) (cmd + 6);
+		ssid_p = &ssid;
+	}
+
+	ret = wpas_rrm_send_neighbor_rep_request(wpa_s, ssid_p,
+						 wpas_ctrl_neighbor_rep_cb,
+						 wpa_s);
+
+	return ret;
+}
+
+
+static int wpas_ctrl_iface_erp_flush(struct wpa_supplicant *wpa_s)
+{
+	eapol_sm_erp_flush(wpa_s->eapol);
+	return 0;
+}
+
+
+static int wpas_ctrl_iface_mac_rand_scan(struct wpa_supplicant *wpa_s,
+					 char *cmd)
+{
+	char *token, *context = NULL;
+	unsigned int enable = ~0, type = 0;
+	u8 _addr[ETH_ALEN], _mask[ETH_ALEN];
+	u8 *addr = NULL, *mask = NULL;
+
+	while ((token = str_token(cmd, " ", &context))) {
+		if (os_strcasecmp(token, "scan") == 0) {
+			type |= MAC_ADDR_RAND_SCAN;
+		} else if (os_strcasecmp(token, "sched") == 0) {
+			type |= MAC_ADDR_RAND_SCHED_SCAN;
+		} else if (os_strcasecmp(token, "pno") == 0) {
+			type |= MAC_ADDR_RAND_PNO;
+		} else if (os_strcasecmp(token, "all") == 0) {
+			type = wpa_s->mac_addr_rand_supported;
+		} else if (os_strncasecmp(token, "enable=", 7) == 0) {
+			enable = atoi(token + 7);
+		} else if (os_strncasecmp(token, "addr=", 5) == 0) {
+			addr = _addr;
+			if (hwaddr_aton(token + 5, addr)) {
+				wpa_printf(MSG_INFO,
+					   "CTRL: Invalid MAC address: %s",
+					   token);
+				return -1;
+			}
+		} else if (os_strncasecmp(token, "mask=", 5) == 0) {
+			mask = _mask;
+			if (hwaddr_aton(token + 5, mask)) {
+				wpa_printf(MSG_INFO,
+					   "CTRL: Invalid MAC address mask: %s",
+					   token);
+				return -1;
+			}
+		} else {
+			wpa_printf(MSG_INFO,
+				   "CTRL: Invalid MAC_RAND_SCAN parameter: %s",
+				   token);
+			return -1;
+		}
+	}
+
+	if (!type) {
+		wpa_printf(MSG_INFO, "CTRL: MAC_RAND_SCAN no type specified");
+		return -1;
+	}
+
+	if ((wpa_s->mac_addr_rand_supported & type) != type) {
+		wpa_printf(MSG_INFO,
+			   "CTRL: MAC_RAND_SCAN types=%u != supported=%u",
+			   type, wpa_s->mac_addr_rand_supported);
+		return -1;
+	}
+
+	if (enable > 1) {
+		wpa_printf(MSG_INFO,
+			   "CTRL: MAC_RAND_SCAN enable=<0/1> not specified");
+		return -1;
+	}
+
+	if (!enable) {
+		wpas_mac_addr_rand_scan_clear(wpa_s, type);
+		if (wpa_s->pno) {
+			if (type & MAC_ADDR_RAND_PNO) {
+				wpas_stop_pno(wpa_s);
+				wpas_start_pno(wpa_s);
+			}
+		} else if (wpa_s->sched_scanning &&
+			   (type & MAC_ADDR_RAND_SCHED_SCAN)) {
+			/* simulate timeout to restart the sched scan */
+			wpa_s->sched_scan_timed_out = 1;
+			wpa_s->prev_sched_ssid = NULL;
+			wpa_supplicant_cancel_sched_scan(wpa_s);
+		}
+		return 0;
+	}
+
+	if ((addr && !mask) || (!addr && mask)) {
+		wpa_printf(MSG_INFO,
+			   "CTRL: MAC_RAND_SCAN invalid addr/mask combination");
+		return -1;
+	}
+
+	if (addr && mask && (!(mask[0] & 0x01) || (addr[0] & 0x01))) {
+		wpa_printf(MSG_INFO,
+			   "CTRL: MAC_RAND_SCAN cannot allow multicast address");
+		return -1;
+	}
+
+	if (type & MAC_ADDR_RAND_SCAN) {
+		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCAN,
+					    addr, mask);
+	}
+
+	if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_SCHED_SCAN,
+					    addr, mask);
+
+		if (wpa_s->sched_scanning && !wpa_s->pno) {
+			/* simulate timeout to restart the sched scan */
+			wpa_s->sched_scan_timed_out = 1;
+			wpa_s->prev_sched_ssid = NULL;
+			wpa_supplicant_cancel_sched_scan(wpa_s);
+		}
+	}
+
+	if (type & MAC_ADDR_RAND_PNO) {
+		wpas_mac_addr_rand_scan_set(wpa_s, MAC_ADDR_RAND_PNO,
+					    addr, mask);
+		if (wpa_s->pno) {
+			wpas_stop_pno(wpa_s);
+			wpas_start_pno(wpa_s);
+		}
+	}
+
+	return 0;
+}
+
+
 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 					 char *buf, size_t *resp_len)
 {
@@ -6515,13 +7288,9 @@
 	} else if (os_strcmp(buf, "MIB") == 0) {
 		reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
 		if (reply_len >= 0) {
-			int res;
-			res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
-					       reply_size - reply_len);
-			if (res < 0)
-				reply_len = -1;
-			else
-				reply_len += res;
+			reply_len += eapol_sm_get_mib(wpa_s->eapol,
+						      reply + reply_len,
+						      reply_size - reply_len);
 		}
 	} else if (os_strncmp(buf, "STATUS", 6) == 0) {
 		reply_len = wpa_supplicant_ctrl_iface_status(
@@ -6642,8 +7411,7 @@
 		if (wpas_wps_er_start(wpa_s, buf + 13))
 			reply_len = -1;
 	} else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
-		if (wpas_wps_er_stop(wpa_s))
-			reply_len = -1;
+		wpas_wps_er_stop(wpa_s);
 	} else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
 		if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
 			reply_len = -1;
@@ -6682,6 +7450,21 @@
 		if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
 			reply_len = -1;
 #endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_MESH
+	} else if (os_strncmp(buf, "MESH_INTERFACE_ADD ", 19) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
+			wpa_s, buf + 19, reply, reply_size);
+	} else if (os_strcmp(buf, "MESH_INTERFACE_ADD") == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_mesh_interface_add(
+			wpa_s, "", reply, reply_size);
+	} else if (os_strncmp(buf, "MESH_GROUP_ADD ", 15) == 0) {
+		if (wpa_supplicant_ctrl_iface_mesh_group_add(wpa_s, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "MESH_GROUP_REMOVE ", 18) == 0) {
+		if (wpa_supplicant_ctrl_iface_mesh_group_remove(wpa_s,
+								buf + 18))
+			reply_len = -1;
+#endif /* CONFIG_MESH */
 #ifdef CONFIG_P2P
 	} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
 		if (p2p_ctrl_find(wpa_s, buf + 9))
@@ -6965,8 +7748,7 @@
 		if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
 			reply_len = -1;
 	} else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
-		if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
-			reply_len = -1;
+		wpa_s->auto_reconnect_disabled = atoi(buf + 16) == 0;
 	} else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
 		if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
 			reply_len = -1;
@@ -6975,8 +7757,7 @@
 							       buf + 17))
 			reply_len = -1;
 	} else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
-		if (wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10))
-			reply_len = -1;
+		wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10);
 #ifdef CONFIG_TDLS
 	} else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
 		if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
@@ -6987,7 +7768,23 @@
 	} else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
 		if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
 			reply_len = -1;
+	} else if (os_strncmp(buf, "TDLS_CHAN_SWITCH ", 17) == 0) {
+		if (wpa_supplicant_ctrl_iface_tdls_chan_switch(wpa_s,
+							       buf + 17))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "TDLS_CANCEL_CHAN_SWITCH ", 24) == 0) {
+		if (wpa_supplicant_ctrl_iface_tdls_cancel_chan_switch(wpa_s,
+								      buf + 24))
+			reply_len = -1;
 #endif /* CONFIG_TDLS */
+	} else if (os_strcmp(buf, "WMM_AC_STATUS") == 0) {
+		reply_len = wpas_wmm_ac_status(wpa_s, reply, reply_size);
+	} else if (os_strncmp(buf, "WMM_AC_ADDTS ", 13) == 0) {
+		if (wmm_ac_ctrl_addts(wpa_s, buf + 13))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WMM_AC_DELTS ", 13) == 0) {
+		if (wmm_ac_ctrl_delts(wpa_s, buf + 13))
+			reply_len = -1;
 	} else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
 		reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
 						       reply_size);
@@ -7032,6 +7829,18 @@
 	} else if (os_strncmp(buf, "DRIVER_EVENT ", 13) == 0) {
 		if (wpas_ctrl_iface_driver_event(wpa_s, buf + 13) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "EAPOL_RX ", 9) == 0) {
+		if (wpas_ctrl_iface_eapol_rx(wpa_s, buf + 9) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DATA_TEST_CONFIG ", 17) == 0) {
+		if (wpas_ctrl_iface_data_test_config(wpa_s, buf + 17) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DATA_TEST_TX ", 13) == 0) {
+		if (wpas_ctrl_iface_data_test_tx(wpa_s, buf + 13) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
+		if (wpas_ctrl_iface_data_test_frame(wpa_s, buf + 16) < 0)
+			reply_len = -1;
 #endif /* CONFIG_TESTING_OPTIONS */
 	} else if (os_strncmp(buf, "VENDOR_ELEM_ADD ", 16) == 0) {
 		if (wpas_ctrl_vendor_elem_add(wpa_s, buf + 16) < 0)
@@ -7042,6 +7851,14 @@
 	} else if (os_strncmp(buf, "VENDOR_ELEM_REMOVE ", 19) == 0) {
 		if (wpas_ctrl_vendor_elem_remove(wpa_s, buf + 19) < 0)
 			reply_len = -1;
+	} else if (os_strncmp(buf, "NEIGHBOR_REP_REQUEST", 20) == 0) {
+		if (wpas_ctrl_iface_send_neigbor_rep(wpa_s, buf + 20))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "ERP_FLUSH") == 0) {
+		wpas_ctrl_iface_erp_flush(wpa_s);
+	} else if (os_strncmp(buf, "MAC_RAND_SCAN ", 14) == 0) {
+		if (wpas_ctrl_iface_mac_rand_scan(wpa_s, buf + 14))
+			reply_len = -1;
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
@@ -7192,7 +8009,7 @@
 		res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
 				  tmp->drv_name, tmp->ifname,
 				  tmp->desc ? tmp->desc : "");
-		if (res < 0 || res >= end - pos) {
+		if (os_snprintf_error(end - pos, res)) {
 			*pos = '\0';
 			break;
 		}
@@ -7218,7 +8035,7 @@
 
 	while (wpa_s) {
 		res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
-		if (res < 0 || res >= end - pos) {
+		if (os_snprintf_error(end - pos, res)) {
 			*pos = '\0';
 			break;
 		}
@@ -7433,12 +8250,12 @@
 				  "p2p_state=%s\n",
 				  MAC2STR(global->p2p_dev_addr),
 				  p2p_get_state_txt(global->p2p));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	} else if (global->p2p) {
 		ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -7447,7 +8264,7 @@
 #ifdef CONFIG_WIFI_DISPLAY
 	ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
 			  !!global->wifi_display);
-	if (ret < 0 || ret >= end - pos)
+	if (os_snprintf_error(end - pos, ret))
 		return pos - buf;
 	pos += ret;
 #endif /* CONFIG_WIFI_DISPLAY */
@@ -7456,7 +8273,7 @@
 		ret = os_snprintf(pos, end - pos, "ifname=%s\n"
 				  "address=" MACSTR "\n",
 				  wpa_s->ifname, MAC2STR(wpa_s->own_addr));
-		if (ret < 0 || ret >= end - pos)
+		if (os_snprintf_error(end - pos, ret))
 			return pos - buf;
 		pos += ret;
 	}
@@ -7550,6 +8367,9 @@
 		if (wpas_module_tests() < 0)
 			reply_len = -1;
 #endif /* CONFIG_MODULE_TESTS */
+	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
+		if (wpa_debug_reopen_file() < 0)
+			reply_len = -1;
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index 9d0674d..bf6a3df 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -218,7 +218,8 @@
 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (res < 0) {
-		perror("recvfrom(ctrl_iface)");
+		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+			   strerror(errno));
 		return;
 	}
 
@@ -356,7 +357,7 @@
 
 	priv->sock = socket(domain, SOCK_DGRAM, 0);
 	if (priv->sock < 0) {
-		perror("socket(PF_INET)");
+		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
 		goto fail;
 	}
 
@@ -386,7 +387,7 @@
 		port--;
 		if ((WPA_CTRL_IFACE_PORT - port) < WPA_CTRL_IFACE_PORT_LIMIT)
 			goto try_again;
-		perror("bind(AF_INET)");
+		wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
 		goto fail;
 	}
 
@@ -482,7 +483,9 @@
 			if (sendto(priv->sock, sbuf, llen + len, 0,
 				   (struct sockaddr *) &dst->addr,
 				   sizeof(dst->addr)) < 0) {
-				perror("sendto(CTRL_IFACE monitor)");
+				wpa_printf(MSG_ERROR,
+					   "sendto(CTRL_IFACE monitor): %s",
+					   strerror(errno));
 				dst->errors++;
 				if (dst->errors > 10) {
 					wpa_supplicant_ctrl_iface_detach(
@@ -551,7 +554,8 @@
 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (res < 0) {
-		perror("recvfrom(ctrl_iface)");
+		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+			   strerror(errno));
 		return;
 	}
 
@@ -634,7 +638,7 @@
 
 	priv->sock = socket(PF_INET, SOCK_DGRAM, 0);
 	if (priv->sock < 0) {
-		perror("socket(PF_INET)");
+		wpa_printf(MSG_ERROR, "socket(PF_INET): %s", strerror(errno));
 		goto fail;
 	}
 
@@ -652,7 +656,7 @@
 		if ((port - WPA_GLOBAL_CTRL_IFACE_PORT) <
 		    WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT)
 			goto try_again;
-		perror("bind(AF_INET)");
+		wpa_printf(MSG_ERROR, "bind(AF_INET): %s", strerror(errno));
 		goto fail;
 	}
 
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 40082e2..2c1c6a0 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -47,6 +47,7 @@
 	struct wpa_supplicant *wpa_s;
 	int sock;
 	struct dl_list ctrl_dst;
+	int android_control_socket;
 };
 
 
@@ -54,6 +55,7 @@
 	struct wpa_global *global;
 	int sock;
 	struct dl_list ctrl_dst;
+	int android_control_socket;
 };
 
 
@@ -270,7 +272,7 @@
 	}
 
 	res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname);
-	if (res < 0 || (size_t) res >= len) {
+	if (os_snprintf_error(len, res)) {
 		os_free(pbuf);
 		os_free(buf);
 		return NULL;
@@ -340,8 +342,10 @@
 	os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
 		    wpa_s->conf->ctrl_interface);
 	priv->sock = android_get_control_socket(addr.sun_path);
-	if (priv->sock >= 0)
+	if (priv->sock >= 0) {
+		priv->android_control_socket = 1;
 		goto havesock;
+	}
 #endif /* ANDROID */
 	if (os_strncmp(buf, "DIR=", 4) == 0) {
 		dir = buf + 4;
@@ -556,6 +560,16 @@
 	if (priv->sock <= 0)
 		return -1;
 
+	/*
+	 * On Android, the control socket being used may be the socket
+	 * that is created when wpa_supplicant is started as a /init.*.rc
+	 * service. Such a socket is maintained as a key-value pair in
+	 * Android's environment. Closing this control socket would leave us
+	 * in a bad state with an invalid socket descriptor.
+	 */
+	if (priv->android_control_socket)
+		return priv->sock;
+
 	eloop_unregister_read_sock(priv->sock);
 	close(priv->sock);
 	priv->sock = -1;
@@ -657,7 +671,7 @@
 		return;
 
 	res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
-	if (res < 0 || (size_t) res >= sizeof(levelstr))
+	if (os_snprintf_error(sizeof(levelstr), res))
 		return;
 	idx = 0;
 	if (ifname) {
@@ -870,6 +884,7 @@
 		}
 		wpa_printf(MSG_DEBUG, "Using Android control socket '%s'",
 			   ctrl + 9);
+		priv->android_control_socket = 1;
 		goto havesock;
 	}
 
@@ -884,6 +899,7 @@
 			wpa_printf(MSG_DEBUG,
 				   "Using Android control socket '%s'",
 				   ctrl);
+			priv->android_control_socket = 1;
 			goto havesock;
 		}
 	}
@@ -1064,6 +1080,16 @@
 	if (priv->sock <= 0)
 		return -1;
 
+	/*
+	 * On Android, the control socket being used may be the socket
+	 * that is created when wpa_supplicant is started as a /init.*.rc
+	 * service. Such a socket is maintained as a key-value pair in
+	 * Android's environment. Closing this control socket would leave us
+	 * in a bad state with an invalid socket descriptor.
+	 */
+	if (priv->android_control_socket)
+		return priv->sock;
+
 	eloop_unregister_read_sock(priv->sock);
 	close(priv->sock);
 	priv->sock = -1;
diff --git a/wpa_supplicant/dbus/dbus_common.c b/wpa_supplicant/dbus/dbus_common.c
index 5cc1505..7ef6cad 100644
--- a/wpa_supplicant/dbus/dbus_common.c
+++ b/wpa_supplicant/dbus/dbus_common.c
@@ -165,6 +165,7 @@
 static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data)
 {
 	struct wpas_dbus_priv *priv = data;
+
 	if (!dbus_timeout_get_enabled(timeout))
 		return TRUE;
 
@@ -180,6 +181,7 @@
 static void remove_timeout(DBusTimeout *timeout, void *data)
 {
 	struct wpas_dbus_priv *priv = data;
+
 	eloop_cancel_timeout(process_timeout, priv, timeout);
 	dbus_timeout_set_data(timeout, NULL, NULL);
 }
@@ -244,8 +246,7 @@
 						   remove_timeout,
 						   timeout_toggled, priv,
 						   NULL)) {
-		wpa_printf(MSG_ERROR, "dbus: Failed to set callback "
-			   "functions");
+		wpa_printf(MSG_ERROR, "dbus: Failed to set callback functions");
 		return -1;
 	}
 
@@ -259,12 +260,12 @@
 
 
 static DBusHandlerResult disconnect_filter(DBusConnection *conn,
-                                           DBusMessage *message, void *data)
+					   DBusMessage *message, void *data)
 {
 	struct wpas_dbus_priv *priv = data;
 
 	if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL,
-	                           "Disconnected")) {
+				   "Disconnected")) {
 		wpa_printf(MSG_DEBUG, "dbus: bus disconnected, terminating");
 		dbus_connection_set_exit_on_disconnect(conn, FALSE);
 		wpa_supplicant_terminate_proc(priv->global);
@@ -284,10 +285,11 @@
 	priv->con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
 	if (priv->con) {
 		dbus_connection_add_filter(priv->con, disconnect_filter, priv,
-		                           NULL);
+					   NULL);
 	} else {
-		wpa_printf(MSG_ERROR, "dbus: Could not acquire the system "
-			   "bus: %s - %s", error.name, error.message);
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not acquire the system bus: %s - %s",
+			   error.name, error.message);
 		ret = -1;
 	}
 	dbus_error_free(&error);
@@ -309,7 +311,7 @@
 	 * FIXME: is there a better solution to this problem?
 	 */
 	eloop_register_timeout(0, 50, dispatch_initial_dbus_messages,
-	                       priv->con, NULL);
+			       priv->con, NULL);
 
 	return 0;
 }
@@ -345,26 +347,14 @@
 		return NULL;
 	priv->global = global;
 
-	if (wpas_dbus_init_common(priv) < 0) {
-		wpas_dbus_deinit(priv);
-		return NULL;
-	}
-
+	if (wpas_dbus_init_common(priv) < 0 ||
 #ifdef CONFIG_CTRL_IFACE_DBUS_NEW
-	if (wpas_dbus_ctrl_iface_init(priv) < 0) {
-		wpas_dbus_deinit(priv);
-		return NULL;
-	}
+	    wpas_dbus_ctrl_iface_init(priv) < 0 ||
 #endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
-
 #ifdef CONFIG_CTRL_IFACE_DBUS
-	if (wpa_supplicant_dbus_ctrl_iface_init(priv) < 0) {
-		wpas_dbus_deinit(priv);
-		return NULL;
-	}
+	    wpa_supplicant_dbus_ctrl_iface_init(priv) < 0 ||
 #endif /* CONFIG_CTRL_IFACE_DBUS */
-
-	if (wpas_dbus_init_common_finish(priv) < 0) {
+	    wpas_dbus_init_common_finish(priv) < 0) {
 		wpas_dbus_deinit(priv);
 		return NULL;
 	}
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index 949ce7c..317661a 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -66,7 +66,7 @@
 
 const char * wpa_dbus_type_as_string(const int type)
 {
-	switch(type) {
+	switch (type) {
 	case DBUS_TYPE_BYTE:
 		return DBUS_TYPE_BYTE_AS_STRING;
 	case DBUS_TYPE_BOOLEAN:
@@ -106,11 +106,8 @@
 					      iter_dict_entry))
 		return FALSE;
 
-	if (!dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
-					    &key))
-		return FALSE;
-
-	return TRUE;
+	return dbus_message_iter_append_basic(iter_dict_entry, DBUS_TYPE_STRING,
+					      &key);
 }
 
 
@@ -120,10 +117,8 @@
 {
 	if (!dbus_message_iter_close_container(iter_dict_entry, iter_dict_val))
 		return FALSE;
-	if (!dbus_message_iter_close_container(iter_dict, iter_dict_entry))
-		return FALSE;
 
-	return TRUE;
+	return dbus_message_iter_close_container(iter_dict, iter_dict_entry);
 }
 
 
@@ -143,22 +138,15 @@
 		return FALSE;
 
 	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
-					    key, value_type))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(&iter_dict_entry,
+					    key, value_type) ||
+	    !dbus_message_iter_open_container(&iter_dict_entry,
 					      DBUS_TYPE_VARIANT,
-					      type_as_string, &iter_dict_val))
+					      type_as_string, &iter_dict_val) ||
+	    !dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
 		return FALSE;
 
-	if (!dbus_message_iter_append_basic(&iter_dict_val, value_type, value))
-		return FALSE;
-
-	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
-					  &iter_dict_val))
-		return FALSE;
-
-	return TRUE;
+	return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+					    &iter_dict_val);
 }
 
 
@@ -170,17 +158,13 @@
 	dbus_uint32_t i;
 
 	if (!_wpa_dbus_add_dict_entry_start(iter_dict, &iter_dict_entry,
-					    key, DBUS_TYPE_ARRAY))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(&iter_dict_entry,
+					    key, DBUS_TYPE_ARRAY) ||
+	    !dbus_message_iter_open_container(&iter_dict_entry,
 					      DBUS_TYPE_VARIANT,
 					      DBUS_TYPE_ARRAY_AS_STRING
 					      DBUS_TYPE_BYTE_AS_STRING,
-					      &iter_dict_val))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
+					      &iter_dict_val) ||
+	    !dbus_message_iter_open_container(&iter_dict_val, DBUS_TYPE_ARRAY,
 					      DBUS_TYPE_BYTE_AS_STRING,
 					      &iter_array))
 		return FALSE;
@@ -195,11 +179,8 @@
 	if (!dbus_message_iter_close_container(&iter_dict_val, &iter_array))
 		return FALSE;
 
-	if (!_wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
-					  &iter_dict_val))
-		return FALSE;
-
-	return TRUE;
+	return _wpa_dbus_add_dict_entry_end(iter_dict, &iter_dict_entry,
+					    &iter_dict_val);
 }
 
 
@@ -428,9 +409,7 @@
 					    const char *value,
 					    const dbus_uint32_t value_len)
 {
-	if (!key)
-		return FALSE;
-	if (!value && (value_len != 0))
+	if (!key || (!value && value_len != 0))
 		return FALSE;
 	return _wpa_dbus_add_dict_entry_byte_array(iter_dict, key, value,
 						   value_len);
@@ -465,27 +444,20 @@
 	err = os_snprintf(array_type, sizeof(array_type),
 			  DBUS_TYPE_ARRAY_AS_STRING "%s",
 			  type);
-	if (err < 0 || err > (int) sizeof(array_type))
+	if (os_snprintf_error(sizeof(array_type), err))
 		return FALSE;
 
-	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
-		return FALSE;
-
-	if (!_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
-					    key, DBUS_TYPE_ARRAY))
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(iter_dict_entry,
+	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
+	    !_wpa_dbus_add_dict_entry_start(iter_dict, iter_dict_entry,
+					    key, DBUS_TYPE_ARRAY) ||
+	    !dbus_message_iter_open_container(iter_dict_entry,
 					      DBUS_TYPE_VARIANT,
 					      array_type,
 					      iter_dict_val))
 		return FALSE;
 
-	if (!dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
-					      type, iter_array))
-		return FALSE;
-
-	return TRUE;
+	return dbus_message_iter_open_container(iter_dict_val, DBUS_TYPE_ARRAY,
+						type, iter_array);
 }
 
 
@@ -542,10 +514,8 @@
 	DBusMessageIter iter_bytes;
 	size_t i;
 
-	if (!iter_array || !value)
-		return FALSE;
-
-	if (!dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
+	if (!iter_array || !value ||
+	    !dbus_message_iter_open_container(iter_array, DBUS_TYPE_ARRAY,
 					      DBUS_TYPE_BYTE_AS_STRING,
 					      &iter_bytes))
 		return FALSE;
@@ -557,10 +527,7 @@
 			return FALSE;
 	}
 
-	if (!dbus_message_iter_close_container(iter_array, &iter_bytes))
-		return FALSE;
-
-	return TRUE;
+	return dbus_message_iter_close_container(iter_array, &iter_bytes);
 }
 
 
@@ -586,17 +553,12 @@
 				    DBusMessageIter *iter_dict_val,
 				    DBusMessageIter *iter_array)
 {
-	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array)
+	if (!iter_dict || !iter_dict_entry || !iter_dict_val || !iter_array ||
+	    !dbus_message_iter_close_container(iter_dict_val, iter_array))
 		return FALSE;
 
-	if (!dbus_message_iter_close_container(iter_dict_val, iter_array))
-		return FALSE;
-
-	if (!_wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
-					  iter_dict_val))
-		return FALSE;
-
-	return TRUE;
+	return _wpa_dbus_add_dict_entry_end(iter_dict, iter_dict_entry,
+					    iter_dict_val);
 }
 
 
@@ -619,12 +581,8 @@
 	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
 	dbus_uint32_t i;
 
-	if (!key)
-		return FALSE;
-	if (!items && (num_items != 0))
-		return FALSE;
-
-	if (!wpa_dbus_dict_begin_string_array(iter_dict, key,
+	if (!key || (!items && num_items != 0) ||
+	    !wpa_dbus_dict_begin_string_array(iter_dict, key,
 					      &iter_dict_entry, &iter_dict_val,
 					      &iter_array))
 		return FALSE;
@@ -635,11 +593,8 @@
 			return FALSE;
 	}
 
-	if (!wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
-					    &iter_dict_val, &iter_array))
-		return FALSE;
-
-	return TRUE;
+	return wpa_dbus_dict_end_string_array(iter_dict, &iter_dict_entry,
+					      &iter_dict_val, &iter_array);
 }
 
 
@@ -662,12 +617,9 @@
 	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array;
 	dbus_uint32_t i;
 
-	if (!key)
-		return FALSE;
-	if (!items && (num_items != 0))
-		return FALSE;
-
-	if (!wpa_dbus_dict_begin_array(iter_dict, key,
+	if (!key ||
+	    (!items && num_items != 0) ||
+	    !wpa_dbus_dict_begin_array(iter_dict, key,
 				       DBUS_TYPE_ARRAY_AS_STRING
 				       DBUS_TYPE_BYTE_AS_STRING,
 				       &iter_dict_entry, &iter_dict_val,
@@ -681,11 +633,8 @@
 			return FALSE;
 	}
 
-	if (!wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
-				     &iter_dict_val, &iter_array))
-		return FALSE;
-
-	return TRUE;
+	return wpa_dbus_dict_end_array(iter_dict, &iter_dict_entry,
+				       &iter_dict_val, &iter_array);
 }
 
 
@@ -707,16 +656,25 @@
 				    DBusMessageIter *iter_dict,
 				    DBusError *error)
 {
+	int type;
+
+	wpa_printf(MSG_MSGDUMP, "%s: start reading a dict entry", __func__);
 	if (!iter || !iter_dict) {
 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
-		                     "[internal] missing message iterators");
+				     "[internal] missing message iterators");
 		return FALSE;
 	}
 
-	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
+	type = dbus_message_iter_get_arg_type(iter);
+	if (type != DBUS_TYPE_ARRAY ||
 	    dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: unexpected message argument types (arg=%c element=%c)",
+			   __func__, type,
+			   type != DBUS_TYPE_ARRAY ? '?' :
+			   dbus_message_iter_get_element_type(iter));
 		dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
-		                     "unexpected message argument types");
+				     "unexpected message argument types");
 		return FALSE;
 	}
 
@@ -753,10 +711,9 @@
 				BYTE_ARRAY_ITEM_SIZE);
 			if (nbuffer == NULL) {
 				os_free(buffer);
-				wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
-					   "entry_get_byte_array out of "
-					   "memory trying to retrieve the "
-					   "string array");
+				wpa_printf(MSG_ERROR,
+					   "dbus: %s out of memory trying to retrieve the string array",
+					   __func__);
 				goto done;
 			}
 			buffer = nbuffer;
@@ -768,6 +725,8 @@
 		entry->array_len = ++count;
 		dbus_message_iter_next(iter);
 	}
+	wpa_hexdump_key(MSG_MSGDUMP, "dbus: byte array contents",
+			entry->bytearray_value, entry->array_len);
 
 	/* Zero-length arrays are valid. */
 	if (entry->array_len == 0) {
@@ -812,10 +771,9 @@
 				STR_ARRAY_ITEM_SIZE);
 			if (nbuffer == NULL) {
 				os_free(buffer);
-				wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_"
-					   "entry_get_string_array out of "
-					   "memory trying to retrieve the "
-					   "string array");
+				wpa_printf(MSG_ERROR,
+					   "dbus: %s out of memory trying to retrieve the string array",
+					   __func__);
 				goto done;
 			}
 			buffer = nbuffer;
@@ -823,17 +781,21 @@
 		entry->strarray_value = buffer;
 
 		dbus_message_iter_get_basic(iter, &value);
+		wpa_printf(MSG_MSGDUMP, "%s: string_array value: %s",
+			   __func__, wpa_debug_show_keys ? value : "[omitted]");
 		str = os_strdup(value);
 		if (str == NULL) {
-			wpa_printf(MSG_ERROR, "dbus: _wpa_dbus_dict_entry_get_"
-				   "string_array out of memory trying to "
-				   "duplicate the string array");
+			wpa_printf(MSG_ERROR,
+				   "dbus: %s out of memory trying to duplicate the string array",
+				   __func__);
 			goto done;
 		}
 		entry->strarray_value[count] = str;
 		entry->array_len = ++count;
 		dbus_message_iter_next(iter);
 	}
+	wpa_printf(MSG_MSGDUMP, "%s: string_array length %u",
+		   __func__, entry->array_len);
 
 	/* Zero-length arrays are valid. */
 	if (entry->array_len == 0) {
@@ -856,15 +818,31 @@
 {
 	struct wpa_dbus_dict_entry tmpentry;
 	size_t buflen = 0;
-	int i;
-
-	if (dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
-		return FALSE;
+	int i, type;
 
 	entry->array_type = WPAS_DBUS_TYPE_BINARRAY;
 	entry->array_len = 0;
 	entry->binarray_value = NULL;
 
+	type = dbus_message_iter_get_arg_type(iter);
+	wpa_printf(MSG_MSGDUMP, "%s: parsing binarray type %c", __func__, type);
+	if (type == DBUS_TYPE_INVALID) {
+		/* Likely an empty array of arrays */
+		return TRUE;
+	}
+	if (type != DBUS_TYPE_ARRAY) {
+		wpa_printf(MSG_DEBUG, "%s: not an array type: %c",
+			   __func__, type);
+		return FALSE;
+	}
+
+	type = dbus_message_iter_get_element_type(iter);
+	if (type != DBUS_TYPE_BYTE) {
+		wpa_printf(MSG_DEBUG, "%s: unexpected element type %c",
+			   __func__, type);
+		return FALSE;
+	}
+
 	while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_ARRAY) {
 		DBusMessageIter iter_array;
 
@@ -884,7 +862,7 @@
 		os_memset(&tmpentry, 0, sizeof(tmpentry));
 		tmpentry.type = DBUS_TYPE_ARRAY;
 		if (_wpa_dbus_dict_entry_get_byte_array(&iter_array, &tmpentry)
-					== FALSE)
+		    == FALSE)
 			goto cleanup;
 
 		entry->binarray_value[entry->array_len] =
@@ -897,6 +875,8 @@
 		entry->array_len++;
 		dbus_message_iter_next(iter);
 	}
+	wpa_printf(MSG_MSGDUMP, "%s: binarray length %u",
+		   __func__, entry->array_len);
 
 	return TRUE;
 
@@ -917,12 +897,11 @@
 	dbus_bool_t success = FALSE;
 	DBusMessageIter iter_array;
 
-	if (!entry)
-		return FALSE;
+	wpa_printf(MSG_MSGDUMP, "%s: array_type %c", __func__, array_type);
 
 	dbus_message_iter_recurse(iter_dict_val, &iter_array);
 
- 	switch (array_type) {
+	switch (array_type) {
 	case DBUS_TYPE_BYTE:
 		success = _wpa_dbus_dict_entry_get_byte_array(&iter_array,
 							      entry);
@@ -936,6 +915,8 @@
 		success = _wpa_dbus_dict_entry_get_binarray(&iter_array, entry);
 		break;
 	default:
+		wpa_printf(MSG_MSGDUMP, "%s: unsupported array type %c",
+			   __func__, array_type);
 		break;
 	}
 
@@ -950,42 +931,72 @@
 
 	switch (entry->type) {
 	case DBUS_TYPE_OBJECT_PATH:
+		dbus_message_iter_get_basic(iter, &v);
+		wpa_printf(MSG_MSGDUMP, "%s: object path value: %s",
+			   __func__, v);
+		entry->str_value = os_strdup(v);
+		if (entry->str_value == NULL)
+			return FALSE;
+		break;
 	case DBUS_TYPE_STRING:
 		dbus_message_iter_get_basic(iter, &v);
+		wpa_printf(MSG_MSGDUMP, "%s: string value: %s",
+			   __func__, wpa_debug_show_keys ? v : "[omitted]");
 		entry->str_value = os_strdup(v);
 		if (entry->str_value == NULL)
 			return FALSE;
 		break;
 	case DBUS_TYPE_BOOLEAN:
 		dbus_message_iter_get_basic(iter, &entry->bool_value);
+		wpa_printf(MSG_MSGDUMP, "%s: boolean value: %d",
+			   __func__, entry->bool_value);
 		break;
 	case DBUS_TYPE_BYTE:
 		dbus_message_iter_get_basic(iter, &entry->byte_value);
+		wpa_printf(MSG_MSGDUMP, "%s: byte value: %d",
+			   __func__, entry->byte_value);
 		break;
 	case DBUS_TYPE_INT16:
 		dbus_message_iter_get_basic(iter, &entry->int16_value);
+		wpa_printf(MSG_MSGDUMP, "%s: int16 value: %d",
+			   __func__, entry->int16_value);
 		break;
 	case DBUS_TYPE_UINT16:
 		dbus_message_iter_get_basic(iter, &entry->uint16_value);
+		wpa_printf(MSG_MSGDUMP, "%s: uint16 value: %d",
+			   __func__, entry->uint16_value);
 		break;
 	case DBUS_TYPE_INT32:
 		dbus_message_iter_get_basic(iter, &entry->int32_value);
+		wpa_printf(MSG_MSGDUMP, "%s: int32 value: %d",
+			   __func__, entry->int32_value);
 		break;
 	case DBUS_TYPE_UINT32:
 		dbus_message_iter_get_basic(iter, &entry->uint32_value);
+		wpa_printf(MSG_MSGDUMP, "%s: uint32 value: %d",
+			   __func__, entry->uint32_value);
 		break;
 	case DBUS_TYPE_INT64:
 		dbus_message_iter_get_basic(iter, &entry->int64_value);
+		wpa_printf(MSG_MSGDUMP, "%s: int64 value: %lld",
+			   __func__, (long long int) entry->int64_value);
 		break;
 	case DBUS_TYPE_UINT64:
 		dbus_message_iter_get_basic(iter, &entry->uint64_value);
+		wpa_printf(MSG_MSGDUMP, "%s: uint64 value: %llu",
+			   __func__,
+			   (unsigned long long int) entry->uint64_value);
 		break;
 	case DBUS_TYPE_DOUBLE:
 		dbus_message_iter_get_basic(iter, &entry->double_value);
+		wpa_printf(MSG_MSGDUMP, "%s: double value: %f",
+			   __func__, entry->double_value);
 		break;
 	case DBUS_TYPE_ARRAY:
 		return _wpa_dbus_dict_entry_get_array(iter, entry);
 	default:
+		wpa_printf(MSG_MSGDUMP, "%s: unsupported type %c",
+			   __func__, entry->type);
 		return FALSE;
 	}
 
@@ -1016,26 +1027,40 @@
 	int type;
 	const char *key;
 
-	if (!iter_dict || !entry)
+	if (!iter_dict || !entry ||
+	    dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY) {
+		wpa_printf(MSG_DEBUG, "%s: not a dict entry", __func__);
 		goto error;
-
-	if (dbus_message_iter_get_arg_type(iter_dict) != DBUS_TYPE_DICT_ENTRY)
-		goto error;
+	}
 
 	dbus_message_iter_recurse(iter_dict, &iter_dict_entry);
 	dbus_message_iter_get_basic(&iter_dict_entry, &key);
+	wpa_printf(MSG_MSGDUMP, "%s: dict entry key: %s", __func__, key);
 	entry->key = key;
 
-	if (!dbus_message_iter_next(&iter_dict_entry))
+	if (!dbus_message_iter_next(&iter_dict_entry)) {
+		wpa_printf(MSG_DEBUG, "%s: no variant in dict entry", __func__);
 		goto error;
+	}
 	type = dbus_message_iter_get_arg_type(&iter_dict_entry);
-	if (type != DBUS_TYPE_VARIANT)
+	if (type != DBUS_TYPE_VARIANT) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: unexpected dict entry variant type: %c",
+			   __func__, type);
 		goto error;
+	}
 
 	dbus_message_iter_recurse(&iter_dict_entry, &iter_dict_val);
 	entry->type = dbus_message_iter_get_arg_type(&iter_dict_val);
-	if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val))
+	wpa_printf(MSG_MSGDUMP, "%s: dict entry variant content type: %c",
+		   __func__, entry->type);
+	entry->array_type = DBUS_TYPE_INVALID;
+	if (!_wpa_dbus_dict_fill_value_from_variant(entry, &iter_dict_val)) {
+		wpa_printf(MSG_DEBUG,
+			   "%s: failed to fetch dict values from variant",
+			   __func__);
 		goto error;
+	}
 
 	dbus_message_iter_next(iter_dict);
 	return TRUE;
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index 9666349..b068431 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -72,28 +72,28 @@
 
 /* Manual construction and addition of array elements */
 dbus_bool_t wpa_dbus_dict_begin_array(DBusMessageIter *iter_dict,
-                                      const char *key, const char *type,
-                                      DBusMessageIter *iter_dict_entry,
-                                      DBusMessageIter *iter_dict_val,
-                                      DBusMessageIter *iter_array);
+				      const char *key, const char *type,
+				      DBusMessageIter *iter_dict_entry,
+				      DBusMessageIter *iter_dict_val,
+				      DBusMessageIter *iter_array);
 
 dbus_bool_t wpa_dbus_dict_begin_string_array(DBusMessageIter *iter_dict,
-                                             const char *key,
-                                             DBusMessageIter *iter_dict_entry,
-                                             DBusMessageIter *iter_dict_val,
-                                             DBusMessageIter *iter_array);
+					     const char *key,
+					     DBusMessageIter *iter_dict_entry,
+					     DBusMessageIter *iter_dict_val,
+					     DBusMessageIter *iter_array);
 
 dbus_bool_t wpa_dbus_dict_string_array_add_element(DBusMessageIter *iter_array,
-                                             const char *elem);
+						   const char *elem);
 
 dbus_bool_t wpa_dbus_dict_bin_array_add_element(DBusMessageIter *iter_array,
 						const u8 *value,
 						size_t value_len);
 
 dbus_bool_t wpa_dbus_dict_end_array(DBusMessageIter *iter_dict,
-                                    DBusMessageIter *iter_dict_entry,
-                                    DBusMessageIter *iter_dict_val,
-                                    DBusMessageIter *iter_array);
+				    DBusMessageIter *iter_dict_entry,
+				    DBusMessageIter *iter_dict_val,
+				    DBusMessageIter *iter_array);
 
 static inline dbus_bool_t
 wpa_dbus_dict_end_string_array(DBusMessageIter *iter_dict,
@@ -120,7 +120,11 @@
  * Reading a dict from a DBusMessage
  */
 
-#define WPAS_DBUS_TYPE_BINARRAY (DBUS_NUMBER_OF_TYPES + 100)
+/*
+ * Used only in struct wpa_dbus_dict_entry::array_type internally to identify
+ * special binary array case.
+ */
+#define WPAS_DBUS_TYPE_BINARRAY ((int) '@')
 
 struct wpa_dbus_dict_entry {
 	int type;         /** the dbus type of the dict entry's value */
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 5e58c5b..b21b7a8 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -75,8 +75,7 @@
 			return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 		}
 
-		for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next)
-		{
+		for (wpa_s = priv->global->ifaces; wpa_s; wpa_s = wpa_s->next) {
 			if (wpa_s->preq_notify_peer != NULL &&
 			    os_strcmp(name, wpa_s->preq_notify_peer) == 0 &&
 			    (new_owner == NULL || os_strlen(new_owner) == 0)) {
@@ -148,22 +147,14 @@
 
 	dbus_message_iter_init_append(msg, &iter);
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &wpa_s->dbus_new_path))
-		goto err;
-
-	if (properties) {
-		if (!wpa_dbus_get_object_properties(
-			    iface, wpa_s->dbus_new_path,
-			    WPAS_DBUS_NEW_IFACE_INTERFACE, &iter))
-			goto err;
-	}
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+					    &wpa_s->dbus_new_path) ||
+	    (properties &&
+	     !wpa_dbus_get_object_properties(
+		     iface, wpa_s->dbus_new_path,
+		     WPAS_DBUS_NEW_IFACE_INTERFACE, &iter)))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -229,7 +220,7 @@
 
 
 /**
- * wpas_dbus_signal_blob - Send a BSS related event signal
+ * wpas_dbus_signal_bss - Send a BSS related event signal
  * @wpa_s: %wpa_supplicant network interface data
  * @bss_obj_path: BSS object path
  * @sig_name: signal name - BSSAdded or BSSRemoved
@@ -259,22 +250,14 @@
 
 	dbus_message_iter_init_append(msg, &iter);
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &bss_obj_path))
-		goto err;
-
-	if (properties) {
-		if (!wpa_dbus_get_object_properties(iface, bss_obj_path,
-						    WPAS_DBUS_NEW_IFACE_BSS,
-						    &iter))
-			goto err;
-	}
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+					    &bss_obj_path) ||
+	    (properties &&
+	     !wpa_dbus_get_object_properties(iface, bss_obj_path,
+					     WPAS_DBUS_NEW_IFACE_BSS,
+					     &iter)))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -407,23 +390,14 @@
 	dbus_message_iter_init_append(msg, &iter);
 	path = net_obj_path;
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &path))
-		goto err;
-
-	if (properties) {
-		if (!wpa_dbus_get_object_properties(
-			    iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
-			    &iter))
-			goto err;
-	}
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+					    &path) ||
+	    (properties &&
+	     !wpa_dbus_get_object_properties(
+		     iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
+		     &iter)))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -513,19 +487,12 @@
 
 	dbus_message_iter_init_append(msg, &iter);
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &net_ptr))
-		goto err;
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field))
-		goto err;
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
-		goto err;
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+					    &net_ptr) ||
+	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &field) ||
+	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &txt))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -543,6 +510,7 @@
 {
 
 	char path[WPAS_DBUS_OBJECT_PATH_MAX];
+
 	os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
 		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%d",
 		    wpa_s->dbus_new_path, ssid->id);
@@ -749,15 +717,11 @@
 	if (cred->encr_type & WPS_ENCR_AES)
 		encr_type[et_num++] = "aes";
 
-	if (wpa_s->current_ssid) {
-		if (!wpa_dbus_dict_append_byte_array(
-			    &dict_iter, "BSSID",
-			    (const char *) wpa_s->current_ssid->bssid,
-			    ETH_ALEN))
-			goto nomem;
-	}
-
-	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
+	if ((wpa_s->current_ssid &&
+	     !wpa_dbus_dict_append_byte_array(
+		     &dict_iter, "BSSID",
+		     (const char *) wpa_s->current_ssid->bssid, ETH_ALEN)) ||
+	    !wpa_dbus_dict_append_byte_array(&dict_iter, "SSID",
 					     (const char *) cred->ssid,
 					     cred->ssid_len) ||
 	    !wpa_dbus_dict_append_string_array(&dict_iter, "AuthType",
@@ -804,29 +768,20 @@
 		return;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
-	    !wpa_dbus_dict_append_string(&dict_iter, "subject", subject))
-		goto nomem;
-
-	if (cert_hash &&
-	    !wpa_dbus_dict_append_string(&dict_iter, "cert_hash", cert_hash))
-		goto nomem;
-
-	if (cert &&
-	    !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
-					     wpabuf_head(cert),
-					     wpabuf_len(cert)))
-		goto nomem;
-
-	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto nomem;
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "depth", depth) ||
+	    !wpa_dbus_dict_append_string(&dict_iter, "subject", subject) ||
+	    (cert_hash &&
+	     !wpa_dbus_dict_append_string(&dict_iter, "cert_hash",
+					  cert_hash)) ||
+	    (cert &&
+	     !wpa_dbus_dict_append_byte_array(&dict_iter, "cert",
+					      wpabuf_head(cert),
+					      wpabuf_len(cert))) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -852,15 +807,12 @@
 
 	dbus_message_iter_init_append(msg, &iter);
 
-	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status)
-	    ||
+	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &status) ||
 	    !dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
 					    &parameter))
-		goto nomem;
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -946,49 +898,40 @@
 void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
 					const char *role)
 {
-	int error = 1;
 	DBusMessage *msg;
 	DBusMessageIter iter, dict_iter;
 	struct wpas_dbus_priv *iface = wpa_s->global->dbus;
+	struct wpa_supplicant *parent;
 
 	/* Do nothing if the control interface is not turned on */
 	if (iface == NULL)
 		return;
 
+	parent = wpa_s->parent;
+	if (parent->p2p_mgmt)
+		parent = parent->parent;
+
 	if (!wpa_s->dbus_groupobj_path)
 		return;
 
-	msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path,
+	msg = dbus_message_new_signal(parent->dbus_new_path,
 				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 				      "GroupFinished");
 	if (msg == NULL)
 		return;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_object_path(&dict_iter,
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter,
 					      "interface_object",
-					      wpa_s->dbus_new_path))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_string(&dict_iter, "role", role))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+					      wpa_s->dbus_new_path) ||
+	    !wpa_dbus_dict_append_string(&dict_iter, "role", role) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
 					      wpa_s->dbus_groupobj_path) ||
 	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto nomem;
-
-	error = 0;
-	dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
-	if (error > 0)
-		wpa_printf(MSG_ERROR,
-			   "dbus: Failed to construct GroupFinished");
-
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -1034,6 +977,9 @@
 	if (iface == NULL)
 		return;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	if (request || !status) {
 		if (config_methods & WPS_CONFIG_DISPLAY)
 			_signal = request ?
@@ -1048,9 +994,10 @@
 				   "ProvisionDiscoveryPBCResponse";
 		else
 			return; /* Unknown or un-supported method */
-	} else if (!request && status)
+	} else {
 		/* Explicit check for failure response */
 		_signal = "ProvisionDiscoveryFailure";
+	}
 
 	add_pin = ((request && (config_methods & WPS_CONFIG_DISPLAY)) ||
 		   (!request && !status &&
@@ -1119,6 +1066,9 @@
 	if (iface == NULL)
 		return;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
 		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
 		    wpa_s->dbus_new_path, MAC2STR(src));
@@ -1245,8 +1195,13 @@
 	DBusMessage *msg;
 	DBusMessageIter iter, dict_iter;
 	struct wpas_dbus_priv *iface;
+	struct wpa_supplicant *parent;
 
-	iface = wpa_s->parent->global->dbus;
+	parent = wpa_s->parent;
+	if (parent->p2p_mgmt)
+		parent = parent->parent;
+
+	iface = parent->global->dbus;
 
 	/* Do nothing if the control interface is not turned on */
 	if (iface == NULL)
@@ -1256,41 +1211,33 @@
 		return;
 
 	/* New interface has been created for this group */
-	msg = dbus_message_new_signal(wpa_s->parent->dbus_new_path,
+	msg = dbus_message_new_signal(parent->dbus_new_path,
 				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 				      "GroupStarted");
 	if (msg == NULL)
 		return;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto nomem;
-
 	/*
 	 * In case the device supports creating a separate interface the
 	 * DBus client will need to know the object path for the interface
 	 * object this group was created on, so include it here.
 	 */
-	if (!wpa_dbus_dict_append_object_path(&dict_iter,
-					"interface_object",
-					wpa_s->dbus_new_path))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_string(&dict_iter, "role",
-					 client ? "client" : "GO"))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter,
+					      "interface_object",
+					      wpa_s->dbus_new_path) ||
+	    !wpa_dbus_dict_append_string(&dict_iter, "role",
+					 client ? "client" : "GO") ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter, "group_object",
 					      wpa_s->dbus_groupobj_path) ||
-	   !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto nomem;
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-	if (client)
-		peer_groups_changed(wpa_s);
-
-nomem:
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	} else {
+		dbus_connection_send(iface->con, msg, NULL);
+		if (client)
+			peer_groups_changed(wpa_s);
+	}
 	dbus_message_unref(msg);
 }
 
@@ -1315,6 +1262,9 @@
 
 	iface = wpa_s->global->dbus;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	os_memset(freqs, 0, sizeof(freqs));
 	/* Do nothing if the control interface is not turned on */
 	if (iface == NULL)
@@ -1333,9 +1283,8 @@
 		return;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto err;
-	if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
 					      path) ||
 	    !wpa_dbus_dict_append_int32(&dict_iter, "status", res->status))
 		goto err;
@@ -1344,15 +1293,10 @@
 		int i = 0;
 		int freq_list_num = 0;
 
-		if (res->role_go) {
-			if (!wpa_dbus_dict_append_byte_array(
-				    &dict_iter, "passphrase",
-				    (const char *) res->passphrase,
-				    sizeof(res->passphrase)))
-				goto err;
-		}
-
-		if (!wpa_dbus_dict_append_string(&dict_iter, "role_go",
+		if ((res->role_go &&
+		     !wpa_dbus_dict_append_string(&dict_iter, "passphrase",
+						  res->passphrase)) ||
+		    !wpa_dbus_dict_append_string(&dict_iter, "role_go",
 						 res->role_go ? "GO" :
 						 "client") ||
 		    !wpa_dbus_dict_append_int32(&dict_iter, "frequency",
@@ -1387,22 +1331,16 @@
 					       DBUS_TYPE_INT32_AS_STRING,
 					       &iter_dict_entry,
 					       &iter_dict_val,
-					       &iter_dict_array))
-			goto err;
-
-		if (!dbus_message_iter_append_fixed_array(&iter_dict_array,
+					       &iter_dict_array) ||
+		    !dbus_message_iter_append_fixed_array(&iter_dict_array,
 							  DBUS_TYPE_INT32,
 							  &f_array,
-							  freq_list_num))
-			goto err;
-
-		if (!wpa_dbus_dict_end_array(&dict_iter,
+							  freq_list_num) ||
+		    !wpa_dbus_dict_end_array(&dict_iter,
 					     &iter_dict_entry,
 					     &iter_dict_val,
-					     &iter_dict_array))
-			goto err;
-
-		if (!wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
+					     &iter_dict_array) ||
+		    !wpa_dbus_dict_append_int32(&dict_iter, "persistent_group",
 						res->persistent_group) ||
 		    !wpa_dbus_dict_append_uint32(&dict_iter,
 						 "peer_config_timeout",
@@ -1441,6 +1379,9 @@
 	if (iface == NULL)
 		return;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
 				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 				      "InvitationResult");
@@ -1449,23 +1390,16 @@
 		return;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_int32(&dict_iter, "status", status))
-		goto nomem;
-	if (bssid) {
-		if (!wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
-						     (const char *) bssid,
-						     ETH_ALEN))
-			goto nomem;
-	}
-	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto nomem;
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-nomem:
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_int32(&dict_iter, "status", status) ||
+	    (bssid &&
+	     !wpa_dbus_dict_append_byte_array(&dict_iter, "BSSID",
+					      (const char *) bssid,
+					      ETH_ALEN)) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -1486,6 +1420,7 @@
 	DBusMessage *msg;
 	DBusMessageIter iter;
 	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+	struct wpa_supplicant *parent;
 
 	iface = wpa_s->global->dbus;
 
@@ -1496,10 +1431,14 @@
 	if (!wpa_s->dbus_groupobj_path)
 		return;
 
+	parent = wpa_s->parent;
+	if (parent->p2p_mgmt)
+		parent = parent->parent;
+
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
 			"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
 			COMPACT_MACSTR,
-			wpa_s->parent->dbus_new_path, MAC2STR(peer_addr));
+			parent->dbus_new_path, MAC2STR(peer_addr));
 
 	msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
 				      WPAS_DBUS_NEW_IFACE_P2P_GROUP,
@@ -1510,18 +1449,12 @@
 	dbus_message_iter_init_append(msg, &iter);
 	path = peer_obj_path;
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &path))
-		goto err;
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-
-	wpas_dbus_signal_peer_groups_changed(wpa_s->parent, peer_addr);
-
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+					    &path)) {
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	} else {
+		dbus_connection_send(iface->con, msg, NULL);
+		wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
+	}
 	dbus_message_unref(msg);
 }
 
@@ -1542,6 +1475,7 @@
 	DBusMessage *msg;
 	DBusMessageIter iter;
 	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+	struct wpa_supplicant *parent;
 
 	iface = wpa_s->global->dbus;
 
@@ -1552,10 +1486,14 @@
 	if (!wpa_s->dbus_groupobj_path)
 		return;
 
+	parent = wpa_s->parent;
+	if (parent->p2p_mgmt)
+		parent = parent->parent;
+
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
 			"%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
 			COMPACT_MACSTR,
-			wpa_s->dbus_groupobj_path, MAC2STR(peer_addr));
+			parent->dbus_new_path, MAC2STR(peer_addr));
 
 	msg = dbus_message_new_signal(wpa_s->dbus_groupobj_path,
 				      WPAS_DBUS_NEW_IFACE_P2P_GROUP,
@@ -1566,19 +1504,13 @@
 	dbus_message_iter_init_append(msg, &iter);
 	path = peer_obj_path;
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &path))
-		goto err;
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-
-	wpas_dbus_signal_peer_groups_changed(wpa_s->parent, peer_addr);
-
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct PeerDisconnected "
-			      "signal");
+					    &path)) {
+		wpa_printf(MSG_ERROR,
+			   "dbus: Failed to construct PeerDisconnected signal");
+	} else {
+		dbus_connection_send(iface->con, msg, NULL);
+		wpas_dbus_signal_peer_groups_changed(parent, peer_addr);
+	}
 	dbus_message_unref(msg);
 }
 
@@ -1605,22 +1537,26 @@
 	DBusMessageIter iter, dict_iter;
 	struct wpas_dbus_priv *iface;
 	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
 	iface = wpa_s->global->dbus;
 
 	/* Do nothing if the control interface is not turned on */
 	if (iface == NULL)
 		return;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
+	/* Check if this is a known peer */
+	if (!p2p_peer_known(wpa_s->global->p2p, sa))
+		return;
+
 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
 				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 				      "ServiceDiscoveryRequest");
 	if (msg == NULL)
 		return;
 
-	/* Check if this is a known peer */
-	if (!p2p_peer_known(wpa_s->global->p2p, sa))
-		goto error;
-
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
 		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
 		    COMPACT_MACSTR, wpa_s->dbus_new_path, MAC2STR(sa));
@@ -1628,11 +1564,8 @@
 	path = peer_obj_path;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto error;
-
-
-	if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
 					      path) ||
 	    !wpa_dbus_dict_append_int32(&dict_iter, "frequency", freq) ||
 	    !wpa_dbus_dict_append_int32(&dict_iter, "dialog_token",
@@ -1643,13 +1576,9 @@
 					     (const char *) tlvs,
 					     tlvs_len) ||
 	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto error;
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-error:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
@@ -1674,21 +1603,25 @@
 	DBusMessageIter iter, dict_iter;
 	struct wpas_dbus_priv *iface;
 	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+
 	iface = wpa_s->global->dbus;
 
 	/* Do nothing if the control interface is not turned on */
 	if (iface == NULL)
 		return;
 
-	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
-				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-				"ServiceDiscoveryResponse");
-	if (msg == NULL)
-		return;
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
 
 	/* Check if this is a known peer */
 	if (!p2p_peer_known(wpa_s->global->p2p, sa))
-		goto error;
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
+				      "ServiceDiscoveryResponse");
+	if (msg == NULL)
+		return;
 
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
 		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/"
@@ -1697,10 +1630,8 @@
 	path = peer_obj_path;
 
 	dbus_message_iter_init_append(msg, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto error;
-
-	if (!wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    !wpa_dbus_dict_append_object_path(&dict_iter, "peer_object",
 					      path) ||
 	    !wpa_dbus_dict_append_uint16(&dict_iter, "update_indicator",
 					 update_indic) ||
@@ -1708,17 +1639,13 @@
 					     (const char *) tlvs,
 					     tlvs_len) ||
 	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
-		goto error;
-
-
-	dbus_connection_send(iface->con, msg, NULL);
-	dbus_message_unref(msg);
-	return;
-error:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 	dbus_message_unref(msg);
 }
 
+
 /**
  * wpas_dbus_signal_persistent_group - Send a persistent group related
  *	event signal
@@ -1744,6 +1671,9 @@
 	if (iface == NULL)
 		return;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	os_snprintf(pgrp_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
 		    "%s/" WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/%u",
 		    wpa_s->dbus_new_path, id);
@@ -1757,23 +1687,15 @@
 	dbus_message_iter_init_append(msg, &iter);
 	path = pgrp_obj_path;
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
-					    &path))
-		goto err;
+					    &path) ||
+	    (properties &&
+	     !wpa_dbus_get_object_properties(
+		     iface, pgrp_obj_path,
+		     WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter)))
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 
-	if (properties) {
-		if (!wpa_dbus_get_object_properties(
-			    iface, pgrp_obj_path,
-			    WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter))
-			goto err;
-	}
-
-	dbus_connection_send(iface->con, msg, NULL);
-
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
 	dbus_message_unref(msg);
 }
 
@@ -1832,6 +1754,9 @@
 	if (iface == NULL)
 		return;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
 				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 				      "WpsFailed");
@@ -1853,7 +1778,7 @@
 	dbus_message_unref(msg);
 }
 
-#endif /*CONFIG_P2P*/
+#endif /* CONFIG_P2P */
 
 
 /**
@@ -2047,7 +1972,7 @@
 
 static const struct wpa_dbus_method_desc wpas_dbus_global_methods[] = {
 	{ "CreateInterface", WPAS_DBUS_NEW_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_create_interface,
+	  (WPADBusMethodHandler) wpas_dbus_handler_create_interface,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  { "path", "o", ARG_OUT },
@@ -2055,14 +1980,14 @@
 	  }
 	},
 	{ "RemoveInterface", WPAS_DBUS_NEW_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_interface,
+	  (WPADBusMethodHandler) wpas_dbus_handler_remove_interface,
 	  {
 		  { "path", "o", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "GetInterface", WPAS_DBUS_NEW_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_get_interface,
+	  (WPADBusMethodHandler) wpas_dbus_handler_get_interface,
 	  {
 		  { "ifname", "s", ARG_IN },
 		  { "path", "o", ARG_OUT },
@@ -2120,14 +2045,6 @@
 		  END_ARGS
 	  }
 	},
-	{ "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  {
-		  { "path", "o", ARG_OUT },
-		  { "field", "s", ARG_OUT },
-		  { "text", "s", ARG_OUT },
-		  END_ARGS
-	  }
-	},
 	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
 	{ "PropertiesChanged", WPAS_DBUS_NEW_INTERFACE,
 	  {
@@ -2154,8 +2071,8 @@
 
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		return -1;
 	}
 
@@ -2269,16 +2186,16 @@
 		   net_obj_path);
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		goto err;
 	}
 
 	/* allocate memory for handlers arguments */
 	arg = os_zalloc(sizeof(struct network_handler_args));
 	if (!arg) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create arguments for method");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create arguments for method");
 		goto err;
 	}
 
@@ -2484,15 +2401,15 @@
 
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		goto err;
 	}
 
 	arg = os_zalloc(sizeof(struct bss_handler_args));
 	if (!arg) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create arguments for handler");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create arguments for handler");
 		goto err;
 	}
 	arg->wpa_s = wpa_s;
@@ -2525,27 +2442,27 @@
 
 static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
 	{ "Scan", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_scan,
+	  (WPADBusMethodHandler) wpas_dbus_handler_scan,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "SignalPoll", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_signal_poll,
+	  (WPADBusMethodHandler) wpas_dbus_handler_signal_poll,
 	  {
 		  { "args", "a{sv}", ARG_OUT },
 		  END_ARGS
 	  }
 	},
 	{ "Disconnect", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_disconnect,
+	  (WPADBusMethodHandler) wpas_dbus_handler_disconnect,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "AddNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_add_network,
+	  (WPADBusMethodHandler) wpas_dbus_handler_add_network,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  { "path", "o", ARG_OUT },
@@ -2553,39 +2470,39 @@
 	  }
 	},
 	{ "Reassociate", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_reassociate,
+	  (WPADBusMethodHandler) wpas_dbus_handler_reassociate,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "Reattach", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_reattach,
+	  (WPADBusMethodHandler) wpas_dbus_handler_reattach,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "RemoveNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_network,
+	  (WPADBusMethodHandler) wpas_dbus_handler_remove_network,
 	  {
 		  { "path", "o", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "RemoveAllNetworks", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_all_networks,
+	  (WPADBusMethodHandler) wpas_dbus_handler_remove_all_networks,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "SelectNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_select_network,
+	  (WPADBusMethodHandler) wpas_dbus_handler_select_network,
 	  {
 		  { "path", "o", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_network_reply,
+	  (WPADBusMethodHandler) wpas_dbus_handler_network_reply,
 	  {
 		  { "path", "o", ARG_IN },
 		  { "field", "s", ARG_IN },
@@ -2595,7 +2512,7 @@
 	},
 #ifndef CONFIG_NO_CONFIG_BLOBS
 	{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
+	  (WPADBusMethodHandler) wpas_dbus_handler_add_blob,
 	  {
 		  { "name", "s", ARG_IN },
 		  { "data", "ay", ARG_IN },
@@ -2603,7 +2520,7 @@
 	  }
 	},
 	{ "GetBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_get_blob,
+	  (WPADBusMethodHandler) wpas_dbus_handler_get_blob,
 	  {
 		  { "name", "s", ARG_IN },
 		  { "data", "ay", ARG_OUT },
@@ -2611,7 +2528,7 @@
 	  }
 	},
 	{ "RemoveBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_remove_blob,
+	  (WPADBusMethodHandler) wpas_dbus_handler_remove_blob,
 	  {
 		  { "name", "s", ARG_IN },
 		  END_ARGS
@@ -2620,7 +2537,7 @@
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 	{ "SetPKCS11EngineAndModulePath", WPAS_DBUS_NEW_IFACE_INTERFACE,
 	  (WPADBusMethodHandler)
-	  &wpas_dbus_handler_set_pkcs11_engine_and_module_path,
+	  wpas_dbus_handler_set_pkcs11_engine_and_module_path,
 	  {
 		  { "pkcs11_engine_path", "s", ARG_IN },
 		  { "pkcs11_module_path", "s", ARG_IN },
@@ -2629,7 +2546,7 @@
 	},
 #ifdef CONFIG_WPS
 	{ "Start", WPAS_DBUS_NEW_IFACE_WPS,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_wps_start,
+	  (WPADBusMethodHandler) wpas_dbus_handler_wps_start,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  { "output", "a{sv}", ARG_OUT },
@@ -2639,41 +2556,41 @@
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
 	{ "Find", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_find,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_find,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "StopFind", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_stop_find,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_stop_find,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "Listen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_listen,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_listen,
 	  {
 		  { "timeout", "i", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "ExtendedListen", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_extendedlisten,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_extendedlisten,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "PresenceRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_presence_request,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_presence_request,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "ProvisionDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_prov_disc_req,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_prov_disc_req,
 	  {
 		  { "peer", "o", ARG_IN },
 		  { "config_method", "s", ARG_IN },
@@ -2681,7 +2598,7 @@
 	  }
 	},
 	{ "Connect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_connect,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  { "generated_pin", "s", ARG_OUT },
@@ -2689,60 +2606,60 @@
 	  }
 	},
 	{ "GroupAdd", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_group_add,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_group_add,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "Invite", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_invite,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_invite,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "Disconnect", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_disconnect,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_disconnect,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "RejectPeer", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_rejectpeer,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_rejectpeer,
 	  {
 		  { "peer", "o", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "Flush", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "AddService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_add_service,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_add_service,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "DeleteService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_delete_service,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_delete_service,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "FlushService", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_flush_service,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_flush_service,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "ServiceDiscoveryRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_req,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_req,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  { "ref", "t", ARG_OUT },
@@ -2750,27 +2667,27 @@
 	  }
 	},
 	{ "ServiceDiscoveryResponse", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_res,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_res,
 	  {
 		  { "args", "a{sv}", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "ServiceDiscoveryCancelRequest", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_sd_cancel_req,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_sd_cancel_req,
 	  {
 		  { "args", "t", ARG_IN },
 		  END_ARGS
 	  }
 	},
 	{ "ServiceUpdate", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_service_update,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_service_update,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "ServiceDiscoveryExternal", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_serv_disc_external,
+	  (WPADBusMethodHandler) wpas_dbus_handler_p2p_serv_disc_external,
 	  {
 		  { "arg", "i", ARG_IN },
 		  END_ARGS
@@ -2800,7 +2717,7 @@
 	},
 #endif /* CONFIG_P2P */
 	{ "FlushBSS", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_flush_bss,
+	  (WPADBusMethodHandler) wpas_dbus_handler_flush_bss,
 	  {
 		  { "age", "u", ARG_IN },
 		  END_ARGS
@@ -2821,20 +2738,20 @@
 	},
 #endif /* CONFIG_AP */
 	{ "EAPLogoff", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_eap_logoff,
+	  (WPADBusMethodHandler) wpas_dbus_handler_eap_logoff,
 	  {
 		  END_ARGS
 	  }
 	},
 	{ "EAPLogon", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_eap_logon,
+	  (WPADBusMethodHandler) wpas_dbus_handler_eap_logon,
 	  {
 		  END_ARGS
 	  }
 	},
 #ifdef CONFIG_AUTOSCAN
 	{ "AutoScan", WPAS_DBUS_NEW_IFACE_INTERFACE,
-	  (WPADBusMethodHandler) &wpas_dbus_handler_autoscan,
+	  (WPADBusMethodHandler) wpas_dbus_handler_autoscan,
 	  {
 		  { "arg", "s", ARG_IN },
 		  END_ARGS
@@ -3080,12 +2997,6 @@
 	},
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
-	{ "P2PStateChanged", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-	  {
-		  { "states", "a{ss}", ARG_OUT },
-		  END_ARGS
-	  }
-	},
 	{ "DeviceFound", WPAS_DBUS_NEW_IFACE_P2PDEVICE,
 	  {
 		  { "path", "o", ARG_OUT },
@@ -3246,6 +3157,14 @@
 		  END_ARGS
 	  }
 	},
+	{ "NetworkRequest", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  {
+		  { "path", "o", ARG_OUT },
+		  { "field", "s", ARG_OUT },
+		  { "text", "s", ARG_OUT },
+		  END_ARGS
+	  }
+	},
 	{ NULL, NULL, { END_ARGS } }
 };
 
@@ -3272,8 +3191,8 @@
 
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		goto err;
 	}
 
@@ -3415,6 +3334,9 @@
 	DBusMessageIter iter;
 	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	iface = wpa_s->global->dbus;
 
 	/* Do nothing if the control interface is not turned on */
@@ -3434,15 +3356,10 @@
 	path = peer_obj_path;
 	if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
 					    &path))
-		goto err;
+		wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
+	else
+		dbus_connection_send(iface->con, msg, NULL);
 
-	dbus_connection_send(iface->con, msg, NULL);
-
-	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: Failed to construct signal");
 	dbus_message_unref(msg);
 }
 
@@ -3500,6 +3417,9 @@
 	if (ctrl_iface == NULL)
 		return 0;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
 		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
 		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
@@ -3508,16 +3428,16 @@
 		   peer_obj_path);
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		goto err;
 	}
 
 	/* allocate memory for handlers arguments */
 	arg = os_zalloc(sizeof(struct peer_handler_args));
 	if (!arg) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create arguments for method");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create arguments for method");
 		goto err;
 	}
 
@@ -3559,6 +3479,10 @@
 	if (wpa_s == NULL || wpa_s->global == NULL ||
 	    wpa_s->dbus_new_path == NULL)
 		return 0;
+
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	ctrl_iface = wpa_s->global->dbus;
 	if (ctrl_iface == NULL)
 		return 0;
@@ -3580,6 +3504,9 @@
 {
 	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
 		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
 		    wpa_s->dbus_new_path, MAC2STR(dev_addr));
@@ -3685,8 +3612,8 @@
 		   group_obj_path);
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "Not enough memory "
-			   "to create object description");
+		wpa_printf(MSG_ERROR,
+			   "Not enough memory to create object description");
 		goto err;
 	}
 
@@ -3723,6 +3650,9 @@
 	if (wpa_s == NULL || wpa_s->global == NULL)
 		return;
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	ctrl_iface = wpa_s->global->dbus;
 	if (ctrl_iface == NULL)
 		return;
@@ -3783,6 +3713,9 @@
 	if (ssid->disabled != 2 && !ssid->p2p_persistent_group)
 		return -1; /* should we return w/o complaining? */
 
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	ctrl_iface = wpa_s->global->dbus;
 	if (ctrl_iface == NULL)
 		return 0;
@@ -3799,8 +3732,8 @@
 		   pgrp_obj_path);
 	obj_desc = os_zalloc(sizeof(struct wpa_dbus_object_desc));
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
-			   "object description");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to create object description");
 		goto err;
 	}
 
@@ -3811,8 +3744,8 @@
 	/* allocate memory for handlers arguments */
 	arg = os_zalloc(sizeof(struct network_handler_args));
 	if (!arg) {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to create "
-			   "arguments for method");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to create arguments for method");
 		goto err;
 	}
 
@@ -3862,6 +3795,10 @@
 	if (wpa_s == NULL || wpa_s->global == NULL ||
 	    wpa_s->dbus_new_path == NULL)
 		return 0;
+
+	if (wpa_s->p2p_mgmt)
+		wpa_s = wpa_s->parent;
+
 	ctrl_iface = wpa_s->global->dbus;
 	if (ctrl_iface == NULL)
 		return 0;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index 9f6c4a3..166db5d 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -29,13 +29,13 @@
 #include "dbus_common_i.h"
 #include "drivers/driver.h"
 
-static const char *debug_strings[] = {
+static const char * const debug_strings[] = {
 	"excessive", "msgdump", "debug", "info", "warning", "error", NULL
 };
 
 
 /**
- * wpas_dbus_error_unknown_error - Return a new InvalidArgs error message
+ * wpas_dbus_error_unknown_error - Return a new UnknownError error message
  * @message: Pointer to incoming dbus message this error refers to
  * @arg: Optional string appended to error message
  * Returns: a dbus error message
@@ -45,20 +45,6 @@
 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
 					    const char *arg)
 {
-	/*
-	 * This function can be called as a result of a failure
-	 * within internal getter calls, which will call this function
-	 * with a NULL message parameter.  However, dbus_message_new_error
-	 * looks very unkindly (i.e, abort()) on a NULL message, so
-	 * in this case, we should not call it.
-	 */
-	if (message == NULL) {
-		wpa_printf(MSG_INFO, "dbus: wpas_dbus_error_unknown_error "
-			   "called with NULL message (arg=%s)",
-			   arg ? arg : "N/A");
-		return NULL;
-	}
-
 	return dbus_message_new_error(message, WPAS_DBUS_ERROR_UNKNOWN_ERROR,
 				      arg);
 }
@@ -73,9 +59,9 @@
  */
 static DBusMessage * wpas_dbus_error_iface_unknown(DBusMessage *message)
 {
-	return dbus_message_new_error(message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
-				      "wpa_supplicant knows nothing about "
-				      "this interface.");
+	return dbus_message_new_error(
+		message, WPAS_DBUS_ERROR_IFACE_UNKNOWN,
+		"wpa_supplicant knows nothing about this interface.");
 }
 
 
@@ -88,9 +74,9 @@
  */
 static DBusMessage * wpas_dbus_error_network_unknown(DBusMessage *message)
 {
-	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
-				      "There is no such a network in this "
-				      "interface.");
+	return dbus_message_new_error(
+		message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+		"There is no such a network in this interface.");
 }
 
 
@@ -106,9 +92,9 @@
 {
 	DBusMessage *reply;
 
-	reply = dbus_message_new_error(message, WPAS_DBUS_ERROR_INVALID_ARGS,
-				       "Did not receive correct message "
-				       "arguments.");
+	reply = dbus_message_new_error(
+		message, WPAS_DBUS_ERROR_INVALID_ARGS,
+		"Did not receive correct message arguments.");
 	if (arg != NULL)
 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
 					 DBUS_TYPE_INVALID);
@@ -125,20 +111,23 @@
  *
  * Convenience function to create and return a scan error
  */
-DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
-					 const char *error)
+static DBusMessage * wpas_dbus_error_scan_error(DBusMessage *message,
+						const char *error)
 {
-	DBusMessage *reply;
-
-	reply = dbus_message_new_error(message,
-				       WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
-				       error);
-
-	return reply;
+	return dbus_message_new_error(message,
+				      WPAS_DBUS_ERROR_IFACE_SCAN_ERROR,
+				      error);
 }
 
 
-static const char *dont_quote[] = {
+DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message)
+{
+	wpa_printf(MSG_DEBUG, "dbus: Failed to allocate memory");
+	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+}
+
+
+static const char * const dont_quote[] = {
 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
 	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
 	"bssid", "scan_freq", "freq_list", NULL
@@ -147,6 +136,7 @@
 static dbus_bool_t should_quote_opt(const char *key)
 {
 	int i = 0;
+
 	while (dont_quote[i] != NULL) {
 		if (os_strcmp(key, dont_quote[i]) == 0)
 			return FALSE;
@@ -233,7 +223,7 @@
 
 				ret = os_snprintf(value, size, "\"%s\"",
 						  entry.str_value);
-				if (ret < 0 || (size_t) ret != (size - 1))
+				if (os_snprintf_error(size, ret))
 					goto error;
 			} else {
 				value = os_strdup(entry.str_value);
@@ -247,7 +237,7 @@
 
 			ret = os_snprintf(value, size, "%u",
 					  entry.uint32_value);
-			if (ret <= 0)
+			if (os_snprintf_error(size, ret))
 				goto error;
 		} else if (entry.type == DBUS_TYPE_INT32) {
 			value = os_zalloc(size);
@@ -256,7 +246,7 @@
 
 			ret = os_snprintf(value, size, "%d",
 					  entry.int32_value);
-			if (ret <= 0)
+			if (os_snprintf_error(size, ret))
 				goto error;
 		} else
 			goto error;
@@ -306,27 +296,21 @@
 
 	if (!dbus_type_is_basic(type)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: given type is not basic", __func__);
+			       "%s: given type is not basic", __func__);
 		return FALSE;
 	}
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-	                                      wpa_dbus_type_as_string(type),
-	                                      &variant_iter))
-		goto error;
-
-	if (!dbus_message_iter_append_basic(&variant_iter, type, val))
-		goto error;
-
-	if (!dbus_message_iter_close_container(iter, &variant_iter))
-		goto error;
+					      wpa_dbus_type_as_string(type),
+					      &variant_iter) ||
+	    !dbus_message_iter_append_basic(&variant_iter, type, val) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: error constructing reply", __func__);
+		return FALSE;
+	}
 
 	return TRUE;
-
-error:
-	dbus_set_error(error, DBUS_ERROR_FAILED,
-	               "%s: error constructing reply", __func__);
-	return FALSE;
 }
 
 
@@ -389,7 +373,7 @@
 
 	if (!dbus_type_is_basic(type)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: given type is not basic", __func__);
+			       "%s: given type is not basic", __func__);
 		return FALSE;
 	}
 
@@ -397,20 +381,15 @@
 	type_str[1] = sub_type_str[0];
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-					      type_str, &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 1", __func__);
-		return FALSE;
-	}
-
-	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+					      type_str, &variant_iter) ||
+	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
 					      sub_type_str, &array_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 2", __func__);
+			       "%s: failed to construct message", __func__);
 		return FALSE;
 	}
 
-	switch(type) {
+	switch (type) {
 	case DBUS_TYPE_BYTE:
 	case DBUS_TYPE_BOOLEAN:
 		element_size = 1;
@@ -436,7 +415,7 @@
 		break;
 	default:
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: unknown element type %d", __func__, type);
+			       "%s: unknown element type %d", __func__, type);
 		return FALSE;
 	}
 
@@ -450,15 +429,10 @@
 		}
 	}
 
-	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 3", __func__);
-		return FALSE;
-	}
-
-	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 4", __func__);
+			       "%s: failed to construct message 3", __func__);
 		return FALSE;
 	}
 
@@ -501,15 +475,11 @@
 	inner_type_str[1] = sub_type_str[0];
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-					      type_str, &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-			       "%s: failed to construct message 1", __func__);
-		return FALSE;
-	}
-	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+					      type_str, &variant_iter) ||
+	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
 					      inner_type_str, &array_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-			       "%s: failed to construct message 2", __func__);
+			       "%s: failed to construct message", __func__);
 		return FALSE;
 	}
 
@@ -520,15 +490,10 @@
 
 	}
 
-	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-			       "%s: failed to close message 2", __func__);
-		return FALSE;
-	}
-
-	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-			       "%s: failed to close message 1", __func__);
+			       "%s: failed to close message", __func__);
 		return FALSE;
 	}
 
@@ -566,29 +531,29 @@
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
-		if (!os_strcmp(entry.key, "Driver") &&
-		    (entry.type == DBUS_TYPE_STRING)) {
+		if (os_strcmp(entry.key, "Driver") == 0 &&
+		    entry.type == DBUS_TYPE_STRING) {
 			os_free(driver);
 			driver = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
 			if (driver == NULL)
 				goto error;
-		} else if (!os_strcmp(entry.key, "Ifname") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
+		} else if (os_strcmp(entry.key, "Ifname") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
 			os_free(ifname);
 			ifname = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
 			if (ifname == NULL)
 				goto error;
-		} else if (!os_strcmp(entry.key, "ConfigFile") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
+		} else if (os_strcmp(entry.key, "ConfigFile") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
 			os_free(confname);
 			confname = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
 			if (confname == NULL)
 				goto error;
-		} else if (!os_strcmp(entry.key, "BridgeIfname") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
+		} else if (os_strcmp(entry.key, "BridgeIfname") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
 			os_free(bridge_ifname);
 			bridge_ifname = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
@@ -608,28 +573,30 @@
 	 * an error if we already control it.
 	 */
 	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
-		reply = dbus_message_new_error(message,
-					       WPAS_DBUS_ERROR_IFACE_EXISTS,
-					       "wpa_supplicant already "
-					       "controls this interface.");
+		reply = dbus_message_new_error(
+			message, WPAS_DBUS_ERROR_IFACE_EXISTS,
+			"wpa_supplicant already controls this interface.");
 	} else {
 		struct wpa_supplicant *wpa_s;
 		struct wpa_interface iface;
+
 		os_memset(&iface, 0, sizeof(iface));
 		iface.driver = driver;
 		iface.ifname = ifname;
 		iface.confname = confname;
 		iface.bridge_ifname = bridge_ifname;
 		/* Otherwise, have wpa_supplicant attach to it. */
-		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
+		wpa_s = wpa_supplicant_add_iface(global, &iface);
+		if (wpa_s) {
 			const char *path = wpa_s->dbus_new_path;
+
 			reply = dbus_message_new_method_return(message);
 			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
-			                         &path, DBUS_TYPE_INVALID);
+						 &path, DBUS_TYPE_INVALID);
 		} else {
 			reply = wpas_dbus_error_unknown_error(
-				message, "wpa_supplicant couldn't grab this "
-				"interface.");
+				message,
+				"wpa_supplicant couldn't grab this interface.");
 		}
 	}
 
@@ -672,8 +639,8 @@
 		reply = wpas_dbus_error_iface_unknown(message);
 	else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
 		reply = wpas_dbus_error_unknown_error(
-			message, "wpa_supplicant couldn't remove this "
-			"interface.");
+			message,
+			"wpa_supplicant couldn't remove this interface.");
 	}
 
 	return reply;
@@ -707,13 +674,11 @@
 	path = wpa_s->dbus_new_path;
 	reply = dbus_message_new_method_return(message);
 	if (reply == NULL)
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		return wpas_dbus_error_no_memory(message);
 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
 				      DBUS_TYPE_INVALID)) {
 		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		return wpas_dbus_error_no_memory(message);
 	}
 
 	return reply;
@@ -756,8 +721,8 @@
  * Getter for "DebugTimestamp" property.
  */
 dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
-                                             DBusError *error,
-                                             void *user_data)
+					     DBusError *error,
+					     void *user_data)
 {
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
 						&wpa_debug_timestamp, error);
@@ -812,8 +777,8 @@
 	if (val < 0 ||
 	    wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
 					    wpa_debug_show_keys)) {
-		dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug "
-				     "level value");
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "wrong debug level value");
 		return FALSE;
 	}
 
@@ -963,8 +928,8 @@
  * and P2P that are determined at compile time.
  */
 dbus_bool_t wpas_dbus_getter_global_capabilities(DBusMessageIter *iter,
-					         DBusError *error,
-					         void *user_data)
+						 DBusError *error,
+						 void *user_data)
 {
 	const char *capabilities[5] = { NULL, NULL, NULL, NULL, NULL };
 	size_t num_items = 0;
@@ -993,8 +958,8 @@
 				   char **type, DBusMessage **reply)
 {
 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Type must be a string");
+		wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a string",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
 			message, "Wrong Type value type. String required");
 		return -1;
@@ -1016,36 +981,36 @@
 	int len;
 
 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
-			   "must be an array of arrays of bytes");
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: ssids must be an array of arrays of bytes",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong SSIDs value type. Array of arrays of "
-			"bytes required");
+			message,
+			"Wrong SSIDs value type. Array of arrays of bytes required");
 		return -1;
 	}
 
 	dbus_message_iter_recurse(var, &array_iter);
 
 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
-	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
-	{
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ssids "
-			   "must be an array of arrays of bytes");
+	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: ssids must be an array of arrays of bytes",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong SSIDs value type. Array of arrays of "
-			"bytes required");
+			message,
+			"Wrong SSIDs value type. Array of arrays of bytes required");
 		return -1;
 	}
 
-	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
-	{
+	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
 		if (ssids_num >= WPAS_MAX_SCAN_SSIDS) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Too many ssids specified on scan dbus "
-				   "call");
+			wpa_printf(MSG_DEBUG,
+				   "%s[dbus]: Too many ssids specified on scan dbus call",
+				   __func__);
 			*reply = wpas_dbus_error_invalid_args(
-				message, "Too many ssids specified. Specify "
-				"at most four");
+				message,
+				"Too many ssids specified. Specify at most four");
 			return -1;
 		}
 
@@ -1055,9 +1020,8 @@
 
 		if (len > MAX_SSID_LEN) {
 			wpa_printf(MSG_DEBUG,
-				   "wpas_dbus_handler_scan[dbus]: "
-				   "SSID too long (len=%d max_len=%d)",
-				   len, MAX_SSID_LEN);
+				   "%s[dbus]: SSID too long (len=%d max_len=%d)",
+				   __func__, len, MAX_SSID_LEN);
 			*reply = wpas_dbus_error_invalid_args(
 				message, "Invalid SSID: too long");
 			return -1;
@@ -1066,12 +1030,7 @@
 		if (len != 0) {
 			ssid = os_malloc(len);
 			if (ssid == NULL) {
-				wpa_printf(MSG_DEBUG,
-					   "wpas_dbus_handler_scan[dbus]: "
-					   "out of memory. Cannot allocate "
-					   "memory for SSID");
-				*reply = dbus_message_new_error(
-					message, DBUS_ERROR_NO_MEMORY, NULL);
+				*reply = wpas_dbus_error_no_memory(message);
 				return -1;
 			}
 			os_memcpy(ssid, val, len);
@@ -1103,28 +1062,28 @@
 	int len;
 
 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
-			   "be an array of arrays of bytes");
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: ies must be an array of arrays of bytes",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong IEs value type. Array of arrays of "
-			"bytes required");
+			message,
+			"Wrong IEs value type. Array of arrays of bytes required");
 		return -1;
 	}
 
 	dbus_message_iter_recurse(var, &array_iter);
 
 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_ARRAY ||
-	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE)
-	{
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: ies must "
-			   "be an array of arrays of bytes");
+	    dbus_message_iter_get_element_type(&array_iter) != DBUS_TYPE_BYTE) {
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: ies must be an array of arrays of bytes",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
 			message, "Wrong IEs value type. Array required");
 		return -1;
 	}
 
-	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY)
-	{
+	while (dbus_message_iter_get_arg_type(&array_iter) == DBUS_TYPE_ARRAY) {
 		dbus_message_iter_recurse(&array_iter, &sub_array_iter);
 
 		dbus_message_iter_get_fixed_array(&sub_array_iter, &val, &len);
@@ -1135,12 +1094,8 @@
 
 		nies = os_realloc(ies, ies_len + len);
 		if (nies == NULL) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "out of memory. Cannot allocate memory for "
-				   "IE");
 			os_free(ies);
-			*reply = dbus_message_new_error(
-				message, DBUS_ERROR_NO_MEMORY, NULL);
+			*reply = wpas_dbus_error_no_memory(message);
 			return -1;
 		}
 		ies = nies;
@@ -1166,11 +1121,12 @@
 	int freqs_num = 0;
 
 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_ARRAY) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Channels must be an array of structs");
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: Channels must be an array of structs",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong Channels value type. Array of structs "
-			"required");
+			message,
+			"Wrong Channels value type. Array of structs required");
 		return -1;
 	}
 
@@ -1178,11 +1134,11 @@
 
 	if (dbus_message_iter_get_arg_type(&array_iter) != DBUS_TYPE_STRUCT) {
 		wpa_printf(MSG_DEBUG,
-			   "wpas_dbus_handler_scan[dbus]: Channels must be an "
-			   "array of structs");
+			   "%s[dbus]: Channels must be an array of structs",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
-			message, "Wrong Channels value type. Array of structs "
-			"required");
+			message,
+			"Wrong Channels value type. Array of structs required");
 		return -1;
 	}
 
@@ -1194,14 +1150,14 @@
 
 		if (dbus_message_iter_get_arg_type(&sub_array_iter) !=
 		    DBUS_TYPE_UINT32) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Channel must by specified by struct of "
-				   "two UINT32s %c",
+			wpa_printf(MSG_DEBUG,
+				   "%s[dbus]: Channel must by specified by struct of two UINT32s %c",
+				   __func__,
 				   dbus_message_iter_get_arg_type(
 					   &sub_array_iter));
 			*reply = wpas_dbus_error_invalid_args(
-				message, "Wrong Channel struct. Two UINT32s "
-				"required");
+				message,
+				"Wrong Channel struct. Two UINT32s required");
 			os_free(freqs);
 			return -1;
 		}
@@ -1210,9 +1166,9 @@
 		if (!dbus_message_iter_next(&sub_array_iter) ||
 		    dbus_message_iter_get_arg_type(&sub_array_iter) !=
 		    DBUS_TYPE_UINT32) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Channel must by specified by struct of "
-				   "two UINT32s");
+			wpa_printf(MSG_DEBUG,
+				   "%s[dbus]: Channel must by specified by struct of two UINT32s",
+				   __func__);
 			*reply = wpas_dbus_error_invalid_args(
 				message,
 				"Wrong Channel struct. Two UINT32s required");
@@ -1232,11 +1188,7 @@
 			freqs = nfreqs;
 		}
 		if (freqs == NULL) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "out of memory. can't allocate memory for "
-				   "freqs");
-			*reply = dbus_message_new_error(
-				message, DBUS_ERROR_NO_MEMORY, NULL);
+			*reply = wpas_dbus_error_no_memory(message);
 			return -1;
 		}
 
@@ -1251,10 +1203,7 @@
 		os_free(freqs);
 	freqs = nfreqs;
 	if (freqs == NULL) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "out of memory. Can't allocate memory for freqs");
-		*reply = dbus_message_new_error(
-			message, DBUS_ERROR_NO_MEMORY, NULL);
+		*reply = wpas_dbus_error_no_memory(message);
 		return -1;
 	}
 	freqs[freqs_num] = 0;
@@ -1270,8 +1219,8 @@
 					 DBusMessage **reply)
 {
 	if (dbus_message_iter_get_arg_type(var) != DBUS_TYPE_BOOLEAN) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Type must be a boolean");
+		wpa_printf(MSG_DEBUG, "%s[dbus]: Type must be a boolean",
+			   __func__);
 		*reply = wpas_dbus_error_invalid_args(
 			message, "Wrong Type value type. Boolean required");
 		return -1;
@@ -1308,7 +1257,7 @@
 	dbus_message_iter_recurse(&iter, &dict_iter);
 
 	while (dbus_message_iter_get_arg_type(&dict_iter) ==
-			DBUS_TYPE_DICT_ENTRY) {
+	       DBUS_TYPE_DICT_ENTRY) {
 		dbus_message_iter_recurse(&dict_iter, &entry_iter);
 		dbus_message_iter_get_basic(&entry_iter, &key);
 		dbus_message_iter_next(&entry_iter);
@@ -1337,8 +1286,8 @@
 							  &reply) < 0)
 				goto out;
 		} else {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "Unknown argument %s", key);
+			wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown argument %s",
+				   __func__, key);
 			reply = wpas_dbus_error_invalid_args(message, key);
 			goto out;
 		}
@@ -1347,19 +1296,20 @@
 	}
 
 	if (!type) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Scan type not specified");
+		wpa_printf(MSG_DEBUG, "%s[dbus]: Scan type not specified",
+			   __func__);
 		reply = wpas_dbus_error_invalid_args(message, key);
 		goto out;
 	}
 
-	if (!os_strcmp(type, "passive")) {
+	if (os_strcmp(type, "passive") == 0) {
 		if (params.num_ssids || params.extra_ies_len) {
-			wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-				   "SSIDs or IEs specified for passive scan.");
+			wpa_printf(MSG_DEBUG,
+				   "%s[dbus]: SSIDs or IEs specified for passive scan.",
+				   __func__);
 			reply = wpas_dbus_error_invalid_args(
-				message, "You can specify only Channels in "
-				"passive scan");
+				message,
+				"You can specify only Channels in passive scan");
 			goto out;
 		} else if (params.freqs && params.freqs[0]) {
 			if (wpa_supplicant_trigger_scan(wpa_s, &params)) {
@@ -1370,7 +1320,7 @@
 			wpa_s->scan_req = MANUAL_SCAN_REQ;
 			wpa_supplicant_req_scan(wpa_s, 0, 0);
 		}
-	} else if (!os_strcmp(type, "active")) {
+	} else if (os_strcmp(type, "active") == 0) {
 		if (!params.num_ssids) {
 			/* Add wildcard ssid */
 			params.num_ssids++;
@@ -1383,8 +1333,8 @@
 				message, "Scan request rejected");
 		}
 	} else {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_scan[dbus]: "
-			   "Unknown scan type: %s", type);
+		wpa_printf(MSG_DEBUG, "%s[dbus]: Unknown scan type: %s",
+			   __func__, type);
 		reply = wpas_dbus_error_invalid_args(message,
 						     "Wrong scan type");
 		goto out;
@@ -1433,45 +1383,30 @@
 	dbus_message_iter_init_append(reply, &iter);
 
 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-					      "a{sv}", &variant_iter))
-		goto nomem;
-	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
-		goto nomem;
-
-	if (!wpa_dbus_dict_append_int32(&iter_dict, "rssi", si.current_signal))
-		goto nomem;
-	if (!wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
-					si.current_txrate / 1000))
-		goto nomem;
-	if (!wpa_dbus_dict_append_int32(&iter_dict, "noise", si.current_noise))
-		goto nomem;
-	if (!wpa_dbus_dict_append_uint32(&iter_dict, "frequency", si.frequency))
-		goto nomem;
-
-	if (si.chanwidth != CHAN_WIDTH_UNKNOWN) {
-		if (!wpa_dbus_dict_append_string(&iter_dict, "width",
-					channel_width_to_string(si.chanwidth)))
-			goto nomem;
-	}
-
-	if (si.center_frq1 > 0 && si.center_frq2 > 0) {
-		if (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
-						si.center_frq1))
-			goto nomem;
-		if (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
-						si.center_frq2))
-			goto nomem;
-	}
-
-	if (si.avg_signal) {
-		if (!wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
-						si.avg_signal))
-			goto nomem;
-	}
-
-	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-		goto nomem;
-	if (!dbus_message_iter_close_container(&iter, &variant_iter))
+					      "a{sv}", &variant_iter) ||
+	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict) ||
+	    !wpa_dbus_dict_append_int32(&iter_dict, "rssi",
+					si.current_signal) ||
+	    !wpa_dbus_dict_append_int32(&iter_dict, "linkspeed",
+					si.current_txrate / 1000) ||
+	    !wpa_dbus_dict_append_int32(&iter_dict, "noise",
+					si.current_noise) ||
+	    !wpa_dbus_dict_append_uint32(&iter_dict, "frequency",
+					 si.frequency) ||
+	    (si.chanwidth != CHAN_WIDTH_UNKNOWN &&
+	     !wpa_dbus_dict_append_string(
+		     &iter_dict, "width",
+		     channel_width_to_string(si.chanwidth))) ||
+	    (si.center_frq1 > 0 && si.center_frq2 > 0 &&
+	     (!wpa_dbus_dict_append_int32(&iter_dict, "center-frq1",
+					  si.center_frq1) ||
+	      !wpa_dbus_dict_append_int32(&iter_dict, "center-frq2",
+					  si.center_frq2))) ||
+	    (si.avg_signal &&
+	     !wpa_dbus_dict_append_int32(&iter_dict, "avg-rssi",
+					 si.avg_signal)) ||
+	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+	    !dbus_message_iter_close_container(&iter, &variant_iter))
 		goto nomem;
 
 	return reply;
@@ -1479,8 +1414,7 @@
 nomem:
 	if (reply)
 		dbus_message_unref(reply);
-	reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
-	return reply;
+	return wpas_dbus_error_no_memory(message);
 }
 
 
@@ -1530,12 +1464,11 @@
 
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_handler_add_network[dbus]: "
-			   "can't add new interface.");
+		wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.",
+			   __func__);
 		reply = wpas_dbus_error_unknown_error(
 			message,
-			"wpa_supplicant could not add "
-			"a network on this interface.");
+			"wpa_supplicant could not add a network on this interface.");
 		goto err;
 	}
 	wpas_notify_network_added(wpa_s, ssid);
@@ -1544,9 +1477,9 @@
 
 	dbus_error_init(&error);
 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_handler_add_network[dbus]:"
-			   "control interface couldn't set network "
-			   "properties");
+		wpa_printf(MSG_DEBUG,
+			   "%s[dbus]: control interface couldn't set network properties",
+			   __func__);
 		reply = wpas_dbus_reply_new_from_error(message, &error,
 						       DBUS_ERROR_INVALID_ARGS,
 						       "Failed to add network");
@@ -1561,15 +1494,13 @@
 
 	reply = dbus_message_new_method_return(message);
 	if (reply == NULL) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
 				      DBUS_TYPE_INVALID)) {
 		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 
@@ -1642,7 +1573,7 @@
 {
 	DBusMessage *reply = NULL;
 	const char *op;
-	char *iface = NULL, *net_id = NULL;
+	char *iface, *net_id;
 	int id;
 	struct wpa_ssid *ssid;
 	int was_disabled;
@@ -1652,7 +1583,9 @@
 
 	/* Extract the network ID and ensure the network */
 	/* is actually a child of this interface */
-	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+	iface = wpas_dbus_new_decompose_object_path(op,
+						    WPAS_DBUS_NEW_NETWORKS_PART,
+						    &net_id);
 	if (iface == NULL || net_id == NULL ||
 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
@@ -1680,25 +1613,24 @@
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
 	else if (!was_disabled && wpa_s->sched_scanning) {
-		wpa_printf(MSG_DEBUG, "Stop ongoing sched_scan to remove "
-			   "network from filters");
+		wpa_printf(MSG_DEBUG,
+			   "Stop ongoing sched_scan to remove network from filters");
 		wpa_supplicant_cancel_sched_scan(wpa_s);
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
 	}
 
 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
 		wpa_printf(MSG_ERROR,
-			   "wpas_dbus_handler_remove_network[dbus]: "
-			   "error occurred when removing network %d", id);
+			   "%s[dbus]: error occurred when removing network %d",
+			   __func__, id);
 		reply = wpas_dbus_error_unknown_error(
-			message, "error removing the specified network on "
-			"this interface.");
+			message,
+			"error removing the specified network on is interface.");
 		goto out;
 	}
 
 out:
 	os_free(iface);
-	os_free(net_id);
 	return reply;
 }
 
@@ -1711,9 +1643,8 @@
 
 	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
 		wpa_printf(MSG_ERROR,
-			   "wpas_dbus_handler_remove_all_networks[dbus]: "
-			   "error occurred when removing network %d",
-			   ssid->id);
+			   "%s[dbus]: error occurred when removing network %d",
+			   __func__, ssid->id);
 		return;
 	}
 
@@ -1756,7 +1687,7 @@
 {
 	DBusMessage *reply = NULL;
 	const char *op;
-	char *iface = NULL, *net_id = NULL;
+	char *iface, *net_id;
 	int id;
 	struct wpa_ssid *ssid;
 
@@ -1765,7 +1696,9 @@
 
 	/* Extract the network ID and ensure the network */
 	/* is actually a child of this interface */
-	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+	iface = wpas_dbus_new_decompose_object_path(op,
+						    WPAS_DBUS_NEW_NETWORKS_PART,
+						    &net_id);
 	if (iface == NULL || net_id == NULL ||
 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
@@ -1790,7 +1723,6 @@
 
 out:
 	os_free(iface);
-	os_free(net_id);
 	return reply;
 }
 
@@ -1809,20 +1741,22 @@
 #ifdef IEEE8021X_EAPOL
 	DBusMessage *reply = NULL;
 	const char *op, *field, *value;
-	char *iface = NULL, *net_id = NULL;
+	char *iface, *net_id;
 	int id;
 	struct wpa_ssid *ssid;
 
 	if (!dbus_message_get_args(message, NULL,
-	                           DBUS_TYPE_OBJECT_PATH, &op,
-	                           DBUS_TYPE_STRING, &field,
-	                           DBUS_TYPE_STRING, &value,
-			           DBUS_TYPE_INVALID))
+				   DBUS_TYPE_OBJECT_PATH, &op,
+				   DBUS_TYPE_STRING, &field,
+				   DBUS_TYPE_STRING, &value,
+				   DBUS_TYPE_INVALID))
 		return wpas_dbus_error_invalid_args(message, NULL);
 
 	/* Extract the network ID and ensure the network */
 	/* is actually a child of this interface */
-	iface = wpas_dbus_new_decompose_object_path(op, 0, &net_id, NULL);
+	iface = wpas_dbus_new_decompose_object_path(op,
+						    WPAS_DBUS_NEW_NETWORKS_PART,
+						    &net_id);
 	if (iface == NULL || net_id == NULL ||
 	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
@@ -1852,7 +1786,6 @@
 
 out:
 	os_free(iface);
-	os_free(net_id);
 	return reply;
 #else /* IEEE8021X_EAPOL */
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
@@ -1898,26 +1831,18 @@
 
 	blob = os_zalloc(sizeof(*blob));
 	if (!blob) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 
 	blob->data = os_malloc(blob_len);
-	if (!blob->data) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+	blob->name = os_strdup(blob_name);
+	if (!blob->data || !blob->name) {
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 	os_memcpy(blob->data, blob_data, blob_len);
-
 	blob->len = blob_len;
-	blob->name = os_strdup(blob_name);
-	if (!blob->name) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto err;
-	}
 
 	wpa_config_set_blob(wpa_s->conf, blob);
 	wpas_notify_blob_added(wpa_s, blob->name);
@@ -1962,39 +1887,21 @@
 	}
 
 	reply = dbus_message_new_method_return(message);
-	if (!reply) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
+	if (!reply)
+		return wpas_dbus_error_no_memory(message);
 
 	dbus_message_iter_init_append(reply, &iter);
 
 	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
 					      DBUS_TYPE_BYTE_AS_STRING,
-					      &array_iter)) {
+					      &array_iter) ||
+	    !dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
+						  &(blob->data), blob->len) ||
+	    !dbus_message_iter_close_container(&iter, &array_iter)) {
 		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
+		reply = wpas_dbus_error_no_memory(message);
 	}
 
-	if (!dbus_message_iter_append_fixed_array(&array_iter, DBUS_TYPE_BYTE,
-						  &(blob->data), blob->len)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
-
-	if (!dbus_message_iter_close_container(&iter, &array_iter)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
-	}
-
-out:
 	return reply;
 }
 
@@ -2076,11 +1983,10 @@
 
 	if (arg != NULL && os_strlen(arg) > 0) {
 		char *tmp;
+
 		tmp = os_strdup(arg);
 		if (tmp == NULL) {
-			reply = dbus_message_new_error(message,
-						       DBUS_ERROR_NO_MEMORY,
-						       NULL);
+			reply = wpas_dbus_error_no_memory(message);
 		} else {
 			os_free(wpa_s->conf->autoscan);
 			wpa_s->conf->autoscan = tmp;
@@ -2342,8 +2248,7 @@
 						   pkcs11_module_path))
 		return dbus_message_new_error(
 			message, DBUS_ERROR_FAILED,
-			"Reinit of the EAPOL state machine with the new PKCS "
-			"#11 engine and module path failed.");
+			"Reinit of the EAPOL state machine with the new PKCS #11 engine and module path failed.");
 
 	wpa_dbus_mark_property_changed(
 		wpa_s->global->dbus, wpa_s->dbus_new_path,
@@ -2376,10 +2281,8 @@
 	const char *scans[] = { "active", "passive", "ssid" };
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-					      "a{sv}", &variant_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+					      "a{sv}", &variant_iter) ||
+	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
 		goto nomem;
 
 	res = wpa_drv_get_capa(wpa_s, &capa);
@@ -2387,6 +2290,7 @@
 	/***** pairwise cipher */
 	if (res < 0) {
 		const char *args[] = {"ccmp", "tkip", "none"};
+
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Pairwise", args,
 			    ARRAY_SIZE(args)))
@@ -2395,46 +2299,26 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Pairwise",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ccmp-256"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "gcmp-256"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ccmp"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "gcmp"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "tkip"))
-				goto nomem;
-		}
-
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "none"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "ccmp-256")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "gcmp-256")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "ccmp")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "gcmp")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "tkip")) ||
+		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "none")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -2446,6 +2330,7 @@
 		const char *args[] = {
 			"ccmp", "tkip", "wep104", "wep40"
 		};
+
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Group", args,
 			    ARRAY_SIZE(args)))
@@ -2454,52 +2339,29 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Group",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ccmp-256"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "gcmp-256"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ccmp"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "gcmp"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "tkip"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wep104"))
-				goto nomem;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wep40"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP_256) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "ccmp-256")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP_256) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "gcmp-256")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "ccmp")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_GCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "gcmp")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "tkip")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "wep104")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "wep40")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -2523,28 +2385,22 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "KeyMgmt",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    "none"))
-			goto nomem;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
+						      &iter_array) ||
+		    !wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "none") ||
+		    !wpa_dbus_dict_string_array_add_element(&iter_array,
 							    "ieee8021x"))
 			goto nomem;
 
 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
 			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa-eap"))
+				    &iter_array, "wpa-eap") ||
+			    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT) &&
+			     !wpa_dbus_dict_string_array_add_element(
+				     &iter_array, "wpa-ft-eap")))
 				goto nomem;
 
-			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT)
-				if (!wpa_dbus_dict_string_array_add_element(
-					    &iter_array, "wpa-ft-eap"))
-					goto nomem;
-
 /* TODO: Ensure that driver actually supports sha256 encryption. */
 #ifdef CONFIG_IEEE80211W
 			if (!wpa_dbus_dict_string_array_add_element(
@@ -2556,14 +2412,13 @@
 		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
 				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
 			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa-psk"))
+				    &iter_array, "wpa-psk") ||
+			    ((capa.key_mgmt &
+			      WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK) &&
+			     !wpa_dbus_dict_string_array_add_element(
+				     &iter_array, "wpa-ft-psk")))
 				goto nomem;
 
-			if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK)
-				if (!wpa_dbus_dict_string_array_add_element(
-					    &iter_array, "wpa-ft-psk"))
-					goto nomem;
-
 /* TODO: Ensure that driver actually supports sha256 encryption. */
 #ifdef CONFIG_IEEE80211W
 			if (!wpa_dbus_dict_string_array_add_element(
@@ -2572,11 +2427,10 @@
 #endif /* CONFIG_IEEE80211W */
 		}
 
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa-none"))
-				goto nomem;
-		}
+		if ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+		    !wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "wpa-none"))
+			goto nomem;
 
 
 #ifdef CONFIG_WPS
@@ -2595,6 +2449,7 @@
 	/***** WPA protocol */
 	if (res < 0) {
 		const char *args[] = { "rsn", "wpa" };
+
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "Protocol", args,
 			    ARRAY_SIZE(args)))
@@ -2603,24 +2458,16 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Protocol",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto nomem;
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "rsn"))
-				goto nomem;
-		}
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "wpa"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "rsn")) ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "wpa")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -2630,6 +2477,7 @@
 	/***** auth alg */
 	if (res < 0) {
 		const char *args[] = { "open", "shared", "leap" };
+
 		if (!wpa_dbus_dict_append_string_array(
 			    &iter_dict, "AuthAlg", args,
 			    ARRAY_SIZE(args)))
@@ -2641,25 +2489,16 @@
 						      &iter_array))
 			goto nomem;
 
-		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "open"))
-				goto nomem;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "shared"))
-				goto nomem;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "leap"))
-				goto nomem;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+		if (((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "open")) ||
+		    ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "shared")) ||
+		    ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "leap")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -2675,32 +2514,18 @@
 	if (!wpa_dbus_dict_begin_string_array(&iter_dict, "Modes",
 					      &iter_dict_entry,
 					      &iter_dict_val,
-					      &iter_array))
-		goto nomem;
-
-	if (!wpa_dbus_dict_string_array_add_element(
-			    &iter_array, "infrastructure"))
-		goto nomem;
-
-	if (!wpa_dbus_dict_string_array_add_element(
-			    &iter_array, "ad-hoc"))
-		goto nomem;
-
-	if (res >= 0) {
-		if (capa.flags & (WPA_DRIVER_FLAGS_AP)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "ap"))
-				goto nomem;
-		}
-
-		if (capa.flags & (WPA_DRIVER_FLAGS_P2P_CAPABLE)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "p2p"))
-				goto nomem;
-		}
-	}
-
-	if (!wpa_dbus_dict_end_string_array(&iter_dict,
+					      &iter_array) ||
+	    !wpa_dbus_dict_string_array_add_element(
+		    &iter_array, "infrastructure") ||
+	    !wpa_dbus_dict_string_array_add_element(
+		    &iter_array, "ad-hoc") ||
+	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_AP) &&
+	     !wpa_dbus_dict_string_array_add_element(
+		     &iter_array, "ap")) ||
+	    (res >= 0 && (capa.flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+	     !wpa_dbus_dict_string_array_add_element(
+		     &iter_array, "p2p")) ||
+	    !wpa_dbus_dict_end_string_array(&iter_dict,
 					    &iter_dict_entry,
 					    &iter_dict_val,
 					    &iter_array))
@@ -2715,9 +2540,8 @@
 			goto nomem;
 	}
 
-	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-		goto nomem;
-	if (!dbus_message_iter_close_container(iter, &variant_iter))
+	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter))
 		goto nomem;
 
 	return TRUE;
@@ -2778,7 +2602,7 @@
  * Getter for "scanning" property.
  */
 dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
-                                      void *user_data)
+				      void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
@@ -2900,6 +2724,7 @@
 {
 	struct wpa_supplicant *wpa_s = user_data;
 	dbus_int32_t reason = wpa_s->disconnect_reason;
+
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT32,
 						&reason, error);
 }
@@ -3154,8 +2979,8 @@
 	const char *driver;
 
 	if (wpa_s->driver == NULL || wpa_s->driver->name == NULL) {
-		wpa_printf(MSG_DEBUG, "wpas_dbus_getter_driver[dbus]: "
-			   "wpa_s has no driver set");
+		wpa_printf(MSG_DEBUG, "%s[dbus]: wpa_s has no driver set",
+			   __func__);
 		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
 			       __func__);
 		return FALSE;
@@ -3275,6 +3100,7 @@
 {
 	struct wpa_supplicant *wpa_s = user_data;
 	const char *bridge_ifname = wpa_s->bridge_ifname;
+
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
 						&bridge_ifname, error);
 }
@@ -3349,14 +3175,6 @@
 	unsigned int i = 0, num = 0;
 	dbus_bool_t success = FALSE;
 
-	if (wpa_s->conf == NULL) {
-		wpa_printf(MSG_ERROR, "%s[dbus]: An error occurred getting "
-			   "networks list.", __func__);
-		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: an error "
-			       "occurred getting the networks list", __func__);
-		return FALSE;
-	}
-
 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
 		if (!network_is_persistent_group(ssid))
 			num++;
@@ -3373,7 +3191,8 @@
 			continue;
 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
 		if (paths[i] == NULL) {
-			dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
+			dbus_set_error(error, DBUS_ERROR_NO_MEMORY,
+				       "no memory");
 			goto out;
 		}
 
@@ -3411,16 +3230,6 @@
 	struct wpa_supplicant *wpa_s = user_data;
 	const char *pkcs11_engine_path;
 
-	if (wpa_s->conf == NULL) {
-		wpa_printf(MSG_ERROR,
-			   "wpas_dbus_getter_pkcs11_engine_path[dbus]: An "
-			   "error occurred getting the PKCS #11 engine path.");
-		dbus_set_error_const(
-			error, DBUS_ERROR_FAILED,
-			"An error occured getting the PKCS #11 engine path.");
-		return FALSE;
-	}
-
 	if (wpa_s->conf->pkcs11_engine_path == NULL)
 		pkcs11_engine_path = "";
 	else
@@ -3446,16 +3255,6 @@
 	struct wpa_supplicant *wpa_s = user_data;
 	const char *pkcs11_module_path;
 
-	if (wpa_s->conf == NULL) {
-		wpa_printf(MSG_ERROR,
-			   "wpas_dbus_getter_pkcs11_module_path[dbus]: An "
-			   "error occurred getting the PKCS #11 module path.");
-		dbus_set_error_const(
-			error, DBUS_ERROR_FAILED,
-			"An error occured getting the PKCS #11 module path.");
-		return FALSE;
-	}
-
 	if (wpa_s->conf->pkcs11_module_path == NULL)
 		pkcs11_module_path = "";
 	else
@@ -3534,7 +3333,7 @@
 
 	if (!res) {
 		wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
-		           func_name, args->id);
+			   func_name, args->id);
 		dbus_set_error(error, DBUS_ERROR_FAILED,
 			       "%s: BSS %d not found",
 			       func_name, args->id);
@@ -3775,7 +3574,7 @@
 	DBusMessageIter iter_dict, variant_iter;
 	const char *group;
 	const char *pairwise[5]; /* max 5 pairwise ciphers is supported */
-	const char *key_mgmt[7]; /* max 7 key managements may be supported */
+	const char *key_mgmt[8]; /* max 8 key managements may be supported */
 	int n;
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
@@ -3799,6 +3598,8 @@
 		key_mgmt[n++] = "wpa-ft-eap";
 	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
 		key_mgmt[n++] = "wpa-eap-sha256";
+	if (ie_data->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+		key_mgmt[n++] = "wpa-eap-suite-b";
 	if (ie_data->key_mgmt & WPA_KEY_MGMT_NONE)
 		key_mgmt[n++] = "wpa-none";
 
@@ -3872,9 +3673,8 @@
 			goto nomem;
 	}
 
-	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-		goto nomem;
-	if (!dbus_message_iter_close_container(iter, &variant_iter))
+	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter))
 		goto nomem;
 
 	return TRUE;
@@ -3908,12 +3708,10 @@
 
 	os_memset(&wpa_data, 0, sizeof(wpa_data));
 	ie = wpa_bss_get_vendor_ie(res, WPA_IE_VENDOR_TYPE);
-	if (ie) {
-		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
-			dbus_set_error_const(error, DBUS_ERROR_FAILED,
-					     "failed to parse WPA IE");
-			return FALSE;
-		}
+	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "failed to parse WPA IE");
+		return FALSE;
 	}
 
 	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
@@ -3943,12 +3741,10 @@
 
 	os_memset(&wpa_data, 0, sizeof(wpa_data));
 	ie = wpa_bss_get_ie(res, WLAN_EID_RSN);
-	if (ie) {
-		if (wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
-			dbus_set_error_const(error, DBUS_ERROR_FAILED,
-					     "failed to parse RSN IE");
-			return FALSE;
-		}
+	if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &wpa_data) < 0) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "failed to parse RSN IE");
+		return FALSE;
 	}
 
 	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
@@ -3980,10 +3776,8 @@
 		return FALSE;
 
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
-					      "a{sv}", &variant_iter))
-		goto nomem;
-
-	if (!wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
+					      "a{sv}", &variant_iter) ||
+	    !wpa_dbus_dict_open_write(&variant_iter, &iter_dict))
 		goto nomem;
 
 #ifdef CONFIG_WPS
@@ -3993,15 +3787,14 @@
 			type = "pbc";
 		else if (wps_is_selected_pin_registrar(wps_ie))
 			type = "pin";
+
+		wpabuf_free(wps_ie);
 	}
 #endif /* CONFIG_WPS */
 
-	if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type))
-		goto nomem;
-
-	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
-		goto nomem;
-	if (!dbus_message_iter_close_container(iter, &variant_iter))
+	if (!wpa_dbus_dict_append_string(&iter_dict, "Type", type) ||
+	    !wpa_dbus_dict_close_write(&variant_iter, &iter_dict) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter))
 		goto nomem;
 
 	return TRUE;
@@ -4223,8 +4016,7 @@
 
 	name = os_strdup(dbus_message_get_sender(message));
 	if (!name)
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      "out of memory");
+		return wpas_dbus_error_no_memory(message);
 
 	wpa_s->preq_notify_peer = name;
 
@@ -4304,28 +4096,22 @@
 
 	dbus_message_iter_init_append(msg, &iter);
 
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter))
-		goto fail;
-	if (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
-						     (const char *) addr,
-						     ETH_ALEN))
-		goto fail;
-	if (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
-						    (const char *) dst,
-						    ETH_ALEN))
-		goto fail;
-	if (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
-						      (const char *) bssid,
-						      ETH_ALEN))
-		goto fail;
-	if (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
-							     (const char *) ie,
-							     ie_len))
-		goto fail;
-	if (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
-						      ssi_signal))
-		goto fail;
-	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    (addr && !wpa_dbus_dict_append_byte_array(&dict_iter, "addr",
+						      (const char *) addr,
+						      ETH_ALEN)) ||
+	    (dst && !wpa_dbus_dict_append_byte_array(&dict_iter, "dst",
+						     (const char *) dst,
+						     ETH_ALEN)) ||
+	    (bssid && !wpa_dbus_dict_append_byte_array(&dict_iter, "bssid",
+						       (const char *) bssid,
+						       ETH_ALEN)) ||
+	    (ie && ie_len && !wpa_dbus_dict_append_byte_array(&dict_iter, "ies",
+							      (const char *) ie,
+							      ie_len)) ||
+	    (ssi_signal && !wpa_dbus_dict_append_int32(&dict_iter, "signal",
+						       ssi_signal)) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter))
 		goto fail;
 
 	dbus_connection_send(priv->con, msg, NULL);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index f6a83cd..6113db5 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -55,8 +55,8 @@
 					 void *user_data);
 
 dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
-                                             DBusError *error,
-                                             void *user_data);
+					     DBusError *error,
+					     void *user_data);
 
 dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
 					     DBusError *error,
@@ -319,6 +319,7 @@
 					   const char *arg);
 DBusMessage * wpas_dbus_error_unknown_error(DBusMessage *message,
 					    const char *arg);
+DBusMessage * wpas_dbus_error_no_memory(DBusMessage *message);
 
 DBusMessage * wpas_dbus_handler_subscribe_preq(
 	DBusMessage *message, struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 7867f0c..9c880a2 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -35,9 +35,9 @@
  * @addr - out param must be of ETH_ALEN size
  * Returns 0 if valid (including MAC), -1 otherwise
  */
-static int parse_peer_object_path(char *peer_path, u8 addr[ETH_ALEN])
+static int parse_peer_object_path(const char *peer_path, u8 addr[ETH_ALEN])
 {
-	char *p;
+	const char *p;
 
 	if (!peer_path)
 		return -1;
@@ -57,12 +57,12 @@
  *
  * Convenience function to create and return an invalid persistent group error.
  */
-static DBusMessage * wpas_dbus_error_persistent_group_unknown(
-	DBusMessage *message)
+static DBusMessage *
+wpas_dbus_error_persistent_group_unknown(DBusMessage *message)
 {
-	return dbus_message_new_error(message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
-				      "There is no such persistent group in "
-				      "this P2P device.");
+	return dbus_message_new_error(
+		message, WPAS_DBUS_ERROR_NETWORK_UNKNOWN,
+		"There is no such persistent group in this P2P device.");
 }
 
 
@@ -74,7 +74,7 @@
 	DBusMessageIter iter;
 	DBusMessageIter iter_dict;
 	unsigned int timeout = 0;
-	enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
+	enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
 	int num_req_dev_types = 0;
 	unsigned int i;
 	u8 *req_dev_types = NULL;
@@ -89,12 +89,12 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "Timeout") &&
-		    (entry.type == DBUS_TYPE_INT32)) {
+		if (os_strcmp(entry.key, "Timeout") == 0 &&
+		    entry.type == DBUS_TYPE_INT32) {
 			timeout = entry.uint32_value;
 		} else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
-			if ((entry.type != DBUS_TYPE_ARRAY) ||
-			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY)
 				goto error_clear;
 
 			os_free(req_dev_types);
@@ -105,20 +105,20 @@
 
 			for (i = 0; i < entry.array_len; i++) {
 				if (wpabuf_len(entry.binarray_value[i]) !=
-							WPS_DEV_TYPE_LEN)
+				    WPS_DEV_TYPE_LEN)
 					goto error_clear;
 				os_memcpy(req_dev_types + i * WPS_DEV_TYPE_LEN,
 					  wpabuf_head(entry.binarray_value[i]),
 					  WPS_DEV_TYPE_LEN);
 			}
 			num_req_dev_types = entry.array_len;
-		} else if (!os_strcmp(entry.key, "DiscoveryType") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
-			if (!os_strcmp(entry.str_value, "start_with_full"))
+		} else if (os_strcmp(entry.key, "DiscoveryType") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
+			if (os_strcmp(entry.str_value, "start_with_full") == 0)
 				type = P2P_FIND_START_WITH_FULL;
-			else if (!os_strcmp(entry.str_value, "social"))
+			else if (os_strcmp(entry.str_value, "social") == 0)
 				type = P2P_FIND_ONLY_SOCIAL;
-			else if (!os_strcmp(entry.str_value, "progressive"))
+			else if (os_strcmp(entry.str_value, "progressive") == 0)
 				type = P2P_FIND_PROGRESSIVE;
 			else
 				goto error_clear;
@@ -127,6 +127,9 @@
 		wpa_dbus_dict_entry_clear(&entry);
 	}
 
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
 	wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types,
 		      NULL, 0);
 	os_free(req_dev_types);
@@ -144,6 +147,9 @@
 DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
 					      struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
 	wpas_p2p_stop_find(wpa_s);
 	return NULL;
 }
@@ -162,6 +168,9 @@
 	if (parse_peer_object_path(peer_object_path, peer_addr) < 0)
 		return wpas_dbus_error_invalid_args(message, NULL);
 
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
 	if (wpas_p2p_reject(wpa_s, peer_addr) < 0)
 		return wpas_dbus_error_unknown_error(message,
 				"Failed to call wpas_p2p_reject method.");
@@ -177,12 +186,16 @@
 
 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_INT32, &timeout,
 				   DBUS_TYPE_INVALID))
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		return wpas_dbus_error_no_memory(message);
 
-	if (wpas_p2p_listen(wpa_s, (unsigned int)timeout))
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
+	if (wpas_p2p_listen(wpa_s, (unsigned int) timeout)) {
+		return dbus_message_new_error(message,
+					      WPAS_DBUS_ERROR_UNKNOWN_ERROR,
+					      "Could not start P2P listen");
+	}
 
 	return NULL;
 }
@@ -206,17 +219,20 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "period") &&
-		    (entry.type == DBUS_TYPE_INT32))
+		if (os_strcmp(entry.key, "period") == 0 &&
+		    entry.type == DBUS_TYPE_INT32)
 			period = entry.uint32_value;
-		else if (!os_strcmp(entry.key, "interval") &&
-			 (entry.type == DBUS_TYPE_INT32))
+		else if (os_strcmp(entry.key, "interval") == 0 &&
+			 entry.type == DBUS_TYPE_INT32)
 			interval = entry.uint32_value;
 		else
 			goto error_clear;
 		wpa_dbus_dict_entry_clear(&entry);
 	}
 
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
 	if (wpas_p2p_ext_listen(wpa_s, period, interval))
 		return wpas_dbus_error_unknown_error(
 			message, "failed to initiate a p2p_ext_listen.");
@@ -248,16 +264,16 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "duration1") &&
-		    (entry.type == DBUS_TYPE_INT32))
+		if (os_strcmp(entry.key, "duration1") == 0 &&
+		    entry.type == DBUS_TYPE_INT32)
 			dur1 = entry.uint32_value;
-		else if (!os_strcmp(entry.key, "interval1") &&
+		else if (os_strcmp(entry.key, "interval1") == 0 &&
 			 entry.type == DBUS_TYPE_INT32)
 			int1 = entry.uint32_value;
-		else if (!os_strcmp(entry.key, "duration2") &&
+		else if (os_strcmp(entry.key, "duration2") == 0 &&
 			 entry.type == DBUS_TYPE_INT32)
 			dur2 = entry.uint32_value;
-		else if (!os_strcmp(entry.key, "interval2") &&
+		else if (os_strcmp(entry.key, "interval2") == 0 &&
 			 entry.type == DBUS_TYPE_INT32)
 			int2 = entry.uint32_value;
 		else
@@ -265,6 +281,10 @@
 
 		wpa_dbus_dict_entry_clear(&entry);
 	}
+
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
 	if (wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2) < 0)
 		return wpas_dbus_error_unknown_error(message,
 				"Failed to invoke presence request.");
@@ -289,7 +309,6 @@
 	int persistent_group = 0;
 	int freq = 0;
 	char *iface = NULL;
-	char *net_id_str = NULL;
 	unsigned int group_id = 0;
 	struct wpa_ssid *ssid;
 
@@ -302,15 +321,16 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto inv_args;
 
-		if (!os_strcmp(entry.key, "persistent") &&
-		    (entry.type == DBUS_TYPE_BOOLEAN)) {
-			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!os_strcmp(entry.key, "frequency") &&
-			   (entry.type == DBUS_TYPE_INT32)) {
+		if (os_strcmp(entry.key, "persistent") == 0 &&
+		    entry.type == DBUS_TYPE_BOOLEAN) {
+			persistent_group = entry.bool_value;
+		} else if (os_strcmp(entry.key, "frequency") == 0 &&
+			   entry.type == DBUS_TYPE_INT32) {
 			freq = entry.int32_value;
 			if (freq <= 0)
 				goto inv_args_clear;
-		} else if (!os_strcmp(entry.key, "persistent_group_object") &&
+		} else if (os_strcmp(entry.key, "persistent_group_object") ==
+			   0 &&
 			   entry.type == DBUS_TYPE_OBJECT_PATH)
 			pg_object_path = os_strdup(entry.str_value);
 		else
@@ -319,15 +339,21 @@
 		wpa_dbus_dict_entry_clear(&entry);
 	}
 
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
 	if (pg_object_path != NULL) {
+		char *net_id_str;
+
 		/*
 		 * A persistent group Object Path is defined meaning we want
 		 * to re-invoke a persistent group.
 		 */
 
-		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
-							    &net_id_str, NULL);
-		if (iface == NULL ||
+		iface = wpas_dbus_new_decompose_object_path(
+			pg_object_path, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+			&net_id_str);
+		if (iface == NULL || net_id_str == NULL ||
 		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 			reply =
 			    wpas_dbus_error_invalid_args(message,
@@ -359,7 +385,6 @@
 
 out:
 	os_free(pg_object_path);
-	os_free(net_id_str);
 	os_free(iface);
 	return reply;
 inv_args_clear:
@@ -394,8 +419,7 @@
 				"P2P is not available for this interface");
 		}
 		dbus_set_error_const(error, DBUS_ERROR_FAILED,
-				     "P2P is not available for this "
-				     "interface");
+				     "P2P is not available for this interface");
 		return FALSE;
 	}
 	return TRUE;
@@ -410,6 +434,9 @@
 	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
 		return reply;
 
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
 	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
 	wpa_s->force_long_sd = 0;
 	p2p_flush(wpa_s->global->p2p);
@@ -450,42 +477,42 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto inv_args;
 
-		if (!os_strcmp(entry.key, "peer") &&
-		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+		if (os_strcmp(entry.key, "peer") == 0 &&
+		    entry.type == DBUS_TYPE_OBJECT_PATH) {
 			peer_object_path = os_strdup(entry.str_value);
-		} else if (!os_strcmp(entry.key, "persistent") &&
-			   (entry.type == DBUS_TYPE_BOOLEAN)) {
-			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!os_strcmp(entry.key, "join") &&
-			   (entry.type == DBUS_TYPE_BOOLEAN)) {
-			join = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!os_strcmp(entry.key, "authorize_only") &&
-			   (entry.type == DBUS_TYPE_BOOLEAN)) {
-			authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!os_strcmp(entry.key, "frequency") &&
-			   (entry.type == DBUS_TYPE_INT32)) {
+		} else if (os_strcmp(entry.key, "persistent") == 0 &&
+			   entry.type == DBUS_TYPE_BOOLEAN) {
+			persistent_group = entry.bool_value;
+		} else if (os_strcmp(entry.key, "join") == 0 &&
+			   entry.type == DBUS_TYPE_BOOLEAN) {
+			join = entry.bool_value;
+		} else if (os_strcmp(entry.key, "authorize_only") == 0 &&
+			   entry.type == DBUS_TYPE_BOOLEAN) {
+			authorize_only = entry.bool_value;
+		} else if (os_strcmp(entry.key, "frequency") == 0 &&
+			   entry.type == DBUS_TYPE_INT32) {
 			freq = entry.int32_value;
 			if (freq <= 0)
 				goto inv_args_clear;
-		} else if (!os_strcmp(entry.key, "go_intent") &&
-			   (entry.type == DBUS_TYPE_INT32)) {
+		} else if (os_strcmp(entry.key, "go_intent") == 0 &&
+			   entry.type == DBUS_TYPE_INT32) {
 			go_intent = entry.int32_value;
 			if ((go_intent < 0) || (go_intent > 15))
 				goto inv_args_clear;
-		} else if (!os_strcmp(entry.key, "wps_method") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
-			if (!os_strcmp(entry.str_value, "pbc"))
+		} else if (os_strcmp(entry.key, "wps_method") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
+			if (os_strcmp(entry.str_value, "pbc") == 0)
 				wps_method = WPS_PBC;
-			else if (!os_strcmp(entry.str_value, "pin"))
+			else if (os_strcmp(entry.str_value, "pin") == 0)
 				wps_method = WPS_PIN_DISPLAY;
-			else if (!os_strcmp(entry.str_value, "display"))
+			else if (os_strcmp(entry.str_value, "display") == 0)
 				wps_method = WPS_PIN_DISPLAY;
-			else if (!os_strcmp(entry.str_value, "keypad"))
+			else if (os_strcmp(entry.str_value, "keypad") == 0)
 				wps_method = WPS_PIN_KEYPAD;
 			else
 				goto inv_args_clear;
-		} else if (!os_strcmp(entry.key, "pin") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
+		} else if (os_strcmp(entry.key, "pin") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
 			pin = os_strdup(entry.str_value);
 		} else
 			goto inv_args_clear;
@@ -493,17 +520,20 @@
 		wpa_dbus_dict_entry_clear(&entry);
 	}
 
-	if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
-	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
+	if (wps_method == WPS_NOT_READY ||
+	    parse_peer_object_path(peer_object_path, addr) < 0 ||
 	    !p2p_peer_known(wpa_s->global->p2p, addr))
 		goto inv_args;
 
 	/*
 	 * Validate the wps_method specified and the pin value.
 	 */
-	if ((!pin || !pin[0]) && (wps_method == WPS_PIN_KEYPAD))
+	if ((!pin || !pin[0]) && wps_method == WPS_PIN_KEYPAD)
 		goto inv_args;
 
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
 				   persistent_group, 0, join, authorize_only,
 				   go_intent, freq, -1, 0, 0, 0);
@@ -511,6 +541,7 @@
 	if (new_pin >= 0) {
 		char npin[9];
 		char *generated_pin;
+
 		os_snprintf(npin, sizeof(npin), "%08d", new_pin);
 		generated_pin = npin;
 		reply = dbus_message_new_method_return(message);
@@ -519,8 +550,8 @@
 	} else {
 		switch (new_pin) {
 		case -2:
-			err_msg = "connect failed due to channel "
-				"unavailability.";
+			err_msg =
+				"connect failed due to channel unavailability.";
 			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE;
 			break;
 
@@ -566,7 +597,6 @@
 	char *peer_object_path = NULL;
 	char *pg_object_path = NULL;
 	char *iface = NULL;
-	char *net_id_str = NULL;
 	u8 peer_addr[ETH_ALEN];
 	unsigned int group_id = 0;
 	int persistent = 0;
@@ -584,12 +614,13 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto err;
 
-		if (!os_strcmp(entry.key, "peer") &&
-		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+		if (os_strcmp(entry.key, "peer") == 0 &&
+		    entry.type == DBUS_TYPE_OBJECT_PATH) {
 			peer_object_path = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
-		} else if (!os_strcmp(entry.key, "persistent_group_object") &&
-			   (entry.type == DBUS_TYPE_OBJECT_PATH)) {
+		} else if (os_strcmp(entry.key, "persistent_group_object") ==
+			   0 &&
+			   entry.type == DBUS_TYPE_OBJECT_PATH) {
 			pg_object_path = os_strdup(entry.str_value);
 			persistent = 1;
 			wpa_dbus_dict_entry_clear(&entry);
@@ -599,21 +630,25 @@
 		}
 	}
 
-	if (!peer_object_path ||
-	    (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
-	    !p2p_peer_known(wpa_s->global->p2p, peer_addr)) {
+	if (parse_peer_object_path(peer_object_path, peer_addr) < 0 ||
+	    !p2p_peer_known(wpa_s->global->p2p, peer_addr))
 		goto err;
-	}
+
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
 
 	if (persistent) {
+		char *net_id_str;
 		/*
 		 * A group ID is defined meaning we want to re-invoke a
 		 * persistent group
 		 */
 
-		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
-							    &net_id_str, NULL);
-		if (iface == NULL ||
+		iface = wpas_dbus_new_decompose_object_path(
+			pg_object_path,
+			WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+			&net_id_str);
+		if (iface == NULL || net_id_str == NULL ||
 		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 			reply = wpas_dbus_error_invalid_args(message,
 							     pg_object_path);
@@ -652,6 +687,7 @@
 	}
 
 out:
+	os_free(iface);
 	os_free(pg_object_path);
 	os_free(peer_object_path);
 	return reply;
@@ -690,6 +726,9 @@
 	    os_strcmp(config_method, "pushbutton"))
 		return wpas_dbus_error_invalid_args(message, NULL);
 
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
 	if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method,
 			       WPAS_P2P_PD_FOR_GO_NEG) < 0)
 		return wpas_dbus_error_unknown_error(message,
@@ -719,6 +758,9 @@
 	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
 		return FALSE;
 
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
 	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
 					      "a{sv}", &variant_iter) ||
 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
@@ -732,8 +774,8 @@
 
 	/* Primary device type */
 	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
-	    				     (char *)wpa_s->conf->device_type,
-	    				     WPS_DEV_TYPE_LEN))
+					     (char *) wpa_s->conf->device_type,
+					     WPS_DEV_TYPE_LEN))
 		goto err_no_mem;
 
 	/* Secondary device types */
@@ -768,75 +810,37 @@
 			wpa_s->conf->wps_vendor_ext[i];
 	}
 
-	if (num_vendor_extensions &&
-	    !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
-					       "VendorExtension",
-					       vendor_ext,
-					       num_vendor_extensions))
-		goto err_no_mem;
-
-	/* GO Intent */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
-					 wpa_s->conf->p2p_go_intent))
-		goto err_no_mem;
-
-	/* Persistent Reconnect */
-	if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
-				       wpa_s->conf->persistent_reconnect))
-		goto err_no_mem;
-
-	/* Listen Reg Class */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
-					 wpa_s->conf->p2p_listen_reg_class))
-		goto err_no_mem;
-
-	/* Listen Channel */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
-					 wpa_s->conf->p2p_listen_channel))
-		goto err_no_mem;
-
-	/* Oper Reg Class */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
-					 wpa_s->conf->p2p_oper_reg_class))
-		goto err_no_mem;
-
-	/* Oper Channel */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
-					 wpa_s->conf->p2p_oper_channel))
-		goto err_no_mem;
-
-	/* SSID Postfix */
-	if (wpa_s->conf->p2p_ssid_postfix &&
-	    !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
-					 wpa_s->conf->p2p_ssid_postfix))
-		goto err_no_mem;
-
-	/* Intra Bss */
-	if (!wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
-				       wpa_s->conf->p2p_intra_bss))
-		goto err_no_mem;
-
-	/* Group Idle */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
-					 wpa_s->conf->p2p_group_idle))
-		goto err_no_mem;
-
-	/* Dissasociation low ack */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
-					 wpa_s->conf->disassoc_low_ack))
-		goto err_no_mem;
-
-	/* No Group Iface */
-	if (!wpa_dbus_dict_append_bool(&dict_iter, "NoGroupIface",
-				       wpa_s->conf->p2p_no_group_iface))
-		goto err_no_mem;
-
-	/* P2P Search Delay */
-	if (!wpa_dbus_dict_append_uint32(&dict_iter, "p2p_search_delay",
-					 wpa_s->conf->p2p_search_delay))
-		goto err_no_mem;
-
-	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+	if ((num_vendor_extensions &&
+	     !wpa_dbus_dict_append_wpabuf_array(&dict_iter,
+						"VendorExtension",
+						vendor_ext,
+						num_vendor_extensions)) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "GOIntent",
+					 wpa_s->conf->p2p_go_intent) ||
+	    !wpa_dbus_dict_append_bool(&dict_iter, "PersistentReconnect",
+				       wpa_s->conf->persistent_reconnect) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "ListenRegClass",
+					 wpa_s->conf->p2p_listen_reg_class) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "ListenChannel",
+					 wpa_s->conf->p2p_listen_channel) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "OperRegClass",
+					 wpa_s->conf->p2p_oper_reg_class) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "OperChannel",
+					 wpa_s->conf->p2p_oper_channel) ||
+	    (wpa_s->conf->p2p_ssid_postfix &&
+	     !wpa_dbus_dict_append_string(&dict_iter, "SsidPostfix",
+					  wpa_s->conf->p2p_ssid_postfix)) ||
+	    !wpa_dbus_dict_append_bool(&dict_iter, "IntraBss",
+				       wpa_s->conf->p2p_intra_bss) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "GroupIdle",
+					 wpa_s->conf->p2p_group_idle) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "disassoc_low_ack",
+					 wpa_s->conf->disassoc_low_ack) ||
+	    !wpa_dbus_dict_append_bool(&dict_iter, "NoGroupIface",
+				       wpa_s->conf->p2p_no_group_iface) ||
+	    !wpa_dbus_dict_append_uint32(&dict_iter, "p2p_search_delay",
+					 wpa_s->conf->p2p_search_delay) ||
+	    !wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
 	    !dbus_message_iter_close_container(iter, &variant_iter))
 		goto err_no_mem;
 
@@ -860,6 +864,9 @@
 	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
 		return FALSE;
 
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
 	dbus_message_iter_recurse(iter, &variant_iter);
 	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
 		return FALSE;
@@ -915,8 +922,8 @@
 			wpa_s->conf->changed_parameters |=
 					CFG_CHANGED_SEC_DEVICE_TYPE;
 		} else if (os_strcmp(entry.key, "VendorExtension") == 0) {
-			if ((entry.type != DBUS_TYPE_ARRAY) ||
-			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != WPAS_DBUS_TYPE_BINARRAY ||
 			    (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
 				goto error;
 
@@ -932,30 +939,30 @@
 				} else
 					wpa_s->conf->wps_vendor_ext[i] = NULL;
 			}
-		} else if ((os_strcmp(entry.key, "GOIntent") == 0) &&
-			   (entry.type == DBUS_TYPE_UINT32) &&
+		} else if (os_strcmp(entry.key, "GOIntent") == 0 &&
+			   entry.type == DBUS_TYPE_UINT32 &&
 			   (entry.uint32_value <= 15))
 			wpa_s->conf->p2p_go_intent = entry.uint32_value;
-		else if ((os_strcmp(entry.key, "PersistentReconnect") == 0) &&
-			 (entry.type == DBUS_TYPE_BOOLEAN))
+		else if (os_strcmp(entry.key, "PersistentReconnect") == 0 &&
+			 entry.type == DBUS_TYPE_BOOLEAN)
 			wpa_s->conf->persistent_reconnect = entry.bool_value;
-		else if ((os_strcmp(entry.key, "ListenRegClass") == 0) &&
-			 (entry.type == DBUS_TYPE_UINT32)) {
+		else if (os_strcmp(entry.key, "ListenRegClass") == 0 &&
+			 entry.type == DBUS_TYPE_UINT32) {
 			wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
 			wpa_s->conf->changed_parameters |=
 				CFG_CHANGED_P2P_LISTEN_CHANNEL;
-		} else if ((os_strcmp(entry.key, "ListenChannel") == 0) &&
-			   (entry.type == DBUS_TYPE_UINT32)) {
+		} else if (os_strcmp(entry.key, "ListenChannel") == 0 &&
+			   entry.type == DBUS_TYPE_UINT32) {
 			wpa_s->conf->p2p_listen_channel = entry.uint32_value;
 			wpa_s->conf->changed_parameters |=
 				CFG_CHANGED_P2P_LISTEN_CHANNEL;
-		} else if ((os_strcmp(entry.key, "OperRegClass") == 0) &&
-			   (entry.type == DBUS_TYPE_UINT32)) {
+		} else if (os_strcmp(entry.key, "OperRegClass") == 0 &&
+			   entry.type == DBUS_TYPE_UINT32) {
 			wpa_s->conf->p2p_oper_reg_class = entry.uint32_value;
 			wpa_s->conf->changed_parameters |=
 				CFG_CHANGED_P2P_OPER_CHANNEL;
-		} else if ((os_strcmp(entry.key, "OperChannel") == 0) &&
-			   (entry.type == DBUS_TYPE_UINT32)) {
+		} else if (os_strcmp(entry.key, "OperChannel") == 0 &&
+			   entry.type == DBUS_TYPE_UINT32) {
 			wpa_s->conf->p2p_oper_channel = entry.uint32_value;
 			wpa_s->conf->changed_parameters |=
 				CFG_CHANGED_P2P_OPER_CHANNEL;
@@ -974,13 +981,13 @@
 
 			wpa_s->conf->changed_parameters |=
 					CFG_CHANGED_P2P_SSID_POSTFIX;
-		} else if ((os_strcmp(entry.key, "IntraBss") == 0) &&
-			   (entry.type == DBUS_TYPE_BOOLEAN)) {
+		} else if (os_strcmp(entry.key, "IntraBss") == 0 &&
+			   entry.type == DBUS_TYPE_BOOLEAN) {
 			wpa_s->conf->p2p_intra_bss = entry.bool_value;
 			wpa_s->conf->changed_parameters |=
 				CFG_CHANGED_P2P_INTRA_BSS;
-		} else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
-			   (entry.type == DBUS_TYPE_UINT32))
+		} else if (os_strcmp(entry.key, "GroupIdle") == 0 &&
+			   entry.type == DBUS_TYPE_UINT32)
 			wpa_s->conf->p2p_group_idle = entry.uint32_value;
 		else if (os_strcmp(entry.key, "disassoc_low_ack") == 0 &&
 			 entry.type == DBUS_TYPE_UINT32)
@@ -1260,8 +1267,8 @@
 
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
-                                                    DBusError *error,
-                                                    void *user_data)
+						    DBusError *error,
+						    void *user_data)
 {
 	struct peer_handler_args *peer_args = user_data;
 	const struct p2p_peer_info *info;
@@ -1285,8 +1292,8 @@
 
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data)
+					    DBusError *error,
+					    void *user_data)
 {
 	struct peer_handler_args *peer_args = user_data;
 	const struct p2p_peer_info *info;
@@ -1310,8 +1317,8 @@
 
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
-                                                        DBusError *error,
-                                                        void *user_data)
+							DBusError *error,
+							void *user_data)
 {
 	struct peer_handler_args *peer_args = user_data;
 	const struct p2p_peer_info *info;
@@ -1369,8 +1376,7 @@
 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
 				  peer_args->p2p_device_addr, 0);
 	if (info == NULL) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-			       "failed to find peer");
+		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
 		return FALSE;
 	}
 
@@ -1378,18 +1384,13 @@
 					      DBUS_TYPE_ARRAY_AS_STRING
 					      DBUS_TYPE_ARRAY_AS_STRING
 					      DBUS_TYPE_BYTE_AS_STRING,
-					      &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 1", __func__);
-		return FALSE;
-	}
-
-	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+					      &variant_iter) ||
+	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
 					      DBUS_TYPE_ARRAY_AS_STRING
 					      DBUS_TYPE_BYTE_AS_STRING,
 					      &array_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 2", __func__);
+			       "%s: failed to construct message 1", __func__);
 		return FALSE;
 	}
 
@@ -1404,29 +1405,14 @@
 			if (!dbus_message_iter_open_container(
 				    &array_iter, DBUS_TYPE_ARRAY,
 				    DBUS_TYPE_BYTE_AS_STRING,
-				    &inner_array_iter)) {
-				dbus_set_error(error, DBUS_ERROR_FAILED,
-					       "%s: failed to construct "
-					       "message 3 (%d)",
-					       __func__, i);
-				return FALSE;
-			}
-
-			if (!dbus_message_iter_append_fixed_array(
+				    &inner_array_iter) ||
+			    !dbus_message_iter_append_fixed_array(
 				    &inner_array_iter, DBUS_TYPE_BYTE,
-				    &sec_dev_type_list, WPS_DEV_TYPE_LEN)) {
-				dbus_set_error(error, DBUS_ERROR_FAILED,
-					       "%s: failed to construct "
-					       "message 4 (%d)",
-					       __func__, i);
-				return FALSE;
-			}
-
-			if (!dbus_message_iter_close_container(
+				    &sec_dev_type_list, WPS_DEV_TYPE_LEN) ||
+			    !dbus_message_iter_close_container(
 				    &array_iter, &inner_array_iter)) {
 				dbus_set_error(error, DBUS_ERROR_FAILED,
-					       "%s: failed to construct "
-					       "message 5 (%d)",
+					       "%s: failed to construct message 2 (%d)",
 					       __func__, i);
 				return FALSE;
 			}
@@ -1435,15 +1421,10 @@
 		}
 	}
 
-	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
 		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 6", __func__);
-		return FALSE;
-	}
-
-	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
-		dbus_set_error(error, DBUS_ERROR_FAILED,
-		               "%s: failed to construct message 7", __func__);
+			       "%s: failed to construct message 3", __func__);
 		return FALSE;
 	}
 
@@ -1583,7 +1564,7 @@
 	struct peer_handler_args *peer_args = user_data;
 	const struct p2p_peer_info *info;
 	struct peer_group_data data;
-	struct wpa_supplicant *wpa_s_go;
+	struct wpa_supplicant *wpa_s, *wpa_s_go;
 	dbus_bool_t success = FALSE;
 
 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
@@ -1595,8 +1576,12 @@
 	}
 
 	os_memset(&data, 0, sizeof(data));
-	wpa_s_go = wpas_get_p2p_client_iface(peer_args->wpa_s,
-					     info->p2p_device_addr);
+
+	wpa_s = peer_args->wpa_s;
+	if (wpa_s->p2p_dev)
+		wpa_s = wpa_s->p2p_dev;
+
+	wpa_s_go = wpas_get_p2p_client_iface(wpa_s, info->p2p_device_addr);
 	if (wpa_s_go) {
 		data.paths = os_calloc(1, sizeof(char *));
 		if (data.paths == NULL)
@@ -1651,15 +1636,6 @@
 	unsigned int i = 0, num = 0;
 	dbus_bool_t success = FALSE;
 
-	if (wpa_s->conf == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: %s: "
-			   "An error occurred getting persistent groups list",
-			   __func__);
-		dbus_set_error_const(error, DBUS_ERROR_FAILED, "an error "
-				     "occurred getting persistent groups list");
-		return FALSE;
-	}
-
 	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
 		if (network_is_persistent_group(ssid))
 			num++;
@@ -1772,12 +1748,12 @@
 
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: %s: "
-			   "Cannot add new persistent group", __func__);
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: Cannot add new persistent group",
+			   __func__);
 		reply = wpas_dbus_error_unknown_error(
 			message,
-			"wpa_supplicant could not add "
-			"a persistent group on this interface.");
+			"wpa_supplicant could not add a persistent group on this interface.");
 		goto err;
 	}
 
@@ -1790,13 +1766,12 @@
 
 	dbus_error_init(&error);
 	if (!set_network_properties(wpa_s, ssid, &iter, &error)) {
-		wpa_printf(MSG_DEBUG, "dbus: %s: "
-			   "Control interface could not set persistent group "
-			   "properties", __func__);
-		reply = wpas_dbus_reply_new_from_error(message, &error,
-						       DBUS_ERROR_INVALID_ARGS,
-						       "Failed to set network "
-						       "properties");
+		wpa_printf(MSG_DEBUG,
+			   "dbus: %s: Control interface could not set persistent group properties",
+			   __func__);
+		reply = wpas_dbus_reply_new_from_error(
+			message, &error, DBUS_ERROR_INVALID_ARGS,
+			"Failed to set network properties");
 		dbus_error_free(&error);
 		goto err;
 	}
@@ -1808,15 +1783,13 @@
 
 	reply = dbus_message_new_method_return(message);
 	if (reply == NULL) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 	if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
 				      DBUS_TYPE_INVALID)) {
 		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		reply = wpas_dbus_error_no_memory(message);
 		goto err;
 	}
 
@@ -1846,7 +1819,7 @@
 {
 	DBusMessage *reply = NULL;
 	const char *op;
-	char *iface = NULL, *persistent_group_id = NULL;
+	char *iface = NULL, *persistent_group_id;
 	int id;
 	struct wpa_ssid *ssid;
 
@@ -1857,10 +1830,11 @@
 	 * Extract the network ID and ensure the network is actually a child of
 	 * this interface.
 	 */
-	iface = wpas_dbus_new_decompose_object_path(op, 1,
-						    &persistent_group_id,
-						    NULL);
-	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+	iface = wpas_dbus_new_decompose_object_path(
+		op, WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART,
+		&persistent_group_id);
+	if (iface == NULL || persistent_group_id == NULL ||
+	    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
 		reply = wpas_dbus_error_invalid_args(message, op);
 		goto out;
 	}
@@ -1880,19 +1854,17 @@
 	wpas_notify_persistent_group_removed(wpa_s, ssid);
 
 	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
-		wpa_printf(MSG_ERROR, "dbus: %s: "
-			   "error occurred when removing persistent group %d",
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: error occurred when removing persistent group %d",
 			   __func__, id);
 		reply = wpas_dbus_error_unknown_error(
 			message,
-			"error removing the specified persistent group on "
-			"this interface.");
+			"error removing the specified persistent group on this interface.");
 		goto out;
 	}
 
 out:
 	os_free(iface);
-	os_free(persistent_group_id);
 	return reply;
 }
 
@@ -1903,8 +1875,8 @@
 	wpas_notify_persistent_group_removed(wpa_s, ssid);
 
 	if (wpa_config_remove_network(wpa_s->conf, ssid->id) < 0) {
-		wpa_printf(MSG_ERROR, "dbus: %s: "
-			   "error occurred when removing persistent group %d",
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: error occurred when removing persistent group %d",
 			   __func__, ssid->id);
 		return;
 	}
@@ -2012,6 +1984,7 @@
 					    DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
+
 	if (wpa_s->current_ssid == NULL)
 		return FALSE;
 	return wpas_dbus_simple_array_property_getter(
@@ -2072,15 +2045,14 @@
 						  void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	u8 role = wpas_get_p2p_role(wpa_s);
-	char *p_pass = NULL;
+	char *p_pass;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
 
-	/* Verify correct role for this property */
-	if (role == WPAS_P2P_ROLE_GO) {
-		if (wpa_s->current_ssid == NULL)
-			return FALSE;
-		p_pass = wpa_s->current_ssid->passphrase;
-	} else
+	if (ssid == NULL)
+		return FALSE;
+
+	p_pass = ssid->passphrase;
+	if (!p_pass)
 		p_pass = "";
 
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
@@ -2093,20 +2065,20 @@
 					   DBusError *error, void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	u8 role = wpas_get_p2p_role(wpa_s);
 	u8 *p_psk = NULL;
 	u8 psk_len = 0;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
 
-	/* Verify correct role for this property */
-	if (role == WPAS_P2P_ROLE_CLIENT) {
-		if (wpa_s->current_ssid == NULL)
-			return FALSE;
-		p_psk = wpa_s->current_ssid->psk;
-		psk_len = 32;
+	if (ssid == NULL)
+		return FALSE;
+
+	if (ssid->psk_set) {
+		p_psk = ssid->psk;
+		psk_len = sizeof(ssid->psk);
 	}
 
 	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
-						      &p_psk, psk_len, error);
+						      p_psk, psk_len, error);
 }
 
 
@@ -2150,7 +2122,7 @@
 						  void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	DBusMessageIter variant_iter, iter_dict;
+	DBusMessageIter variant_iter, iter_dict, array_iter, sub;
 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
 	unsigned int i;
 	struct hostapd_data *hapd = NULL;
@@ -2162,6 +2134,82 @@
 		return FALSE;
 
 	dbus_message_iter_recurse(iter, &variant_iter);
+	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY)
+		return FALSE;
+
+	/*
+	 * This is supposed to be array of bytearrays (aay), but the earlier
+	 * implementation used a dict with "WPSVendorExtensions" as the key in
+	 * this setter function which does not match the format used by the
+	 * getter function. For backwards compatibility, allow both formats to
+	 * be used in the setter.
+	 */
+	if (dbus_message_iter_get_element_type(&variant_iter) ==
+	    DBUS_TYPE_ARRAY) {
+		/* This is the proper format matching the getter */
+		struct wpabuf *vals[MAX_WPS_VENDOR_EXTENSIONS];
+
+		dbus_message_iter_recurse(&variant_iter, &array_iter);
+
+		if (dbus_message_iter_get_arg_type(&array_iter) !=
+		    DBUS_TYPE_ARRAY ||
+		    dbus_message_iter_get_element_type(&array_iter) !=
+		    DBUS_TYPE_BYTE) {
+			wpa_printf(MSG_DEBUG,
+				   "dbus: Not an array of array of bytes");
+			return FALSE;
+		}
+
+		i = 0;
+		os_memset(vals, 0, sizeof(vals));
+
+		while (dbus_message_iter_get_arg_type(&array_iter) ==
+		       DBUS_TYPE_ARRAY) {
+			char *val;
+			int len;
+
+			if (i == MAX_WPS_VENDOR_EXTENSIONS) {
+				wpa_printf(MSG_DEBUG,
+					   "dbus: Too many WPSVendorExtensions values");
+				i = MAX_WPS_VENDOR_EXTENSIONS + 1;
+				break;
+			}
+
+			dbus_message_iter_recurse(&array_iter, &sub);
+			dbus_message_iter_get_fixed_array(&sub, &val, &len);
+			wpa_hexdump(MSG_DEBUG, "dbus: WPSVendorExtentions[]",
+				    val, len);
+			vals[i] = wpabuf_alloc_copy(val, len);
+			if (vals[i] == NULL) {
+				i = MAX_WPS_VENDOR_EXTENSIONS + 1;
+				break;
+			}
+			i++;
+			dbus_message_iter_next(&array_iter);
+		}
+
+		if (i > MAX_WPS_VENDOR_EXTENSIONS) {
+			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+				wpabuf_free(vals[i]);
+			return FALSE;
+		}
+
+		for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+			wpabuf_free(hapd->conf->wps_vendor_ext[i]);
+			hapd->conf->wps_vendor_ext[i] = vals[i];
+		}
+
+		hostapd_update_wps(hapd);
+
+		return TRUE;
+	}
+
+	if (dbus_message_iter_get_element_type(&variant_iter) !=
+	    DBUS_TYPE_DICT_ENTRY)
+		return FALSE;
+
+	wpa_printf(MSG_DEBUG,
+		   "dbus: Try to use backwards compatibility version of WPSVendorExtensions setter");
 	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
 		return FALSE;
 
@@ -2179,6 +2227,7 @@
 				goto error;
 
 			for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+				wpabuf_free(hapd->conf->wps_vendor_ext[i]);
 				if (i < entry.array_len) {
 					hapd->conf->wps_vendor_ext[i] =
 						entry.binarray_value[i];
@@ -2227,30 +2276,31 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "service_type") &&
-		    (entry.type == DBUS_TYPE_STRING)) {
-			if (!os_strcmp(entry.str_value, "upnp"))
+		if (os_strcmp(entry.key, "service_type") == 0 &&
+		    entry.type == DBUS_TYPE_STRING) {
+			if (os_strcmp(entry.str_value, "upnp") == 0)
 				upnp = 1;
-			else if (!os_strcmp(entry.str_value, "bonjour"))
+			else if (os_strcmp(entry.str_value, "bonjour") == 0)
 				bonjour = 1;
 			else
 				goto error_clear;
-		} else if (!os_strcmp(entry.key, "version") &&
-		           entry.type == DBUS_TYPE_INT32) {
+		} else if (os_strcmp(entry.key, "version") == 0 &&
+			   entry.type == DBUS_TYPE_INT32) {
 			version = entry.uint32_value;
-		} else if (!os_strcmp(entry.key, "service") &&
-			     (entry.type == DBUS_TYPE_STRING)) {
+		} else if (os_strcmp(entry.key, "service") == 0 &&
+			   entry.type == DBUS_TYPE_STRING) {
+			os_free(service);
 			service = os_strdup(entry.str_value);
-		} else if (!os_strcmp(entry.key, "query")) {
-			if ((entry.type != DBUS_TYPE_ARRAY) ||
-			    (entry.array_type != DBUS_TYPE_BYTE))
+		} else if (os_strcmp(entry.key, "query") == 0) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != DBUS_TYPE_BYTE)
 				goto error_clear;
 			query = wpabuf_alloc_copy(
 				entry.bytearray_value,
 				entry.array_len);
-		} else if (!os_strcmp(entry.key, "response")) {
-			if ((entry.type != DBUS_TYPE_ARRAY) ||
-			    (entry.array_type != DBUS_TYPE_BYTE))
+		} else if (os_strcmp(entry.key, "response") == 0) {
+			if (entry.type != DBUS_TYPE_ARRAY ||
+			    entry.array_type != DBUS_TYPE_BYTE)
 				goto error_clear;
 			resp = wpabuf_alloc_copy(entry.bytearray_value,
 						 entry.array_len);
@@ -2265,8 +2315,6 @@
 		if (wpas_p2p_service_add_upnp(wpa_s, version, service) != 0)
 			goto error;
 
-		os_free(service);
-		service = NULL;
 	} else if (bonjour == 1) {
 		if (query == NULL || resp == NULL)
 			goto error;
@@ -2278,6 +2326,7 @@
 	} else
 		goto error;
 
+	os_free(service);
 	return reply;
 error_clear:
 	wpa_dbus_dict_entry_clear(&entry);
@@ -2312,11 +2361,11 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "service_type") &&
-		    (entry.type == DBUS_TYPE_STRING)) {
-			if (!os_strcmp(entry.str_value, "upnp"))
+		if (os_strcmp(entry.key, "service_type") == 0 &&
+		    entry.type == DBUS_TYPE_STRING) {
+			if (os_strcmp(entry.str_value, "upnp") == 0)
 				upnp = 1;
-			else if (!os_strcmp(entry.str_value, "bonjour"))
+			else if (os_strcmp(entry.str_value, "bonjour") == 0)
 				bonjour = 1;
 			else
 				goto error_clear;
@@ -2327,13 +2376,14 @@
 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 				goto error;
-			if (!os_strcmp(entry.key, "version") &&
+			if (os_strcmp(entry.key, "version") == 0 &&
 			    entry.type == DBUS_TYPE_INT32)
 				version = entry.uint32_value;
-			else if (!os_strcmp(entry.key, "service") &&
-				 entry.type == DBUS_TYPE_STRING)
+			else if (os_strcmp(entry.key, "service") == 0 &&
+				 entry.type == DBUS_TYPE_STRING) {
+				os_free(service);
 				service = os_strdup(entry.str_value);
-			else
+			} else
 				goto error_clear;
 
 			wpa_dbus_dict_entry_clear(&entry);
@@ -2343,7 +2393,6 @@
 			goto error;
 
 		ret = wpas_p2p_service_del_upnp(wpa_s, version, service);
-		os_free(service);
 		if (ret != 0)
 			goto error;
 	} else if (bonjour == 1) {
@@ -2351,10 +2400,11 @@
 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 				goto error;
 
-			if (!os_strcmp(entry.key, "query")) {
-				if ((entry.type != DBUS_TYPE_ARRAY) ||
-				    (entry.array_type != DBUS_TYPE_BYTE))
+			if (os_strcmp(entry.key, "query") == 0) {
+				if (entry.type != DBUS_TYPE_ARRAY ||
+				    entry.array_type != DBUS_TYPE_BYTE)
 					goto error_clear;
+				wpabuf_free(query);
 				query = wpabuf_alloc_copy(
 					entry.bytearray_value,
 					entry.array_len);
@@ -2370,14 +2420,17 @@
 		ret = wpas_p2p_service_del_bonjour(wpa_s, query);
 		if (ret != 0)
 			goto error;
-		wpabuf_free(query);
 	} else
 		goto error;
 
+	wpabuf_free(query);
+	os_free(service);
 	return reply;
 error_clear:
 	wpa_dbus_dict_entry_clear(&entry);
 error:
+	wpabuf_free(query);
+	os_free(service);
 	return wpas_dbus_error_invalid_args(message, NULL);
 }
 
@@ -2413,22 +2466,22 @@
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
-		if (!os_strcmp(entry.key, "peer_object") &&
+		if (os_strcmp(entry.key, "peer_object") == 0 &&
 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
 			peer_object_path = os_strdup(entry.str_value);
-		} else if (!os_strcmp(entry.key, "service_type") &&
+		} else if (os_strcmp(entry.key, "service_type") == 0 &&
 			   entry.type == DBUS_TYPE_STRING) {
-			if (!os_strcmp(entry.str_value, "upnp"))
+			if (os_strcmp(entry.str_value, "upnp") == 0)
 				upnp = 1;
 			else
 				goto error_clear;
-		} else if (!os_strcmp(entry.key, "version") &&
+		} else if (os_strcmp(entry.key, "version") == 0 &&
 			   entry.type == DBUS_TYPE_INT32) {
 			version = entry.uint32_value;
-		} else if (!os_strcmp(entry.key, "service") &&
+		} else if (os_strcmp(entry.key, "service") == 0 &&
 			   entry.type == DBUS_TYPE_STRING) {
 			service = os_strdup(entry.str_value);
-		} else if (!os_strcmp(entry.key, "tlv")) {
+		} else if (os_strcmp(entry.key, "tlv") == 0) {
 			if (entry.type != DBUS_TYPE_ARRAY ||
 			    entry.array_type != DBUS_TYPE_BYTE)
 				goto error_clear;
@@ -2506,16 +2559,17 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!os_strcmp(entry.key, "peer_object") &&
+		if (os_strcmp(entry.key, "peer_object") == 0 &&
 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
 			peer_object_path = os_strdup(entry.str_value);
-		} else if (!os_strcmp(entry.key, "frequency") &&
+		} else if (os_strcmp(entry.key, "frequency") == 0 &&
 			   entry.type == DBUS_TYPE_INT32) {
 			freq = entry.uint32_value;
-		} else if (!os_strcmp(entry.key, "dialog_token") &&
-			   entry.type == DBUS_TYPE_UINT32) {
+		} else if (os_strcmp(entry.key, "dialog_token") == 0 &&
+			   (entry.type == DBUS_TYPE_UINT32 ||
+			    entry.type == DBUS_TYPE_INT32)) {
 			dlg_tok = entry.uint32_value;
-		} else if (!os_strcmp(entry.key, "tlvs")) {
+		} else if (os_strcmp(entry.key, "tlvs") == 0) {
 			if (entry.type != DBUS_TYPE_ARRAY ||
 			    entry.array_type != DBUS_TYPE_BYTE)
 				goto error_clear;
@@ -2526,12 +2580,9 @@
 
 		wpa_dbus_dict_entry_clear(&entry);
 	}
-	if (!peer_object_path ||
-	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
-	    !p2p_peer_known(wpa_s->global->p2p, addr))
-		goto error;
-
-	if (tlv == NULL)
+	if (parse_peer_object_path(peer_object_path, addr) < 0 ||
+	    !p2p_peer_known(wpa_s->global->p2p, addr) ||
+	    tlv == NULL)
 		goto error;
 
 	wpas_p2p_sd_response(wpa_s, freq, addr, (u8) dlg_tok, tlv);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index 6e67c89..fdaccba 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -109,34 +109,34 @@
  */
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_device_name(DBusMessageIter *iter,
-                                                  DBusError *error,
-                                                  void *user_data);
+						  DBusError *error,
+						  void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_primary_device_type(
 	DBusMessageIter *iter, DBusError *error, void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_config_method(DBusMessageIter *iter,
-                                                    DBusError *error,
-                                                    void *user_data);
+						    DBusError *error,
+						    void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_level(DBusMessageIter *iter,
-                                            DBusError *error,
-                                            void *user_data);
+					    DBusError *error,
+					    void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_device_capability(DBusMessageIter *iter,
-                                                        DBusError *error,
-                                                        void *user_data);
+							DBusError *error,
+							void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_group_capability(DBusMessageIter *iter,
-                                                       DBusError *error,
-                                                       void *user_data);
+						       DBusError *error,
+						       void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_secondary_device_types(
 	DBusMessageIter *iter, DBusError *error, void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_vendor_extension(DBusMessageIter *iter,
-                                                       DBusError *error,
-                                                       void *user_data);
+						       DBusError *error,
+						       void *user_data);
 
 dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
 					  DBusError *error,
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index 8ecf7db..a94a0e5 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -41,8 +41,8 @@
 	dbus_message_iter_recurse(entry_iter, &variant_iter);
 	if (dbus_message_iter_get_arg_type(&variant_iter) !=
 	    DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Role type, "
-			   "string required");
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong Role type, string required");
 		*reply = wpas_dbus_error_invalid_args(message,
 						      "Role must be a string");
 		return -1;
@@ -70,10 +70,9 @@
 	char *val;
 
 	dbus_message_iter_recurse(entry_iter, &variant_iter);
-	if (dbus_message_iter_get_arg_type(&variant_iter) !=
-	    DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Type type, "
-			   "string required");
+	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) {
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong Type type, string required");
 		*reply = wpas_dbus_error_invalid_args(message,
 						      "Type must be a string");
 		return -1;
@@ -105,8 +104,8 @@
 	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
 	    dbus_message_iter_get_element_type(&variant_iter) !=
 	    DBUS_TYPE_BYTE) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Bssid type, "
-			   "byte array required");
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong Bssid type, byte array required");
 		*reply = wpas_dbus_error_invalid_args(
 			message, "Bssid must be a byte array");
 		return -1;
@@ -114,8 +113,8 @@
 	dbus_message_iter_recurse(&variant_iter, &array_iter);
 	dbus_message_iter_get_fixed_array(&array_iter, &params->bssid, &len);
 	if (len != ETH_ALEN) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length "
-			   "%d", len);
+		wpa_printf(MSG_DEBUG, "dbus: WPS.Stsrt - Wrong Bssid length %d",
+			   len);
 		*reply = wpas_dbus_error_invalid_args(message,
 						      "Bssid is wrong length");
 		return -1;
@@ -132,10 +131,9 @@
 	DBusMessageIter variant_iter;
 
 	dbus_message_iter_recurse(entry_iter, &variant_iter);
-	if (dbus_message_iter_get_arg_type(&variant_iter) !=
-	    DBUS_TYPE_STRING) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong Pin type, "
-			   "string required");
+	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_STRING) {
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong Pin type, string required");
 		*reply = wpas_dbus_error_invalid_args(message,
 						      "Pin must be a string");
 		return -1;
@@ -158,8 +156,8 @@
 	if (dbus_message_iter_get_arg_type(&variant_iter) != DBUS_TYPE_ARRAY ||
 	    dbus_message_iter_get_element_type(&variant_iter) !=
 	    DBUS_TYPE_BYTE) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
-			   "P2PDeviceAddress type, byte array required");
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong P2PDeviceAddress type, byte array required");
 		*reply = wpas_dbus_error_invalid_args(
 			message, "P2PDeviceAddress must be a byte array");
 		return -1;
@@ -168,11 +166,11 @@
 	dbus_message_iter_get_fixed_array(&array_iter, &params->p2p_dev_addr,
 					  &len);
 	if (len != ETH_ALEN) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Wrong "
-			   "P2PDeviceAddress length %d", len);
-		*reply = wpas_dbus_error_invalid_args(message,
-						      "P2PDeviceAddress "
-						      "has wrong length");
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start - Wrong P2PDeviceAddress length %d",
+			   len);
+		*reply = wpas_dbus_error_invalid_args(
+			message, "P2PDeviceAddress has wrong length");
 		return -1;
 	}
 	return 0;
@@ -249,54 +247,54 @@
 		dbus_message_iter_next(&dict_iter);
 	}
 
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface && params.type == 1) {
+		if (params.pin == NULL) {
+			wpa_printf(MSG_DEBUG,
+				   "dbus: WPS.Start - Pin required for registrar role");
+			return wpas_dbus_error_invalid_args(
+				message, "Pin required for registrar role.");
+		}
+		ret = wpa_supplicant_ap_wps_pin(wpa_s,
+						params.bssid,
+						params.pin,
+						npin, sizeof(npin), 0);
+	} else if (wpa_s->ap_iface) {
+		ret = wpa_supplicant_ap_wps_pbc(wpa_s,
+						params.bssid,
+						params.p2p_dev_addr);
+	} else
+#endif /* CONFIG_AP */
 	if (params.role == 0) {
 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Role not specified");
 		return wpas_dbus_error_invalid_args(message,
 						    "Role not specified");
-	} else if (params.role == 1 && params.type == 0) {
+	} else if (params.role == 2) {
+		if (params.pin == NULL) {
+			wpa_printf(MSG_DEBUG,
+				   "dbus: WPS.Start - Pin required for registrar role");
+			return wpas_dbus_error_invalid_args(
+				message, "Pin required for registrar role.");
+		}
+		ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
+					 NULL);
+	} else if (params.type == 0) {
 		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Type not specified");
 		return wpas_dbus_error_invalid_args(message,
 						    "Type not specified");
-	} else if (params.role == 2 && params.pin == NULL) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start - Pin required for "
-			   "registrar role");
-		return wpas_dbus_error_invalid_args(
-			message, "Pin required for registrar role.");
-	}
-
-	if (params.role == 2)
-		ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
-					 NULL);
-	else if (params.type == 1) {
-#ifdef CONFIG_AP
-		if (wpa_s->ap_iface)
-			ret = wpa_supplicant_ap_wps_pin(wpa_s,
-							params.bssid,
-							params.pin,
-							npin, sizeof(npin), 0);
-		else
-#endif /* CONFIG_AP */
-		{
-			ret = wpas_wps_start_pin(wpa_s, params.bssid,
-						 params.pin, 0,
-						 DEV_PW_DEFAULT);
-			if (ret > 0)
-				os_snprintf(npin, sizeof(npin), "%08d", ret);
-		}
+	} else if (params.type == 1) {
+		ret = wpas_wps_start_pin(wpa_s, params.bssid,
+					 params.pin, 0,
+					 DEV_PW_DEFAULT);
+		if (ret > 0)
+			os_snprintf(npin, sizeof(npin), "%08d", ret);
 	} else {
-#ifdef CONFIG_AP
-		if (wpa_s->ap_iface)
-			ret = wpa_supplicant_ap_wps_pbc(wpa_s,
-							params.bssid,
-							params.p2p_dev_addr);
-		else
-#endif /* CONFIG_AP */
 		ret = wpas_wps_start_pbc(wpa_s, params.bssid, 0);
 	}
 
 	if (ret < 0) {
-		wpa_printf(MSG_DEBUG, "dbus: WPS.Start wpas_wps_failed in "
-			   "role %s and key %s",
+		wpa_printf(MSG_DEBUG,
+			   "dbus: WPS.Start wpas_wps_failed in role %s and key %s",
 			   (params.role == 1 ? "enrollee" : "registrar"),
 			   (params.type == 0 ? "" :
 			    (params.type == 1 ? "pin" : "pbc")));
@@ -305,31 +303,16 @@
 	}
 
 	reply = dbus_message_new_method_return(message);
-	if (!reply) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
+	if (!reply)
+		return wpas_dbus_error_no_memory(message);
 
 	dbus_message_iter_init_append(reply, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
+	if (!wpa_dbus_dict_open_write(&iter, &dict_iter) ||
+	    (os_strlen(npin) > 0 &&
+	     !wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) ||
+	    !wpa_dbus_dict_close_write(&iter, &dict_iter)) {
 		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	if (os_strlen(npin) > 0) {
-		if (!wpa_dbus_dict_append_string(&dict_iter, "Pin", npin)) {
-			dbus_message_unref(reply);
-			return dbus_message_new_error(message,
-						      DBUS_ERROR_NO_MEMORY,
-						      NULL);
-		}
-	}
-
-	if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		return wpas_dbus_error_no_memory(message);
 	}
 
 	return reply;
@@ -351,7 +334,8 @@
 						 void *user_data)
 {
 	struct wpa_supplicant *wpa_s = user_data;
-	dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1);
+	dbus_bool_t process = wpa_s->conf->wps_cred_processing != 1;
+
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
 						&process, error);
 }
@@ -378,7 +362,7 @@
 					      &process_credentials))
 		return FALSE;
 
-	old_pc = (wpa_s->conf->wps_cred_processing != 1);
+	old_pc = wpa_s->conf->wps_cred_processing != 1;
 	wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1);
 
 	if ((wpa_s->conf->wps_cred_processing != 1) != old_pc)
@@ -408,6 +392,8 @@
 	struct wpa_supplicant *wpa_s = user_data;
 	char *methods = wpa_s->conf->config_methods;
 
+	if (methods == NULL)
+		methods = "";
 	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
 						&methods, error);
 }
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index 750522d..15b0901 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -15,6 +15,7 @@
 #include "dbus_common_i.h"
 #include "dbus_new.h"
 #include "dbus_new_helpers.h"
+#include "dbus_new_handlers.h"
 #include "dbus_dict_helpers.h"
 
 
@@ -73,46 +74,36 @@
  * with properties names as keys and theirs values as values.
  */
 static DBusMessage * get_all_properties(DBusMessage *message, char *interface,
-				        struct wpa_dbus_object_desc *obj_dsc)
+					struct wpa_dbus_object_desc *obj_dsc)
 {
 	DBusMessage *reply;
 	DBusMessageIter iter, dict_iter;
 	DBusError error;
 
 	reply = dbus_message_new_method_return(message);
-	if (reply == NULL) {
-		wpa_printf(MSG_ERROR, "%s: out of memory creating dbus reply",
-			   __func__);
-		return NULL;
-	}
+	if (reply == NULL)
+		return wpas_dbus_error_no_memory(message);
 
 	dbus_message_iter_init_append(reply, &iter);
 	if (!wpa_dbus_dict_open_write(&iter, &dict_iter)) {
-		wpa_printf(MSG_ERROR, "%s: out of memory creating reply",
-			   __func__);
 		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       "out of memory");
-		return reply;
+		return wpas_dbus_error_no_memory(message);
 	}
 
 	dbus_error_init(&error);
 	if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties,
-				       interface, obj_dsc->user_data, &error))
-	{
+				       interface, obj_dsc->user_data, &error)) {
 		dbus_message_unref(reply);
-		reply = wpas_dbus_reply_new_from_error(message, &error,
-						       DBUS_ERROR_INVALID_ARGS,
-						       "No readable properties"
-						       " in this interface");
+		reply = wpas_dbus_reply_new_from_error(
+			message, &error, DBUS_ERROR_INVALID_ARGS,
+			"No readable properties in this interface");
 		dbus_error_free(&error);
 		return reply;
 	}
 
 	if (!wpa_dbus_dict_close_write(&iter, &dict_iter)) {
 		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      "out of memory");
+		return wpas_dbus_error_no_memory(message);
 	}
 
 	return reply;
@@ -135,8 +126,9 @@
 	for (arg = method_dsc->args; arg && arg->name; arg++) {
 		if (arg->dir == ARG_IN) {
 			size_t blen = registered_sig + MAX_SIG_LEN - pos;
+
 			ret = os_snprintf(pos, blen, "%s", arg->type);
-			if (ret < 0 || (size_t) ret >= blen)
+			if (os_snprintf_error(blen, ret))
 				return 0;
 			pos += ret;
 		}
@@ -270,10 +262,13 @@
 	}
 
 	if (os_strncmp(WPA_DBUS_PROPERTIES_GET, method,
-		       WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0)
+		       WPAS_DBUS_METHOD_SIGNAL_PROP_MAX) == 0) {
+		wpa_printf(MSG_MSGDUMP, "%s: Get(%s)", __func__, property);
 		return properties_get(message, property_dsc,
 				      obj_dsc->user_data);
+	}
 
+	wpa_printf(MSG_MSGDUMP, "%s: Set(%s)", __func__, property);
 	return properties_set(message, property_dsc, obj_dsc->user_data);
 }
 
@@ -295,8 +290,7 @@
 	    !os_strncmp(WPA_DBUS_PROPERTIES_GETALL, method,
 			WPAS_DBUS_METHOD_SIGNAL_PROP_MAX)) {
 		/* First argument: interface name (DBUS_TYPE_STRING) */
-		if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-		{
+		if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
 			return dbus_message_new_error(message,
 						      DBUS_ERROR_INVALID_ARGS,
 						      NULL);
@@ -352,8 +346,7 @@
 					      NULL);
 	}
 
-	return method_dsc->method_handler(message,
-					  obj_dsc->user_data);
+	return method_dsc->method_handler(message, obj_dsc->user_data);
 }
 
 
@@ -388,8 +381,9 @@
 	if (!method || !path || !msg_interface)
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-	wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s)",
-		   msg_interface, method, path);
+	wpa_printf(MSG_MSGDUMP, "dbus: %s.%s (%s) [%s]",
+		   msg_interface, method, path,
+		   dbus_message_get_signature(message));
 
 	/* if message is introspection method call */
 	if (!os_strncmp(WPA_DBUS_INTROSPECTION_METHOD, method,
@@ -401,8 +395,7 @@
 #else /* CONFIG_CTRL_IFACE_DBUS_INTRO */
 		reply = dbus_message_new_error(
 			message, DBUS_ERROR_UNKNOWN_METHOD,
-			"wpa_supplicant was compiled without "
-			"introspection support.");
+			"wpa_supplicant was compiled without introspection support.");
 #endif /* CONFIG_CTRL_IFACE_DBUS_INTRO */
 	} else if (!os_strncmp(WPA_DBUS_PROPERTIES_INTERFACE, msg_interface,
 			     WPAS_DBUS_INTERFACE_MAX)) {
@@ -455,6 +448,7 @@
 	free_dbus_object_desc(obj_dsc);
 }
 
+
 /**
  * wpa_dbus_ctrl_iface_init - Initialize dbus control interface
  * @application_data: Pointer to application specific data structure
@@ -482,30 +476,28 @@
 	obj_desc->path = os_strdup(dbus_path);
 
 	/* Register the message handler for the global dbus interface */
-	if (!dbus_connection_register_object_path(iface->con,
-						  dbus_path, &wpa_vtable,
-						  obj_desc)) {
-		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-			   "handler");
+	if (!dbus_connection_register_object_path(iface->con, dbus_path,
+						  &wpa_vtable, obj_desc)) {
+		wpa_printf(MSG_ERROR, "dbus: Could not set up message handler");
 		return -1;
 	}
 
 	/* Register our service with the message bus */
 	dbus_error_init(&error);
-	switch (dbus_bus_request_name(iface->con, dbus_service,
-				      0, &error)) {
+	switch (dbus_bus_request_name(iface->con, dbus_service, 0, &error)) {
 	case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER:
 		ret = 0;
 		break;
 	case DBUS_REQUEST_NAME_REPLY_EXISTS:
 	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
 	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "already registered");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not request service name: already registered");
 		break;
 	default:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "%s %s", error.name, error.message);
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not request service name: %s %s",
+			   error.name, error.message);
 		break;
 	}
 	dbus_error_free(&error);
@@ -529,14 +521,12 @@
  *
  * Registers a new interface with dbus and assigns it a dbus object path.
  */
-int wpa_dbus_register_object_per_iface(
-	struct wpas_dbus_priv *ctrl_iface,
-	const char *path, const char *ifname,
-	struct wpa_dbus_object_desc *obj_desc)
+int wpa_dbus_register_object_per_iface(struct wpas_dbus_priv *ctrl_iface,
+				       const char *path, const char *ifname,
+				       struct wpa_dbus_object_desc *obj_desc)
 {
 	DBusConnection *con;
 	DBusError error;
-
 	DBusObjectPathVTable vtable = {
 		&free_dbus_object_desc_cb, &message_handler,
 		NULL, NULL, NULL, NULL
@@ -554,14 +544,12 @@
 	/* Register the message handler for the interface functions */
 	if (!dbus_connection_try_register_object_path(con, path, &vtable,
 						      obj_desc, &error)) {
-		if (!os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE)) {
+		if (os_strcmp(error.name, DBUS_ERROR_OBJECT_PATH_IN_USE) == 0) {
 			wpa_printf(MSG_DEBUG, "dbus: %s", error.message);
 		} else {
-			wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-				   "handler for interface %s object %s",
-				   ifname, path);
-			wpa_printf(MSG_ERROR, "dbus error: %s", error.name);
-			wpa_printf(MSG_ERROR, "dbus: %s", error.message);
+			wpa_printf(MSG_ERROR,
+				   "dbus: Could not set up message handler for interface %s object %s (error: %s message: %s)",
+				   ifname, path, error.name, error.message);
 		}
 		dbus_error_free(&error);
 		return -1;
@@ -591,8 +579,9 @@
 
 	dbus_connection_get_object_path_data(con, path, (void **) &obj_desc);
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: %s: Could not obtain object's "
-			   "private data: %s", __func__, path);
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: Could not obtain object's private data: %s",
+			   __func__, path);
 		return 0;
 	}
 
@@ -626,24 +615,22 @@
 
 		if (!dbus_message_iter_open_container(dict_iter,
 						      DBUS_TYPE_DICT_ENTRY,
-						      NULL, &entry_iter))
-			return FALSE;
-
-		if (!dbus_message_iter_append_basic(&entry_iter,
+						      NULL, &entry_iter) ||
+		    !dbus_message_iter_append_basic(&entry_iter,
 						    DBUS_TYPE_STRING,
 						    &dsc->dbus_property))
 			return FALSE;
 
 		dbus_error_init(&error);
 		if (!dsc->getter(&entry_iter, &error, obj_dsc->user_data)) {
-			if (dbus_error_is_set (&error)) {
-				wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
-					   "new value of property %s: (%s) %s",
-				           __func__, dsc->dbus_property,
-				           error.name, error.message);
+			if (dbus_error_is_set(&error)) {
+				wpa_printf(MSG_ERROR,
+					   "dbus: %s: Cannot get new value of property %s: (%s) %s",
+					   __func__, dsc->dbus_property,
+					   error.name, error.message);
 			} else {
-				wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
-					   "new value of property %s",
+				wpa_printf(MSG_ERROR,
+					   "dbus: %s: Cannot get new value of property %s",
 					   __func__, dsc->dbus_property);
 			}
 			dbus_error_free(&error);
@@ -673,38 +660,23 @@
 	dbus_message_iter_init_append(msg, &signal_iter);
 
 	if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING,
-					    &interface))
-		goto err;
+					    &interface) ||
+	    /* Changed properties dict */
+	    !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+					      "{sv}", &dict_iter) ||
+	    !put_changed_properties(obj_dsc, interface, &dict_iter, 0) ||
+	    !dbus_message_iter_close_container(&signal_iter, &dict_iter) ||
+	    /* Invalidated properties array (empty) */
+	    !dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
+					      "s", &dict_iter) ||
+	    !dbus_message_iter_close_container(&signal_iter, &dict_iter)) {
+		wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
+			   __func__);
+	} else {
+		dbus_connection_send(con, msg, NULL);
+	}
 
-	/* Changed properties dict */
-	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
-					      "{sv}", &dict_iter))
-		goto err;
-
-	if (!put_changed_properties(obj_dsc, interface, &dict_iter, 0))
-		goto err;
-
-	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
-		goto err;
-
-	/* Invalidated properties array (empty) */
-	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
-					      "s", &dict_iter))
-		goto err;
-
-	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
-		goto err;
-
-	dbus_connection_send(con, msg, NULL);
-
-out:
 	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
-		   __func__);
-	goto out;
 }
 
 
@@ -722,25 +694,16 @@
 	dbus_message_iter_init_append(msg, &signal_iter);
 
 	if (!dbus_message_iter_open_container(&signal_iter, DBUS_TYPE_ARRAY,
-					      "{sv}", &dict_iter))
-		goto err;
+					      "{sv}", &dict_iter) ||
+	    !put_changed_properties(obj_dsc, interface, &dict_iter, 1) ||
+	    !dbus_message_iter_close_container(&signal_iter, &dict_iter)) {
+		wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
+			   __func__);
+	} else {
+		dbus_connection_send(con, msg, NULL);
+	}
 
-	if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1))
-		goto err;
-
-	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
-		goto err;
-
-	dbus_connection_send(con, msg, NULL);
-
-out:
 	dbus_message_unref(msg);
-	return;
-
-err:
-	wpa_printf(MSG_DEBUG, "dbus: %s: Failed to construct signal",
-		   __func__);
-	goto out;
 }
 
 
@@ -772,8 +735,9 @@
 	DBusConnection *con = eloop_ctx;
 	struct wpa_dbus_object_desc *obj_desc = timeout_ctx;
 
-	wpa_printf(MSG_DEBUG, "dbus: %s: Timeout - sending changed properties "
-		   "of object %s", __func__, obj_desc->path);
+	wpa_printf(MSG_DEBUG,
+		   "dbus: %s: Timeout - sending changed properties of object %s",
+		   __func__, obj_desc->path);
 	wpa_dbus_flush_object_changed_properties(con, obj_desc->path);
 }
 
@@ -884,8 +848,9 @@
 	dbus_connection_get_object_path_data(iface->con, path,
 					     (void **) &obj_desc);
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
-			   "could not obtain object's private data: %s", path);
+		wpa_printf(MSG_ERROR,
+			   "dbus: wpa_dbus_property_changed: could not obtain object's private data: %s",
+			   path);
 		return;
 	}
 
@@ -898,13 +863,14 @@
 		}
 
 	if (!dsc || !dsc->dbus_property) {
-		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_property_changed: "
-			   "no property %s in object %s", property, path);
+		wpa_printf(MSG_ERROR,
+			   "dbus: wpa_dbus_property_changed: no property %s in object %s",
+			   property, path);
 		return;
 	}
 
 	if (!eloop_is_timeout_registered(flush_object_timeout_handler,
-					 iface->con, obj_desc->path)) {
+					 iface->con, obj_desc)) {
 		eloop_register_timeout(0, WPA_DBUS_SEND_PROP_CHANGED_TIMEOUT,
 				       flush_object_timeout_handler,
 				       iface->con, obj_desc);
@@ -936,8 +902,9 @@
 	dbus_connection_get_object_path_data(iface->con, path,
 					     (void **) &obj_desc);
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: %s: could not obtain object's "
-		           "private data: %s", __func__, path);
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: could not obtain object's private data: %s",
+			   __func__, path);
 		return FALSE;
 	}
 
@@ -951,10 +918,11 @@
 	if (!fill_dict_with_properties(&dict_iter, obj_desc->properties,
 				       interface, obj_desc->user_data,
 				       &error)) {
-		wpa_printf(MSG_ERROR, "dbus: %s: failed to get object"
-		           " properties: (%s) %s", __func__,
-		           dbus_error_is_set(&error) ? error.name : "none",
-		           dbus_error_is_set(&error) ? error.message : "none");
+		wpa_printf(MSG_ERROR,
+			   "dbus: %s: failed to get object properties: (%s) %s",
+			   __func__,
+			   dbus_error_is_set(&error) ? error.name : "none",
+			   dbus_error_is_set(&error) ? error.message : "none");
 		dbus_error_free(&error);
 		return FALSE;
 	}
@@ -965,29 +933,34 @@
 /**
  * wpas_dbus_new_decompose_object_path - Decompose an interface object path into parts
  * @path: The dbus object path
- * @p2p_persistent_group: indicates whether to parse the path as a P2P
- *                        persistent group object
- * @network: (out) the configured network this object path refers to, if any
- * @bssid: (out) the scanned bssid this object path refers to, if any
- * Returns: The object path of the network interface this path refers to
+ * @sep: Separating part (e.g., "Networks" or "PersistentGroups")
+ * @item: (out) The part following the specified separator, if any
+ * Returns: The object path of the interface this path refers to
  *
- * For a given object path, decomposes the object path into object id, network,
- * and BSSID parts, if those parts exist.
+ * For a given object path, decomposes the object path into object id and
+ * requested part, if those parts exist. The caller is responsible for freeing
+ * the returned value. The *item pointer points to that allocated value and must
+ * not be freed separately.
+ *
+ * As an example, path = "/fi/w1/wpa_supplicant1/Interfaces/1/Networks/0" and
+ * sep = "Networks" would result in "/fi/w1/wpa_supplicant1/Interfaces/1"
+ * getting returned and *items set to point to "0".
  */
-char *wpas_dbus_new_decompose_object_path(const char *path,
-					   int p2p_persistent_group,
-					   char **network,
-					   char **bssid)
+char * wpas_dbus_new_decompose_object_path(const char *path, const char *sep,
+					   char **item)
 {
 	const unsigned int dev_path_prefix_len =
 		os_strlen(WPAS_DBUS_NEW_PATH_INTERFACES "/");
 	char *obj_path_only;
-	char *next_sep;
+	char *pos;
+	size_t sep_len;
 
-	/* Be a bit paranoid about path */
-	if (!path || os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
-				dev_path_prefix_len))
-		return NULL;
+	*item = NULL;
+
+	/* Verify that this starts with our interface prefix */
+	if (os_strncmp(path, WPAS_DBUS_NEW_PATH_INTERFACES "/",
+		       dev_path_prefix_len) != 0)
+		return NULL; /* not our path */
 
 	/* Ensure there's something at the end of the path */
 	if ((path + dev_path_prefix_len)[0] == '\0')
@@ -997,39 +970,20 @@
 	if (obj_path_only == NULL)
 		return NULL;
 
-	next_sep = os_strchr(obj_path_only + dev_path_prefix_len, '/');
-	if (next_sep != NULL) {
-		const char *net_part = os_strstr(
-			next_sep, p2p_persistent_group ?
-			WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "/" :
-			WPAS_DBUS_NEW_NETWORKS_PART "/");
-		const char *bssid_part = os_strstr(
-			next_sep, WPAS_DBUS_NEW_BSSIDS_PART "/");
+	pos = obj_path_only + dev_path_prefix_len;
+	pos = os_strchr(pos, '/');
+	if (pos == NULL)
+		return obj_path_only; /* no next item on the path */
 
-		if (network && net_part) {
-			/* Deal with a request for a configured network */
-			const char *net_name = net_part +
-				os_strlen(p2p_persistent_group ?
-					  WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART
-					  "/" :
-					  WPAS_DBUS_NEW_NETWORKS_PART "/");
-			*network = NULL;
-			if (os_strlen(net_name))
-				*network = os_strdup(net_name);
-		} else if (bssid && bssid_part) {
-			/* Deal with a request for a scanned BSSID */
-			const char *bssid_name = bssid_part +
-				os_strlen(WPAS_DBUS_NEW_BSSIDS_PART "/");
-			if (os_strlen(bssid_name))
-				*bssid = os_strdup(bssid_name);
-			else
-				*bssid = NULL;
-		}
+	 /* Separate network interface prefix from the path */
+	*pos++ = '\0';
 
-		/* Cut off interface object path before "/" */
-		*next_sep = '\0';
-	}
+	sep_len = os_strlen(sep);
+	if (os_strncmp(pos, sep, sep_len) != 0 || pos[sep_len] != '/')
+		return obj_path_only; /* no match */
 
+	 /* return a pointer to the requested item */
+	*item = pos + sep_len + 1;
 	return obj_path_only;
 }
 
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h
index 6d31ad5..6e2c1f1 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -12,13 +12,13 @@
 
 #include <dbus/dbus.h>
 
-typedef DBusMessage * (* WPADBusMethodHandler)(DBusMessage *message,
-					       void *user_data);
-typedef void (* WPADBusArgumentFreeFunction)(void *handler_arg);
+typedef DBusMessage * (*WPADBusMethodHandler)(DBusMessage *message,
+					      void *user_data);
+typedef void (*WPADBusArgumentFreeFunction)(void *handler_arg);
 
-typedef dbus_bool_t (* WPADBusPropertyAccessor)(DBusMessageIter *iter,
-                                                DBusError *error,
-						void *user_data);
+typedef dbus_bool_t (*WPADBusPropertyAccessor)(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data);
 
 struct wpa_dbus_object_desc {
 	DBusConnection *connection;
@@ -137,10 +137,8 @@
 DBusMessage * wpa_dbus_introspect(DBusMessage *message,
 				  struct wpa_dbus_object_desc *obj_dsc);
 
-char *wpas_dbus_new_decompose_object_path(const char *path,
-					   int p2p_persistent_group,
-					   char **network,
-					   char **bssid);
+char * wpas_dbus_new_decompose_object_path(const char *path, const char *sep,
+					   char **item);
 
 DBusMessage *wpas_dbus_reply_new_from_error(DBusMessage *message,
 					    DBusError *error,
diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c
index 3b090c0..e0dd9e2 100644
--- a/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -96,6 +96,7 @@
 {
 	const struct wpa_dbus_method_desc *dsc;
 	struct interfaces *iface;
+
 	for (dsc = methods; dsc && dsc->dbus_method; dsc++) {
 		iface = add_interface(list, dsc->dbus_interface);
 		if (iface)
@@ -110,6 +111,7 @@
 {
 	const struct wpa_dbus_signal_desc *dsc;
 	struct interfaces *iface;
+
 	for (dsc = signals; dsc && dsc->dbus_signal; dsc++) {
 		iface = add_interface(list, dsc->dbus_interface);
 		if (iface)
@@ -124,6 +126,7 @@
 {
 	const struct wpa_dbus_property_desc *dsc;
 	struct interfaces *iface;
+
 	for (dsc = properties; dsc && dsc->dbus_property; dsc++) {
 		iface = add_interface(list, dsc->dbus_interface);
 		if (iface)
@@ -154,14 +157,14 @@
 static void add_interfaces(struct dl_list *list, struct wpabuf *xml)
 {
 	struct interfaces *iface, *n;
+
 	dl_list_for_each_safe(iface, n, list, struct interfaces, list) {
 		if (wpabuf_len(iface->xml) + 20 < wpabuf_tailroom(xml)) {
 			wpabuf_put_buf(xml, iface->xml);
 			wpabuf_put_str(xml, "</interface>");
 		} else {
-			wpa_printf(MSG_DEBUG, "dbus: Not enough room for "
-				   "add_interfaces inspect data: tailroom %u, "
-				   "add %u",
+			wpa_printf(MSG_DEBUG,
+				   "dbus: Not enough room for add_interfaces inspect data: tailroom %u, add %u",
 				   (unsigned int) wpabuf_tailroom(xml),
 				   (unsigned int) wpabuf_len(iface->xml));
 		}
@@ -229,6 +232,7 @@
 				struct wpa_dbus_object_desc *obj_dsc)
 {
 	struct dl_list ifaces;
+
 	dl_list_init(&ifaces);
 	extract_interfaces(&ifaces, obj_dsc);
 	add_interfaces(&ifaces, xml);
@@ -270,6 +274,7 @@
 	reply = dbus_message_new_method_return(message);
 	if (reply) {
 		const char *intro_str = wpabuf_head(xml);
+
 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
 					 DBUS_TYPE_INVALID);
 	}
diff --git a/wpa_supplicant/dbus/dbus_old.c b/wpa_supplicant/dbus/dbus_old.c
index 85d8a78..2899132 100644
--- a/wpa_supplicant/dbus/dbus_old.c
+++ b/wpa_supplicant/dbus/dbus_old.c
@@ -92,9 +92,9 @@
  */
 DBusMessage * wpas_dbus_new_invalid_iface_error(DBusMessage *message)
 {
-	return dbus_message_new_error(message, WPAS_ERROR_INVALID_IFACE,
-				      "wpa_supplicant knows nothing about "
-				      "this interface.");
+	return dbus_message_new_error(
+		message, WPAS_ERROR_INVALID_IFACE,
+		"wpa_supplicant knows nothing about this interface.");
 }
 
 
@@ -216,8 +216,12 @@
 	if (!msg_interface)
 		goto out;
 
+	wpa_printf(MSG_MSGDUMP, "dbus[old/iface]: %s.%s (%s) [%s]",
+		   msg_interface, method, path,
+		   dbus_message_get_signature(message));
+
 	iface_obj_path = wpas_dbus_decompose_object_path(path, &network,
-	                                                 &bssid);
+							 &bssid);
 	if (iface_obj_path == NULL) {
 		reply = wpas_dbus_new_invalid_iface_error(message);
 		goto out;
@@ -227,7 +231,7 @@
 	 * wpa_supplicant structure it's supposed to (which is wpa_s)
 	 */
 	if (wpa_supplicant_get_iface_by_dbus_path(wpa_s->global,
-	                                          iface_obj_path) != wpa_s) {
+						  iface_obj_path) != wpa_s) {
 		reply = wpas_dbus_new_invalid_iface_error(message);
 		goto out;
 	}
@@ -235,6 +239,7 @@
 	if (network && !strcmp(msg_interface, WPAS_DBUS_IFACE_NETWORK)) {
 		/* A method for one of this interface's configured networks */
 		int nid = strtoul(network, NULL, 10);
+
 		if (errno != EINVAL)
 			reply = wpas_dispatch_network_method(message, wpa_s,
 							     nid);
@@ -275,14 +280,14 @@
 			reply = wpas_dbus_iface_remove_blobs(message, wpa_s);
 #endif /* CONFIG_NO_CONFIG_BLOBS */
 #ifdef CONFIG_WPS
-		else if (!os_strcmp(method, "wpsPbc"))
+		else if (os_strcmp(method, "wpsPbc") == 0)
 			reply = wpas_dbus_iface_wps_pbc(message, wpa_s);
-		else if (!os_strcmp(method, "wpsPin"))
+		else if (os_strcmp(method, "wpsPin") == 0)
 			reply = wpas_dbus_iface_wps_pin(message, wpa_s);
-		else if (!os_strcmp(method, "wpsReg"))
+		else if (os_strcmp(method, "wpsReg") == 0)
 			reply = wpas_dbus_iface_wps_reg(message, wpa_s);
 #endif /* CONFIG_WPS */
-		else if (!os_strcmp(method, "flush"))
+		else if (os_strcmp(method, "flush") == 0)
 			reply = wpas_dbus_iface_flush(message, wpa_s);
 	}
 
@@ -328,6 +333,10 @@
 	if (!method || !path || !ctrl_iface || !msg_interface)
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
+	wpa_printf(MSG_MSGDUMP, "dbus[old]: %s.%s (%s) [%s]",
+		   msg_interface, method, path,
+		   dbus_message_get_signature(message));
+
 	/* Validate the method interface */
 	if (strcmp(msg_interface, WPAS_DBUS_INTERFACE) != 0)
 		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -381,8 +390,8 @@
 					  WPAS_DBUS_IFACE_INTERFACE,
 					  "ScanResultsAvailable");
 	if (_signal == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
-			   "results signal");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to send scan results signal");
 		return;
 	}
 	dbus_connection_send(iface->con, _signal, NULL);
@@ -426,29 +435,21 @@
 					  "StateChange");
 	if (_signal == NULL) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_state_change: "
-		           "could not create dbus signal; likely out of "
-		           "memory");
+			   "dbus: %s: could not create dbus signal; likely out of memory",
+			   __func__);
 		return;
 	}
 
 	new_state_str = wpa_supplicant_state_txt(new_state);
 	old_state_str = wpa_supplicant_state_txt(old_state);
-	if (new_state_str == NULL || old_state_str == NULL) {
-		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_state_change: "
-		           "Could not convert state strings");
-		goto out;
-	}
 
 	if (!dbus_message_append_args(_signal,
-	                              DBUS_TYPE_STRING, &new_state_str,
-	                              DBUS_TYPE_STRING, &old_state_str,
-	                              DBUS_TYPE_INVALID)) {
+				      DBUS_TYPE_STRING, &new_state_str,
+				      DBUS_TYPE_STRING, &old_state_str,
+				      DBUS_TYPE_INVALID)) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_state_change: "
-		           "Not enough memory to construct state change "
-		           "signal");
+			   "dbus: %s: Not enough memory to construct state change signal",
+			   __func__);
 		goto out;
 	}
 
@@ -480,18 +481,18 @@
 					  WPAS_DBUS_IFACE_INTERFACE,
 					  "Scanning");
 	if (_signal == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to send scan "
-			   "results signal");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to send scan results signal");
 		return;
 	}
 
 	if (dbus_message_append_args(_signal,
-	                             DBUS_TYPE_BOOLEAN, &scanning,
-	                             DBUS_TYPE_INVALID)) {
+				     DBUS_TYPE_BOOLEAN, &scanning,
+				     DBUS_TYPE_INVALID)) {
 		dbus_connection_send(iface->con, _signal, NULL);
 	} else {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to construct "
-			   "signal");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to construct signal");
 	}
 	dbus_message_unref(_signal);
 }
@@ -516,19 +517,18 @@
 					  "WpsCred");
 	if (_signal == NULL) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
-		           "Could not create dbus signal; likely out of "
-		           "memory");
+			   "dbus: %s: Could not create dbus signal; likely out of memory",
+			   __func__);
 		return;
 	}
 
 	if (!dbus_message_append_args(_signal,
-	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+				      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
 				      &cred->cred_attr, cred->cred_attr_len,
-	                              DBUS_TYPE_INVALID)) {
+				      DBUS_TYPE_INVALID)) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_wps_cred: "
-		           "Not enough memory to construct signal");
+			   "dbus: %s: Not enough memory to construct signal",
+			   __func__);
 		goto out;
 	}
 
@@ -567,9 +567,8 @@
 					  "Certification");
 	if (_signal == NULL) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_certification: "
-		           "Could not create dbus signal; likely out of "
-		           "memory");
+			   "dbus: %s: Could not create dbus signal; likely out of memory",
+			   __func__);
 		return;
 	}
 
@@ -578,15 +577,15 @@
 	cert_hex_len = cert ? wpabuf_len(cert) : 0;
 
 	if (!dbus_message_append_args(_signal,
-				      DBUS_TYPE_INT32,&depth,
+				      DBUS_TYPE_INT32, &depth,
 				      DBUS_TYPE_STRING, &subject,
-	                              DBUS_TYPE_STRING, &hash,
-	                              DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+				      DBUS_TYPE_STRING, &hash,
+				      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
 				      &cert_hex, cert_hex_len,
-	                              DBUS_TYPE_INVALID)) {
+				      DBUS_TYPE_INVALID)) {
 		wpa_printf(MSG_ERROR,
-		           "dbus: wpa_supplicant_dbus_notify_certification: "
-		           "Not enough memory to construct signal");
+			   "dbus: %s: Not enough memory to construct signal",
+			   __func__);
 		goto out;
 	}
 
@@ -618,8 +617,7 @@
 	if (!dbus_connection_register_object_path(iface->con,
 						  WPAS_DBUS_PATH, &wpas_vtable,
 						  iface)) {
-		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-			   "handler");
+		wpa_printf(MSG_ERROR, "dbus: Could not set up message handler");
 		return -1;
 	}
 
@@ -633,12 +631,13 @@
 	case DBUS_REQUEST_NAME_REPLY_EXISTS:
 	case DBUS_REQUEST_NAME_REPLY_IN_QUEUE:
 	case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "already registered");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not request service name: already registered");
 		break;
 	default:
-		wpa_printf(MSG_ERROR, "dbus: Could not request service name: "
-			   "%s %s", error.name, error.message);
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not request service name: %s %s",
+			   error.name, error.message);
 		break;
 	}
 	dbus_error_free(&error);
@@ -687,8 +686,9 @@
 	/* Register the message handler for the interface functions */
 	if (!dbus_connection_register_fallback(con, wpa_s->dbus_path, &vtable,
 					       wpa_s)) {
-		wpa_printf(MSG_ERROR, "dbus: Could not set up message "
-			   "handler for interface %s", wpa_s->ifname);
+		wpa_printf(MSG_ERROR,
+			   "dbus: Could not set up message handler for interface %s",
+			   wpa_s->ifname);
 		return -1;
 	}
 
diff --git a/wpa_supplicant/dbus/dbus_old.h b/wpa_supplicant/dbus/dbus_old.h
index e668231..451a9f8 100644
--- a/wpa_supplicant/dbus/dbus_old.h
+++ b/wpa_supplicant/dbus/dbus_old.h
@@ -82,7 +82,7 @@
 					      const struct wpabuf *cert);
 
 char * wpas_dbus_decompose_object_path(const char *path, char **network,
-                                       char **bssid);
+				       char **bssid);
 
 int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s);
 int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s);
@@ -104,7 +104,12 @@
 {
 }
 
-#define wpa_supplicant_dbus_notify_state_change(w,n,o) do { } while (0)
+static inline void
+wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
+					enum wpa_states new_state,
+					enum wpa_states old_state)
+{
+}
 
 static inline void
 wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index 048158f..504de2a 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -37,9 +37,9 @@
 {
 	DBusMessage *reply;
 
-	reply = dbus_message_new_error(message, WPAS_ERROR_INVALID_OPTS,
-				       "Did not receive correct message "
-				       "arguments.");
+	reply = dbus_message_new_error(
+		message, WPAS_ERROR_INVALID_OPTS,
+		"Did not receive correct message arguments.");
 	if (arg != NULL)
 		dbus_message_append_args(reply, DBUS_TYPE_STRING, &arg,
 					 DBUS_TYPE_INVALID);
@@ -112,28 +112,28 @@
 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 				goto error;
 			if (!strcmp(entry.key, "driver") &&
-			    (entry.type == DBUS_TYPE_STRING)) {
+			    entry.type == DBUS_TYPE_STRING) {
 				os_free(driver);
 				driver = os_strdup(entry.str_value);
 				wpa_dbus_dict_entry_clear(&entry);
 				if (driver == NULL)
 					goto error;
 			} else if (!strcmp(entry.key, "driver-params") &&
-				   (entry.type == DBUS_TYPE_STRING)) {
+				   entry.type == DBUS_TYPE_STRING) {
 				os_free(driver_param);
 				driver_param = os_strdup(entry.str_value);
 				wpa_dbus_dict_entry_clear(&entry);
 				if (driver_param == NULL)
 					goto error;
 			} else if (!strcmp(entry.key, "config-file") &&
-				   (entry.type == DBUS_TYPE_STRING)) {
+				   entry.type == DBUS_TYPE_STRING) {
 				os_free(confname);
 				confname = os_strdup(entry.str_value);
 				wpa_dbus_dict_entry_clear(&entry);
 				if (confname == NULL)
 					goto error;
 			} else if (!strcmp(entry.key, "bridge-ifname") &&
-				   (entry.type == DBUS_TYPE_STRING)) {
+				   entry.type == DBUS_TYPE_STRING) {
 				os_free(bridge_ifname);
 				bridge_ifname = os_strdup(entry.str_value);
 				wpa_dbus_dict_entry_clear(&entry);
@@ -151,13 +151,13 @@
 	 * an error if we already control it.
 	 */
 	if (wpa_supplicant_get_iface(global, ifname) != NULL) {
-		reply = dbus_message_new_error(message,
-					       WPAS_ERROR_EXISTS_ERROR,
-					       "wpa_supplicant already "
-					       "controls this interface.");
+		reply = dbus_message_new_error(
+			message, WPAS_ERROR_EXISTS_ERROR,
+			"wpa_supplicant already controls this interface.");
 	} else {
 		struct wpa_supplicant *wpa_s;
 		struct wpa_interface iface;
+
 		os_memset(&iface, 0, sizeof(iface));
 		iface.ifname = ifname;
 		iface.driver = driver;
@@ -165,17 +165,17 @@
 		iface.confname = confname;
 		iface.bridge_ifname = bridge_ifname;
 		/* Otherwise, have wpa_supplicant attach to it. */
-		if ((wpa_s = wpa_supplicant_add_iface(global, &iface))) {
+		wpa_s = wpa_supplicant_add_iface(global, &iface);
+		if (wpa_s) {
 			const char *path = wpa_s->dbus_path;
+
 			reply = dbus_message_new_method_return(message);
 			dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH,
-			                         &path, DBUS_TYPE_INVALID);
+						 &path, DBUS_TYPE_INVALID);
 		} else {
-			reply = dbus_message_new_error(message,
-						       WPAS_ERROR_ADD_ERROR,
-						       "wpa_supplicant "
-						       "couldn't grab this "
-						       "interface.");
+			reply = dbus_message_new_error(
+				message, WPAS_ERROR_ADD_ERROR,
+				"wpa_supplicant couldn't grab this interface.");
 		}
 	}
 
@@ -226,10 +226,9 @@
 	if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
 		reply = wpas_dbus_new_success_reply(message);
 	} else {
-		reply = dbus_message_new_error(message,
-					       WPAS_ERROR_REMOVE_ERROR,
-					       "wpa_supplicant couldn't "
-					       "remove this interface.");
+		reply = dbus_message_new_error(
+			message, WPAS_ERROR_REMOVE_ERROR,
+			"wpa_supplicant couldn't remove this interface.");
 	}
 
 out:
@@ -256,8 +255,8 @@
 	struct wpa_supplicant *wpa_s;
 
 	if (!dbus_message_get_args(message, NULL,
-	                           DBUS_TYPE_STRING, &ifname,
-	                           DBUS_TYPE_INVALID)) {
+				   DBUS_TYPE_STRING, &ifname,
+				   DBUS_TYPE_INVALID)) {
 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
 		goto out;
 	}
@@ -271,8 +270,8 @@
 	path = wpa_s->dbus_path;
 	reply = dbus_message_new_method_return(message);
 	dbus_message_append_args(reply,
-	                         DBUS_TYPE_OBJECT_PATH, &path,
-	                         DBUS_TYPE_INVALID);
+				 DBUS_TYPE_OBJECT_PATH, &path,
+				 DBUS_TYPE_INVALID);
 
 out:
 	return reply;
@@ -298,10 +297,10 @@
 	dbus_bool_t debug_show_keys;
 
 	if (!dbus_message_get_args(message, NULL,
-	                           DBUS_TYPE_INT32, &debug_level,
-	                           DBUS_TYPE_BOOLEAN, &debug_timestamp,
-	                           DBUS_TYPE_BOOLEAN, &debug_show_keys,
-	                           DBUS_TYPE_INVALID)) {
+				   DBUS_TYPE_INT32, &debug_level,
+				   DBUS_TYPE_BOOLEAN, &debug_timestamp,
+				   DBUS_TYPE_BOOLEAN, &debug_show_keys,
+				   DBUS_TYPE_INVALID)) {
 		return wpas_dbus_new_invalid_opts_error(message, NULL);
 	}
 
@@ -409,84 +408,56 @@
 {
 	DBusMessage *reply;
 	DBusMessageIter iter, iter_dict;
-	const u8 *ie;
+	const u8 *wpa_ie, *rsn_ie, *wps_ie;
 
 	/* Dump the properties into a dbus message */
 	reply = dbus_message_new_method_return(message);
 
+	wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+	rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	wps_ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
+
 	dbus_message_iter_init_append(reply, &iter);
-	if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-		goto error;
-
-	if (!wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
+	if (!wpa_dbus_dict_open_write(&iter, &iter_dict) ||
+	    !wpa_dbus_dict_append_byte_array(&iter_dict, "bssid",
 					     (const char *) bss->bssid,
-					     ETH_ALEN))
-		goto error;
-
-	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
-						     (const char *) (ie + 2),
-						     ie[1]))
-			goto error;
+					     ETH_ALEN) ||
+	    !wpa_dbus_dict_append_byte_array(&iter_dict, "ssid",
+					     (const char *) bss->ssid,
+					     bss->ssid_len) ||
+	    (wpa_ie &&
+	     !wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
+					      (const char *) wpa_ie,
+					      wpa_ie[1] + 2)) ||
+	    (rsn_ie &&
+	     !wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
+					      (const char *) rsn_ie,
+					      rsn_ie[1] + 2)) ||
+	    (wps_ie &&
+	     !wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
+					     (const char *) wps_ie,
+					      wps_ie[1] + 2)) ||
+	    (bss->freq &&
+	     !wpa_dbus_dict_append_int32(&iter_dict, "frequency", bss->freq)) ||
+	    !wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
+					 bss->caps) ||
+	    (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
+	     !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual)) ||
+	    (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
+	     !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise)) ||
+	    (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
+	     !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level)) ||
+	    !wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
+					wpa_bss_get_max_rate(bss) * 500000) ||
+	    !wpa_dbus_dict_close_write(&iter, &iter_dict)) {
+		if (reply)
+			dbus_message_unref(reply);
+		reply = dbus_message_new_error(
+			message, WPAS_ERROR_INTERNAL_ERROR,
+			"an internal error occurred returning BSSID properties.");
 	}
 
-	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpaie",
-						     (const char *) ie,
-						     ie[1] + 2))
-			goto error;
-	}
-
-	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "rsnie",
-						     (const char *) ie,
-						     ie[1] + 2))
-			goto error;
-	}
-
-	ie = wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE);
-	if (ie) {
-		if (!wpa_dbus_dict_append_byte_array(&iter_dict, "wpsie",
-						     (const char *) ie,
-						     ie[1] + 2))
-			goto error;
-	}
-
-	if (bss->freq) {
-		if (!wpa_dbus_dict_append_int32(&iter_dict, "frequency",
-						bss->freq))
-			goto error;
-	}
-	if (!wpa_dbus_dict_append_uint16(&iter_dict, "capabilities",
-					 bss->caps))
-		goto error;
-	if (!(bss->flags & WPA_BSS_QUAL_INVALID) &&
-	    !wpa_dbus_dict_append_int32(&iter_dict, "quality", bss->qual))
-		goto error;
-	if (!(bss->flags & WPA_BSS_NOISE_INVALID) &&
-	    !wpa_dbus_dict_append_int32(&iter_dict, "noise", bss->noise))
-		goto error;
-	if (!(bss->flags & WPA_BSS_LEVEL_INVALID) &&
-	    !wpa_dbus_dict_append_int32(&iter_dict, "level", bss->level))
-		goto error;
-	if (!wpa_dbus_dict_append_int32(&iter_dict, "maxrate",
-					wpa_bss_get_max_rate(bss) * 500000))
-		goto error;
-
-	if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
-		goto error;
-
 	return reply;
-
-error:
-	if (reply)
-		dbus_message_unref(reply);
-	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
-				      "an internal error occurred returning "
-				      "BSSID properties.");
 }
 
 
@@ -546,6 +517,7 @@
 	if (res < 0) {
 		if (!strict) {
 			const char *args[] = {"CCMP", "TKIP", "NONE"};
+
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "pairwise", args,
 				    ARRAY_SIZE(args)))
@@ -555,28 +527,17 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "pairwise",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "CCMP"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "TKIP"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "NONE"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "CCMP")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "TKIP")) ||
+		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "NONE")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -589,6 +550,7 @@
 			const char *args[] = {
 				"CCMP", "TKIP", "WEP104", "WEP40"
 			};
+
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "group", args,
 				    ARRAY_SIZE(args)))
@@ -601,31 +563,19 @@
 						      &iter_array))
 			goto error;
 
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "CCMP"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "TKIP"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WEP104"))
-				goto error;
-		}
-
-		if (capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WEP40"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+		if (((capa.enc & WPA_DRIVER_CAPA_ENC_CCMP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "CCMP")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_TKIP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "TKIP")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP104) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WEP104")) ||
+		    ((capa.enc & WPA_DRIVER_CAPA_ENC_WEP40) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WEP40")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -648,38 +598,23 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "key_mgmt",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    "NONE"))
-			goto error;
-
-		if (!wpa_dbus_dict_string_array_add_element(&iter_array,
-							    "IEEE8021X"))
-			goto error;
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA-EAP"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA-PSK"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA-NONE"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    !wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "NONE") ||
+		    !wpa_dbus_dict_string_array_add_element(&iter_array,
+							    "IEEE8021X") ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WPA-EAP")) ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WPA-PSK")) ||
+		    ((capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WPA-NONE")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -690,6 +625,7 @@
 	if (res < 0) {
 		if (!strict) {
 			const char *args[] = { "RSN", "WPA" };
+
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "proto", args,
 				    ARRAY_SIZE(args)))
@@ -699,24 +635,16 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "proto",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "RSN"))
-				goto error;
-		}
-
-		if (capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
-				     WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "WPA"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "RSN")) ||
+		    ((capa.key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+				       WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "WPA")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -727,6 +655,7 @@
 	if (res < 0) {
 		if (!strict) {
 			const char *args[] = { "OPEN", "SHARED", "LEAP" };
+
 			if (!wpa_dbus_dict_append_string_array(
 				    &iter_dict, "auth_alg", args,
 				    ARRAY_SIZE(args)))
@@ -736,28 +665,17 @@
 		if (!wpa_dbus_dict_begin_string_array(&iter_dict, "auth_alg",
 						      &iter_dict_entry,
 						      &iter_dict_val,
-						      &iter_array))
-			goto error;
-
-		if (capa.auth & (WPA_DRIVER_AUTH_OPEN)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "OPEN"))
-				goto error;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_SHARED)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "SHARED"))
-				goto error;
-		}
-
-		if (capa.auth & (WPA_DRIVER_AUTH_LEAP)) {
-			if (!wpa_dbus_dict_string_array_add_element(
-				    &iter_array, "LEAP"))
-				goto error;
-		}
-
-		if (!wpa_dbus_dict_end_string_array(&iter_dict,
+						      &iter_array) ||
+		    ((capa.auth & WPA_DRIVER_AUTH_OPEN) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "OPEN")) ||
+		    ((capa.auth & WPA_DRIVER_AUTH_SHARED) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "SHARED")) ||
+		    ((capa.auth & WPA_DRIVER_AUTH_LEAP) &&
+		     !wpa_dbus_dict_string_array_add_element(
+			     &iter_array, "LEAP")) ||
+		    !wpa_dbus_dict_end_string_array(&iter_dict,
 						    &iter_dict_entry,
 						    &iter_dict_val,
 						    &iter_array))
@@ -772,9 +690,9 @@
 error:
 	if (reply)
 		dbus_message_unref(reply);
-	return dbus_message_new_error(message, WPAS_ERROR_INTERNAL_ERROR,
-				      "an internal error occurred returning "
-				      "interface capabilities.");
+	return dbus_message_new_error(
+		message, WPAS_ERROR_INTERNAL_ERROR,
+		"an internal error occurred returning interface capabilities.");
 }
 
 
@@ -795,10 +713,9 @@
 
 	ssid = wpa_config_add_network(wpa_s->conf);
 	if (ssid == NULL) {
-		reply = dbus_message_new_error(message,
-					       WPAS_ERROR_ADD_NETWORK_ERROR,
-					       "wpa_supplicant could not add "
-					       "a network on this interface.");
+		reply = dbus_message_new_error(
+			message, WPAS_ERROR_ADD_NETWORK_ERROR,
+			"wpa_supplicant could not add a network on this interface.");
 		goto out;
 	}
 	wpas_notify_network_added(wpa_s, ssid);
@@ -838,15 +755,15 @@
 	struct wpa_ssid *ssid;
 
 	if (!dbus_message_get_args(message, NULL,
-	                           DBUS_TYPE_OBJECT_PATH, &op,
-	                           DBUS_TYPE_INVALID)) {
+				   DBUS_TYPE_OBJECT_PATH, &op,
+				   DBUS_TYPE_INVALID)) {
 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
 		goto out;
 	}
 
 	/* Extract the network ID */
 	iface = wpas_dbus_decompose_object_path(op, &net_id, NULL);
-	if (iface == NULL) {
+	if (iface == NULL || net_id == NULL) {
 		reply = wpas_dbus_new_invalid_network_error(message);
 		goto out;
 	}
@@ -866,17 +783,17 @@
 
 	wpas_notify_network_removed(wpa_s, ssid);
 
-	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
-		reply = dbus_message_new_error(message,
-					       WPAS_ERROR_REMOVE_NETWORK_ERROR,
-					       "error removing the specified "
-					       "on this interface.");
-		goto out;
-	}
-
 	if (ssid == wpa_s->current_ssid)
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
+
+	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+		reply = dbus_message_new_error(
+			message, WPAS_ERROR_REMOVE_NETWORK_ERROR,
+			"error removing the specified on this interface.");
+		goto out;
+	}
+
 	reply = wpas_dbus_new_success_reply(message);
 
 out:
@@ -886,7 +803,7 @@
 }
 
 
-static const char *dont_quote[] = {
+static const char  const *dont_quote[] = {
 	"key_mgmt", "proto", "pairwise", "auth_alg", "group", "eap",
 	"opensc_engine_path", "pkcs11_engine_path", "pkcs11_module_path",
 	"bssid", NULL
@@ -896,8 +813,9 @@
 static dbus_bool_t should_quote_opt(const char *key)
 {
 	int i = 0;
+
 	while (dont_quote[i] != NULL) {
-		if (strcmp(key, dont_quote[i]) == 0)
+		if (os_strcmp(key, dont_quote[i]) == 0)
 			return FALSE;
 		i++;
 	}
@@ -968,7 +886,7 @@
 					goto error;
 				ret = os_snprintf(value, size, "\"%s\"",
 						  entry.str_value);
-				if (ret < 0 || (size_t) ret != (size - 1))
+				if (os_snprintf_error(size, ret))
 					goto error;
 			} else {
 				value = os_strdup(entry.str_value);
@@ -981,7 +899,7 @@
 				goto error;
 			ret = os_snprintf(value, size, "%u",
 					  entry.uint32_value);
-			if (ret <= 0)
+			if (os_snprintf_error(size, ret))
 				goto error;
 		} else if (entry.type == DBUS_TYPE_INT32) {
 			value = os_zalloc(size);
@@ -989,7 +907,7 @@
 				goto error;
 			ret = os_snprintf(value, size, "%d",
 					  entry.int32_value);
-			if (ret <= 0)
+			if (os_snprintf_error(size, ret))
 				goto error;
 		} else
 			goto error;
@@ -1102,7 +1020,8 @@
 			goto out;
 		}
 		/* Ensure the object path really points to this interface */
-		if (os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
+		if (network == NULL ||
+		    os_strcmp(iface_obj_path, wpa_s->dbus_path) != 0) {
 			reply = wpas_dbus_new_invalid_network_error(message);
 			goto out;
 		}
@@ -1212,19 +1131,19 @@
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 		if (!strcmp(entry.key, "opensc_engine_path") &&
-		    (entry.type == DBUS_TYPE_STRING)) {
+		    entry.type == DBUS_TYPE_STRING) {
 			os_free(opensc_engine_path);
 			opensc_engine_path = os_strdup(entry.str_value);
 			if (opensc_engine_path == NULL)
 				goto error;
 		} else if (!strcmp(entry.key, "pkcs11_engine_path") &&
-			   (entry.type == DBUS_TYPE_STRING)) {
+			   entry.type == DBUS_TYPE_STRING) {
 			os_free(pkcs11_engine_path);
 			pkcs11_engine_path = os_strdup(entry.str_value);
 			if (pkcs11_engine_path == NULL)
 				goto error;
 		} else if (!strcmp(entry.key, "pkcs11_module_path") &&
-				 (entry.type == DBUS_TYPE_STRING)) {
+				 entry.type == DBUS_TYPE_STRING) {
 			os_free(pkcs11_module_path);
 			pkcs11_module_path = os_strdup(entry.str_value);
 			if (pkcs11_module_path == NULL)
@@ -1304,8 +1223,8 @@
 		dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
 					 DBUS_TYPE_INVALID);
 	} else {
-		wpa_printf(MSG_ERROR, "dbus: Not enough memory to return "
-			   "scanning state");
+		wpa_printf(MSG_ERROR,
+			   "dbus: Not enough memory to return scanning state");
 	}
 
 	return reply;
@@ -1378,7 +1297,7 @@
 		blob->len = entry.array_len;
 		os_memcpy(blob->data, (u8 *) entry.bytearray_value,
 				entry.array_len);
-		if (blob->name == NULL || blob->data == NULL) {
+		if (blob->name == NULL) {
 			wpa_config_free_blob(blob);
 			reply = dbus_message_new_error(
 				message, WPAS_ERROR_ADD_ERROR,
@@ -1417,8 +1336,8 @@
 
 	dbus_message_iter_init(message, &iter);
 
-	if ((dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_ARRAY) ||
-	    (dbus_message_iter_get_element_type (&iter) != DBUS_TYPE_STRING))
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
+	    dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRING)
 		return wpas_dbus_new_invalid_opts_error(message, NULL);
 
 	dbus_message_iter_recurse(&iter, &array);
@@ -1428,8 +1347,7 @@
 		dbus_message_iter_get_basic(&array, &name);
 		if (!os_strlen(name))
 			err_msg = "Invalid blob name.";
-
-		if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
+		else if (wpa_config_remove_blob(wpa_s->conf, name) != 0)
 			err_msg = "Error removing blob.";
 		else
 			wpas_notify_blob_removed(wpa_s, name);
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.h b/wpa_supplicant/dbus/dbus_old_handlers.h
index 825bc6d..e60ad06 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.h
+++ b/wpa_supplicant/dbus/dbus_old_handlers.h
@@ -58,13 +58,13 @@
 					      struct wpa_ssid *ssid);
 
 DBusMessage * wpas_dbus_iface_select_network(DBusMessage *message,
-                                             struct wpa_supplicant *wpa_s);
+					     struct wpa_supplicant *wpa_s);
 
 DBusMessage * wpas_dbus_iface_disconnect(DBusMessage *message,
 					 struct wpa_supplicant *wpa_s);
 
 DBusMessage * wpas_dbus_iface_set_ap_scan(DBusMessage *message,
-                                          struct wpa_supplicant *wpa_s);
+					  struct wpa_supplicant *wpa_s);
 
 DBusMessage * wpas_dbus_iface_set_smartcard_modules(
 	DBusMessage *message, struct wpa_supplicant *wpa_s);
@@ -76,7 +76,7 @@
 					   struct wpa_supplicant *wpa_s);
 
 DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
-				        struct wpa_supplicant *wpa_s);
+					struct wpa_supplicant *wpa_s);
 
 DBusMessage * wpas_dbus_iface_remove_blobs(DBusMessage *message,
 					   struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/dbus/dbus_old_handlers_wps.c b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
index bb79382..3cf9dc3 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers_wps.c
@@ -36,7 +36,7 @@
 				   DBUS_TYPE_INVALID))
 		return wpas_dbus_new_invalid_opts_error(message, NULL);
 
-	if (!os_strcmp(arg_bssid, "any"))
+	if (os_strcmp(arg_bssid, "any") == 0)
 		ret = wpas_wps_start_pbc(wpa_s, NULL, 0);
 	else if (!hwaddr_aton(arg_bssid, bssid))
 		ret = wpas_wps_start_pbc(wpa_s, bssid, 0);
@@ -46,10 +46,9 @@
 	}
 
 	if (ret < 0) {
-		return dbus_message_new_error(message,
-					      WPAS_ERROR_WPS_PBC_ERROR,
-					      "Could not start PBC "
-					      "negotiation");
+		return dbus_message_new_error(
+			message, WPAS_ERROR_WPS_PBC_ERROR,
+			"Could not start PBC negotiation");
 	}
 
 	return wpas_dbus_new_success_reply(message);
@@ -73,12 +72,13 @@
 	char *pin = NULL;
 	u8 bssid[ETH_ALEN], *_bssid = NULL;
 	int ret = 0;
+	char npin[9];
 
 	if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg_bssid,
 				   DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
 		return wpas_dbus_new_invalid_opts_error(message, NULL);
 
-	if (!os_strcmp(arg_bssid, "any"))
+	if (os_strcmp(arg_bssid, "any") == 0)
 		_bssid = NULL;
 	else if (!hwaddr_aton(arg_bssid, bssid))
 		_bssid = bssid;
@@ -104,15 +104,12 @@
 	if (reply == NULL)
 		return NULL;
 
-	if (ret == 0) {
-		dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin,
-					 DBUS_TYPE_INVALID);
-	} else {
-		char npin[9];
+	if (ret > 0) {
 		os_snprintf(npin, sizeof(npin), "%08d", ret);
-		dbus_message_append_args(reply, DBUS_TYPE_STRING, &npin,
-					 DBUS_TYPE_INVALID);
+		pin = npin;
 	}
+	dbus_message_append_args(reply, DBUS_TYPE_STRING, &pin,
+				 DBUS_TYPE_INVALID);
 	return reply;
 }
 
@@ -138,9 +135,7 @@
 				   DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID))
 		return wpas_dbus_new_invalid_opts_error(message, NULL);
 
-	if (!os_strcmp(arg_bssid, "any"))
-		ret = wpas_wps_start_reg(wpa_s, NULL, pin, NULL);
-	else if (!hwaddr_aton(arg_bssid, bssid))
+	if (!hwaddr_aton(arg_bssid, bssid))
 		ret = wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
 	else {
 		return wpas_dbus_new_invalid_opts_error(message,
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 94c94b1..7f627fd 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -67,9 +67,6 @@
 # wpa_supplicant.
 # CONFIG_USE_NDISUIO=y
 
-# Driver interface for development testing
-#CONFIG_DRIVER_TEST=y
-
 # Driver interface for wired Ethernet drivers
 CONFIG_DRIVER_WIRED=y
 
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
index 182060d..e7bf4e0 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.sgml
@@ -469,7 +469,7 @@
 	  <para>Enable DBus control interface. If enabled, interface
 	  definitions may be omitted. (This is only available
 	  if <command>wpa_supplicant</command> was built with
-	  the <literal>CONFIG_DBUS</literal> option.)</para>0
+	  the <literal>CONFIG_DBUS</literal> option.)</para>
 	</listitem>
       </varlistentry>
 
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index 649de9b..8dc48d3 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -65,6 +65,28 @@
 	return -1;
 }
 
+static inline int wpa_drv_init_mesh(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->init_mesh)
+		return wpa_s->driver->init_mesh(wpa_s->drv_priv);
+	return -1;
+}
+
+static inline int wpa_drv_join_mesh(struct wpa_supplicant *wpa_s,
+				    struct wpa_driver_mesh_join_params *params)
+{
+	if (wpa_s->driver->join_mesh)
+		return wpa_s->driver->join_mesh(wpa_s->drv_priv, params);
+	return -1;
+}
+
+static inline int wpa_drv_leave_mesh(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->leave_mesh)
+		return wpa_s->driver->leave_mesh(wpa_s->drv_priv);
+	return -1;
+}
+
 static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
 			       struct wpa_driver_scan_params *params)
 {
@@ -222,16 +244,6 @@
 	return NULL;
 }
 
-static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s,
-				     const u8 *dst, u16 proto,
-				     const u8 *data, size_t data_len)
-{
-	if (wpa_s->driver->send_eapol)
-		return wpa_s->driver->send_eapol(wpa_s->drv_priv, dst, proto,
-						 data, data_len);
-	return -1;
-}
-
 static inline int wpa_drv_set_operstate(struct wpa_supplicant *wpa_s,
 					int state)
 {
@@ -288,16 +300,6 @@
 	return -1;
 }
 
-static inline int wpa_drv_send_ft_action(struct wpa_supplicant *wpa_s,
-					 u8 action, const u8 *target_ap,
-					 const u8 *ies, size_t ies_len)
-{
-	if (wpa_s->driver->send_ft_action)
-		return wpa_s->driver->send_ft_action(wpa_s->drv_priv, action,
-						     target_ap, ies, ies_len);
-	return -1;
-}
-
 static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s,
 				 struct wpa_driver_ap_params *params)
 {
@@ -587,6 +589,45 @@
 	return wpa_s->driver->switch_channel(wpa_s->drv_priv, settings);
 }
 
+static inline int wpa_drv_add_ts(struct wpa_supplicant *wpa_s, u8 tsid,
+				 const u8 *address, u8 user_priority,
+				 u16 admitted_time)
+{
+	if (!wpa_s->driver->add_tx_ts)
+		return -1;
+	return wpa_s->driver->add_tx_ts(wpa_s->drv_priv, tsid, address,
+					user_priority, admitted_time);
+}
+
+static inline int wpa_drv_del_ts(struct wpa_supplicant *wpa_s, u8 tid,
+				 const u8 *address)
+{
+	if (!wpa_s->driver->del_tx_ts)
+		return -1;
+	return wpa_s->driver->del_tx_ts(wpa_s->drv_priv, tid, address);
+}
+
+static inline int wpa_drv_tdls_enable_channel_switch(
+	struct wpa_supplicant *wpa_s, const u8 *addr, u8 oper_class,
+	const struct hostapd_freq_params *freq_params)
+{
+	if (!wpa_s->driver->tdls_enable_channel_switch)
+		return -1;
+	return wpa_s->driver->tdls_enable_channel_switch(wpa_s->drv_priv, addr,
+							 oper_class,
+							 freq_params);
+}
+
+static inline int
+wpa_drv_tdls_disable_channel_switch(struct wpa_supplicant *wpa_s,
+				    const u8 *addr)
+{
+	if (!wpa_s->driver->tdls_disable_channel_switch)
+		return -1;
+	return wpa_s->driver->tdls_disable_channel_switch(wpa_s->drv_priv,
+							  addr);
+}
+
 static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
 				   enum wnm_oper oper, const u8 *peer,
 				   u8 *buf, u16 *buf_len)
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index e19782f..aa9ab50 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -461,7 +461,7 @@
 	len = os_snprintf(buf, buflen,
 			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
 			  field_name, ssid->id, txt);
-	if (len < 0 || (size_t) len >= buflen) {
+	if (os_snprintf_error(buflen, len)) {
 		os_free(buf);
 		return;
 	}
@@ -568,6 +568,7 @@
 	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
 	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
 	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+	ctx->openssl_ciphers = wpa_s->conf->openssl_ciphers;
 	ctx->eap_param_needed = eapol_test_eap_param_needed;
 	ctx->cert_cb = eapol_test_cert_cb;
 	ctx->cert_in_cb = 1;
@@ -928,7 +929,11 @@
 		*pos++ = a[3];
 	}
 #else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
-	inet_aton(authsrv, &as->addr.u.v4);
+	if (inet_aton(authsrv, &as->addr.u.v4) < 0) {
+		wpa_printf(MSG_ERROR, "Invalid IP address '%s'",
+			   authsrv);
+		assert(0);
+	}
 #endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
 	as->addr.af = AF_INET;
 	as->port = port;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 985fa6e..8464ed4 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -42,6 +42,9 @@
 #include "scan.h"
 #include "offchannel.h"
 #include "interworking.h"
+#include "mesh.h"
+#include "mesh_mpm.h"
+#include "wmm_ac.h"
 
 
 #ifndef CONFIG_NO_SCAN_PROCESSING
@@ -199,20 +202,12 @@
 	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
 	os_memset(wpa_s->bssid, 0, ETH_ALEN);
 	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
-#ifdef CONFIG_SME
-	wpa_s->sme.prev_bssid_set = 0;
-#endif /* CONFIG_SME */
+	sme_clear_on_disassoc(wpa_s);
 #ifdef CONFIG_P2P
 	os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
 #endif /* CONFIG_P2P */
 	wpa_s->current_bss = NULL;
 	wpa_s->assoc_freq = 0;
-#ifdef CONFIG_IEEE80211R
-#ifdef CONFIG_SME
-	if (wpa_s->sme.ft_ies)
-		sme_update_ft_ies(wpa_s, NULL, NULL, 0);
-#endif /* CONFIG_SME */
-#endif /* CONFIG_IEEE80211R */
 
 	if (bssid_changed)
 		wpas_notify_bssid_changed(wpa_s);
@@ -225,6 +220,8 @@
 	wpa_s->current_ssid = NULL;
 	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 	wpa_s->key_mgmt = 0;
+
+	wpas_rrm_reset(wpa_s);
 }
 
 
@@ -582,42 +579,6 @@
 }
 
 
-int ht_supported(const struct hostapd_hw_modes *mode)
-{
-	if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
-		/*
-		 * The driver did not indicate whether it supports HT. Assume
-		 * it does to avoid connection issues.
-		 */
-		return 1;
-	}
-
-	/*
-	 * IEEE Std 802.11n-2009 20.1.1:
-	 * An HT non-AP STA shall support all EQM rates for one spatial stream.
-	 */
-	return mode->mcs_set[0] == 0xff;
-}
-
-
-int vht_supported(const struct hostapd_hw_modes *mode)
-{
-	if (!(mode->flags & HOSTAPD_MODE_FLAG_VHT_INFO_KNOWN)) {
-		/*
-		 * The driver did not indicate whether it supports VHT. Assume
-		 * it does to avoid connection issues.
-		 */
-		return 1;
-	}
-
-	/*
-	 * A VHT non-AP STA shall support MCS 0-7 for one spatial stream.
-	 * TODO: Verify if this complies with the standard
-	 */
-	return (mode->vht_mcs_set[0] & 0x3) != 3;
-}
-
-
 static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
 {
 	const struct hostapd_hw_modes *mode = NULL, *modes;
@@ -1136,7 +1097,8 @@
 			if (wpas_network_disabled(wpa_s, ssid))
 				continue;
 			if (ssid->mode == IEEE80211_MODE_IBSS ||
-			    ssid->mode == IEEE80211_MODE_AP)
+			    ssid->mode == IEEE80211_MODE_AP ||
+			    ssid->mode == IEEE80211_MODE_MESH)
 				return ssid;
 		}
 	}
@@ -1346,6 +1308,9 @@
 		return 0;
 	}
 
+	if (wnm_scan_process(wpa_s, 1) > 0)
+		goto scan_work_done;
+
 	if (sme_proc_obss_scan(wpa_s) > 0)
 		goto scan_work_done;
 
@@ -1416,6 +1381,13 @@
 		 */
 		return 1;
 	} else {
+#ifdef CONFIG_MESH
+		if (wpa_s->ifmsh) {
+			wpa_msg(wpa_s, MSG_INFO,
+				"Avoiding join because we already joined a mesh group");
+			return 0;
+		}
+#endif /* CONFIG_MESH */
 		wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
 		ssid = wpa_supplicant_pick_new_network(wpa_s);
 		if (ssid) {
@@ -2067,6 +2039,15 @@
 #endif /* CONFIG_IBSS_RSN */
 
 	wpas_wps_notify_assoc(wpa_s, bssid);
+
+	if (data) {
+		wmm_ac_notify_assoc(wpa_s, data->assoc_info.resp_ies,
+				    data->assoc_info.resp_ies_len,
+				    &data->assoc_info.wmm_params);
+
+		if (wpa_s->reassoc_same_bss)
+			wmm_ac_restore_tspecs(wpa_s);
+	}
 }
 
 
@@ -2801,7 +2782,8 @@
 
 
 static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
-				      const u8 *frame, size_t len, int freq)
+				      const u8 *frame, size_t len, int freq,
+				      int rssi)
 {
 	const struct ieee80211_mgmt *mgmt;
 	const u8 *payload;
@@ -2820,6 +2802,11 @@
 		" Category=%u DataLen=%d freq=%d MHz",
 		MAC2STR(mgmt->sa), category, (int) plen, freq);
 
+	if (category == WLAN_ACTION_WMM) {
+		wmm_ac_rx_action(wpa_s, mgmt->da, mgmt->sa, payload, plen);
+		return;
+	}
+
 #ifdef CONFIG_IEEE80211R
 	if (category == WLAN_ACTION_FT) {
 		ft_rx_action(wpa_s, payload, plen);
@@ -2877,8 +2864,24 @@
 	}
 #endif /* CONFIG_INTERWORKING */
 
+	if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
+	    payload[0] == WLAN_RRM_NEIGHBOR_REPORT_RESPONSE) {
+		wpas_rrm_process_neighbor_rep(wpa_s, payload + 1, plen - 1);
+		return;
+	}
+
+	if (category == WLAN_ACTION_RADIO_MEASUREMENT &&
+	    payload[0] == WLAN_RRM_LINK_MEASUREMENT_REQUEST) {
+		wpas_rrm_handle_link_measurement_request(wpa_s, mgmt->sa,
+							 payload + 1, plen - 1,
+							 rssi);
+		return;
+	}
+
 	wpas_p2p_rx_action(wpa_s, mgmt->da, mgmt->sa, mgmt->bssid,
 			   category, payload, plen, freq);
+	if (wpa_s->ifmsh)
+		mesh_mpm_action_rx(wpa_s, mgmt, len);
 }
 
 
@@ -2934,6 +2937,24 @@
 }
 
 
+static void wpa_supplicant_event_assoc_auth(struct wpa_supplicant *wpa_s,
+					    union wpa_event_data *data)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG,
+		"Connection authorized by device, previous state %d",
+		wpa_s->wpa_state);
+	if (wpa_s->wpa_state == WPA_ASSOCIATED) {
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+	}
+	wpa_sm_set_rx_replay_ctr(wpa_s->wpa, data->assoc_info.key_replay_ctr);
+	wpa_sm_set_ptk_kck_kek(wpa_s->wpa, data->assoc_info.ptk_kck,
+			       data->assoc_info.ptk_kek);
+}
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
@@ -2974,6 +2995,8 @@
 		break;
 	case EVENT_ASSOC:
 		wpa_supplicant_event_assoc(wpa_s, data);
+		if (data && data->assoc_info.authorized)
+			wpa_supplicant_event_assoc_auth(wpa_s, data);
 		break;
 	case EVENT_DISASSOC:
 		wpas_event_disassoc(wpa_s,
@@ -3084,10 +3107,24 @@
 		}
 		break;
 	case EVENT_AUTH_TIMED_OUT:
+		/* It is possible to get this event from earlier connection */
+		if (wpa_s->current_ssid &&
+		    wpa_s->current_ssid->mode == WPAS_MODE_MESH) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"Ignore AUTH_TIMED_OUT in mesh configuration");
+			break;
+		}
 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
 			sme_event_auth_timed_out(wpa_s, data);
 		break;
 	case EVENT_ASSOC_TIMED_OUT:
+		/* It is possible to get this event from earlier connection */
+		if (wpa_s->current_ssid &&
+		    wpa_s->current_ssid->mode == WPAS_MODE_MESH) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"Ignore ASSOC_TIMED_OUT in mesh configuration");
+			break;
+		}
 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
 			sme_event_assoc_timed_out(wpa_s, data);
 		break;
@@ -3228,7 +3265,9 @@
 			}
 #endif /* CONFIG_P2P */
 #ifdef CONFIG_IBSS_RSN
-			if (stype == WLAN_FC_STYPE_AUTH &&
+			if (wpa_s->current_ssid &&
+			    wpa_s->current_ssid->mode == WPAS_MODE_IBSS &&
+			    stype == WLAN_FC_STYPE_AUTH &&
 			    data->rx_mgmt.frame_len >= 30) {
 				wpa_supplicant_event_ibss_auth(wpa_s, data);
 				break;
@@ -3239,7 +3278,13 @@
 				wpas_event_rx_mgmt_action(
 					wpa_s, data->rx_mgmt.frame,
 					data->rx_mgmt.frame_len,
-					data->rx_mgmt.freq);
+					data->rx_mgmt.freq,
+					data->rx_mgmt.ssi_signal);
+				break;
+			}
+
+			if (wpa_s->ifmsh) {
+				mesh_mpm_mgmt_rx(wpa_s, &data->rx_mgmt);
 				break;
 			}
 
@@ -3475,6 +3520,15 @@
 			data->connect_failed_reason.code);
 #endif /* CONFIG_AP */
 		break;
+	case EVENT_NEW_PEER_CANDIDATE:
+#ifdef CONFIG_MESH
+		if (!wpa_s->ifmsh || !data)
+			break;
+		wpa_mesh_notify_peer(wpa_s, data->mesh_peer.peer,
+				     data->mesh_peer.ies,
+				     data->mesh_peer.ie_len);
+#endif /* CONFIG_MESH */
+		break;
 	default:
 		wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
 		break;
diff --git a/wpa_supplicant/examples/wps-ap-cli b/wpa_supplicant/examples/wps-ap-cli
index 7c6b0aa..cc2cff2 100755
--- a/wpa_supplicant/examples/wps-ap-cli
+++ b/wpa_supplicant/examples/wps-ap-cli
@@ -14,11 +14,13 @@
 enter_pin()
 {
 	echo "Enter a PIN from a station to be enrolled to the network."
-	read -p "Enrollee PIN: " pin
+	echo -n "Enrollee PIN: "
+	read pin
 	cpin=`$CLI wps_check_pin "$pin" | tail -1`
 	if [ "$cpin" = "FAIL-CHECKSUM" ]; then
 		echo "Checksum digit is not valid"
-		read -p "Do you want to use this PIN (y/n)? " resp
+		echo -n "Do you want to use this PIN (y/n)? "
+		read resp
 		case "$resp" in
 			y*)
 				cpin=`echo "$pin" | sed "s/[^1234567890]//g"`
@@ -50,7 +52,8 @@
 	echo "3: Show current configuration"
 	echo "0: Exit wps-ap-cli"
 
-	read -p "Command: " cmd
+	echo -n "Command: "
+	read cmd
 
 	case "$cmd" in
 		1)
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
index 3a89674..10ecce7 100644
--- a/wpa_supplicant/gas_query.c
+++ b/wpa_supplicant/gas_query.c
@@ -442,6 +442,7 @@
 	u16 comeback_delay, resp_len;
 	const u8 *pos, *adv_proto;
 	int prot, pmf;
+	unsigned int left;
 
 	if (gas == NULL || len < 4)
 		return -1;
@@ -543,17 +544,17 @@
 	resp_len = WPA_GET_LE16(pos);
 	pos += 2;
 
-	if (pos + resp_len > data + len) {
+	left = data + len - pos;
+	if (resp_len > left) {
 		wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in "
 			   "response from " MACSTR, MAC2STR(sa));
 		return 0;
 	}
 
-	if (pos + resp_len < data + len) {
+	if (resp_len < left) {
 		wpa_printf(MSG_DEBUG, "GAS: Ignore %u octets of extra data "
 			   "after Query Response from " MACSTR,
-			   (unsigned int) (data + len - pos - resp_len),
-			   MAC2STR(sa));
+			   left - resp_len, MAC2STR(sa));
 	}
 
 	if (action == WLAN_PA_GAS_COMEBACK_RESP)
diff --git a/wpa_supplicant/hs20_supplicant.c b/wpa_supplicant/hs20_supplicant.c
index 257aa6d..9eb5064 100644
--- a/wpa_supplicant/hs20_supplicant.c
+++ b/wpa_supplicant/hs20_supplicant.c
@@ -562,6 +562,7 @@
 	const u8 *end = pos + len;
 	u16 len2;
 	const u8 *pos2;
+	u8 uri_len, osu_method_len, osu_nai_len;
 
 	wpa_hexdump(MSG_DEBUG, "HS 2.0: Parsing OSU Provider", pos, len);
 	prov = os_realloc_array(wpa_s->osu_prov,
@@ -585,7 +586,7 @@
 	}
 	len2 = WPA_GET_LE16(pos);
 	pos += 2;
-	if (pos + len2 > end) {
+	if (len2 > end - pos) {
 		wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
 			   "Friendly Name Duples");
 		return;
@@ -607,22 +608,34 @@
 	}
 
 	/* OSU Server URI */
-	if (pos + 1 > end || pos + 1 + pos[0] > end) {
+	if (pos + 1 > end) {
+		wpa_printf(MSG_DEBUG,
+			   "HS 2.0: Not enough room for OSU Server URI length");
+		return;
+	}
+	uri_len = *pos++;
+	if (uri_len > end - pos) {
 		wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Server "
 			   "URI");
 		return;
 	}
-	os_memcpy(prov->server_uri, pos + 1, pos[0]);
-	pos += 1 + pos[0];
+	os_memcpy(prov->server_uri, pos, uri_len);
+	pos += uri_len;
 
 	/* OSU Method list */
-	if (pos + 1 > end || pos + 1 + pos[0] > end) {
+	if (pos + 1 > end) {
+		wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
+			   "list length");
+		return;
+	}
+	osu_method_len = pos[0];
+	if (osu_method_len > end - pos - 1) {
 		wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU Method "
 			   "list");
 		return;
 	}
 	pos2 = pos + 1;
-	pos += 1 + pos[0];
+	pos += 1 + osu_method_len;
 	while (pos2 < pos) {
 		if (*pos2 < 32)
 			prov->osu_methods |= BIT(*pos2);
@@ -637,7 +650,7 @@
 	}
 	len2 = WPA_GET_LE16(pos);
 	pos += 2;
-	if (pos + len2 > end) {
+	if (len2 > end - pos) {
 		wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for Icons "
 			   "Available");
 		return;
@@ -648,6 +661,8 @@
 	/* Icons Available */
 	while (pos2 < pos) {
 		struct osu_icon *icon = &prov->icon[prov->icon_count];
+		u8 flen;
+
 		if (pos2 + 2 + 2 + 3 + 1 + 1 > pos) {
 			wpa_printf(MSG_DEBUG, "HS 2.0: Invalid Icon Metadata");
 			break;
@@ -660,31 +675,43 @@
 		os_memcpy(icon->lang, pos2, 3);
 		pos2 += 3;
 
-		if (pos2 + 1 + pos2[0] > pos) {
+		flen = pos2[0];
+		if (flen > pos - pos2 - 1) {
 			wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon Type");
 			break;
 		}
-		os_memcpy(icon->icon_type, pos2 + 1, pos2[0]);
-		pos2 += 1 + pos2[0];
+		os_memcpy(icon->icon_type, pos2 + 1, flen);
+		pos2 += 1 + flen;
 
-		if (pos2 + 1 + pos2[0] > pos) {
+		if (pos2 + 1 > pos) {
+			wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
+				   "Filename length");
+			break;
+		}
+		flen = pos2[0];
+		if (flen > pos - pos2 - 1) {
 			wpa_printf(MSG_DEBUG, "HS 2.0: Not room for Icon "
 				   "Filename");
 			break;
 		}
-		os_memcpy(icon->filename, pos2 + 1, pos2[0]);
-		pos2 += 1 + pos2[0];
+		os_memcpy(icon->filename, pos2 + 1, flen);
+		pos2 += 1 + flen;
 
 		prov->icon_count++;
 	}
 
 	/* OSU_NAI */
-	if (pos + 1 > end || pos + 1 + pos[0] > end) {
+	if (pos + 1 > end) {
 		wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
 		return;
 	}
-	os_memcpy(prov->osu_nai, pos + 1, pos[0]);
-	pos += 1 + pos[0];
+	osu_nai_len = pos[0];
+	if (osu_nai_len > end - pos - 1) {
+		wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU_NAI");
+		return;
+	}
+	os_memcpy(prov->osu_nai, pos + 1, osu_nai_len);
+	pos += 1 + osu_nai_len;
 
 	/* OSU Service Description Length */
 	if (pos + 2 > end) {
@@ -694,7 +721,7 @@
 	}
 	len2 = WPA_GET_LE16(pos);
 	pos += 2;
-	if (pos + len2 > end) {
+	if (len2 > end - pos) {
 		wpa_printf(MSG_DEBUG, "HS 2.0: Not enough room for OSU "
 			   "Service Description Duples");
 		return;
@@ -705,15 +732,18 @@
 	/* OSU Service Description Duples */
 	while (pos2 + 4 <= pos && prov->serv_desc_count < OSU_MAX_ITEMS) {
 		struct osu_lang_string *f;
-		if (pos2 + 1 + pos2[0] > pos || pos2[0] < 3) {
+		u8 descr_len;
+
+		descr_len = pos2[0];
+		if (descr_len > pos - pos2 - 1 || descr_len < 3) {
 			wpa_printf(MSG_DEBUG, "Invalid OSU Service "
 				   "Description");
 			break;
 		}
 		f = &prov->serv_desc[prov->serv_desc_count++];
 		os_memcpy(f->lang, pos2 + 1, 3);
-		os_memcpy(f->text, pos2 + 1 + 3, pos2[0] - 3);
-		pos2 += 1 + pos2[0];
+		os_memcpy(f->text, pos2 + 1 + 3, descr_len - 3);
+		pos2 += 1 + descr_len;
 	}
 
 	wpa_printf(MSG_DEBUG, "HS 2.0: Added OSU Provider through " MACSTR,
@@ -778,7 +808,7 @@
 			num_providers--;
 			len = WPA_GET_LE16(pos);
 			pos += 2;
-			if (pos + len > end)
+			if (len > (unsigned int) (end - pos))
 				break;
 			hs20_osu_add_prov(wpa_s, bss, osu_ssid,
 					  osu_ssid_len, pos, len);
@@ -801,6 +831,10 @@
 				      struct wpa_scan_results *scan_res)
 {
 	wpa_printf(MSG_DEBUG, "OSU provisioning fetch scan completed");
+	if (!wpa_s->fetch_osu_waiting_scan) {
+		wpa_printf(MSG_DEBUG, "OSU fetch have been canceled");
+		return;
+	}
 	wpa_s->network_select = 0;
 	wpa_s->fetch_all_anqp = 1;
 	wpa_s->fetch_osu_info = 1;
@@ -849,6 +883,7 @@
 
 void hs20_start_osu_scan(struct wpa_supplicant *wpa_s)
 {
+	wpa_s->fetch_osu_waiting_scan = 1;
 	wpa_s->num_osu_scans++;
 	wpa_s->scan_req = MANUAL_SCAN_REQ;
 	wpa_s->scan_res_handler = hs20_osu_scan_res_handler;
@@ -860,6 +895,7 @@
 {
 	wpa_printf(MSG_DEBUG, "Cancel OSU fetch");
 	interworking_stop_fetch_anqp(wpa_s);
+	wpa_s->fetch_osu_waiting_scan = 0;
 	wpa_s->network_select = 0;
 	wpa_s->fetch_osu_info = 0;
 	wpa_s->fetch_osu_icon_in_progress = 0;
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 3083dd8..d0ae135 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -72,7 +72,7 @@
 	if (wpa_s->l2)
 		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
 
-	return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+	return -1;
 }
 
 
@@ -230,7 +230,7 @@
 	wpa_sm_set_param(peer->supp, WPA_PARAM_PAIRWISE, WPA_CIPHER_CCMP);
 	wpa_sm_set_param(peer->supp, WPA_PARAM_GROUP, WPA_CIPHER_CCMP);
 	wpa_sm_set_param(peer->supp, WPA_PARAM_KEY_MGMT, WPA_KEY_MGMT_PSK);
-	wpa_sm_set_pmk(peer->supp, psk, PMK_LEN);
+	wpa_sm_set_pmk(peer->supp, psk, PMK_LEN, NULL);
 
 	peer->supp_ie_len = sizeof(peer->supp_ie);
 	if (wpa_sm_set_assoc_wpa_ie_default(peer->supp, peer->supp_ie,
@@ -283,7 +283,7 @@
 		return l2_packet_send(wpa_s->l2, addr, ETH_P_EAPOL, data,
 				      data_len);
 
-	return wpa_drv_send_eapol(wpa_s, addr, ETH_P_EAPOL, data, data_len);
+	return -1;
 }
 
 
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
index 19b6e38..116df05 100644
--- a/wpa_supplicant/interworking.c
+++ b/wpa_supplicant/interworking.c
@@ -508,20 +508,25 @@
 	struct nai_realm *realm;
 	const u8 *pos, *end;
 	u16 i, num;
+	size_t left;
 
-	if (anqp == NULL || wpabuf_len(anqp) < 2)
+	if (anqp == NULL)
+		return NULL;
+	left = wpabuf_len(anqp);
+	if (left < 2)
 		return NULL;
 
 	pos = wpabuf_head_u8(anqp);
-	end = pos + wpabuf_len(anqp);
+	end = pos + left;
 	num = WPA_GET_LE16(pos);
 	wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
 	pos += 2;
+	left -= 2;
 
-	if (num * 5 > end - pos) {
+	if (num > left / 5) {
 		wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
 			   "enough data (%u octets) for that many realms",
-			   num, (unsigned int) (end - pos));
+			   num, (unsigned int) left);
 		return NULL;
 	}
 
@@ -2525,6 +2530,7 @@
 	if (found == 0) {
 		if (wpa_s->fetch_osu_info) {
 			if (wpa_s->num_prov_found == 0 &&
+			    wpa_s->fetch_osu_waiting_scan &&
 			    wpa_s->num_osu_scans < 3) {
 				wpa_printf(MSG_DEBUG, "HS 2.0: No OSU providers seen - try to scan again");
 				hs20_start_osu_scan(wpa_s);
@@ -2808,7 +2814,9 @@
 	end = pos + wpabuf_len(resp);
 
 	while (pos < end) {
-		if (pos + 4 > end) {
+		unsigned int left = end - pos;
+
+		if (left < 4) {
 			wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
 			break;
 		}
@@ -2816,7 +2824,8 @@
 		pos += 2;
 		slen = WPA_GET_LE16(pos);
 		pos += 2;
-		if (pos + slen > end) {
+		left -= 4;
+		if (left < slen) {
 			wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
 				   "for Info ID %u", info_id);
 			break;
diff --git a/wpa_supplicant/main.c b/wpa_supplicant/main.c
index e596468..13e9769 100644
--- a/wpa_supplicant/main.c
+++ b/wpa_supplicant/main.c
@@ -327,14 +327,6 @@
 			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, iface->conf_p2p_dev) <
-		    0)
-			exitcode = -1;
-#endif /* CONFIG_P2P */
 	}
 
 	if (exitcode == 0)
diff --git a/wpa_supplicant/mesh.c b/wpa_supplicant/mesh.c
new file mode 100644
index 0000000..7a4f3de
--- /dev/null
+++ b/wpa_supplicant/mesh.c
@@ -0,0 +1,540 @@
+/*
+ * WPA Supplicant - Basic mesh mode routines
+ * Copyright (c) 2013-2014, cozybit, Inc.  All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/uuid.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "ap/sta_info.h"
+#include "ap/hostapd.h"
+#include "ap/ieee802_11.h"
+#include "config_ssid.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "notify.h"
+#include "ap.h"
+#include "mesh_mpm.h"
+#include "mesh_rsn.h"
+#include "mesh.h"
+
+
+static void wpa_supplicant_mesh_deinit(struct wpa_supplicant *wpa_s)
+{
+	wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+	wpa_s->ifmsh = NULL;
+	wpa_s->current_ssid = NULL;
+	os_free(wpa_s->mesh_rsn);
+	wpa_s->mesh_rsn = NULL;
+	/* TODO: leave mesh (stop beacon). This will happen on link down
+	 * anyway, so it's not urgent */
+}
+
+
+void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
+				      struct hostapd_iface *ifmsh)
+{
+	if (!ifmsh)
+		return;
+
+	if (ifmsh->mconf) {
+		mesh_mpm_deinit(wpa_s, ifmsh);
+		if (ifmsh->mconf->ies) {
+			ifmsh->mconf->ies = NULL;
+			/* We cannot free this struct
+			 * because wpa_authenticator on
+			 * hostapd side is also using it
+			 * for now just set to NULL and
+			 * let hostapd code free it.
+			 */
+		}
+		os_free(ifmsh->mconf);
+		ifmsh->mconf = NULL;
+	}
+
+	/* take care of shared data */
+	hostapd_interface_deinit(ifmsh);
+	hostapd_interface_free(ifmsh);
+}
+
+
+static struct mesh_conf * mesh_config_create(struct wpa_ssid *ssid)
+{
+	struct mesh_conf *conf;
+
+	conf = os_zalloc(sizeof(struct mesh_conf));
+	if (!conf)
+		return NULL;
+
+	os_memcpy(conf->meshid, ssid->ssid, ssid->ssid_len);
+	conf->meshid_len = ssid->ssid_len;
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_SAE)
+		conf->security |= MESH_CONF_SEC_AUTH |
+			MESH_CONF_SEC_AMPE;
+	else
+		conf->security |= MESH_CONF_SEC_NONE;
+
+	/* defaults */
+	conf->mesh_pp_id = MESH_PATH_PROTOCOL_HWMP;
+	conf->mesh_pm_id = MESH_PATH_METRIC_AIRTIME;
+	conf->mesh_cc_id = 0;
+	conf->mesh_sp_id = MESH_SYNC_METHOD_NEIGHBOR_OFFSET;
+	conf->mesh_auth_id = (conf->security & MESH_CONF_SEC_AUTH) ? 1 : 0;
+	conf->dot11MeshMaxRetries = ssid->dot11MeshMaxRetries;
+	conf->dot11MeshRetryTimeout = ssid->dot11MeshRetryTimeout;
+	conf->dot11MeshConfirmTimeout = ssid->dot11MeshConfirmTimeout;
+	conf->dot11MeshHoldingTimeout = ssid->dot11MeshHoldingTimeout;
+
+	return conf;
+}
+
+
+static void wpas_mesh_copy_groups(struct hostapd_data *bss,
+				  struct wpa_supplicant *wpa_s)
+{
+	int num_groups;
+	size_t groups_size;
+
+	for (num_groups = 0; wpa_s->conf->sae_groups[num_groups] > 0;
+	     num_groups++)
+		;
+
+	groups_size = (num_groups + 1) * sizeof(wpa_s->conf->sae_groups[0]);
+	bss->conf->sae_groups = os_malloc(groups_size);
+	if (bss->conf->sae_groups)
+		os_memcpy(bss->conf->sae_groups, wpa_s->conf->sae_groups,
+			  groups_size);
+}
+
+
+static int wpa_supplicant_mesh_init(struct wpa_supplicant *wpa_s,
+				    struct wpa_ssid *ssid)
+{
+	struct hostapd_iface *ifmsh;
+	struct hostapd_data *bss;
+	struct hostapd_config *conf;
+	struct mesh_conf *mconf;
+	int basic_rates_erp[] = { 10, 20, 55, 60, 110, 120, 240, -1 };
+	static int default_groups[] = { 19, 20, 21, 25, 26, -1 };
+	size_t len;
+	int rate_len;
+
+	if (!wpa_s->conf->user_mpm) {
+		/* not much for us to do here */
+		wpa_msg(wpa_s, MSG_WARNING,
+			"user_mpm is not enabled in configuration");
+		return 0;
+	}
+
+	wpa_s->ifmsh = ifmsh = os_zalloc(sizeof(*wpa_s->ifmsh));
+	if (!ifmsh)
+		return -ENOMEM;
+
+	ifmsh->drv_flags = wpa_s->drv_flags;
+	ifmsh->num_bss = 1;
+	ifmsh->bss = os_calloc(wpa_s->ifmsh->num_bss,
+			       sizeof(struct hostapd_data *));
+	if (!ifmsh->bss)
+		goto out_free;
+
+	ifmsh->bss[0] = bss = os_zalloc(sizeof(struct hostapd_data));
+	if (!bss)
+		goto out_free;
+
+	os_memcpy(bss->own_addr, wpa_s->own_addr, ETH_ALEN);
+	bss->driver = wpa_s->driver;
+	bss->drv_priv = wpa_s->drv_priv;
+	bss->iface = ifmsh;
+	bss->mesh_sta_free_cb = mesh_mpm_free_sta;
+	wpa_s->assoc_freq = ssid->frequency;
+	wpa_s->current_ssid = ssid;
+
+	/* setup an AP config for auth processing */
+	conf = hostapd_config_defaults();
+	if (!conf)
+		goto out_free;
+
+	bss->conf = *conf->bss;
+	bss->conf->start_disabled = 1;
+	bss->conf->mesh = MESH_ENABLED;
+	bss->iconf = conf;
+	ifmsh->conf = conf;
+
+	ifmsh->bss[0]->max_plinks = wpa_s->conf->max_peer_links;
+	os_strlcpy(bss->conf->iface, wpa_s->ifname, sizeof(bss->conf->iface));
+
+	mconf = mesh_config_create(ssid);
+	if (!mconf)
+		goto out_free;
+	ifmsh->mconf = mconf;
+
+	/* need conf->hw_mode for supported rates. */
+	if (ssid->frequency == 0) {
+		conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+		conf->channel = 1;
+	} else {
+		conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+						       &conf->channel);
+	}
+	if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+		wpa_printf(MSG_ERROR, "Unsupported mesh mode frequency: %d MHz",
+			   ssid->frequency);
+		goto out_free;
+	}
+
+	if (ssid->mesh_basic_rates == NULL) {
+		/*
+		 * XXX: Hack! This is so an MPM which correctly sets the ERP
+		 * mandatory rates as BSSBasicRateSet doesn't reject us. We
+		 * could add a new hw_mode HOSTAPD_MODE_IEEE80211G_ERP, but
+		 * this is way easier. This also makes our BSSBasicRateSet
+		 * advertised in beacons match the one in peering frames, sigh.
+		 */
+		if (conf->hw_mode == HOSTAPD_MODE_IEEE80211G) {
+			conf->basic_rates = os_malloc(sizeof(basic_rates_erp));
+			if (!conf->basic_rates)
+				goto out_free;
+			os_memcpy(conf->basic_rates, basic_rates_erp,
+				  sizeof(basic_rates_erp));
+		}
+	} else {
+		rate_len = 0;
+		while (1) {
+			if (ssid->mesh_basic_rates[rate_len] < 1)
+				break;
+			rate_len++;
+		}
+		conf->basic_rates = os_calloc(rate_len + 1, sizeof(int));
+		if (conf->basic_rates == NULL)
+			goto out_free;
+		os_memcpy(conf->basic_rates, ssid->mesh_basic_rates,
+			  rate_len * sizeof(int));
+		conf->basic_rates[rate_len] = -1;
+	}
+
+	if (hostapd_setup_interface(ifmsh)) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to initialize hostapd interface for mesh");
+		return -1;
+	}
+
+	if (wpa_drv_init_mesh(wpa_s)) {
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh in driver");
+		return -1;
+	}
+
+	if (mconf->security != MESH_CONF_SEC_NONE) {
+		if (ssid->passphrase == NULL) {
+			wpa_printf(MSG_ERROR,
+				   "mesh: Passphrase for SAE not configured");
+			goto out_free;
+		}
+
+		bss->conf->wpa = ssid->proto;
+		bss->conf->wpa_key_mgmt = ssid->key_mgmt;
+
+		if (wpa_s->conf->sae_groups &&
+		    wpa_s->conf->sae_groups[0] > 0) {
+			wpas_mesh_copy_groups(bss, wpa_s);
+		} else {
+			bss->conf->sae_groups =
+				os_malloc(sizeof(default_groups));
+			if (!bss->conf->sae_groups)
+				goto out_free;
+			os_memcpy(bss->conf->sae_groups, default_groups,
+				  sizeof(default_groups));
+		}
+
+		len = os_strlen(ssid->passphrase);
+		bss->conf->ssid.wpa_passphrase =
+			dup_binstr(ssid->passphrase, len);
+
+		wpa_s->mesh_rsn = mesh_rsn_auth_init(wpa_s, mconf);
+		if (!wpa_s->mesh_rsn)
+			goto out_free;
+	}
+
+	wpa_supplicant_conf_ap_ht(wpa_s, ssid, conf);
+
+	return 0;
+out_free:
+	wpa_supplicant_mesh_deinit(wpa_s);
+	return -ENOMEM;
+}
+
+
+void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+			  const u8 *ies, size_t ie_len)
+{
+	struct ieee802_11_elems elems;
+
+	wpa_msg(wpa_s, MSG_INFO,
+		"new peer notification for " MACSTR, MAC2STR(addr));
+
+	if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
+		wpa_msg(wpa_s, MSG_INFO, "Could not parse beacon from " MACSTR,
+			MAC2STR(addr));
+		return;
+	}
+	wpa_mesh_new_mesh_peer(wpa_s, addr, &elems);
+}
+
+
+void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
+				     struct wpabuf **extra_ie)
+{
+	/* EID + 0-length (wildcard) mesh-id */
+	size_t ielen = 2;
+
+	if (wpabuf_resize(extra_ie, ielen) == 0) {
+		wpabuf_put_u8(*extra_ie, WLAN_EID_MESH_ID);
+		wpabuf_put_u8(*extra_ie, 0);
+	}
+}
+
+
+int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid *ssid)
+{
+	struct wpa_driver_mesh_join_params params;
+	int ret = 0;
+
+	if (!ssid || !ssid->ssid || !ssid->ssid_len || !ssid->frequency) {
+		ret = -ENOENT;
+		goto out;
+	}
+
+	wpa_supplicant_mesh_deinit(wpa_s);
+
+	os_memset(&params, 0, sizeof(params));
+	params.meshid = ssid->ssid;
+	params.meshid_len = ssid->ssid_len;
+	params.freq = ssid->frequency;
+	if (ssid->beacon_int > 0)
+		params.beacon_int = ssid->beacon_int;
+	else if (wpa_s->conf->beacon_int > 0)
+		params.beacon_int = wpa_s->conf->beacon_int;
+	params.max_peer_links = wpa_s->conf->max_peer_links;
+#ifdef CONFIG_IEEE80211N
+	params.ht_mode = ssid->mesh_ht_mode;
+#endif /* CONFIG_IEEE80211N */
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_SAE) {
+		params.flags |= WPA_DRIVER_MESH_FLAG_SAE_AUTH;
+		params.flags |= WPA_DRIVER_MESH_FLAG_AMPE;
+		wpa_s->conf->user_mpm = 1;
+	}
+
+	if (wpa_s->conf->user_mpm) {
+		params.flags |= WPA_DRIVER_MESH_FLAG_USER_MPM;
+		params.conf.flags &= ~WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+	} else {
+		params.flags |= WPA_DRIVER_MESH_FLAG_DRIVER_MPM;
+		params.conf.flags |= WPA_DRIVER_MESH_CONF_FLAG_AUTO_PLINKS;
+	}
+
+	if (wpa_supplicant_mesh_init(wpa_s, ssid)) {
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to init mesh");
+		ret = -1;
+		goto out;
+	}
+
+	if (wpa_s->ifmsh) {
+		params.ies = wpa_s->ifmsh->mconf->ies;
+		params.ie_len = wpa_s->ifmsh->mconf->ie_len;
+		params.basic_rates = wpa_s->ifmsh->basic_rates;
+	}
+
+	wpa_msg(wpa_s, MSG_INFO, "joining mesh %s",
+		wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+	ret = wpa_drv_join_mesh(wpa_s, &params);
+	if (ret)
+		wpa_msg(wpa_s, MSG_ERROR, "mesh join error=%d\n", ret);
+
+	/* hostapd sets the interface down until we associate */
+	wpa_drv_set_operstate(wpa_s, 1);
+
+out:
+	return ret;
+}
+
+
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s)
+{
+	int ret = 0;
+
+	wpa_msg(wpa_s, MSG_INFO, "leaving mesh");
+
+	/* Need to send peering close messages first */
+	wpa_supplicant_mesh_deinit(wpa_s);
+
+	ret = wpa_drv_leave_mesh(wpa_s);
+	if (ret)
+		wpa_msg(wpa_s, MSG_ERROR, "mesh leave error=%d", ret);
+
+	wpa_drv_set_operstate(wpa_s, 1);
+
+	return ret;
+}
+
+
+static int mesh_attr_text(const u8 *ies, size_t ies_len, char *buf, char *end)
+{
+	struct ieee802_11_elems elems;
+	char *mesh_id, *pos = buf;
+	u8 *bss_basic_rate_set;
+	int bss_basic_rate_set_len, ret, i;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 0) == ParseFailed)
+		return -1;
+
+	if (elems.mesh_id_len < 1)
+		return 0;
+
+	mesh_id = os_malloc(elems.mesh_id_len + 1);
+	if (mesh_id == NULL)
+		return -1;
+
+	os_memcpy(mesh_id, elems.mesh_id, elems.mesh_id_len);
+	mesh_id[elems.mesh_id_len] = '\0';
+	ret = os_snprintf(pos, end - pos, "mesh_id=%s\n", mesh_id);
+	os_free(mesh_id);
+	if (os_snprintf_error(end - pos, ret))
+		return pos - buf;
+	pos += ret;
+
+	if (elems.mesh_config_len > 6) {
+		ret = os_snprintf(pos, end - pos,
+				  "active_path_selection_protocol_id=0x%02x\n"
+				  "active_path_selection_metric_id=0x%02x\n"
+				  "congestion_control_mode_id=0x%02x\n"
+				  "synchronization_method_id=0x%02x\n"
+				  "authentication_protocol_id=0x%02x\n"
+				  "mesh_formation_info=0x%02x\n"
+				  "mesh_capability=0x%02x\n",
+				  elems.mesh_config[0], elems.mesh_config[1],
+				  elems.mesh_config[2], elems.mesh_config[3],
+				  elems.mesh_config[4], elems.mesh_config[5],
+				  elems.mesh_config[6]);
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+	}
+
+	bss_basic_rate_set = os_malloc(elems.supp_rates_len +
+		elems.ext_supp_rates_len);
+	if (bss_basic_rate_set == NULL)
+		return -1;
+
+	bss_basic_rate_set_len = 0;
+	for (i = 0; i < elems.supp_rates_len; i++) {
+		if (elems.supp_rates[i] & 0x80) {
+			bss_basic_rate_set[bss_basic_rate_set_len++] =
+				(elems.supp_rates[i] & 0x7f) * 5;
+		}
+	}
+	for (i = 0; i < elems.ext_supp_rates_len; i++) {
+		if (elems.ext_supp_rates[i] & 0x80) {
+			bss_basic_rate_set[bss_basic_rate_set_len++] =
+				(elems.ext_supp_rates[i] & 0x7f) * 5;
+		}
+	}
+	if (bss_basic_rate_set_len > 0) {
+		ret = os_snprintf(pos, end - pos, "bss_basic_rate_set=%d",
+				  bss_basic_rate_set[0]);
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+
+		for (i = 1; i < bss_basic_rate_set_len; i++) {
+			ret = os_snprintf(pos, end - pos, " %d",
+					  bss_basic_rate_set[i]);
+			if (os_snprintf_error(end - pos, ret))
+				return pos - buf;
+			pos += ret;
+		}
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (os_snprintf_error(end - pos, ret))
+			return pos - buf;
+		pos += ret;
+	}
+	os_free(bss_basic_rate_set);
+
+	return pos - buf;
+}
+
+
+int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+			       char *end)
+{
+	return mesh_attr_text(ies, ies_len, buf, end);
+}
+
+
+static int wpas_mesh_get_ifname(struct wpa_supplicant *wpa_s, char *ifname,
+				size_t len)
+{
+	char *ifname_ptr = wpa_s->ifname;
+	int res;
+
+	res = os_snprintf(ifname, len, "mesh-%s-%d", ifname_ptr,
+			  wpa_s->mesh_if_idx);
+	if (os_snprintf_error(len, res) ||
+	    (os_strlen(ifname) >= IFNAMSIZ &&
+	     os_strlen(wpa_s->ifname) < IFNAMSIZ)) {
+		/* Try to avoid going over the IFNAMSIZ length limit */
+		res = os_snprintf(ifname, len, "mesh-%d", wpa_s->mesh_if_idx);
+		if (os_snprintf_error(len, res))
+			return -1;
+	}
+	wpa_s->mesh_if_idx++;
+	return 0;
+}
+
+
+int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
+			    size_t len)
+{
+	struct wpa_interface iface;
+	struct wpa_supplicant *mesh_wpa_s;
+	u8 addr[ETH_ALEN];
+
+	if (ifname[0] == '\0' && wpas_mesh_get_ifname(wpa_s, ifname, len) < 0)
+		return -1;
+
+	if (wpa_drv_if_add(wpa_s, WPA_IF_MESH, ifname, NULL, NULL, NULL, addr,
+			   NULL) < 0) {
+		wpa_printf(MSG_ERROR,
+			   "mesh: Failed to create new mesh interface");
+		return -1;
+	}
+	wpa_printf(MSG_INFO, "mesh: Created virtual interface %s addr "
+		   MACSTR, ifname, MAC2STR(addr));
+
+	os_memset(&iface, 0, sizeof(iface));
+	iface.ifname = ifname;
+	iface.driver = wpa_s->driver->name;
+	iface.driver_param = wpa_s->conf->driver_param;
+	iface.ctrl_interface = wpa_s->conf->ctrl_interface;
+
+	mesh_wpa_s = wpa_supplicant_add_iface(wpa_s->global, &iface);
+	if (!mesh_wpa_s) {
+		wpa_printf(MSG_ERROR,
+			   "mesh: Failed to create new wpa_supplicant interface");
+		wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
+		return -1;
+	}
+	mesh_wpa_s->mesh_if_created = 1;
+	mesh_wpa_s->parent = wpa_s;
+	return 0;
+}
diff --git a/wpa_supplicant/mesh.h b/wpa_supplicant/mesh.h
new file mode 100644
index 0000000..3cb7f1b
--- /dev/null
+++ b/wpa_supplicant/mesh.h
@@ -0,0 +1,44 @@
+/*
+ * WPA Supplicant - Basic mesh mode routines
+ * Copyright (c) 2013-2014, cozybit, Inc.  All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_H
+#define MESH_H
+
+int wpa_supplicant_join_mesh(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid *ssid);
+int wpa_supplicant_leave_mesh(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_mesh_iface_deinit(struct wpa_supplicant *wpa_s,
+				      struct hostapd_iface *ifmsh);
+int wpas_mesh_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+			       char *end);
+int wpas_mesh_add_interface(struct wpa_supplicant *wpa_s, char *ifname,
+			    size_t len);
+
+#ifdef CONFIG_MESH
+
+void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+			  const u8 *ies, size_t ie_len);
+void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
+				     struct wpabuf **extra_ie);
+
+#else /* CONFIG_MESH */
+
+static inline void wpa_mesh_notify_peer(struct wpa_supplicant *wpa_s,
+					const u8 *addr,
+					const u8 *ies, size_t ie_len)
+{
+}
+
+static inline void wpa_supplicant_mesh_add_scan_ie(struct wpa_supplicant *wpa_s,
+						   struct wpabuf **extra_ie)
+{
+}
+
+#endif /* CONFIG_MESH */
+
+#endif /* MESH_H */
diff --git a/wpa_supplicant/mesh_mpm.c b/wpa_supplicant/mesh_mpm.c
new file mode 100644
index 0000000..e7c53ea
--- /dev/null
+++ b/wpa_supplicant/mesh_mpm.c
@@ -0,0 +1,1030 @@
+/*
+ * WPA Supplicant - Basic mesh peer management
+ * Copyright (c) 2013-2014, cozybit, Inc.  All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "ap/hostapd.h"
+#include "ap/sta_info.h"
+#include "ap/ieee802_11.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "mesh_mpm.h"
+#include "mesh_rsn.h"
+
+struct mesh_peer_mgmt_ie {
+	const u8 *proto_id;
+	const u8 *llid;
+	const u8 *plid;
+	const u8 *reason;
+	const u8 *pmk;
+};
+
+static void plink_timer(void *eloop_ctx, void *user_data);
+
+
+enum plink_event {
+	PLINK_UNDEFINED,
+	OPN_ACPT,
+	OPN_RJCT,
+	OPN_IGNR,
+	CNF_ACPT,
+	CNF_RJCT,
+	CNF_IGNR,
+	CLS_ACPT,
+	CLS_IGNR
+};
+
+static const char * const mplstate[] = {
+	[PLINK_LISTEN] = "LISTEN",
+	[PLINK_OPEN_SENT] = "OPEN_SENT",
+	[PLINK_OPEN_RCVD] = "OPEN_RCVD",
+	[PLINK_CNF_RCVD] = "CNF_RCVD",
+	[PLINK_ESTAB] = "ESTAB",
+	[PLINK_HOLDING] = "HOLDING",
+	[PLINK_BLOCKED] = "BLOCKED"
+};
+
+static const char * const mplevent[] = {
+	[PLINK_UNDEFINED] = "UNDEFINED",
+	[OPN_ACPT] = "OPN_ACPT",
+	[OPN_RJCT] = "OPN_RJCT",
+	[OPN_IGNR] = "OPN_IGNR",
+	[CNF_ACPT] = "CNF_ACPT",
+	[CNF_RJCT] = "CNF_RJCT",
+	[CNF_IGNR] = "CNF_IGNR",
+	[CLS_ACPT] = "CLS_ACPT",
+	[CLS_IGNR] = "CLS_IGNR"
+};
+
+
+static int mesh_mpm_parse_peer_mgmt(struct wpa_supplicant *wpa_s,
+				    u8 action_field,
+				    const u8 *ie, size_t len,
+				    struct mesh_peer_mgmt_ie *mpm_ie)
+{
+	os_memset(mpm_ie, 0, sizeof(*mpm_ie));
+
+	/* remove optional PMK at end */
+	if (len >= 16) {
+		len -= 16;
+		mpm_ie->pmk = ie + len - 16;
+	}
+
+	if ((action_field == PLINK_OPEN && len != 4) ||
+	    (action_field == PLINK_CONFIRM && len != 6) ||
+	    (action_field == PLINK_CLOSE && len != 6 && len != 8)) {
+		wpa_msg(wpa_s, MSG_DEBUG, "MPM: Invalid peer mgmt ie");
+		return -1;
+	}
+
+	/* required fields */
+	if (len < 4)
+		return -1;
+	mpm_ie->proto_id = ie;
+	mpm_ie->llid = ie + 2;
+	ie += 4;
+	len -= 4;
+
+	/* close reason is always present at end for close */
+	if (action_field == PLINK_CLOSE) {
+		if (len < 2)
+			return -1;
+		mpm_ie->reason = ie + len - 2;
+		len -= 2;
+	}
+
+	/* plid, present for confirm, and possibly close */
+	if (len)
+		mpm_ie->plid = ie;
+
+	return 0;
+}
+
+
+static int plink_free_count(struct hostapd_data *hapd)
+{
+	if (hapd->max_plinks > hapd->num_plinks)
+		return hapd->max_plinks - hapd->num_plinks;
+	return 0;
+}
+
+
+static u16 copy_supp_rates(struct wpa_supplicant *wpa_s,
+			   struct sta_info *sta,
+			   struct ieee802_11_elems *elems)
+{
+	if (!elems->supp_rates) {
+		wpa_msg(wpa_s, MSG_ERROR, "no supported rates from " MACSTR,
+			MAC2STR(sta->addr));
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	if (elems->supp_rates_len + elems->ext_supp_rates_len >
+	    sizeof(sta->supported_rates)) {
+		wpa_msg(wpa_s, MSG_ERROR,
+			"Invalid supported rates element length " MACSTR
+			" %d+%d", MAC2STR(sta->addr), elems->supp_rates_len,
+			elems->ext_supp_rates_len);
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	sta->supported_rates_len = merge_byte_arrays(
+		sta->supported_rates, sizeof(sta->supported_rates),
+		elems->supp_rates, elems->supp_rates_len,
+		elems->ext_supp_rates, elems->ext_supp_rates_len);
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+/* return true if elems from a neighbor match this MBSS */
+static Boolean matches_local(struct wpa_supplicant *wpa_s,
+			     struct ieee802_11_elems *elems)
+{
+	struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
+
+	if (elems->mesh_config_len < 5)
+		return FALSE;
+
+	return (mconf->meshid_len == elems->mesh_id_len &&
+		os_memcmp(mconf->meshid, elems->mesh_id,
+			  elems->mesh_id_len) == 0 &&
+		mconf->mesh_pp_id == elems->mesh_config[0] &&
+		mconf->mesh_pm_id == elems->mesh_config[1] &&
+		mconf->mesh_cc_id == elems->mesh_config[2] &&
+		mconf->mesh_sp_id == elems->mesh_config[3] &&
+		mconf->mesh_auth_id == elems->mesh_config[4]);
+}
+
+
+/* check if local link id is already used with another peer */
+static Boolean llid_in_use(struct wpa_supplicant *wpa_s, u16 llid)
+{
+	struct sta_info *sta;
+	struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		if (sta->my_lid == llid)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+
+/* generate an llid for a link and set to initial state */
+static void mesh_mpm_init_link(struct wpa_supplicant *wpa_s,
+			       struct sta_info *sta)
+{
+	u16 llid;
+
+	do {
+		if (os_get_random((u8 *) &llid, sizeof(llid)) < 0)
+			continue;
+	} while (!llid || llid_in_use(wpa_s, llid));
+
+	sta->my_lid = llid;
+	sta->peer_lid = 0;
+	sta->plink_state = PLINK_LISTEN;
+}
+
+
+static void mesh_mpm_send_plink_action(struct wpa_supplicant *wpa_s,
+				       struct sta_info *sta,
+				       enum plink_action_field type,
+				       u16 close_reason)
+{
+	struct wpabuf *buf;
+	struct hostapd_iface *ifmsh = wpa_s->ifmsh;
+	struct hostapd_data *bss = ifmsh->bss[0];
+	struct mesh_conf *conf = ifmsh->mconf;
+	u8 supp_rates[2 + 2 + 32];
+#ifdef CONFIG_IEEE80211N
+	u8 ht_capa_oper[2 + 26 + 2 + 22];
+#endif /* CONFIG_IEEE80211N */
+	u8 *pos, *cat;
+	u8 ie_len, add_plid = 0;
+	int ret;
+	int ampe = conf->security & MESH_CONF_SEC_AMPE;
+	size_t buf_len;
+
+	if (!sta)
+		return;
+
+	buf_len = 2 +      /* capability info */
+		  2 +      /* AID */
+		  2 + 8 +  /* supported rates */
+		  2 + (32 - 8) +
+		  2 + 32 + /* mesh ID */
+		  2 + 7 +  /* mesh config */
+		  2 + 23 + /* peering management */
+		  2 + 96 + /* AMPE */
+		  2 + 16;  /* MIC */
+#ifdef CONFIG_IEEE80211N
+	if (type != PLINK_CLOSE &&
+	    wpa_s->current_ssid->mesh_ht_mode > CHAN_NO_HT) {
+		buf_len += 2 + 26 + /* HT capabilities */
+			   2 + 22;  /* HT operation */
+	}
+#endif /* CONFIG_IEEE80211N */
+	buf = wpabuf_alloc(buf_len);
+	if (!buf)
+		return;
+
+	cat = wpabuf_mhead_u8(buf);
+	wpabuf_put_u8(buf, WLAN_ACTION_SELF_PROTECTED);
+	wpabuf_put_u8(buf, type);
+
+	if (type != PLINK_CLOSE) {
+		u8 info;
+
+		/* capability info */
+		wpabuf_put_le16(buf, ampe ? IEEE80211_CAP_PRIVACY : 0);
+
+		/* aid */
+		if (type == PLINK_CONFIRM)
+			wpabuf_put_le16(buf, sta->peer_lid);
+
+		/* IE: supp + ext. supp rates */
+		pos = hostapd_eid_supp_rates(bss, supp_rates);
+		pos = hostapd_eid_ext_supp_rates(bss, pos);
+		wpabuf_put_data(buf, supp_rates, pos - supp_rates);
+
+		/* IE: Mesh ID */
+		wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
+		wpabuf_put_u8(buf, conf->meshid_len);
+		wpabuf_put_data(buf, conf->meshid, conf->meshid_len);
+
+		/* IE: mesh conf */
+		wpabuf_put_u8(buf, WLAN_EID_MESH_CONFIG);
+		wpabuf_put_u8(buf, 7);
+		wpabuf_put_u8(buf, conf->mesh_pp_id);
+		wpabuf_put_u8(buf, conf->mesh_pm_id);
+		wpabuf_put_u8(buf, conf->mesh_cc_id);
+		wpabuf_put_u8(buf, conf->mesh_sp_id);
+		wpabuf_put_u8(buf, conf->mesh_auth_id);
+		info = (bss->num_plinks > 63 ? 63 : bss->num_plinks) << 1;
+		/* TODO: Add Connected to Mesh Gate/AS subfields */
+		wpabuf_put_u8(buf, info);
+		/* always forwarding & accepting plinks for now */
+		wpabuf_put_u8(buf, 0x1 | 0x8);
+	} else {	/* Peer closing frame */
+		/* IE: Mesh ID */
+		wpabuf_put_u8(buf, WLAN_EID_MESH_ID);
+		wpabuf_put_u8(buf, conf->meshid_len);
+		wpabuf_put_data(buf, conf->meshid, conf->meshid_len);
+	}
+
+	/* IE: Mesh Peering Management element */
+	ie_len = 4;
+	if (ampe)
+		ie_len += PMKID_LEN;
+	switch (type) {
+	case PLINK_OPEN:
+		break;
+	case PLINK_CONFIRM:
+		ie_len += 2;
+		add_plid = 1;
+		break;
+	case PLINK_CLOSE:
+		ie_len += 2;
+		add_plid = 1;
+		ie_len += 2; /* reason code */
+		break;
+	}
+
+	wpabuf_put_u8(buf, WLAN_EID_PEER_MGMT);
+	wpabuf_put_u8(buf, ie_len);
+	/* peering protocol */
+	if (ampe)
+		wpabuf_put_le16(buf, 1);
+	else
+		wpabuf_put_le16(buf, 0);
+	wpabuf_put_le16(buf, sta->my_lid);
+	if (add_plid)
+		wpabuf_put_le16(buf, sta->peer_lid);
+	if (type == PLINK_CLOSE)
+		wpabuf_put_le16(buf, close_reason);
+	if (ampe) {
+		if (sta->sae == NULL) {
+			wpa_msg(wpa_s, MSG_INFO, "Mesh MPM: no SAE session");
+			goto fail;
+		}
+		mesh_rsn_get_pmkid(wpa_s->mesh_rsn, sta,
+				   wpabuf_put(buf, PMKID_LEN));
+	}
+
+#ifdef CONFIG_IEEE80211N
+	if (type != PLINK_CLOSE &&
+	    wpa_s->current_ssid->mesh_ht_mode > CHAN_NO_HT) {
+		pos = hostapd_eid_ht_capabilities(bss, ht_capa_oper);
+		pos = hostapd_eid_ht_operation(bss, pos);
+		wpabuf_put_data(buf, ht_capa_oper, pos - ht_capa_oper);
+	}
+#endif /* CONFIG_IEEE80211N */
+
+	if (ampe && mesh_rsn_protect_frame(wpa_s->mesh_rsn, sta, cat, buf)) {
+		wpa_msg(wpa_s, MSG_INFO,
+			"Mesh MPM: failed to add AMPE and MIC IE");
+		goto fail;
+	}
+
+	ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
+				  sta->addr, wpa_s->own_addr, wpa_s->own_addr,
+				  wpabuf_head(buf), wpabuf_len(buf), 0);
+	if (ret < 0)
+		wpa_msg(wpa_s, MSG_INFO,
+			"Mesh MPM: failed to send peering frame");
+
+fail:
+	wpabuf_free(buf);
+}
+
+
+/* configure peering state in ours and driver's station entry */
+static void
+wpa_mesh_set_plink_state(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+			 enum mesh_plink_state state)
+{
+	struct hostapd_sta_add_params params;
+	int ret;
+
+	sta->plink_state = state;
+
+	os_memset(&params, 0, sizeof(params));
+	params.addr = sta->addr;
+	params.plink_state = state;
+	params.set = 1;
+
+	wpa_msg(wpa_s, MSG_DEBUG, "MPM set " MACSTR " into %s",
+		MAC2STR(sta->addr), mplstate[state]);
+	ret = wpa_drv_sta_add(wpa_s, &params);
+	if (ret) {
+		wpa_msg(wpa_s, MSG_ERROR, "Driver failed to set " MACSTR
+			": %d", MAC2STR(sta->addr), ret);
+	}
+}
+
+
+static void mesh_mpm_fsm_restart(struct wpa_supplicant *wpa_s,
+				 struct sta_info *sta)
+{
+	struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+
+	eloop_cancel_timeout(plink_timer, wpa_s, sta);
+
+	if (sta->mpm_close_reason == WLAN_REASON_MESH_CLOSE_RCVD) {
+		ap_free_sta(hapd, sta);
+		return;
+	}
+
+	wpa_mesh_set_plink_state(wpa_s, sta, PLINK_LISTEN);
+	sta->my_lid = sta->peer_lid = sta->mpm_close_reason = 0;
+	sta->mpm_retries = 0;
+}
+
+
+static void plink_timer(void *eloop_ctx, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct sta_info *sta = user_data;
+	u16 reason = 0;
+	struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+
+	switch (sta->plink_state) {
+	case PLINK_OPEN_RCVD:
+	case PLINK_OPEN_SENT:
+		/* retry timer */
+		if (sta->mpm_retries < conf->dot11MeshMaxRetries) {
+			eloop_register_timeout(
+				conf->dot11MeshRetryTimeout / 1000,
+				(conf->dot11MeshRetryTimeout % 1000) * 1000,
+				plink_timer, wpa_s, sta);
+			mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0);
+			sta->mpm_retries++;
+			break;
+		}
+		reason = WLAN_REASON_MESH_MAX_RETRIES;
+		/* fall through on else */
+
+	case PLINK_CNF_RCVD:
+		/* confirm timer */
+		if (!reason)
+			reason = WLAN_REASON_MESH_CONFIRM_TIMEOUT;
+		sta->plink_state = PLINK_HOLDING;
+		eloop_register_timeout(conf->dot11MeshHoldingTimeout / 1000,
+			(conf->dot11MeshHoldingTimeout % 1000) * 1000,
+			plink_timer, wpa_s, sta);
+		mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+		break;
+	case PLINK_HOLDING:
+		/* holding timer */
+		mesh_mpm_fsm_restart(wpa_s, sta);
+		break;
+	default:
+		break;
+	}
+}
+
+
+/* initiate peering with station */
+static void
+mesh_mpm_plink_open(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+		    enum mesh_plink_state next_state)
+{
+	struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+
+	eloop_cancel_timeout(plink_timer, wpa_s, sta);
+	eloop_register_timeout(conf->dot11MeshRetryTimeout / 1000,
+			       (conf->dot11MeshRetryTimeout % 1000) * 1000,
+			       plink_timer, wpa_s, sta);
+	mesh_mpm_send_plink_action(wpa_s, sta, PLINK_OPEN, 0);
+	wpa_mesh_set_plink_state(wpa_s, sta, next_state);
+}
+
+
+int mesh_mpm_plink_close(struct hostapd_data *hapd,
+			 struct sta_info *sta, void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	int reason = WLAN_REASON_MESH_PEERING_CANCELLED;
+
+	if (sta) {
+		wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+		mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CLOSE, reason);
+		wpa_printf(MSG_DEBUG, "MPM closing plink sta=" MACSTR,
+			   MAC2STR(sta->addr));
+		eloop_cancel_timeout(plink_timer, wpa_s, sta);
+		return 0;
+	}
+
+	return 1;
+}
+
+
+void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh)
+{
+	struct hostapd_data *hapd = ifmsh->bss[0];
+
+	/* notify peers we're leaving */
+	ap_for_each_sta(hapd, mesh_mpm_plink_close, wpa_s);
+
+	hapd->num_plinks = 0;
+	hostapd_free_stas(hapd);
+}
+
+
+/* for mesh_rsn to indicate this peer has completed authentication, and we're
+ * ready to start AMPE */
+void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+	struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+	struct hostapd_sta_add_params params;
+	struct sta_info *sta;
+	int ret;
+
+	sta = ap_get_sta(data, addr);
+	if (!sta) {
+		wpa_msg(wpa_s, MSG_DEBUG, "no such mesh peer");
+		return;
+	}
+
+	/* TODO: Should do nothing if this STA is already authenticated, but
+	 * the AP code already sets this flag. */
+	sta->flags |= WLAN_STA_AUTH;
+
+	mesh_rsn_init_ampe_sta(wpa_s, sta);
+
+	os_memset(&params, 0, sizeof(params));
+	params.addr = sta->addr;
+	params.flags = WPA_STA_AUTHENTICATED | WPA_STA_AUTHORIZED;
+	params.set = 1;
+
+	wpa_msg(wpa_s, MSG_DEBUG, "MPM authenticating " MACSTR,
+		MAC2STR(sta->addr));
+	ret = wpa_drv_sta_add(wpa_s, &params);
+	if (ret) {
+		wpa_msg(wpa_s, MSG_ERROR,
+			"Driver failed to set " MACSTR ": %d",
+			MAC2STR(sta->addr), ret);
+	}
+
+	if (!sta->my_lid)
+		mesh_mpm_init_link(wpa_s, sta);
+
+	mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+}
+
+
+void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+			    struct ieee802_11_elems *elems)
+{
+	struct hostapd_sta_add_params params;
+	struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+	struct hostapd_data *data = wpa_s->ifmsh->bss[0];
+	struct sta_info *sta;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	int ret = 0;
+
+	sta = ap_get_sta(data, addr);
+	if (!sta) {
+		sta = ap_sta_add(data, addr);
+		if (!sta)
+			return;
+	}
+
+	/* initialize sta */
+	if (copy_supp_rates(wpa_s, sta, elems))
+		return;
+
+	mesh_mpm_init_link(wpa_s, sta);
+
+#ifdef CONFIG_IEEE80211N
+	copy_sta_ht_capab(data, sta, elems->ht_capabilities,
+			elems->ht_capabilities_len);
+	update_ht_state(data, sta);
+#endif /* CONFIG_IEEE80211N */
+
+	/* insert into driver */
+	os_memset(&params, 0, sizeof(params));
+	params.supp_rates = sta->supported_rates;
+	params.supp_rates_len = sta->supported_rates_len;
+	params.addr = addr;
+	params.plink_state = sta->plink_state;
+	params.aid = sta->peer_lid;
+	params.listen_interval = 100;
+	params.ht_capabilities = sta->ht_capabilities;
+	params.flags |= WPA_STA_WMM;
+	params.flags_mask |= WPA_STA_AUTHENTICATED;
+	if (conf->security == MESH_CONF_SEC_NONE) {
+		params.flags |= WPA_STA_AUTHORIZED;
+		params.flags |= WPA_STA_AUTHENTICATED;
+	} else {
+		sta->flags |= WLAN_STA_MFP;
+		params.flags |= WPA_STA_MFP;
+	}
+
+	ret = wpa_drv_sta_add(wpa_s, &params);
+	if (ret) {
+		wpa_msg(wpa_s, MSG_ERROR,
+			"Driver failed to insert " MACSTR ": %d",
+			MAC2STR(addr), ret);
+		return;
+	}
+
+	if (ssid && ssid->no_auto_peer) {
+		wpa_msg(wpa_s, MSG_INFO, "will not initiate new peer link with "
+			MACSTR " because of no_auto_peer", MAC2STR(addr));
+		if (data->mesh_pending_auth) {
+			struct os_reltime age;
+			const struct ieee80211_mgmt *mgmt;
+			struct hostapd_frame_info fi;
+
+			mgmt = wpabuf_head(data->mesh_pending_auth);
+			os_reltime_age(&data->mesh_pending_auth_time, &age);
+			if (age.sec < 2 &&
+			    os_memcmp(mgmt->sa, addr, ETH_ALEN) == 0) {
+				wpa_printf(MSG_DEBUG,
+					   "mesh: Process pending Authentication frame from %u.%06u seconds ago",
+					   (unsigned int) age.sec,
+					   (unsigned int) age.usec);
+				os_memset(&fi, 0, sizeof(fi));
+				ieee802_11_mgmt(
+					data,
+					wpabuf_head(data->mesh_pending_auth),
+					wpabuf_len(data->mesh_pending_auth),
+					&fi);
+			}
+			wpabuf_free(data->mesh_pending_auth);
+			data->mesh_pending_auth = NULL;
+		}
+		return;
+	}
+
+	if (conf->security == MESH_CONF_SEC_NONE)
+		mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_SENT);
+	else
+		mesh_rsn_auth_sae_sta(wpa_s, sta);
+}
+
+
+void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s, struct rx_mgmt *rx_mgmt)
+{
+	struct hostapd_frame_info fi;
+
+	os_memset(&fi, 0, sizeof(fi));
+	fi.datarate = rx_mgmt->datarate;
+	fi.ssi_signal = rx_mgmt->ssi_signal;
+	ieee802_11_mgmt(wpa_s->ifmsh->bss[0], rx_mgmt->frame,
+			rx_mgmt->frame_len, &fi);
+}
+
+
+static void mesh_mpm_plink_estab(struct wpa_supplicant *wpa_s,
+				 struct sta_info *sta)
+{
+	struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+	struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+	u8 seq[6] = {};
+
+	wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR " established",
+		MAC2STR(sta->addr));
+
+	if (conf->security & MESH_CONF_SEC_AMPE) {
+		wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 0, 0,
+				seq, sizeof(seq), sta->mtk, sizeof(sta->mtk));
+		wpa_drv_set_key(wpa_s, WPA_ALG_CCMP, sta->addr, 1, 0,
+				seq, sizeof(seq),
+				sta->mgtk, sizeof(sta->mgtk));
+		wpa_drv_set_key(wpa_s, WPA_ALG_IGTK, sta->addr, 4, 0,
+				seq, sizeof(seq),
+				sta->mgtk, sizeof(sta->mgtk));
+
+		wpa_hexdump_key(MSG_DEBUG, "mtk:", sta->mtk, sizeof(sta->mtk));
+		wpa_hexdump_key(MSG_DEBUG, "mgtk:",
+				sta->mgtk, sizeof(sta->mgtk));
+	}
+
+	wpa_mesh_set_plink_state(wpa_s, sta, PLINK_ESTAB);
+	hapd->num_plinks++;
+
+	sta->flags |= WLAN_STA_ASSOC;
+
+	eloop_cancel_timeout(plink_timer, wpa_s, sta);
+
+	/* Send ctrl event */
+	wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_PEER_CONNECTED MACSTR,
+		     MAC2STR(sta->addr));
+}
+
+
+static void mesh_mpm_fsm(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+			 enum plink_event event)
+{
+	struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+	struct mesh_conf *conf = wpa_s->ifmsh->mconf;
+	u16 reason = 0;
+
+	wpa_msg(wpa_s, MSG_DEBUG, "MPM " MACSTR " state %s event %s",
+		MAC2STR(sta->addr), mplstate[sta->plink_state],
+		mplevent[event]);
+
+	switch (sta->plink_state) {
+	case PLINK_LISTEN:
+		switch (event) {
+		case CLS_ACPT:
+			mesh_mpm_fsm_restart(wpa_s, sta);
+			break;
+		case OPN_ACPT:
+			mesh_mpm_plink_open(wpa_s, sta, PLINK_OPEN_RCVD);
+			mesh_mpm_send_plink_action(wpa_s, sta, PLINK_CONFIRM,
+						   0);
+			break;
+		default:
+			break;
+		}
+		break;
+	case PLINK_OPEN_SENT:
+		switch (event) {
+		case OPN_RJCT:
+		case CNF_RJCT:
+			reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+			/* fall-through */
+		case CLS_ACPT:
+			wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+			if (!reason)
+				reason = WLAN_REASON_MESH_CLOSE_RCVD;
+			eloop_register_timeout(
+				conf->dot11MeshHoldingTimeout / 1000,
+				(conf->dot11MeshHoldingTimeout % 1000) * 1000,
+				plink_timer, wpa_s, sta);
+			mesh_mpm_send_plink_action(wpa_s, sta,
+						   PLINK_CLOSE, reason);
+			break;
+		case OPN_ACPT:
+			/* retry timer is left untouched */
+			wpa_mesh_set_plink_state(wpa_s, sta, PLINK_OPEN_RCVD);
+			mesh_mpm_send_plink_action(wpa_s, sta,
+						   PLINK_CONFIRM, 0);
+			break;
+		case CNF_ACPT:
+			wpa_mesh_set_plink_state(wpa_s, sta, PLINK_CNF_RCVD);
+			eloop_register_timeout(
+				conf->dot11MeshConfirmTimeout / 1000,
+				(conf->dot11MeshConfirmTimeout % 1000) * 1000,
+				plink_timer, wpa_s, sta);
+			break;
+		default:
+			break;
+		}
+		break;
+	case PLINK_OPEN_RCVD:
+		switch (event) {
+		case OPN_RJCT:
+		case CNF_RJCT:
+			reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+			/* fall-through */
+		case CLS_ACPT:
+			wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+			if (!reason)
+				reason = WLAN_REASON_MESH_CLOSE_RCVD;
+			eloop_register_timeout(
+				conf->dot11MeshHoldingTimeout / 1000,
+				(conf->dot11MeshHoldingTimeout % 1000) * 1000,
+				plink_timer, wpa_s, sta);
+			sta->mpm_close_reason = reason;
+			mesh_mpm_send_plink_action(wpa_s, sta,
+						   PLINK_CLOSE, reason);
+			break;
+		case OPN_ACPT:
+			mesh_mpm_send_plink_action(wpa_s, sta,
+						   PLINK_CONFIRM, 0);
+			break;
+		case CNF_ACPT:
+			if (conf->security & MESH_CONF_SEC_AMPE)
+				mesh_rsn_derive_mtk(wpa_s, sta);
+			mesh_mpm_plink_estab(wpa_s, sta);
+			break;
+		default:
+			break;
+		}
+		break;
+	case PLINK_CNF_RCVD:
+		switch (event) {
+		case OPN_RJCT:
+		case CNF_RJCT:
+			reason = WLAN_REASON_MESH_CONFIG_POLICY_VIOLATION;
+			/* fall-through */
+		case CLS_ACPT:
+			wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+			if (!reason)
+				reason = WLAN_REASON_MESH_CLOSE_RCVD;
+			eloop_register_timeout(
+				conf->dot11MeshHoldingTimeout / 1000,
+				(conf->dot11MeshHoldingTimeout % 1000) * 1000,
+				plink_timer, wpa_s, sta);
+			sta->mpm_close_reason = reason;
+			mesh_mpm_send_plink_action(wpa_s, sta,
+						   PLINK_CLOSE, reason);
+			break;
+		case OPN_ACPT:
+			mesh_mpm_plink_estab(wpa_s, sta);
+			mesh_mpm_send_plink_action(wpa_s, sta,
+						   PLINK_CONFIRM, 0);
+			break;
+		default:
+			break;
+		}
+		break;
+	case PLINK_ESTAB:
+		switch (event) {
+		case CLS_ACPT:
+			wpa_mesh_set_plink_state(wpa_s, sta, PLINK_HOLDING);
+			reason = WLAN_REASON_MESH_CLOSE_RCVD;
+
+			eloop_register_timeout(
+				conf->dot11MeshHoldingTimeout / 1000,
+				(conf->dot11MeshHoldingTimeout % 1000) * 1000,
+				plink_timer, wpa_s, sta);
+			sta->mpm_close_reason = reason;
+
+			wpa_msg(wpa_s, MSG_INFO, "mesh plink with " MACSTR
+				" closed with reason %d",
+				MAC2STR(sta->addr), reason);
+
+			wpa_msg_ctrl(wpa_s, MSG_INFO,
+				     MESH_PEER_DISCONNECTED MACSTR,
+				     MAC2STR(sta->addr));
+
+			hapd->num_plinks--;
+
+			mesh_mpm_send_plink_action(wpa_s, sta,
+						   PLINK_CLOSE, reason);
+			break;
+		case OPN_ACPT:
+			mesh_mpm_send_plink_action(wpa_s, sta,
+						   PLINK_CONFIRM, 0);
+			break;
+		default:
+			break;
+		}
+		break;
+	case PLINK_HOLDING:
+		switch (event) {
+		case CLS_ACPT:
+			mesh_mpm_fsm_restart(wpa_s, sta);
+			break;
+		case OPN_ACPT:
+		case CNF_ACPT:
+		case OPN_RJCT:
+		case CNF_RJCT:
+			reason = sta->mpm_close_reason;
+			mesh_mpm_send_plink_action(wpa_s, sta,
+						   PLINK_CLOSE, reason);
+			break;
+		default:
+			break;
+		}
+		break;
+	default:
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"Unsupported MPM event %s for state %s",
+			mplevent[event], mplstate[sta->plink_state]);
+		break;
+	}
+}
+
+
+void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
+			const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	u8 action_field;
+	struct hostapd_data *hapd = wpa_s->ifmsh->bss[0];
+	struct mesh_conf *mconf = wpa_s->ifmsh->mconf;
+	struct sta_info *sta;
+	u16 plid = 0, llid = 0;
+	enum plink_event event;
+	struct ieee802_11_elems elems;
+	struct mesh_peer_mgmt_ie peer_mgmt_ie;
+	const u8 *ies;
+	size_t ie_len;
+	int ret;
+
+	if (mgmt->u.action.category != WLAN_ACTION_SELF_PROTECTED)
+		return;
+
+	action_field = mgmt->u.action.u.slf_prot_action.action;
+	if (action_field != PLINK_OPEN &&
+	    action_field != PLINK_CONFIRM &&
+	    action_field != PLINK_CLOSE)
+		return;
+
+	ies = mgmt->u.action.u.slf_prot_action.variable;
+	ie_len = (const u8 *) mgmt + len -
+		mgmt->u.action.u.slf_prot_action.variable;
+
+	/* at least expect mesh id and peering mgmt */
+	if (ie_len < 2 + 2) {
+		wpa_printf(MSG_DEBUG,
+			   "MPM: Ignore too short action frame %u ie_len %u",
+			   action_field, (unsigned int) ie_len);
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "MPM: Received PLINK action %u", action_field);
+
+	if (action_field == PLINK_OPEN || action_field == PLINK_CONFIRM) {
+		wpa_printf(MSG_DEBUG, "MPM: Capability 0x%x",
+			   WPA_GET_LE16(ies));
+		ies += 2;	/* capability */
+		ie_len -= 2;
+	}
+	if (action_field == PLINK_CONFIRM) {
+		wpa_printf(MSG_DEBUG, "MPM: AID 0x%x", WPA_GET_LE16(ies));
+		ies += 2;	/* aid */
+		ie_len -= 2;
+	}
+
+	/* check for mesh peering, mesh id and mesh config IEs */
+	if (ieee802_11_parse_elems(ies, ie_len, &elems, 0) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "MPM: Failed to parse PLINK IEs");
+		return;
+	}
+	if (!elems.peer_mgmt) {
+		wpa_printf(MSG_DEBUG,
+			   "MPM: No Mesh Peering Management element");
+		return;
+	}
+	if (action_field != PLINK_CLOSE) {
+		if (!elems.mesh_id || !elems.mesh_config) {
+			wpa_printf(MSG_DEBUG,
+				   "MPM: No Mesh ID or Mesh Configuration element");
+			return;
+		}
+
+		if (!matches_local(wpa_s, &elems)) {
+			wpa_printf(MSG_DEBUG,
+				   "MPM: Mesh ID or Mesh Configuration element do not match local MBSS");
+			return;
+		}
+	}
+
+	ret = mesh_mpm_parse_peer_mgmt(wpa_s, action_field,
+				       elems.peer_mgmt,
+				       elems.peer_mgmt_len,
+				       &peer_mgmt_ie);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "MPM: Mesh parsing rejected frame");
+		return;
+	}
+
+	/* the sender's llid is our plid and vice-versa */
+	plid = WPA_GET_LE16(peer_mgmt_ie.llid);
+	if (peer_mgmt_ie.plid)
+		llid = WPA_GET_LE16(peer_mgmt_ie.plid);
+	wpa_printf(MSG_DEBUG, "MPM: plid=0x%x llid=0x%x", plid, llid);
+
+	sta = ap_get_sta(hapd, mgmt->sa);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "MPM: No STA entry for peer");
+		return;
+	}
+
+#ifdef CONFIG_SAE
+	/* peer is in sae_accepted? */
+	if (sta->sae && sta->sae->state != SAE_ACCEPTED) {
+		wpa_printf(MSG_DEBUG, "MPM: SAE not yet accepted for peer");
+		return;
+	}
+#endif /* CONFIG_SAE */
+
+	if (!sta->my_lid)
+		mesh_mpm_init_link(wpa_s, sta);
+
+	if ((mconf->security & MESH_CONF_SEC_AMPE) &&
+	    mesh_rsn_process_ampe(wpa_s, sta, &elems,
+				  &mgmt->u.action.category,
+				  ies, ie_len)) {
+		wpa_printf(MSG_DEBUG, "MPM: RSN process rejected frame");
+		return;
+	}
+
+	if (sta->plink_state == PLINK_BLOCKED) {
+		wpa_printf(MSG_DEBUG, "MPM: PLINK_BLOCKED");
+		return;
+	}
+
+	/* Now we will figure out the appropriate event... */
+	switch (action_field) {
+	case PLINK_OPEN:
+		if (plink_free_count(hapd) == 0) {
+			event = OPN_IGNR;
+			wpa_printf(MSG_INFO,
+				   "MPM: Peer link num over quota(%d)",
+				   hapd->max_plinks);
+		} else if (sta->peer_lid && sta->peer_lid != plid) {
+			event = OPN_IGNR;
+		} else {
+			sta->peer_lid = plid;
+			event = OPN_ACPT;
+		}
+		break;
+	case PLINK_CONFIRM:
+		if (plink_free_count(hapd) == 0) {
+			event = CNF_IGNR;
+			wpa_printf(MSG_INFO,
+				   "MPM: Peer link num over quota(%d)",
+				   hapd->max_plinks);
+		} else if (sta->my_lid != llid ||
+			   (sta->peer_lid && sta->peer_lid != plid)) {
+			event = CNF_IGNR;
+		} else {
+			if (!sta->peer_lid)
+				sta->peer_lid = plid;
+			event = CNF_ACPT;
+		}
+		break;
+	case PLINK_CLOSE:
+		if (sta->plink_state == PLINK_ESTAB)
+			/* Do not check for llid or plid. This does not
+			 * follow the standard but since multiple plinks
+			 * per cand are not supported, it is necessary in
+			 * order to avoid a livelock when MP A sees an
+			 * establish peer link to MP B but MP B does not
+			 * see it. This can be caused by a timeout in
+			 * B's peer link establishment or B being
+			 * restarted.
+			 */
+			event = CLS_ACPT;
+		else if (sta->peer_lid != plid)
+			event = CLS_IGNR;
+		else if (peer_mgmt_ie.plid && sta->my_lid != llid)
+			event = CLS_IGNR;
+		else
+			event = CLS_ACPT;
+		break;
+	default:
+		/*
+		 * This cannot be hit due to the action_field check above, but
+		 * compilers may not be able to figure that out and can warn
+		 * about uninitialized event below.
+		 */
+		return;
+	}
+	mesh_mpm_fsm(wpa_s, sta, event);
+}
+
+
+/* called by ap_free_sta */
+void mesh_mpm_free_sta(struct sta_info *sta)
+{
+	eloop_cancel_timeout(plink_timer, ELOOP_ALL_CTX, sta);
+	eloop_cancel_timeout(mesh_auth_timer, ELOOP_ALL_CTX, sta);
+}
diff --git a/wpa_supplicant/mesh_mpm.h b/wpa_supplicant/mesh_mpm.h
new file mode 100644
index 0000000..2f7f6a7
--- /dev/null
+++ b/wpa_supplicant/mesh_mpm.h
@@ -0,0 +1,40 @@
+/*
+ * WPA Supplicant - Basic mesh peer management
+ * Copyright (c) 2013-2014, cozybit, Inc.  All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_MPM_H
+#define MESH_MPM_H
+
+/* notify MPM of new mesh peer to be inserted in MPM and driver */
+void wpa_mesh_new_mesh_peer(struct wpa_supplicant *wpa_s, const u8 *addr,
+			    struct ieee802_11_elems *elems);
+void mesh_mpm_deinit(struct wpa_supplicant *wpa_s, struct hostapd_iface *ifmsh);
+void mesh_mpm_auth_peer(struct wpa_supplicant *wpa_s, const u8 *addr);
+void mesh_mpm_free_sta(struct sta_info *sta);
+
+#ifdef CONFIG_MESH
+
+void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
+			const struct ieee80211_mgmt *mgmt, size_t len);
+void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s, struct rx_mgmt *rx_mgmt);
+
+#else /* CONFIG_MESH */
+
+static inline void mesh_mpm_action_rx(struct wpa_supplicant *wpa_s,
+				      const struct ieee80211_mgmt *mgmt,
+				      size_t len)
+{
+}
+
+static inline void mesh_mpm_mgmt_rx(struct wpa_supplicant *wpa_s,
+				    struct rx_mgmt *rx_mgmt)
+{
+}
+
+#endif /* CONFIG_MESH */
+
+#endif /* MESH_MPM_H */
diff --git a/wpa_supplicant/mesh_rsn.c b/wpa_supplicant/mesh_rsn.c
new file mode 100644
index 0000000..e6ae7c3
--- /dev/null
+++ b/wpa_supplicant/mesh_rsn.c
@@ -0,0 +1,615 @@
+/*
+ * WPA Supplicant - Mesh RSN routines
+ * Copyright (c) 2013-2014, cozybit, Inc.  All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "crypto/aes.h"
+#include "crypto/aes_siv.h"
+#include "rsn_supp/wpa.h"
+#include "ap/hostapd.h"
+#include "ap/wpa_auth.h"
+#include "ap/sta_info.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "wpas_glue.h"
+#include "mesh_mpm.h"
+#include "mesh_rsn.h"
+
+#define MESH_AUTH_TIMEOUT 10
+#define MESH_AUTH_RETRY 3
+
+void mesh_auth_timer(void *eloop_ctx, void *user_data)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct sta_info *sta = user_data;
+
+	if (sta->sae->state != SAE_ACCEPTED) {
+		wpa_printf(MSG_DEBUG, "AUTH: Re-authenticate with " MACSTR
+			   " (attempt %d) ",
+			   MAC2STR(sta->addr), sta->sae_auth_retry);
+		if (sta->sae_auth_retry < MESH_AUTH_RETRY) {
+			mesh_rsn_auth_sae_sta(wpa_s, sta);
+		} else {
+			/* block the STA if exceeded the number of attempts */
+			sta->plink_state = PLINK_BLOCKED;
+			sta->sae->state = SAE_NOTHING;
+		}
+		sta->sae_auth_retry++;
+	}
+}
+
+
+static void auth_logger(void *ctx, const u8 *addr, logger_level level,
+			const char *txt)
+{
+	if (addr)
+		wpa_printf(MSG_DEBUG, "AUTH: " MACSTR " - %s",
+			   MAC2STR(addr), txt);
+	else
+		wpa_printf(MSG_DEBUG, "AUTH: %s", txt);
+}
+
+
+static const u8 *auth_get_psk(void *ctx, const u8 *addr,
+			      const u8 *p2p_dev_addr, const u8 *prev_psk)
+{
+	struct mesh_rsn *mesh_rsn = ctx;
+	struct hostapd_data *hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+
+	wpa_printf(MSG_DEBUG, "AUTH: %s (addr=" MACSTR " prev_psk=%p)",
+		   __func__, MAC2STR(addr), prev_psk);
+
+	if (sta && sta->auth_alg == WLAN_AUTH_SAE) {
+		if (!sta->sae || prev_psk)
+			return NULL;
+		return sta->sae->pmk;
+	}
+
+	return NULL;
+}
+
+
+static int auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
+			const u8 *addr, int idx, u8 *key, size_t key_len)
+{
+	struct mesh_rsn *mesh_rsn = ctx;
+	u8 seq[6];
+
+	os_memset(seq, 0, sizeof(seq));
+
+	if (addr) {
+		wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d addr=" MACSTR
+			   " key_idx=%d)",
+			   __func__, alg, MAC2STR(addr), idx);
+	} else {
+		wpa_printf(MSG_DEBUG, "AUTH: %s(alg=%d key_idx=%d)",
+			   __func__, alg, idx);
+	}
+	wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
+
+	return wpa_drv_set_key(mesh_rsn->wpa_s, alg, addr, idx,
+			       1, seq, 6, key, key_len);
+}
+
+
+static int auth_start_ampe(void *ctx, const u8 *addr)
+{
+	struct mesh_rsn *mesh_rsn = ctx;
+	struct hostapd_data *hapd;
+	struct sta_info *sta;
+
+	if (mesh_rsn->wpa_s->current_ssid->mode != WPAS_MODE_MESH)
+		return -1;
+
+	hapd = mesh_rsn->wpa_s->ifmsh->bss[0];
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		eloop_cancel_timeout(mesh_auth_timer, mesh_rsn->wpa_s, sta);
+
+	mesh_mpm_auth_peer(mesh_rsn->wpa_s, addr);
+	return 0;
+}
+
+
+static int __mesh_rsn_auth_init(struct mesh_rsn *rsn, const u8 *addr)
+{
+	struct wpa_auth_config conf;
+	struct wpa_auth_callbacks cb;
+	u8 seq[6] = {};
+
+	wpa_printf(MSG_DEBUG, "AUTH: Initializing group state machine");
+
+	os_memset(&conf, 0, sizeof(conf));
+	conf.wpa = 2;
+	conf.wpa_key_mgmt = WPA_KEY_MGMT_SAE;
+	conf.wpa_pairwise = WPA_CIPHER_CCMP;
+	conf.rsn_pairwise = WPA_CIPHER_CCMP;
+	conf.wpa_group = WPA_CIPHER_CCMP;
+	conf.eapol_version = 0;
+	conf.wpa_group_rekey = -1;
+
+	os_memset(&cb, 0, sizeof(cb));
+	cb.ctx = rsn;
+	cb.logger = auth_logger;
+	cb.get_psk = auth_get_psk;
+	cb.set_key = auth_set_key;
+	cb.start_ampe = auth_start_ampe;
+
+	rsn->auth = wpa_init(addr, &conf, &cb);
+	if (rsn->auth == NULL) {
+		wpa_printf(MSG_DEBUG, "AUTH: wpa_init() failed");
+		return -1;
+	}
+
+	/* TODO: support rekeying */
+	if (random_get_bytes(rsn->mgtk, 16) < 0) {
+		wpa_deinit(rsn->auth);
+		return -1;
+	}
+
+	/* group mgmt */
+	wpa_drv_set_key(rsn->wpa_s, WPA_ALG_IGTK, NULL, 4, 1,
+			seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+
+	/* group privacy / data frames */
+	wpa_drv_set_key(rsn->wpa_s, WPA_ALG_CCMP, NULL, 1, 1,
+			seq, sizeof(seq), rsn->mgtk, sizeof(rsn->mgtk));
+
+	return 0;
+}
+
+
+static void mesh_rsn_deinit(struct mesh_rsn *rsn)
+{
+	os_memset(rsn->mgtk, 0, sizeof(rsn->mgtk));
+	wpa_deinit(rsn->auth);
+}
+
+
+struct mesh_rsn *mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
+				    struct mesh_conf *conf)
+{
+	struct mesh_rsn *mesh_rsn;
+	struct hostapd_data *bss = wpa_s->ifmsh->bss[0];
+	const u8 *ie;
+	size_t ie_len;
+
+	mesh_rsn = os_zalloc(sizeof(*mesh_rsn));
+	if (mesh_rsn == NULL)
+		return NULL;
+	mesh_rsn->wpa_s = wpa_s;
+
+	if (__mesh_rsn_auth_init(mesh_rsn, wpa_s->own_addr) < 0) {
+		mesh_rsn_deinit(mesh_rsn);
+		return NULL;
+	}
+
+	bss->wpa_auth = mesh_rsn->auth;
+
+	ie = wpa_auth_get_wpa_ie(mesh_rsn->auth, &ie_len);
+	conf->ies = (u8 *) ie;
+	conf->ie_len = ie_len;
+
+	wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
+
+	return mesh_rsn;
+}
+
+
+static int index_within_array(const int *array, int idx)
+{
+	int i;
+
+	for (i = 0; i < idx; i++) {
+		if (array[i] == -1)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+static int mesh_rsn_sae_group(struct wpa_supplicant *wpa_s,
+			      struct sae_data *sae)
+{
+	int *groups = wpa_s->ifmsh->bss[0]->conf->sae_groups;
+
+	/* Configuration may have changed, so validate current index */
+	if (!index_within_array(groups, wpa_s->mesh_rsn->sae_group_index))
+		return -1;
+
+	for (;;) {
+		int group = groups[wpa_s->mesh_rsn->sae_group_index];
+
+		if (group <= 0)
+			break;
+		if (sae_set_group(sae, group) == 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "SME: Selected SAE group %d",
+				sae->group);
+			return 0;
+		}
+		wpa_s->mesh_rsn->sae_group_index++;
+	}
+
+	return -1;
+}
+
+
+struct wpabuf *
+mesh_rsn_build_sae_commit(struct wpa_supplicant *wpa_s,
+			  struct wpa_ssid *ssid, struct sta_info *sta)
+{
+	struct wpabuf *buf;
+	int len;
+
+	if (ssid->passphrase == NULL) {
+		wpa_msg(wpa_s, MSG_DEBUG, "SAE: No password available");
+		return NULL;
+	}
+
+	if (mesh_rsn_sae_group(wpa_s, sta->sae) < 0) {
+		wpa_msg(wpa_s, MSG_DEBUG, "SAE: Failed to select group");
+		return NULL;
+	}
+
+	if (sae_prepare_commit(wpa_s->own_addr, sta->addr,
+			       (u8 *) ssid->passphrase,
+			       os_strlen(ssid->passphrase), sta->sae) < 0) {
+		wpa_msg(wpa_s, MSG_DEBUG, "SAE: Could not pick PWE");
+		return NULL;
+	}
+
+	len = wpa_s->mesh_rsn->sae_token ?
+		wpabuf_len(wpa_s->mesh_rsn->sae_token) : 0;
+	buf = wpabuf_alloc(4 + SAE_COMMIT_MAX_LEN + len);
+	if (buf == NULL)
+		return NULL;
+
+	sae_write_commit(sta->sae, buf, wpa_s->mesh_rsn->sae_token);
+
+	return buf;
+}
+
+
+static void mesh_rsn_send_auth(struct wpa_supplicant *wpa_s,
+			       const u8 *dst, const u8 *src,
+			       u16 auth_transaction, u16 resp,
+			       struct wpabuf *data)
+{
+	struct ieee80211_mgmt *auth;
+	u8 *buf;
+	size_t len, ielen = 0;
+
+	if (data)
+		ielen = wpabuf_len(data);
+	len = IEEE80211_HDRLEN + sizeof(auth->u.auth) + ielen;
+	buf = os_zalloc(len);
+	if (buf == NULL)
+		return;
+
+	auth = (struct ieee80211_mgmt *) buf;
+	auth->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_AUTH);
+	os_memcpy(auth->da, dst, ETH_ALEN);
+	os_memcpy(auth->sa, src, ETH_ALEN);
+	os_memcpy(auth->bssid, src, ETH_ALEN);
+
+	auth->u.auth.auth_alg = host_to_le16(WLAN_AUTH_SAE);
+	auth->u.auth.auth_transaction = host_to_le16(auth_transaction);
+	auth->u.auth.status_code = host_to_le16(resp);
+
+	if (data)
+		os_memcpy(auth->u.auth.variable, wpabuf_head(data), ielen);
+
+	wpa_msg(wpa_s, MSG_DEBUG, "authentication frame: STA=" MACSTR
+		" auth_transaction=%d resp=%d (IE len=%lu)",
+		MAC2STR(dst), auth_transaction, resp, (unsigned long) ielen);
+	if (wpa_drv_send_mlme(wpa_s, buf, len, 0) < 0)
+		wpa_printf(MSG_INFO, "send_auth_reply: send_mlme failed: %s",
+			   strerror(errno));
+
+	os_free(buf);
+}
+
+
+/* initiate new SAE authentication with sta */
+int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s,
+			  struct sta_info *sta)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	struct wpabuf *buf;
+	unsigned int rnd;
+
+	if (!ssid) {
+		wpa_msg(wpa_s, MSG_DEBUG,
+			"AUTH: No current_ssid known to initiate new SAE");
+		return -1;
+	}
+
+	if (!sta->sae) {
+		sta->sae = os_zalloc(sizeof(*sta->sae));
+		if (sta->sae == NULL)
+			return -1;
+	}
+
+	buf = mesh_rsn_build_sae_commit(wpa_s, ssid, sta);
+	if (!buf)
+		return -1;
+
+	wpa_msg(wpa_s, MSG_DEBUG,
+		"AUTH: started authentication with SAE peer: " MACSTR,
+		MAC2STR(sta->addr));
+
+	sta->sae->state = SAE_COMMITTED;
+	wpa_supplicant_set_state(wpa_s, WPA_AUTHENTICATING);
+
+	mesh_rsn_send_auth(wpa_s, sta->addr, wpa_s->own_addr,
+			   1, WLAN_STATUS_SUCCESS, buf);
+
+	rnd = rand() % MESH_AUTH_TIMEOUT;
+	eloop_register_timeout(MESH_AUTH_TIMEOUT + rnd, 0, mesh_auth_timer,
+			       wpa_s, sta);
+	wpabuf_free(buf);
+
+	return 0;
+}
+
+
+void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid)
+{
+	/* don't expect wpa auth to cache the pmkid for now */
+	rsn_pmkid(sta->sae->pmk, PMK_LEN, rsn->wpa_s->own_addr,
+		  sta->addr, pmkid,
+		  wpa_key_mgmt_sha256(wpa_auth_sta_key_mgmt(sta->wpa_sm)));
+}
+
+
+static void
+mesh_rsn_derive_aek(struct mesh_rsn *rsn, struct sta_info *sta)
+{
+	u8 *myaddr = rsn->wpa_s->own_addr;
+	u8 *peer = sta->addr;
+	u8 *addr1 = peer, *addr2 = myaddr;
+	u8 context[AES_BLOCK_SIZE];
+
+	/* SAE */
+	RSN_SELECTOR_PUT(context, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+
+	if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
+		addr1 = myaddr;
+		addr2 = peer;
+	}
+	os_memcpy(context + 4, addr1, ETH_ALEN);
+	os_memcpy(context + 10, addr2, ETH_ALEN);
+
+	sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk), "AEK Derivation",
+		   context, sizeof(context), sta->aek, sizeof(sta->aek));
+}
+
+
+/* derive mesh temporal key from pmk */
+int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta)
+{
+	u8 *ptr;
+	u8 *min, *max;
+	u16 min_lid, max_lid;
+	size_t nonce_len = sizeof(sta->my_nonce);
+	size_t lid_len = sizeof(sta->my_lid);
+	u8 *myaddr = wpa_s->own_addr;
+	u8 *peer = sta->addr;
+	/* 2 nonces, 2 linkids, akm suite, 2 mac addrs */
+	u8 context[64 + 4 + 4 + 12];
+
+	ptr = context;
+	if (os_memcmp(sta->my_nonce, sta->peer_nonce, nonce_len) < 0) {
+		min = sta->my_nonce;
+		max = sta->peer_nonce;
+	} else {
+		min = sta->peer_nonce;
+		max = sta->my_nonce;
+	}
+	os_memcpy(ptr, min, nonce_len);
+	os_memcpy(ptr + nonce_len, max, nonce_len);
+	ptr += 2 * nonce_len;
+
+	if (sta->my_lid < sta->peer_lid) {
+		min_lid = host_to_le16(sta->my_lid);
+		max_lid = host_to_le16(sta->peer_lid);
+	} else {
+		min_lid = host_to_le16(sta->peer_lid);
+		max_lid = host_to_le16(sta->my_lid);
+	}
+	os_memcpy(ptr, &min_lid, lid_len);
+	os_memcpy(ptr + lid_len, &max_lid, lid_len);
+	ptr += 2 * lid_len;
+
+	/* SAE */
+	RSN_SELECTOR_PUT(ptr, wpa_cipher_to_suite(0, WPA_CIPHER_GCMP));
+	ptr += 4;
+
+	if (os_memcmp(myaddr, peer, ETH_ALEN) < 0) {
+		min = myaddr;
+		max = peer;
+	} else {
+		min = peer;
+		max = myaddr;
+	}
+	os_memcpy(ptr, min, ETH_ALEN);
+	os_memcpy(ptr + ETH_ALEN, max, ETH_ALEN);
+
+	sha256_prf(sta->sae->pmk, sizeof(sta->sae->pmk),
+		   "Temporal Key Derivation", context, sizeof(context),
+		   sta->mtk, sizeof(sta->mtk));
+	return 0;
+}
+
+
+void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta)
+{
+	if (random_get_bytes(sta->my_nonce, 32) < 0) {
+		wpa_printf(MSG_INFO, "mesh: Failed to derive random nonce");
+		/* TODO: How to handle this more cleanly? */
+	}
+	os_memset(sta->peer_nonce, 0, 32);
+	mesh_rsn_derive_aek(wpa_s->mesh_rsn, sta);
+}
+
+
+/* insert AMPE and encrypted MIC at @ie.
+ * @mesh_rsn: mesh RSN context
+ * @sta: STA we're sending to
+ * @cat: pointer to category code in frame header.
+ * @buf: wpabuf to add encrypted AMPE and MIC to.
+ * */
+int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
+			   const u8 *cat, struct wpabuf *buf)
+{
+	struct ieee80211_ampe_ie *ampe;
+	u8 const *ie = wpabuf_head_u8(buf) + wpabuf_len(buf);
+	u8 *ampe_ie = NULL, *mic_ie = NULL, *mic_payload;
+	const u8 *aad[] = { rsn->wpa_s->own_addr, sta->addr, cat };
+	const size_t aad_len[] = { ETH_ALEN, ETH_ALEN, ie - cat };
+	int ret = 0;
+
+	if (AES_BLOCK_SIZE + 2 + sizeof(*ampe) + 2 > wpabuf_tailroom(buf)) {
+		wpa_printf(MSG_ERROR, "protect frame: buffer too small");
+		return -EINVAL;
+	}
+
+	ampe_ie = os_zalloc(2 + sizeof(*ampe));
+	if (!ampe_ie) {
+		wpa_printf(MSG_ERROR, "protect frame: out of memory");
+		return -ENOMEM;
+	}
+
+	mic_ie = os_zalloc(2 + AES_BLOCK_SIZE);
+	if (!mic_ie) {
+		wpa_printf(MSG_ERROR, "protect frame: out of memory");
+		ret = -ENOMEM;
+		goto free;
+	}
+
+	/*  IE: AMPE */
+	ampe_ie[0] = WLAN_EID_AMPE;
+	ampe_ie[1] = sizeof(*ampe);
+	ampe = (struct ieee80211_ampe_ie *) (ampe_ie + 2);
+
+	RSN_SELECTOR_PUT(ampe->selected_pairwise_suite,
+		     wpa_cipher_to_suite(WPA_PROTO_RSN, WPA_CIPHER_CCMP));
+	os_memcpy(ampe->local_nonce, sta->my_nonce, 32);
+	os_memcpy(ampe->peer_nonce, sta->peer_nonce, 32);
+	/* incomplete: see 13.5.4 */
+	/* TODO: static mgtk for now since we don't support rekeying! */
+	os_memcpy(ampe->mgtk, rsn->mgtk, 16);
+	/*  TODO: Populate Key RSC */
+	/*  expire in 13 decades or so */
+	os_memset(ampe->key_expiration, 0xff, 4);
+
+	/* IE: MIC */
+	mic_ie[0] = WLAN_EID_MIC;
+	mic_ie[1] = AES_BLOCK_SIZE;
+	wpabuf_put_data(buf, mic_ie, 2);
+	/* MIC field is output ciphertext */
+
+	/* encrypt after MIC */
+	mic_payload = (u8 *) wpabuf_put(buf, 2 + sizeof(*ampe) +
+					AES_BLOCK_SIZE);
+
+	if (aes_siv_encrypt(sta->aek, ampe_ie, 2 + sizeof(*ampe), 3,
+			    aad, aad_len, mic_payload)) {
+		wpa_printf(MSG_ERROR, "protect frame: failed to encrypt");
+		ret = -ENOMEM;
+		goto free;
+	}
+
+free:
+	os_free(ampe_ie);
+	os_free(mic_ie);
+
+	return ret;
+}
+
+
+int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+			  struct ieee802_11_elems *elems, const u8 *cat,
+			  const u8 *start, size_t elems_len)
+{
+	int ret = 0;
+	struct ieee80211_ampe_ie *ampe;
+	u8 null_nonce[32] = {};
+	u8 ampe_eid;
+	u8 ampe_ie_len;
+	u8 *ampe_buf, *crypt = NULL;
+	size_t crypt_len;
+	const u8 *aad[] = { sta->addr, wpa_s->own_addr, cat };
+	const size_t aad_len[] = { ETH_ALEN, ETH_ALEN,
+				   (elems->mic - 2) - cat };
+
+	if (!elems->mic || elems->mic_len < AES_BLOCK_SIZE) {
+		wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing mic ie");
+		return -1;
+	}
+
+	ampe_buf = (u8 *) elems->mic + elems->mic_len;
+	if ((int) elems_len < ampe_buf - start)
+		return -1;
+
+	crypt_len = elems_len - (elems->mic - start);
+	if (crypt_len < 2) {
+		wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: missing ampe ie");
+		return -1;
+	}
+
+	/* crypt is modified by siv_decrypt */
+	crypt = os_zalloc(crypt_len);
+	if (!crypt) {
+		wpa_printf(MSG_ERROR, "Mesh RSN: out of memory");
+		ret = -ENOMEM;
+		goto free;
+	}
+
+	os_memcpy(crypt, elems->mic, crypt_len);
+
+	if (aes_siv_decrypt(sta->aek, crypt, crypt_len, 3,
+			    aad, aad_len, ampe_buf)) {
+		wpa_printf(MSG_ERROR, "Mesh RSN: frame verification failed!");
+		ret = -1;
+		goto free;
+	}
+
+	ampe_eid = *ampe_buf++;
+	ampe_ie_len = *ampe_buf++;
+
+	if (ampe_eid != WLAN_EID_AMPE ||
+	    ampe_ie_len < sizeof(struct ieee80211_ampe_ie)) {
+		wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid ampe ie");
+		ret = -1;
+		goto free;
+	}
+
+	ampe = (struct ieee80211_ampe_ie *) ampe_buf;
+	if (os_memcmp(ampe->peer_nonce, null_nonce, 32) != 0 &&
+	    os_memcmp(ampe->peer_nonce, sta->my_nonce, 32) != 0) {
+		wpa_msg(wpa_s, MSG_DEBUG, "Mesh RSN: invalid peer nonce");
+		ret = -1;
+		goto free;
+	}
+	os_memcpy(sta->peer_nonce, ampe->local_nonce,
+		  sizeof(ampe->local_nonce));
+	os_memcpy(sta->mgtk, ampe->mgtk, sizeof(ampe->mgtk));
+
+	/* todo parse mgtk expiration */
+free:
+	os_free(crypt);
+	return ret;
+}
diff --git a/wpa_supplicant/mesh_rsn.h b/wpa_supplicant/mesh_rsn.h
new file mode 100644
index 0000000..b1471b2
--- /dev/null
+++ b/wpa_supplicant/mesh_rsn.h
@@ -0,0 +1,36 @@
+/*
+ * WPA Supplicant - Mesh RSN routines
+ * Copyright (c) 2013-2014, cozybit, Inc.  All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MESH_RSN_H
+#define MESH_RSN_H
+
+struct mesh_rsn {
+	struct wpa_supplicant *wpa_s;
+	struct wpa_authenticator *auth;
+	u8 mgtk[16];
+#ifdef CONFIG_SAE
+	struct wpabuf *sae_token;
+	int sae_group_index;
+#endif /* CONFIG_SAE */
+};
+
+struct mesh_rsn * mesh_rsn_auth_init(struct wpa_supplicant *wpa_s,
+				     struct mesh_conf *conf);
+int mesh_rsn_auth_sae_sta(struct wpa_supplicant *wpa_s, struct sta_info *sta);
+int mesh_rsn_derive_mtk(struct wpa_supplicant *wpa_s, struct sta_info *sta);
+void mesh_rsn_get_pmkid(struct mesh_rsn *rsn, struct sta_info *sta, u8 *pmkid);
+void mesh_rsn_init_ampe_sta(struct wpa_supplicant *wpa_s,
+			    struct sta_info *sta);
+int mesh_rsn_protect_frame(struct mesh_rsn *rsn, struct sta_info *sta,
+			   const u8 *cat, struct wpabuf *buf);
+int mesh_rsn_process_ampe(struct wpa_supplicant *wpa_s, struct sta_info *sta,
+			  struct ieee802_11_elems *elems, const u8 *cat,
+			  const u8 *start, size_t elems_len);
+void mesh_auth_timer(void *eloop_ctx, void *user_data);
+
+#endif /* MESH_RSN_H */
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 617ce84..df1ce9e 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -48,6 +48,9 @@
 
 int wpas_notify_iface_added(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->p2p_mgmt)
+		return 0;
+
 	if (wpas_dbus_register_iface(wpa_s))
 		return -1;
 
@@ -60,6 +63,9 @@
 
 void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	/* unregister interface in old DBus ctrl iface */
 	wpas_dbus_unregister_iface(wpa_s);
 
@@ -72,6 +78,9 @@
 			       enum wpa_states new_state,
 			       enum wpa_states old_state)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	/* notify the old DBus API */
 	wpa_supplicant_dbus_notify_state_change(wpa_s, new_state,
 						old_state);
@@ -101,30 +110,45 @@
 
 void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON);
 }
 
 
 void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK);
 }
 
 
 void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AP_SCAN);
 }
 
 
 void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_BSS);
 }
 
 
 void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_AUTH_MODE);
 }
 
@@ -132,6 +156,9 @@
 void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
 					 struct wpa_ssid *ssid)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_signal_network_enabled_changed(wpa_s, ssid);
 }
 
@@ -139,6 +166,9 @@
 void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_signal_network_selected(wpa_s, ssid->id);
 }
 
@@ -148,12 +178,18 @@
 				 enum wpa_ctrl_req_type rtype,
 				 const char *default_txt)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_signal_network_request(wpa_s, ssid, rtype, default_txt);
 }
 
 
 void wpas_notify_scanning(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	/* notify the old DBus API */
 	wpa_supplicant_dbus_notify_scanning(wpa_s);
 
@@ -164,12 +200,18 @@
 
 void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_signal_scan_done(wpa_s, success);
 }
 
 
 void wpas_notify_scan_results(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	/* notify the old DBus API */
 	wpa_supplicant_dbus_notify_scan_results(wpa_s);
 
@@ -180,6 +222,9 @@
 void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s,
 				const struct wps_credential *cred)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 #ifdef CONFIG_WPS
 	/* notify the old DBus API */
 	wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred);
@@ -192,6 +237,9 @@
 void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s,
 			       struct wps_event_m2d *m2d)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 #ifdef CONFIG_WPS
 	wpas_dbus_signal_wps_event_m2d(wpa_s, m2d);
 #endif /* CONFIG_WPS */
@@ -201,6 +249,9 @@
 void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s,
 				struct wps_event_fail *fail)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 #ifdef CONFIG_WPS
 	wpas_dbus_signal_wps_event_fail(wpa_s, fail);
 #endif /* CONFIG_WPS */
@@ -209,6 +260,9 @@
 
 void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 #ifdef CONFIG_WPS
 	wpas_dbus_signal_wps_event_success(wpa_s);
 #endif /* CONFIG_WPS */
@@ -218,6 +272,9 @@
 void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
 			       struct wpa_ssid *ssid)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	/*
 	 * Networks objects created during any P2P activities should not be
 	 * exposed out. They might/will confuse certain non-P2P aware
@@ -250,12 +307,18 @@
 void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
 				 struct wpa_ssid *ssid)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	if (wpa_s->next_ssid == ssid)
 		wpa_s->next_ssid = NULL;
 	if (wpa_s->wpa)
 		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
 	if (!ssid->p2p_group && wpa_s->global->p2p_group_formation != wpa_s)
 		wpas_dbus_unregister_network(wpa_s, ssid->id);
+	if (network_is_persistent_group(ssid))
+		wpas_notify_persistent_group_removed(wpa_s, ssid);
+
 	wpas_p2p_network_removed(wpa_s, ssid);
 }
 
@@ -263,6 +326,9 @@
 void wpas_notify_bss_added(struct wpa_supplicant *wpa_s,
 			   u8 bssid[], unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_register_bss(wpa_s, bssid, id);
 	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_ADDED "%u " MACSTR,
 		     id, MAC2STR(bssid));
@@ -272,6 +338,9 @@
 void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s,
 			     u8 bssid[], unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_unregister_bss(wpa_s, bssid, id);
 	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_REMOVED "%u " MACSTR,
 		     id, MAC2STR(bssid));
@@ -281,6 +350,9 @@
 void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s,
 				  unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_FREQ, id);
 }
 
@@ -288,6 +360,9 @@
 void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s,
 				    unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_SIGNAL,
 					  id);
 }
@@ -296,6 +371,9 @@
 void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s,
 				     unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_PRIVACY,
 					  id);
 }
@@ -304,6 +382,9 @@
 void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s,
 				  unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_MODE, id);
 }
 
@@ -311,6 +392,9 @@
 void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s,
 				   unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPA, id);
 }
 
@@ -318,6 +402,9 @@
 void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
 				   unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RSN, id);
 }
 
@@ -325,6 +412,9 @@
 void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
 				 unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 #ifdef CONFIG_WPS
 	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPS, id);
 #endif /* CONFIG_WPS */
@@ -334,6 +424,9 @@
 void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
 				   unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_IES, id);
 }
 
@@ -341,24 +434,36 @@
 void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
 				   unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RATES, id);
 }
 
 
 void wpas_notify_bss_seen(struct wpa_supplicant *wpa_s, unsigned int id)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_AGE, id);
 }
 
 
 void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_signal_blob_added(wpa_s, name);
 }
 
 
 void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name)
 {
+	if (wpa_s->p2p_mgmt)
+		return;
+
 	wpas_dbus_signal_blob_removed(wpa_s, name);
 }
 
@@ -546,7 +651,8 @@
 	 * Create 'peer-joined' signal on group object -- will also
 	 * check P2P itself.
 	 */
-	wpas_dbus_signal_p2p_peer_joined(wpa_s, p2p_dev_addr);
+	if (p2p_dev_addr)
+		wpas_dbus_signal_p2p_peer_joined(wpa_s, p2p_dev_addr);
 #endif /* CONFIG_P2P */
 
 	/* Notify listeners a new station has been authorized */
@@ -563,7 +669,8 @@
 	 * Create 'peer-disconnected' signal on group object if this
 	 * is a P2P group.
 	 */
-	wpas_dbus_signal_p2p_peer_disconnected(wpa_s, p2p_dev_addr);
+	if (p2p_dev_addr)
+		wpas_dbus_signal_p2p_peer_disconnected(wpa_s, p2p_dev_addr);
 #endif /* CONFIG_P2P */
 
 	/* Notify listeners a station has been deauthorized */
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
index 17689c5..7a86347 100644
--- a/wpa_supplicant/offchannel.c
+++ b/wpa_supplicant/offchannel.c
@@ -31,8 +31,7 @@
 	 */
 	iface = wpa_s->global->ifaces;
 	while (iface) {
-		if (os_memcmp(wpa_s->pending_action_src,
-			      iface->own_addr, ETH_ALEN) == 0)
+		if (os_memcmp(src, iface->own_addr, ETH_ALEN) == 0)
 			break;
 		iface = iface->next;
 	}
@@ -85,6 +84,7 @@
 			   wpa_s->off_channel_freq,
 			   iface->assoc_freq);
 		if (without_roc && wpa_s->off_channel_freq == 0) {
+			unsigned int duration = 200;
 			/*
 			 * We may get here if wpas_send_action() found us to be
 			 * on the correct channel, but remain-on-channel cancel
@@ -92,9 +92,18 @@
 			 */
 			wpa_printf(MSG_DEBUG, "Off-channel: Schedule "
 				   "remain-on-channel to send Action frame");
+#ifdef CONFIG_TESTING_OPTIONS
+			if (wpa_s->extra_roc_dur) {
+				wpa_printf(MSG_DEBUG,
+					   "TESTING: Increase ROC duration %u -> %u",
+					   duration,
+					   duration + wpa_s->extra_roc_dur);
+				duration += wpa_s->extra_roc_dur;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 			if (wpa_drv_remain_on_channel(
-				    wpa_s, wpa_s->pending_action_freq, 200) <
-			    0) {
+				    wpa_s, wpa_s->pending_action_freq,
+				    duration) < 0) {
 				wpa_printf(MSG_DEBUG, "Off-channel: Failed to "
 					   "request driver to remain on "
 					   "channel (%u MHz) for Action Frame "
@@ -190,11 +199,13 @@
 			data, data_len, result);
 	}
 
+#ifdef CONFIG_P2P
 	if (wpa_s->p2p_long_listen > 0) {
 		/* Continue the listen */
 		wpa_printf(MSG_DEBUG, "P2P: Continuing long Listen state");
 		wpas_p2p_listen_start(wpa_s, wpa_s->p2p_long_listen);
 	}
+#endif /* CONFIG_P2P */
 }
 
 
@@ -262,8 +273,7 @@
 		struct wpa_supplicant *iface;
 		int ret;
 
-		iface = wpas_get_tx_interface(wpa_s,
-					      wpa_s->pending_action_src);
+		iface = wpas_get_tx_interface(wpa_s, src);
 		wpa_s->action_tx_wait_time = wait_time;
 
 		ret = wpa_drv_send_action(
@@ -315,6 +325,13 @@
 		wait_time = wpa_s->max_remain_on_chan;
 	else if (wait_time == 0)
 		wait_time = 20;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->extra_roc_dur) {
+		wpa_printf(MSG_DEBUG, "TESTING: Increase ROC duration %u -> %u",
+			   wait_time, wait_time + wpa_s->extra_roc_dur);
+		wait_time += wpa_s->extra_roc_dur;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
 	if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
 		wpa_printf(MSG_DEBUG, "Off-channel: Failed to request driver "
 			   "to remain on channel (%u MHz) for Action "
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 640154c..42e5014 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -119,7 +119,7 @@
 static void wpas_p2p_group_freq_conflict(void *eloop_ctx, void *timeout_ctx);
 static void wpas_p2p_fallback_to_go_neg(struct wpa_supplicant *wpa_s,
 					int group_added);
-static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
+static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s);
 static void wpas_stop_listen(void *ctx);
 static void wpas_p2p_psk_failure_removal(void *eloop_ctx, void *timeout_ctx);
 static void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
@@ -269,9 +269,11 @@
 	work->ctx = NULL;
 	if (ret) {
 		radio_work_done(work);
+		p2p_notify_scan_trigger_status(wpa_s->global->p2p, ret);
 		return;
 	}
 
+	p2p_notify_scan_trigger_status(wpa_s->global->p2p, ret);
 	os_get_reltime(&wpa_s->scan_trigger_time);
 	wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
 	wpa_s->own_scan_requested = 1;
@@ -279,6 +281,22 @@
 }
 
 
+static int wpas_p2p_search_social_channel(struct wpa_supplicant *wpa_s,
+					  int freq)
+{
+	if (wpa_s->global->p2p_24ghz_social_channels &&
+	    (freq == 2412 || freq == 2437 || freq == 2462)) {
+		/*
+		 * Search all social channels regardless of whether these have
+		 * been disabled for P2P operating channel use to avoid missing
+		 * peers.
+		 */
+		return 1;
+	}
+	return p2p_supported_freq(wpa_s->global->p2p, freq);
+}
+
+
 static int wpas_p2p_scan(void *ctx, enum p2p_scan_type type, int freq,
 			 unsigned int num_req_dev_types,
 			 const u8 *req_dev_types, const u8 *dev_id, u16 pw_id)
@@ -348,8 +366,8 @@
 		if (params->freqs == NULL)
 			goto fail;
 		for (i = 0; i < ARRAY_SIZE(social_channels_freq); i++) {
-			if (p2p_supported_freq(wpa_s->global->p2p,
-					       social_channels_freq[i]))
+			if (wpas_p2p_search_social_channel(
+				    wpa_s, social_channels_freq[i]))
 				params->freqs[num_channels++] =
 					social_channels_freq[i];
 		}
@@ -363,8 +381,8 @@
 		if (params->freqs == NULL)
 			goto fail;
 		for (i = 0; i < ARRAY_SIZE(social_channels_freq); i++) {
-			if (p2p_supported_freq(wpa_s->global->p2p,
-					       social_channels_freq[i]))
+			if (wpas_p2p_search_social_channel(
+				    wpa_s, social_channels_freq[i]))
 				params->freqs[num_channels++] =
 					social_channels_freq[i];
 		}
@@ -426,6 +444,37 @@
 }
 
 
+static void run_wpas_p2p_disconnect(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	wpa_printf(MSG_DEBUG,
+		   "P2P: Complete previously requested removal of %s",
+		   wpa_s->ifname);
+	wpas_p2p_disconnect(wpa_s);
+}
+
+
+static int wpas_p2p_disconnect_safely(struct wpa_supplicant *wpa_s,
+				      struct wpa_supplicant *calling_wpa_s)
+{
+	if (calling_wpa_s == wpa_s && wpa_s &&
+	    wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+		/*
+		 * The calling wpa_s instance is going to be removed. Do that
+		 * from an eloop callback to keep the instance available until
+		 * the caller has returned. This my be needed, e.g., to provide
+		 * control interface responses on the per-interface socket.
+		 */
+		if (eloop_register_timeout(0, 0, run_wpas_p2p_disconnect,
+					   wpa_s, NULL) < 0)
+			return -1;
+		return 0;
+	}
+
+	return wpas_p2p_disconnect(wpa_s);
+}
+
+
 static int wpas_p2p_group_delete(struct wpa_supplicant *wpa_s,
 				 enum p2p_group_removal_reason removal_reason)
 {
@@ -467,8 +516,17 @@
 	if (removal_reason != P2P_GROUP_REMOVAL_SILENT && ssid)
 		wpas_notify_p2p_group_removed(wpa_s, ssid, gtype);
 
-	if (os_strcmp(gtype, "client") == 0)
+	if (os_strcmp(gtype, "client") == 0) {
 		wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+		if (eloop_is_timeout_registered(wpas_p2p_psk_failure_removal,
+						wpa_s, NULL)) {
+			wpa_printf(MSG_DEBUG,
+				   "P2P: PSK failure removal was scheduled, so use PSK failure as reason for group removal");
+			removal_reason = P2P_GROUP_REMOVAL_PSK_FAILURE;
+			eloop_cancel_timeout(wpas_p2p_psk_failure_removal,
+					     wpa_s, NULL);
+		}
+	}
 
 	if (wpa_s->cross_connect_in_use) {
 		wpa_s->cross_connect_in_use = 0;
@@ -536,6 +594,7 @@
 		global = wpa_s->global;
 		ifname = os_strdup(wpa_s->ifname);
 		type = wpas_p2p_if_type(wpa_s->p2p_group_interface);
+		eloop_cancel_timeout(run_wpas_p2p_disconnect, wpa_s, NULL);
 		wpa_supplicant_remove_iface(wpa_s->global, wpa_s, 0);
 		wpa_s = global->ifaces;
 		if (wpa_s && ifname)
@@ -553,6 +612,10 @@
 	os_free(wpa_s->go_params);
 	wpa_s->go_params = NULL;
 
+	os_free(wpa_s->p2p_group_common_freqs);
+	wpa_s->p2p_group_common_freqs = NULL;
+	wpa_s->p2p_group_common_freqs_num = 0;
+
 	wpa_s->waiting_presence_resp = 0;
 
 	wpa_printf(MSG_DEBUG, "P2P: Remove temporary group network");
@@ -882,6 +945,7 @@
 		wpa_s->p2p_in_provisioning = 0;
 	}
 	wpa_s->p2p_in_invitation = 0;
+	wpa_s->group_formation_reported = 1;
 
 	if (!success) {
 		wpa_msg_global(wpa_s->parent, MSG_INFO,
@@ -1169,6 +1233,7 @@
 static void wpas_start_wps_enrollee(struct wpa_supplicant *wpa_s,
 				    struct p2p_go_neg_results *res)
 {
+	wpa_s->group_formation_reported = 0;
 	wpa_printf(MSG_DEBUG, "P2P: Start WPS Enrollee for peer " MACSTR
 		   " dev_addr " MACSTR " wps_method %d",
 		   MAC2STR(res->peer_interface_addr),
@@ -1239,6 +1304,40 @@
 }
 
 
+static void p2p_go_dump_common_freqs(struct wpa_supplicant *wpa_s)
+{
+	unsigned int i;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Common group frequencies (len=%u):",
+		wpa_s->p2p_group_common_freqs_num);
+
+	for (i = 0; i < wpa_s->p2p_group_common_freqs_num; i++)
+		wpa_dbg(wpa_s, MSG_DEBUG, "freq[%u]: %d",
+			i, wpa_s->p2p_group_common_freqs[i]);
+}
+
+
+static void p2p_go_save_group_common_freqs(struct wpa_supplicant *wpa_s,
+					   struct p2p_go_neg_results *params)
+{
+	unsigned int i, len = int_array_len(wpa_s->go_params->freq_list);
+
+	wpa_s->p2p_group_common_freqs_num = 0;
+	os_free(wpa_s->p2p_group_common_freqs);
+	wpa_s->p2p_group_common_freqs = os_calloc(len, sizeof(int));
+	if (!wpa_s->p2p_group_common_freqs)
+		return;
+
+	for (i = 0; i < len; i++) {
+		if (!wpa_s->go_params->freq_list[i])
+			break;
+		wpa_s->p2p_group_common_freqs[i] =
+			wpa_s->go_params->freq_list[i];
+	}
+	wpa_s->p2p_group_common_freqs_num = i;
+}
+
+
 static void p2p_go_configured(void *ctx, void *data)
 {
 	struct wpa_supplicant *wpa_s = ctx;
@@ -1246,6 +1345,9 @@
 	struct wpa_ssid *ssid;
 	int network_id = -1;
 
+	p2p_go_save_group_common_freqs(wpa_s, params);
+	p2p_go_dump_common_freqs(wpa_s);
+
 	ssid = wpa_s->current_ssid;
 	if (ssid && ssid->mode == WPAS_MODE_P2P_GO) {
 		wpa_printf(MSG_DEBUG, "P2P: Group setup without provisioning");
@@ -1257,6 +1359,7 @@
 				       params->passphrase,
 				       wpa_s->global->p2p_dev_addr,
 				       params->persistent_group, "");
+		wpa_s->group_formation_reported = 1;
 
 		os_get_reltime(&wpa_s->global->p2p_go_wait_client);
 		if (params->persistent_group) {
@@ -1340,6 +1443,8 @@
 	}
 
 	wpa_s->show_group_started = 0;
+	wpa_s->p2p_go_group_formation_completed = 0;
+	wpa_s->group_formation_reported = 0;
 
 	wpa_config_set_network_defaults(ssid);
 	ssid->temporary = 1;
@@ -1359,6 +1464,15 @@
 	ssid->key_mgmt = WPA_KEY_MGMT_PSK;
 	ssid->proto = WPA_PROTO_RSN;
 	ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+	ssid->group_cipher = WPA_CIPHER_CCMP;
+	if (params->freq > 56160) {
+		/*
+		 * Enable GCMP instead of CCMP as pairwise_cipher and
+		 * group_cipher in 60 GHz.
+		 */
+		ssid->pairwise_cipher = WPA_CIPHER_GCMP;
+		ssid->group_cipher = WPA_CIPHER_GCMP;
+	}
 	if (os_strlen(params->passphrase) > 0) {
 		ssid->passphrase = os_strdup(params->passphrase);
 		if (ssid->passphrase == NULL) {
@@ -1443,8 +1557,12 @@
 	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) {
+		int res;
+
 		/* Try to avoid going over the IFNAMSIZ length limit */
-		os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx);
+		res = os_snprintf(ifname, len, "p2p-%d", wpa_s->p2p_group_idx);
+		if (os_snprintf_error(len, res) && len)
+			ifname[len - 1] = '\0';
 	}
 }
 
@@ -1721,7 +1839,7 @@
 	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%s",
+		       "dev_capab=0x%x group_capab=0x%x%s%s%s new=%d",
 		       MAC2STR(addr), MAC2STR(info->p2p_device_addr),
 		       wps_dev_type_bin2str(info->pri_dev_type, devtype,
 					    sizeof(devtype)),
@@ -1729,7 +1847,8 @@
 		       info->dev_capab, info->group_capab,
 		       wfd_dev_info_hex ? " wfd_dev_info=0x" : "",
 		       wfd_dev_info_hex ? wfd_dev_info_hex : "",
-		       info->vendor_elems ? " vendor_elems=1" : "");
+		       info->vendor_elems ? " vendor_elems=1" : "",
+		       new_device);
 
 	os_free(wfd_dev_info_hex);
 #endif /* CONFIG_NO_STDOUT_DEBUG */
@@ -1790,6 +1909,7 @@
 {
 	struct wpa_supplicant *wpa_s = work->wpa_s;
 	struct wpas_p2p_listen_work *lwork = work->ctx;
+	unsigned int duration;
 
 	if (deinit) {
 		if (work->started) {
@@ -1814,8 +1934,16 @@
 	wpa_s->pending_listen_freq = lwork->freq;
 	wpa_s->pending_listen_duration = lwork->duration;
 
-	if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, lwork->duration) < 0)
-	{
+	duration = lwork->duration;
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->extra_roc_dur) {
+		wpa_printf(MSG_DEBUG, "TESTING: Increase ROC duration %u -> %u",
+			   duration, duration + wpa_s->extra_roc_dur);
+		duration += wpa_s->extra_roc_dur;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	if (wpa_drv_remain_on_channel(wpa_s, lwork->freq, duration) < 0) {
 		wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver "
 			   "to remain on channel (%u MHz) for Listen "
 			   "state", lwork->freq);
@@ -2824,6 +2952,7 @@
 	u8 empty_dev_type[8];
 	unsigned int generated_pin = 0;
 	struct wpa_supplicant *group = NULL;
+	int res;
 
 	if (group_id) {
 		for (group = wpa_s->global->ifaces; group; group = group->next)
@@ -2842,15 +2971,17 @@
 		os_memset(empty_dev_type, 0, sizeof(empty_dev_type));
 		pri_dev_type = empty_dev_type;
 	}
-	os_snprintf(params, sizeof(params), " 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(dev_addr),
-		    wps_dev_type_bin2str(pri_dev_type, devtype,
-					 sizeof(devtype)),
-		    dev_name, supp_config_methods, dev_capab, group_capab,
-		    group ? " group=" : "",
-		    group ? group->ifname : "");
+	res = os_snprintf(params, sizeof(params), " 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(dev_addr),
+			  wps_dev_type_bin2str(pri_dev_type, devtype,
+					       sizeof(devtype)),
+			  dev_name, supp_config_methods, dev_capab, group_capab,
+			  group ? " group=" : "",
+			  group ? group->ifname : "");
+	if (os_snprintf_error(sizeof(params), res))
+		wpa_printf(MSG_DEBUG, "P2P: PD Request event truncated");
 	params[sizeof(params) - 1] = '\0';
 
 	if (config_methods & WPS_CONFIG_DISPLAY) {
@@ -2886,10 +3017,14 @@
 	}
 
 	if (wpa_s->pending_pd_use == AUTO_PD_JOIN ||
-	    wpa_s->pending_pd_use == AUTO_PD_GO_NEG)
-		os_snprintf(params, sizeof(params), " peer_go=%d",
-			    wpa_s->pending_pd_use == AUTO_PD_JOIN);
-	else
+	    wpa_s->pending_pd_use == AUTO_PD_GO_NEG) {
+		int res;
+
+		res = os_snprintf(params, sizeof(params), " peer_go=%d",
+				  wpa_s->pending_pd_use == AUTO_PD_JOIN);
+		if (os_snprintf_error(sizeof(params), res))
+			params[sizeof(params) - 1] = '\0';
+	} else
 		params[0] = '\0';
 
 	if (config_methods & WPS_CONFIG_DISPLAY)
@@ -3369,6 +3504,8 @@
 {
 	int i, cla = 0;
 
+	wpa_s->global->p2p_24ghz_social_channels = 1;
+
 	os_memset(cli_chan, 0, sizeof(*cli_chan));
 
 	wpa_printf(MSG_DEBUG, "P2P: Enable operating classes for 2.4 GHz "
@@ -3439,7 +3576,7 @@
 
 
 enum chan_allowed {
-	NOT_ALLOWED, PASSIVE_ONLY, ALLOWED
+	NOT_ALLOWED, NO_IR, ALLOWED
 };
 
 static int has_channel(struct wpa_global *global,
@@ -3461,10 +3598,8 @@
 			    (HOSTAPD_CHAN_DISABLED |
 			     HOSTAPD_CHAN_RADAR))
 				return NOT_ALLOWED;
-			if (mode->channels[i].flag &
-			    (HOSTAPD_CHAN_PASSIVE_SCAN |
-			     HOSTAPD_CHAN_NO_IBSS))
-				return PASSIVE_ONLY;
+			if (mode->channels[i].flag & HOSTAPD_CHAN_NO_IR)
+				return NO_IR;
 			return ALLOWED;
 		}
 	}
@@ -3553,8 +3688,8 @@
 		res = has_channel(wpa_s->global, mode, adj_chan, &flags);
 		if (res == NOT_ALLOWED)
 			return NOT_ALLOWED;
-		if (res == PASSIVE_ONLY)
-			ret = PASSIVE_ONLY;
+		if (res == NO_IR)
+			ret = NO_IR;
 
 		if (i == 0 && !(flags & HOSTAPD_CHAN_VHT_10_70))
 			return NOT_ALLOWED;
@@ -3592,8 +3727,8 @@
 
 	if (res == NOT_ALLOWED || res2 == NOT_ALLOWED)
 		return NOT_ALLOWED;
-	if (res == PASSIVE_ONLY || res2 == PASSIVE_ONLY)
-		return PASSIVE_ONLY;
+	if (res == NO_IR || res2 == NO_IR)
+		return NO_IR;
 	return res;
 }
 
@@ -3622,6 +3757,8 @@
 		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
 		if (mode == NULL)
 			continue;
+		if (mode->mode == HOSTAPD_MODE_IEEE80211G)
+			wpa_s->global->p2p_24ghz_social_channels = 1;
 		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
 			enum chan_allowed res;
 			res = wpas_p2p_verify_channel(wpa_s, mode, ch, o->bw);
@@ -3635,7 +3772,7 @@
 				}
 				reg->channel[reg->channels] = ch;
 				reg->channels++;
-			} else if (res == PASSIVE_ONLY &&
+			} else if (res == NO_IR &&
 				   wpa_s->conf->p2p_add_cli_chan) {
 				if (cli_reg == NULL) {
 					wpa_printf(MSG_DEBUG, "P2P: Add operating class %u (client only)",
@@ -3795,8 +3932,10 @@
 	char force_name[100];
 	int ret;
 
-	os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
-		    wpa_s->ifname);
+	ret = os_snprintf(ifname, sizeof(ifname), P2P_MGMT_DEVICE_PREFIX "%s",
+			  wpa_s->ifname);
+	if (os_snprintf_error(sizeof(ifname), ret))
+		return -1;
 	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,
@@ -3833,6 +3972,7 @@
 		return -1;
 	}
 	p2pdev_wpa_s->parent = wpa_s;
+	wpa_s->p2p_dev = p2pdev_wpa_s;
 
 	wpa_s->pending_interface_name[0] = '\0';
 	return 0;
@@ -4079,6 +4219,10 @@
 	wpabuf_free(wpa_s->p2p_oob_dev_pw);
 	wpa_s->p2p_oob_dev_pw = NULL;
 
+	os_free(wpa_s->p2p_group_common_freqs);
+	wpa_s->p2p_group_common_freqs = NULL;
+	wpa_s->p2p_group_common_freqs_num = 0;
+
 	/* TODO: remove group interface from the driver if this wpa_s instance
 	 * is on top of a P2P group interface */
 }
@@ -4837,8 +4981,10 @@
 		os_strlcpy(wpa_s->p2p_pin, pin, sizeof(wpa_s->p2p_pin));
 	else if (wps_method == WPS_PIN_DISPLAY) {
 		ret = wps_generate_pin();
-		os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin), "%08d",
-			    ret);
+		res = os_snprintf(wpa_s->p2p_pin, sizeof(wpa_s->p2p_pin),
+				  "%08d", ret);
+		if (os_snprintf_error(sizeof(wpa_s->p2p_pin), res))
+			wpa_s->p2p_pin[sizeof(wpa_s->p2p_pin) - 1] = '\0';
 		wpa_printf(MSG_DEBUG, "P2P: Randomly generated PIN: %s",
 			   wpa_s->p2p_pin);
 	} else
@@ -5007,6 +5153,7 @@
 int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname)
 {
 	struct wpa_global *global = wpa_s->global;
+	struct wpa_supplicant *calling_wpa_s = wpa_s;
 
 	if (os_strcmp(ifname, "*") == 0) {
 		struct wpa_supplicant *prev;
@@ -5018,7 +5165,7 @@
 			    NOT_P2P_GROUP_INTERFACE ||
 			    (prev->current_ssid &&
 			     prev->current_ssid->p2p_group))
-				wpas_p2p_disconnect(prev);
+				wpas_p2p_disconnect_safely(prev, calling_wpa_s);
 		}
 		return 0;
 	}
@@ -5028,7 +5175,7 @@
 			break;
 	}
 
-	return wpas_p2p_disconnect(wpa_s);
+	return wpas_p2p_disconnect_safely(wpa_s, calling_wpa_s);
 }
 
 
@@ -5438,13 +5585,21 @@
 
 	wpa_s->p2p_fallback_to_go_neg = 0;
 
-	if (force_freq > 0) {
-		freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
-		if (freq < 0)
-			return -1;
+	if (ssid->mode == WPAS_MODE_P2P_GO) {
+		if (force_freq > 0) {
+			freq = wpas_p2p_select_go_freq(wpa_s, force_freq);
+			if (freq < 0)
+				return -1;
+		} else {
+			freq = wpas_p2p_select_go_freq(wpa_s, neg_freq);
+			if (freq < 0 ||
+			    (freq > 0 && !freq_included(channels, freq)))
+				freq = 0;
+		}
 	} else {
-		freq = wpas_p2p_select_go_freq(wpa_s, neg_freq);
-		if (freq < 0 || (freq > 0 && !freq_included(channels, freq)))
+		freq = neg_freq;
+		if (freq < 0 ||
+		    (freq > 0 && !freq_included(channels, freq)))
 			freq = 0;
 	}
 
@@ -5478,6 +5633,8 @@
 	if (wpa_s == NULL)
 		return -1;
 
+	p2p_channels_to_freqs(channels, params.freq_list, P2P_MAX_CHANNELS);
+
 	wpa_s->p2p_first_connection_timeout = connection_timeout;
 	wpas_start_wps_go(wpa_s, &params, 0);
 
@@ -5757,7 +5914,29 @@
 }
 
 
-static int wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
+static void wpas_p2p_scan_res_ignore_search(struct wpa_supplicant *wpa_s,
+					    struct wpa_scan_results *scan_res)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Ignore scan results");
+
+	if (wpa_s->p2p_scan_work) {
+		struct wpa_radio_work *work = wpa_s->p2p_scan_work;
+		wpa_s->p2p_scan_work = NULL;
+		radio_work_done(work);
+	}
+
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return;
+
+	/*
+	 * Indicate that results have been processed so that the P2P module can
+	 * continue pending tasks.
+	 */
+	p2p_scan_res_handled(wpa_s->global->p2p);
+}
+
+
+static void wpas_p2p_stop_find_oper(struct wpa_supplicant *wpa_s)
 {
 	wpas_p2p_clear_pending_action_tx(wpa_s);
 	wpa_s->p2p_long_listen = 0;
@@ -5767,14 +5946,17 @@
 	if (wpa_s->global->p2p)
 		p2p_stop_find(wpa_s->global->p2p);
 
-	return 0;
+	if (wpa_s->scan_res_handler == wpas_p2p_scan_res_handler) {
+		wpa_printf(MSG_DEBUG,
+			   "P2P: Do not consider the scan results after stop_find");
+		wpa_s->scan_res_handler = wpas_p2p_scan_res_ignore_search;
+	}
 }
 
 
 void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s)
 {
-	if (wpas_p2p_stop_find_oper(wpa_s) > 0)
-		return;
+	wpas_p2p_stop_find_oper(wpa_s);
 	wpas_p2p_remove_pending_group_interface(wpa_s);
 }
 
@@ -6100,11 +6282,16 @@
 
 	ip_addr[0] = '\0';
 	if (wpa_sm_get_p2p_ip_addr(wpa_s->wpa, ip) == 0) {
-		os_snprintf(ip_addr, sizeof(ip_addr), " ip_addr=%u.%u.%u.%u "
-			    "ip_mask=%u.%u.%u.%u go_ip_addr=%u.%u.%u.%u",
-			    ip[0], ip[1], ip[2], ip[3],
-			    ip[4], ip[5], ip[6], ip[7],
-			    ip[8], ip[9], ip[10], ip[11]);
+		int res;
+
+		res = os_snprintf(ip_addr, sizeof(ip_addr),
+				  " ip_addr=%u.%u.%u.%u "
+				  "ip_mask=%u.%u.%u.%u go_ip_addr=%u.%u.%u.%u",
+				  ip[0], ip[1], ip[2], ip[3],
+				  ip[4], ip[5], ip[6], ip[7],
+				  ip[8], ip[9], ip[10], ip[11]);
+		if (os_snprintf_error(sizeof(ip_addr), res))
+			ip_addr[0] = '\0';
 	}
 
 	wpas_p2p_group_started(wpa_s, 0, ssid, freq,
@@ -6546,7 +6733,8 @@
 		if (iface->drv_flags &
 		    WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)
 			continue;
-		if (iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE)
+		if ((iface->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE) &&
+		    iface != wpa_s->parent)
 			continue;
 
 		wpa_s->cross_connect_enabled = 1;
@@ -6885,6 +7073,20 @@
 		 * provisioning step.
 		 */
 		wpa_printf(MSG_DEBUG, "P2P: Canceled P2P group formation timeout on data connection");
+
+		if (!wpa_s->p2p_go_group_formation_completed &&
+		    !wpa_s->group_formation_reported) {
+			/*
+			 * GO has not yet notified group formation success since
+			 * the WPS step was not completed cleanly. Do that
+			 * notification now since the P2P Client was able to
+			 * connect and as such, must have received the
+			 * credential from the WPS step.
+			 */
+			if (wpa_s->global->p2p)
+				p2p_wps_success_cb(wpa_s->global->p2p, addr);
+			wpas_group_formation_completed(wpa_s, 1);
+		}
 	}
 	if (!wpa_s->p2p_go_group_formation_completed) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Marking group formation completed on GO on first data connection");
@@ -7573,7 +7775,7 @@
 	}
 	len = WPA_GET_BE16(pos);
 	pos += 2;
-	if (pos + len > end) {
+	if (len > end - pos) {
 		wpa_printf(MSG_DEBUG, "P2P: Not enough data for WSC "
 			   "attributes");
 		return -1;
@@ -7589,7 +7791,7 @@
 	}
 	len = WPA_GET_BE16(pos);
 	pos += 2;
-	if (pos + len > end) {
+	if (len > end - pos) {
 		wpa_printf(MSG_DEBUG, "P2P: Not enough data for P2P "
 			   "attributes");
 		return -1;
@@ -7921,8 +8123,6 @@
 
 void wpas_p2p_deinit_iface(struct wpa_supplicant *wpa_s)
 {
-	if (wpa_s == wpa_s->parent)
-		wpas_p2p_group_remove(wpa_s, "*");
 	if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
 			"the management interface is being removed");
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 8e23c18..9f5a83b 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -29,7 +29,6 @@
 		     int pd, int ht40, int vht);
 int wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
                                           int freq, struct wpa_ssid *ssid);
-int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
 		       int freq, int ht40, int vht);
 int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
@@ -171,6 +170,7 @@
 int wpas_p2p_wps_eapol_cb(struct wpa_supplicant *wpa_s);
 void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
 			 struct wps_event_fail *fail);
+int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
 
 #else /* CONFIG_P2P */
 
@@ -294,6 +294,12 @@
 {
 }
 
+static inline int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s,
+					const char *ifname)
+{
+	return 0;
+}
+
 #endif /* CONFIG_P2P */
 
 #endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index debceb9..cb2c8d6 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -22,6 +22,7 @@
 #include "notify.h"
 #include "bss.h"
 #include "scan.h"
+#include "mesh.h"
 
 
 static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
@@ -175,6 +176,8 @@
 	if (ret) {
 		wpa_supplicant_notify_scanning(wpa_s, 0);
 		wpas_notify_scan_done(wpa_s, 0);
+		wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_FAILED "ret=%d",
+			     ret);
 		radio_work_done(work);
 		return;
 	}
@@ -291,7 +294,7 @@
 	}
 	if (count == 0)
 		return NULL;
-	ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter));
+	ssids = os_calloc(count, sizeof(struct wpa_driver_scan_filter));
 	if (ssids == NULL)
 		return NULL;
 
@@ -319,7 +322,7 @@
 			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO "
 				"preferred frequency %d MHz",
 				wpa_s->go_params->freq);
-			params->freqs = os_zalloc(2 * sizeof(int));
+			params->freqs = os_calloc(2, sizeof(int));
 			if (params->freqs)
 				params->freqs[0] = wpa_s->go_params->freq;
 		} else if (wpa_s->p2p_in_provisioning < 8 &&
@@ -343,7 +346,7 @@
 		    wpa_s->p2p_invite_go_freq > 0) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO preferred frequency %d MHz during invitation",
 				wpa_s->p2p_invite_go_freq);
-			params->freqs = os_zalloc(2 * sizeof(int));
+			params->freqs = os_calloc(2, sizeof(int));
 			if (params->freqs)
 				params->freqs[0] = wpa_s->p2p_invite_go_freq;
 		}
@@ -369,7 +372,7 @@
 		 */
 		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz "
 			"that was used during provisioning", wpa_s->wps_freq);
-		params->freqs = os_zalloc(2 * sizeof(int));
+		params->freqs = os_calloc(2, sizeof(int));
 		if (params->freqs)
 			params->freqs[0] = wpa_s->wps_freq;
 		wpa_s->after_wps--;
@@ -381,7 +384,7 @@
 		/* Optimize provisioning scan based on already known channel */
 		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz",
 			wpa_s->wps_freq);
-		params->freqs = os_zalloc(2 * sizeof(int));
+		params->freqs = os_calloc(2, sizeof(int));
 		if (params->freqs)
 			params->freqs[0] = wpa_s->wps_freq;
 		wpa_s->known_wps_freq = 0; /* only do this once */
@@ -460,6 +463,8 @@
 	}
 #endif /* CONFIG_P2P */
 
+	wpa_supplicant_mesh_add_scan_ie(wpa_s, &extra_ie);
+
 #endif /* CONFIG_WPS */
 
 #ifdef CONFIG_HS20
@@ -528,7 +533,7 @@
 		return;
 	}
 
-	params->freqs = os_zalloc((mode->num_channels + 1) * sizeof(int));
+	params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
 	if (params->freqs == NULL)
 		return;
 	for (count = 0, i = 0; i < mode->num_channels; i++) {
@@ -600,7 +605,7 @@
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	struct wpa_ssid *ssid;
-	int ret;
+	int ret, p2p_in_prog;
 	struct wpabuf *extra_ie = NULL;
 	struct wpa_driver_scan_params params;
 	struct wpa_driver_scan_params *scan_params;
@@ -653,7 +658,8 @@
 		return;
 	}
 
-	if (wpas_p2p_in_progress(wpa_s)) {
+	p2p_in_prog = wpas_p2p_in_progress(wpa_s);
+	if (p2p_in_prog && p2p_in_prog != 2) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan while P2P operation is in progress");
 		wpa_supplicant_req_scan(wpa_s, 5, 0);
 		return;
@@ -810,7 +816,9 @@
 		    wpa_s->last_scan_req == MANUAL_SCAN_REQ)
 			wpa_set_scan_ssids(wpa_s, &params, max_ssids);
 
-		for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
+		for (tssid = wpa_s->conf->ssid;
+		     wpa_s->last_scan_req != MANUAL_SCAN_REQ && tssid;
+		     tssid = tssid->next) {
 			if (wpas_network_disabled(wpa_s, tssid))
 				continue;
 			if ((params.freqs || !freqs_set) && tssid->scan_freq) {
@@ -930,6 +938,14 @@
 	}
 #endif /* CONFIG_P2P */
 
+	if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCAN) {
+		params.mac_addr_rand = 1;
+		if (wpa_s->mac_addr_scan) {
+			params.mac_addr = wpa_s->mac_addr_scan;
+			params.mac_addr_mask = wpa_s->mac_addr_scan + ETH_ALEN;
+		}
+	}
+
 	scan_params = &params;
 
 scan:
@@ -1145,7 +1161,7 @@
 	os_memset(&params, 0, sizeof(params));
 
 	/* If we can't allocate space for the filters, we just don't filter */
-	params.filter_ssids = os_zalloc(wpa_s->max_match_sets *
+	params.filter_ssids = os_calloc(wpa_s->max_match_sets,
 					sizeof(struct wpa_driver_scan_filter));
 
 	prev_state = wpa_s->wpa_state;
@@ -1273,6 +1289,15 @@
 
 	wpa_setband_scan_freqs(wpa_s, scan_params);
 
+	if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_SCHED_SCAN) {
+		params.mac_addr_rand = 1;
+		if (wpa_s->mac_addr_sched_scan) {
+			params.mac_addr = wpa_s->mac_addr_sched_scan;
+			params.mac_addr_mask = wpa_s->mac_addr_sched_scan +
+				ETH_ALEN;
+		}
+	}
+
 	ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
 					      wpa_s->sched_scan_interval);
 	wpabuf_free(extra_ie);
@@ -1918,6 +1943,23 @@
 	params->only_new_results = src->only_new_results;
 	params->low_priority = src->low_priority;
 
+	if (src->mac_addr_rand) {
+		params->mac_addr_rand = src->mac_addr_rand;
+
+		if (src->mac_addr && src->mac_addr_mask) {
+			u8 *mac_addr;
+
+			mac_addr = os_malloc(2 * ETH_ALEN);
+			if (!mac_addr)
+				goto failed;
+
+			os_memcpy(mac_addr, src->mac_addr, ETH_ALEN);
+			os_memcpy(mac_addr + ETH_ALEN, src->mac_addr_mask,
+				  ETH_ALEN);
+			params->mac_addr = mac_addr;
+			params->mac_addr_mask = mac_addr + ETH_ALEN;
+		}
+	}
 	return params;
 
 failed:
@@ -1938,6 +1980,13 @@
 	os_free((u8 *) params->extra_ies);
 	os_free(params->freqs);
 	os_free(params->filter_ssids);
+
+	/*
+	 * Note: params->mac_addr_mask points to same memory allocation and
+	 * must not be freed separately.
+	 */
+	os_free((u8 *) params->mac_addr);
+
 	os_free(params);
 }
 
@@ -2042,6 +2091,14 @@
 		params.freqs = wpa_s->manual_sched_scan_freqs;
 	}
 
+	if (wpa_s->mac_addr_rand_enable & MAC_ADDR_RAND_PNO) {
+		params.mac_addr_rand = 1;
+		if (wpa_s->mac_addr_pno) {
+			params.mac_addr = wpa_s->mac_addr_pno;
+			params.mac_addr_mask = wpa_s->mac_addr_pno + ETH_ALEN;
+		}
+	}
+
 	ret = wpa_supplicant_start_sched_scan(wpa_s, &params, interval);
 	os_free(params.filter_ssids);
 	if (ret == 0)
@@ -2069,3 +2126,61 @@
 
 	return ret;
 }
+
+
+void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
+				    unsigned int type)
+{
+	type &= MAC_ADDR_RAND_ALL;
+	wpa_s->mac_addr_rand_enable &= ~type;
+
+	if (type & MAC_ADDR_RAND_SCAN) {
+		os_free(wpa_s->mac_addr_scan);
+		wpa_s->mac_addr_scan = NULL;
+	}
+
+	if (type & MAC_ADDR_RAND_SCHED_SCAN) {
+		os_free(wpa_s->mac_addr_sched_scan);
+		wpa_s->mac_addr_sched_scan = NULL;
+	}
+
+	if (type & MAC_ADDR_RAND_PNO) {
+		os_free(wpa_s->mac_addr_pno);
+		wpa_s->mac_addr_pno = NULL;
+	}
+}
+
+
+int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
+				unsigned int type, const u8 *addr,
+				const u8 *mask)
+{
+	u8 *tmp = NULL;
+
+	wpas_mac_addr_rand_scan_clear(wpa_s, type);
+
+	if (addr) {
+		tmp = os_malloc(2 * ETH_ALEN);
+		if (!tmp)
+			return -1;
+		os_memcpy(tmp, addr, ETH_ALEN);
+		os_memcpy(tmp + ETH_ALEN, mask, ETH_ALEN);
+	}
+
+	if (type == MAC_ADDR_RAND_SCAN) {
+		wpa_s->mac_addr_scan = tmp;
+	} else if (type == MAC_ADDR_RAND_SCHED_SCAN) {
+		wpa_s->mac_addr_sched_scan = tmp;
+	} else if (type == MAC_ADDR_RAND_PNO) {
+		wpa_s->mac_addr_pno = tmp;
+	} else {
+		wpa_printf(MSG_INFO,
+			   "scan: Invalid MAC randomization type=0x%x",
+			   type);
+		os_free(tmp);
+		return -1;
+	}
+
+	wpa_s->mac_addr_rand_enable |= type;
+	return 0;
+}
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 946d2b3..7650f5a 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -49,4 +49,10 @@
 int wpas_start_pno(struct wpa_supplicant *wpa_s);
 int wpas_stop_pno(struct wpa_supplicant *wpa_s);
 
+void wpas_mac_addr_rand_scan_clear(struct wpa_supplicant *wpa_s,
+				   unsigned int type);
+int wpas_mac_addr_rand_scan_set(struct wpa_supplicant *wpa_s,
+				unsigned int type, const u8 *addr,
+				const u8 *mask);
+
 #endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index e616319..80c280a 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -137,6 +137,60 @@
 #endif /* CONFIG_SAE */
 
 
+/**
+ * sme_auth_handle_rrm - Handle RRM aspects of current authentication attempt
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: Pointer to the bss which is the target of authentication attempt
+ */
+static void sme_auth_handle_rrm(struct wpa_supplicant *wpa_s,
+				struct wpa_bss *bss)
+{
+	const u8 rrm_ie_len = 5;
+	u8 *pos;
+	const u8 *rrm_ie;
+
+	wpa_s->rrm.rrm_used = 0;
+
+	wpa_printf(MSG_DEBUG,
+		   "RRM: Determining whether RRM can be used - device support: 0x%x",
+		   wpa_s->drv_rrm_flags);
+
+	rrm_ie = wpa_bss_get_ie(bss, WLAN_EID_RRM_ENABLED_CAPABILITIES);
+	if (!rrm_ie || !(bss->caps & IEEE80211_CAP_RRM)) {
+		wpa_printf(MSG_DEBUG, "RRM: No RRM in network");
+		return;
+	}
+
+	if (!(wpa_s->drv_rrm_flags &
+	      WPA_DRIVER_FLAGS_DS_PARAM_SET_IE_IN_PROBES) ||
+	    !(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_QUIET)) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Insufficient RRM support in driver - do not use RRM");
+		return;
+	}
+
+	if (sizeof(wpa_s->sme.assoc_req_ie) <
+	    wpa_s->sme.assoc_req_ie_len + rrm_ie_len + 2) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Unable to use RRM, no room for RRM IE");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "RRM: Adding RRM IE to Association Request");
+	pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
+	os_memset(pos, 0, 2 + rrm_ie_len);
+	*pos++ = WLAN_EID_RRM_ENABLED_CAPABILITIES;
+	*pos++ = rrm_ie_len;
+
+	/* Set supported capabilites flags */
+	if (wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)
+		*pos |= WLAN_RRM_CAPS_LINK_MEASUREMENT;
+
+	wpa_s->sme.assoc_req_ie_len += rrm_ie_len + 2;
+	wpa_s->rrm.rrm_used = 1;
+}
+
+
 static void sme_send_authentication(struct wpa_supplicant *wpa_s,
 				    struct wpa_bss *bss, struct wpa_ssid *ssid,
 				    int start)
@@ -199,17 +253,22 @@
 			"0x%x", params.auth_alg);
 	}
 #ifdef CONFIG_SAE
+	wpa_s->sme.sae_pmksa_caching = 0;
 	if (wpa_key_mgmt_sae(ssid->key_mgmt)) {
 		const u8 *rsn;
 		struct wpa_ie_data ied;
 
 		rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
-		if (rsn &&
-		    wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0) {
-			if (wpa_key_mgmt_sae(ied.key_mgmt)) {
-				wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
-				params.auth_alg = WPA_AUTH_ALG_SAE;
-			}
+		if (!rsn) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"SAE enabled, but target BSS does not advertise RSN");
+		} else if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ied) == 0 &&
+			   wpa_key_mgmt_sae(ied.key_mgmt)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Using SAE auth_alg");
+			params.auth_alg = WPA_AUTH_ALG_SAE;
+		} else {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"SAE enabled, but target BSS does not advertise SAE AKM for RSN");
 		}
 	}
 #endif /* CONFIG_SAE */
@@ -390,7 +449,18 @@
 		os_memcpy(pos, ext_capab, ext_capab_len);
 	}
 
+	sme_auth_handle_rrm(wpa_s, bss);
+
 #ifdef CONFIG_SAE
+	if (params.auth_alg == WPA_AUTH_ALG_SAE &&
+	    pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid, ssid, 0) == 0)
+	{
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"PMKSA cache entry found - try to use PMKSA caching instead of new SAE authentication");
+		params.auth_alg = WPA_AUTH_ALG_OPEN;
+		wpa_s->sme.sae_pmksa_caching = 1;
+	}
+
 	if (params.auth_alg == WPA_AUTH_ALG_SAE) {
 		if (start)
 			resp = sme_auth_build_sae_commit(wpa_s, ssid,
@@ -398,7 +468,7 @@
 		else
 			resp = sme_auth_build_sae_confirm(wpa_s);
 		if (resp == NULL) {
-			wpas_connect_work_done(wpa_s);
+			wpas_connection_failed(wpa_s, bss->bssid);
 			return;
 		}
 		params.sae_data = wpabuf_head(resp);
@@ -545,6 +615,8 @@
 static int sme_sae_auth(struct wpa_supplicant *wpa_s, u16 auth_transaction,
 			u16 status_code, const u8 *data, size_t len)
 {
+	int *groups;
+
 	wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE authentication transaction %u "
 		"status code %u", auth_transaction, status_code);
 
@@ -552,10 +624,32 @@
 	    status_code == WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ &&
 	    wpa_s->sme.sae.state == SAE_COMMITTED &&
 	    wpa_s->current_bss && wpa_s->current_ssid) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "SME: SAE anti-clogging token "
-			"requested");
+		int default_groups[] = { 19, 20, 21, 25, 26, 0 };
+		u16 group;
+
+		groups = wpa_s->conf->sae_groups;
+		if (!groups || groups[0] <= 0)
+			groups = default_groups;
+
+		if (len < sizeof(le16)) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"SME: Too short SAE anti-clogging token request");
+			return -1;
+		}
+		group = WPA_GET_LE16(data);
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"SME: SAE anti-clogging token requested (group %u)",
+			group);
+		if (sae_group_allowed(&wpa_s->sme.sae, groups, group) !=
+		    WLAN_STATUS_SUCCESS) {
+			wpa_dbg(wpa_s, MSG_ERROR,
+				"SME: SAE group %u of anti-clogging request is invalid",
+				group);
+			return -1;
+		}
 		wpabuf_free(wpa_s->sme.sae_token);
-		wpa_s->sme.sae_token = wpabuf_alloc_copy(data, len);
+		wpa_s->sme.sae_token = wpabuf_alloc_copy(data + sizeof(le16),
+							 len - sizeof(le16));
 		sme_send_authentication(wpa_s, wpa_s->current_bss,
 					wpa_s->current_ssid, 1);
 		return 0;
@@ -579,7 +673,7 @@
 		return -1;
 
 	if (auth_transaction == 1) {
-		int *groups = wpa_s->conf->sae_groups;
+		groups = wpa_s->conf->sae_groups;
 
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME SAE commit");
 		if (wpa_s->current_bss == NULL ||
@@ -668,7 +762,8 @@
 
 		wpa_printf(MSG_DEBUG, "SME: SAE completed - setting PMK for "
 			   "4-way handshake");
-		wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN);
+		wpa_sm_set_pmk(wpa_s->wpa, wpa_s->sme.sae.pmk, PMK_LEN,
+			       wpa_s->pending_bssid);
 	}
 #endif /* CONFIG_SAE */
 
@@ -775,6 +870,7 @@
 #endif /* CONFIG_IEEE80211R */
 	params.mode = mode;
 	params.mgmt_frame_protection = wpa_s->sme.mfp;
+	params.rrm_used = wpa_s->rrm.rrm_used;
 	if (wpa_s->sme.prev_bssid_set)
 		params.prev_bssid = wpa_s->sme.prev_bssid;
 
@@ -882,6 +978,27 @@
 
 	eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
 
+#ifdef CONFIG_SAE
+	if (wpa_s->sme.sae_pmksa_caching && wpa_s->current_ssid &&
+	    wpa_key_mgmt_sae(wpa_s->current_ssid->key_mgmt)) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"PMKSA caching attempt rejected - drop PMKSA cache entry and fall back to SAE authentication");
+		wpa_sm_aborted_cached(wpa_s->wpa);
+		wpa_sm_pmksa_cache_flush(wpa_s->wpa, wpa_s->current_ssid);
+		if (wpa_s->current_bss) {
+			struct wpa_bss *bss = wpa_s->current_bss;
+			struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+			wpa_drv_deauthenticate(wpa_s, wpa_s->pending_bssid,
+					       WLAN_REASON_DEAUTH_LEAVING);
+			wpas_connect_work_done(wpa_s);
+			wpa_supplicant_mark_disassoc(wpa_s);
+			wpa_supplicant_connect(wpa_s, bss, ssid);
+			return;
+		}
+	}
+#endif /* CONFIG_SAE */
+
 	/*
 	 * For now, unconditionally terminate the previous authentication. In
 	 * theory, this should not be needed, but mac80211 gets quite confused
@@ -982,6 +1099,21 @@
 }
 
 
+void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->sme.prev_bssid_set = 0;
+#ifdef CONFIG_SAE
+	wpabuf_free(wpa_s->sme.sae_token);
+	wpa_s->sme.sae_token = NULL;
+	sae_clear_data(&wpa_s->sme.sae);
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211R
+	if (wpa_s->sme.ft_ies)
+		sme_update_ft_ies(wpa_s, NULL, NULL, 0);
+#endif /* CONFIG_IEEE80211R */
+}
+
+
 void sme_deinit(struct wpa_supplicant *wpa_s)
 {
 	os_free(wpa_s->sme.ft_ies);
@@ -990,11 +1122,7 @@
 #ifdef CONFIG_IEEE80211W
 	sme_stop_sa_query(wpa_s);
 #endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_SAE
-	wpabuf_free(wpa_s->sme.sae_token);
-	wpa_s->sme.sae_token = NULL;
-	sae_clear_data(&wpa_s->sme.sae);
-#endif /* CONFIG_SAE */
+	sme_clear_on_disassoc(wpa_s);
 
 	eloop_cancel_timeout(sme_assoc_timer, wpa_s, NULL);
 	eloop_cancel_timeout(sme_auth_timer, wpa_s, NULL);
@@ -1136,28 +1264,72 @@
 }
 
 
-static void wpa_setband_scan_freqs_list(struct wpa_supplicant *wpa_s,
-					enum hostapd_hw_mode band,
-					struct wpa_driver_scan_params *params)
+static void wpa_obss_scan_freqs_list(struct wpa_supplicant *wpa_s,
+				     struct wpa_driver_scan_params *params)
 {
-	/* Include only supported channels for the specified band */
+	/* Include only affected channels */
 	struct hostapd_hw_modes *mode;
 	int count, i;
+	int start, end;
 
-	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, band);
+	mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes,
+			HOSTAPD_MODE_IEEE80211G);
 	if (mode == NULL) {
 		/* No channels supported in this band - use empty list */
 		params->freqs = os_zalloc(sizeof(int));
 		return;
 	}
 
+	if (wpa_s->sme.ht_sec_chan == HT_SEC_CHAN_UNKNOWN &&
+	    wpa_s->current_bss) {
+		const u8 *ie;
+
+		ie = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_HT_OPERATION);
+		if (ie && ie[1] >= 2) {
+			u8 o;
+
+			o = ie[3] & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+			if (o == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+				wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_ABOVE;
+			else if (o == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+				wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_BELOW;
+		}
+	}
+
+	start = wpa_s->assoc_freq - 10;
+	end = wpa_s->assoc_freq + 10;
+	switch (wpa_s->sme.ht_sec_chan) {
+	case HT_SEC_CHAN_UNKNOWN:
+		/* HT40+ possible on channels 1..9 */
+		if (wpa_s->assoc_freq <= 2452)
+			start -= 20;
+		/* HT40- possible on channels 5-13 */
+		if (wpa_s->assoc_freq >= 2432)
+			end += 20;
+		break;
+	case HT_SEC_CHAN_ABOVE:
+		end += 20;
+		break;
+	case HT_SEC_CHAN_BELOW:
+		start -= 20;
+		break;
+	}
+	wpa_printf(MSG_DEBUG,
+		   "OBSS: assoc_freq %d possible affected range %d-%d",
+		   wpa_s->assoc_freq, start, end);
+
 	params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
 	if (params->freqs == NULL)
 		return;
 	for (count = 0, i = 0; i < mode->num_channels; i++) {
+		int freq;
+
 		if (mode->channels[i].flag & HOSTAPD_CHAN_DISABLED)
 			continue;
-		params->freqs[count++] = mode->channels[i].freq;
+		freq = mode->channels[i].freq;
+		if (freq - 10 >= end || freq + 10 <= start)
+			continue; /* not affected */
+		params->freqs[count++] = freq;
 	}
 }
 
@@ -1173,7 +1345,7 @@
 	}
 
 	os_memset(&params, 0, sizeof(params));
-	wpa_setband_scan_freqs_list(wpa_s, HOSTAPD_MODE_IEEE80211G, &params);
+	wpa_obss_scan_freqs_list(wpa_s, &params);
 	params.low_priority = 1;
 	wpa_printf(MSG_DEBUG, "SME OBSS: Request an OBSS scan");
 
@@ -1198,6 +1370,7 @@
 
 	eloop_cancel_timeout(sme_obss_scan_timeout, wpa_s, NULL);
 	wpa_s->sme.sched_obss_scan = 0;
+	wpa_s->sme.ht_sec_chan = HT_SEC_CHAN_UNKNOWN;
 	if (!enable)
 		return;
 
diff --git a/wpa_supplicant/sme.h b/wpa_supplicant/sme.h
index 04404c1..fd5c3b4 100644
--- a/wpa_supplicant/sme.h
+++ b/wpa_supplicant/sme.h
@@ -33,6 +33,7 @@
 void sme_state_changed(struct wpa_supplicant *wpa_s);
 void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
 				       const u8 *prev_pending_bssid);
+void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s);
 void sme_deinit(struct wpa_supplicant *wpa_s);
 
 int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
@@ -94,6 +95,10 @@
 {
 }
 
+static inline void sme_clear_on_disassoc(struct wpa_supplicant *wpa_s)
+{
+}
+
 static inline void sme_deinit(struct wpa_supplicant *wpa_s)
 {
 }
diff --git a/wpa_supplicant/todo.txt b/wpa_supplicant/todo.txt
index b84cccc..4c9f98e 100644
--- a/wpa_supplicant/todo.txt
+++ b/wpa_supplicant/todo.txt
@@ -5,8 +5,6 @@
   authentication has been completed (cache scard data based on serial#(?)
   and try to optimize next connection if the same card is present for next
   auth)
-- on disconnect event, could try to associate with another AP if one is
-  present in scan results; would need to update scan results periodically..
 - if driver/hw is not WPA2 capable, must remove WPA_PROTO_RSN flag from
   ssid->proto fields to avoid detecting downgrade attacks when the driver
   is not reporting RSN IE, but msg 3/4 has one
@@ -24,14 +22,12 @@
   RFC 3748 Sect. 4.2
 - test compilation with gcc -W options (more warnings?)
   (Done once; number of unused function arguments still present)
-- add proper support for using dot11RSNAConfigSATimeout
-- ctrl_iface: get/set/remove blob
+- ctrl_iface: get/remove blob
 - use doc/docbook/*.sgml and docbook2{txt,html,pdf} to replace README and
   web pages including the same information.. i.e., have this information only
   in one page; how to build a PDF file with all the SGML included?
 - EAP-POTP/RSA SecurID profile (RFC 4793)
 - document wpa_gui build and consider adding it to 'make install'
-- test madwifi with pairwise=TKIP group=WEP104
 - consider merging hostapd and wpa_supplicant PMKSA cache implementations
 - consider redesigning pending EAP requests (identity/password/otp from
   ctrl_iface) by moving the retrying of the previous request into EAP
@@ -57,14 +53,11 @@
 - try to work around race in configuring PTK and sending msg 4/4 (some NDIS
   drivers with ndiswrapper end up not being able to complete 4-way handshake
   in some cases; extra delay before setting the key seems to help)
-- add wpa_secure_memzero() macro and secure implementation (volatile u8*) to
-  clear memory; this would be used to clear temporary buffers containing
-  private data (e.g., keys); the macro can be defined to NOP in order to save
-  space (i.e., no code should depend on the macro doing something)
 - make sure that TLS session cache is not shared between EAP types or if it
   is, that the cache entries are bound to only one EAP type; e.g., cache entry
   created with EAP-TLS must not be allowed to do fast re-auth with EAP-TTLS
-- consider moving eap_tls_build_ack() call into eap_tls_process_helper()
+- consider moving eap_peer_tls_build_ack() call into
+  eap_peer_tls_process_helper()
   (it seems to be called always if helper returns 1)
   * could need to modify eap_{ttls,peap,fast}_decrypt to do same
 - add support for fetching full user cert chain from Windows certificate
diff --git a/wpa_supplicant/wifi_display.c b/wpa_supplicant/wifi_display.c
index 6dc41de..c363b21 100644
--- a/wpa_supplicant/wifi_display.c
+++ b/wpa_supplicant/wifi_display.c
@@ -233,15 +233,31 @@
 	if (pos == NULL)
 		return -1;
 	*pos++ = '\0';
-	subelem = atoi(cmd);
-	if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
-		return -1;
 
 	len = os_strlen(pos);
 	if (len & 1)
 		return -1;
 	len /= 2;
 
+	if (os_strcmp(cmd, "all") == 0) {
+		int res;
+
+		e = wpabuf_alloc(len);
+		if (e == NULL)
+			return -1;
+		if (hexstr2bin(pos, wpabuf_put(e, len), len) < 0) {
+			wpabuf_free(e);
+			return -1;
+		}
+		res = wifi_display_subelem_set_from_ies(global, e);
+		wpabuf_free(e);
+		return res;
+	}
+
+	subelem = atoi(cmd);
+	if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
+		return -1;
+
 	if (len == 0) {
 		/* Clear subelement */
 		e = NULL;
@@ -271,7 +287,7 @@
 {
 	int subelements[MAX_WFD_SUBELEMS] = {};
 	const u8 *pos, *end;
-	int len, subelem;
+	unsigned int len, subelem;
 	struct wpabuf *e;
 
 	wpa_printf(MSG_DEBUG, "WFD IEs set: %p - %lu",
@@ -292,7 +308,7 @@
 		wpa_printf(MSG_DEBUG, "WFD Sub-Element ID %d - len %d",
 			   *pos, len - 3);
 
-		if (pos + len > end)
+		if (len > (unsigned int) (end - pos))
 			break;
 
 		subelem = *pos;
@@ -325,6 +341,19 @@
 {
 	int subelem;
 
+	if (os_strcmp(cmd, "all") == 0) {
+		struct wpabuf *ie;
+		int res;
+
+		ie = wifi_display_get_wfd_ie(global);
+		if (ie == NULL)
+			return 0;
+		res = wpa_snprintf_hex(buf, buflen, wpabuf_head(ie),
+				       wpabuf_len(ie));
+		wpabuf_free(ie);
+		return res;
+	}
+
 	subelem = atoi(cmd);
 	if (subelem < 0 || subelem >= MAX_WFD_SUBELEMS)
 		return -1;
diff --git a/wpa_supplicant/wmm_ac.c b/wpa_supplicant/wmm_ac.c
new file mode 100644
index 0000000..5625d36
--- /dev/null
+++ b/wpa_supplicant/wmm_ac.c
@@ -0,0 +1,995 @@
+/*
+ * Wi-Fi Multimedia Admission Control (WMM-AC)
+ * Copyright(c) 2014, Intel Mobile Communication GmbH.
+ * Copyright(c) 2014, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "utils/common.h"
+#include "utils/list.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_common.h"
+#include "wpa_supplicant_i.h"
+#include "bss.h"
+#include "driver_i.h"
+#include "wmm_ac.h"
+
+static void wmm_ac_addts_req_timeout(void *eloop_ctx, void *timeout_ctx);
+
+static const enum wmm_ac up_to_ac[8] = {
+	WMM_AC_BK,
+	WMM_AC_BE,
+	WMM_AC_BE,
+	WMM_AC_BK,
+	WMM_AC_VI,
+	WMM_AC_VI,
+	WMM_AC_VO,
+	WMM_AC_VO
+};
+
+
+static inline u8 wmm_ac_get_tsid(const struct wmm_tspec_element *tspec)
+{
+	return (tspec->ts_info[0] >> 1) & 0x0f;
+}
+
+
+static u8 wmm_ac_get_direction(const struct wmm_tspec_element *tspec)
+{
+	return (tspec->ts_info[0] >> 5) & 0x03;
+}
+
+
+static u8 wmm_ac_get_user_priority(const struct wmm_tspec_element *tspec)
+{
+	return (tspec->ts_info[1] >> 3) & 0x07;
+}
+
+
+static u8 wmm_ac_direction_to_idx(u8 direction)
+{
+	switch (direction) {
+	case WMM_AC_DIR_UPLINK:
+		return TS_DIR_IDX_UPLINK;
+	case WMM_AC_DIR_DOWNLINK:
+		return TS_DIR_IDX_DOWNLINK;
+	case WMM_AC_DIR_BIDIRECTIONAL:
+		return TS_DIR_IDX_BIDI;
+	default:
+		wpa_printf(MSG_ERROR, "Invalid direction: %d", direction);
+		return WMM_AC_DIR_UPLINK;
+	}
+}
+
+
+static int wmm_ac_add_ts(struct wpa_supplicant *wpa_s, const u8 *addr,
+			 const struct wmm_tspec_element *tspec)
+{
+	struct wmm_tspec_element *_tspec;
+	int ret;
+	u16 admitted_time = le_to_host16(tspec->medium_time);
+	u8 up = wmm_ac_get_user_priority(tspec);
+	u8 ac = up_to_ac[up];
+	u8 dir = wmm_ac_get_direction(tspec);
+	u8 tsid = wmm_ac_get_tsid(tspec);
+	enum ts_dir_idx idx = wmm_ac_direction_to_idx(dir);
+
+	/* should have been verified before, but double-check here */
+	if (wpa_s->tspecs[ac][idx]) {
+		wpa_printf(MSG_ERROR,
+			   "WMM AC: tspec (ac=%d, dir=%d) already exists!",
+			   ac, dir);
+		return -1;
+	}
+
+	/* copy tspec */
+	_tspec = os_malloc(sizeof(*_tspec));
+	if (!_tspec)
+		return -1;
+
+	/* store the admitted TSPEC */
+	os_memcpy(_tspec, tspec, sizeof(*_tspec));
+
+	if (dir != WMM_AC_DIR_DOWNLINK) {
+		ret = wpa_drv_add_ts(wpa_s, tsid, addr, up, admitted_time);
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: Add TS: addr=" MACSTR
+			   " TSID=%u admitted time=%u, ret=%d",
+			   MAC2STR(addr), tsid, admitted_time, ret);
+		if (ret < 0) {
+			os_free(_tspec);
+			return -1;
+		}
+	}
+
+	wpa_s->tspecs[ac][idx] = _tspec;
+
+	wpa_printf(MSG_DEBUG, "Traffic stream was created successfully");
+
+	wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_ADDED
+		"tsid=%d addr=" MACSTR " admitted_time=%d",
+		tsid, MAC2STR(addr), admitted_time);
+
+	return 0;
+}
+
+
+static void wmm_ac_del_ts_idx(struct wpa_supplicant *wpa_s, u8 ac,
+			      enum ts_dir_idx dir)
+{
+	struct wmm_tspec_element *tspec = wpa_s->tspecs[ac][dir];
+	u8 tsid;
+
+	if (!tspec)
+		return;
+
+	tsid = wmm_ac_get_tsid(tspec);
+	wpa_printf(MSG_DEBUG, "WMM AC: Del TS ac=%d tsid=%d", ac, tsid);
+
+	/* update the driver in case of uplink/bidi */
+	if (wmm_ac_get_direction(tspec) != WMM_AC_DIR_DOWNLINK)
+		wpa_drv_del_ts(wpa_s, tsid, wpa_s->bssid);
+
+	wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REMOVED
+		"tsid=%d addr=" MACSTR, tsid, MAC2STR(wpa_s->bssid));
+
+	os_free(wpa_s->tspecs[ac][dir]);
+	wpa_s->tspecs[ac][dir] = NULL;
+}
+
+
+static void wmm_ac_del_req(struct wpa_supplicant *wpa_s, int failed)
+{
+	struct wmm_ac_addts_request *req = wpa_s->addts_request;
+
+	if (!req)
+		return;
+
+	if (failed)
+		wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REQ_FAILED
+			"tsid=%u", wmm_ac_get_tsid(&req->tspec));
+
+	eloop_cancel_timeout(wmm_ac_addts_req_timeout, wpa_s, req);
+	wpa_s->addts_request = NULL;
+	os_free(req);
+}
+
+
+static void wmm_ac_addts_req_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct wmm_ac_addts_request *addts_req = timeout_ctx;
+
+	wpa_printf(MSG_DEBUG,
+		   "Timeout getting ADDTS response (tsid=%d up=%d)",
+		   wmm_ac_get_tsid(&addts_req->tspec),
+		   wmm_ac_get_user_priority(&addts_req->tspec));
+
+	wmm_ac_del_req(wpa_s, 1);
+}
+
+
+static int wmm_ac_send_addts_request(struct wpa_supplicant *wpa_s,
+				     const struct wmm_ac_addts_request *req)
+{
+	struct wpabuf *buf;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "Sending ADDTS Request to " MACSTR,
+		   MAC2STR(req->address));
+
+	/* category + action code + dialog token + status + sizeof(tspec) */
+	buf = wpabuf_alloc(4 + sizeof(req->tspec));
+	if (!buf) {
+		wpa_printf(MSG_ERROR, "WMM AC: Allocation error");
+		return -1;
+	}
+
+	wpabuf_put_u8(buf, WLAN_ACTION_WMM);
+	wpabuf_put_u8(buf, WMM_ACTION_CODE_ADDTS_REQ);
+	wpabuf_put_u8(buf, req->dialog_token);
+	wpabuf_put_u8(buf, 0); /* status code */
+	wpabuf_put_data(buf, &req->tspec, sizeof(req->tspec));
+
+	ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, req->address,
+				wpa_s->own_addr, wpa_s->bssid,
+				wpabuf_head(buf), wpabuf_len(buf), 0);
+	if (ret) {
+		wpa_printf(MSG_WARNING,
+			   "WMM AC: Failed to send ADDTS Request");
+	}
+
+	wpabuf_free(buf);
+	return ret;
+}
+
+
+static int wmm_ac_send_delts(struct wpa_supplicant *wpa_s,
+			     const struct wmm_tspec_element *tspec,
+			     const u8 *address)
+{
+	struct wpabuf *buf;
+	int ret;
+
+	/* category + action code + dialog token + status + sizeof(tspec) */
+	buf = wpabuf_alloc(4 + sizeof(*tspec));
+	if (!buf)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "Sending DELTS to " MACSTR, MAC2STR(address));
+
+	/* category + action code + dialog token + status + sizeof(tspec) */
+	wpabuf_put_u8(buf, WLAN_ACTION_WMM);
+	wpabuf_put_u8(buf, WMM_ACTION_CODE_DELTS);
+	wpabuf_put_u8(buf, 0); /* Dialog Token (not used) */
+	wpabuf_put_u8(buf, 0); /* Status Code (not used) */
+	wpabuf_put_data(buf, tspec, sizeof(*tspec));
+
+	ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, address,
+				  wpa_s->own_addr, wpa_s->bssid,
+				  wpabuf_head(buf), wpabuf_len(buf), 0);
+	if (ret)
+		wpa_printf(MSG_WARNING, "Failed to send DELTS frame");
+
+	wpabuf_free(buf);
+	return ret;
+}
+
+
+/* return the AC using the given TSPEC tid */
+static int wmm_ac_find_tsid(struct wpa_supplicant *wpa_s, u8 tsid,
+			    enum ts_dir_idx *dir)
+{
+	int ac;
+	enum ts_dir_idx idx;
+
+	for (ac = 0; ac < WMM_AC_NUM; ac++) {
+		for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+			if (wpa_s->tspecs[ac][idx] &&
+			    wmm_ac_get_tsid(wpa_s->tspecs[ac][idx]) == tsid) {
+				if (dir)
+					*dir = idx;
+				return ac;
+			}
+		}
+	}
+
+	return -1;
+}
+
+
+static struct wmm_ac_addts_request *
+wmm_ac_build_addts_req(struct wpa_supplicant *wpa_s,
+		       const struct wmm_ac_ts_setup_params *params,
+		       const u8 *address)
+{
+	struct wmm_ac_addts_request *addts_req;
+	struct wmm_tspec_element *tspec;
+	u8 ac = up_to_ac[params->user_priority];
+	u8 uapsd = wpa_s->wmm_ac_assoc_info->ac_params[ac].uapsd;
+
+	addts_req = os_zalloc(sizeof(*addts_req));
+	if (!addts_req)
+		return NULL;
+
+	tspec = &addts_req->tspec;
+	os_memcpy(addts_req->address, address, ETH_ALEN);
+
+	/* The dialog token cannot be zero */
+	if (++wpa_s->wmm_ac_last_dialog_token == 0)
+		wpa_s->wmm_ac_last_dialog_token++;
+
+	addts_req->dialog_token = wpa_s->wmm_ac_last_dialog_token;
+	tspec->eid = WLAN_EID_VENDOR_SPECIFIC;
+	tspec->length = sizeof(*tspec) - 2; /* reduce eid and length */
+	tspec->oui[0] = 0x00;
+	tspec->oui[1] = 0x50;
+	tspec->oui[2] = 0xf2;
+	tspec->oui_type = WMM_OUI_TYPE;
+	tspec->oui_subtype = WMM_OUI_SUBTYPE_TSPEC_ELEMENT;
+	tspec->version = WMM_VERSION;
+
+	tspec->ts_info[0] = params->tsid << 1;
+	tspec->ts_info[0] |= params->direction << 5;
+	tspec->ts_info[0] |= WMM_AC_ACCESS_POLICY_EDCA << 7;
+	tspec->ts_info[1] = uapsd << 2;
+	tspec->ts_info[1] |= params->user_priority << 3;
+	tspec->ts_info[2] = 0;
+
+	tspec->nominal_msdu_size = host_to_le16(params->nominal_msdu_size);
+	if (params->fixed_nominal_msdu)
+		tspec->nominal_msdu_size |=
+			host_to_le16(WMM_AC_FIXED_MSDU_SIZE);
+
+	tspec->mean_data_rate = host_to_le32(params->mean_data_rate);
+	tspec->minimum_phy_rate = host_to_le32(params->minimum_phy_rate);
+	tspec->surplus_bandwidth_allowance =
+		host_to_le16(params->surplus_bandwidth_allowance);
+
+	return addts_req;
+}
+
+
+static int param_in_range(const char *name, long value,
+			  long min_val, long max_val)
+{
+	if (value < min_val || (max_val >= 0 && value > max_val)) {
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: param %s (%ld) is out of range (%ld-%ld)",
+			   name, value, min_val, max_val);
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static int wmm_ac_should_replace_ts(struct wpa_supplicant *wpa_s,
+				    u8 tsid, u8 ac, u8 dir)
+{
+	enum ts_dir_idx idx;
+	int cur_ac, existing_ts = 0, replace_ts = 0;
+
+	cur_ac = wmm_ac_find_tsid(wpa_s, tsid, &idx);
+	if (cur_ac >= 0) {
+		if (cur_ac != ac) {
+			wpa_printf(MSG_DEBUG,
+				   "WMM AC: TSID %i already exists on different ac (%d)",
+				   tsid, cur_ac);
+			return -1;
+		}
+
+		/* same tsid - this tspec will replace the current one */
+		replace_ts |= BIT(idx);
+	}
+
+	for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+		if (wpa_s->tspecs[ac][idx])
+			existing_ts |= BIT(idx);
+	}
+
+	switch (dir) {
+	case WMM_AC_DIR_UPLINK:
+		/* replace existing uplink/bidi tspecs */
+		replace_ts |= existing_ts & (BIT(TS_DIR_IDX_UPLINK) |
+					     BIT(TS_DIR_IDX_BIDI));
+		break;
+	case WMM_AC_DIR_DOWNLINK:
+		/* replace existing downlink/bidi tspecs */
+		replace_ts |= existing_ts & (BIT(TS_DIR_IDX_DOWNLINK) |
+					     BIT(TS_DIR_IDX_BIDI));
+		break;
+	case WMM_AC_DIR_BIDIRECTIONAL:
+		/* replace all existing tspecs */
+		replace_ts |= existing_ts;
+		break;
+	default:
+		return -1;
+	}
+
+	return replace_ts;
+}
+
+
+static int wmm_ac_ts_req_is_valid(struct wpa_supplicant *wpa_s,
+				  const struct wmm_ac_ts_setup_params *params)
+{
+	enum wmm_ac req_ac;
+
+#define PARAM_IN_RANGE(field, min_value, max_value) \
+	param_in_range(#field, params->field, min_value, max_value)
+
+	if (!PARAM_IN_RANGE(tsid, 0, WMM_AC_MAX_TID) ||
+	    !PARAM_IN_RANGE(user_priority, 0, WMM_AC_MAX_USER_PRIORITY) ||
+	    !PARAM_IN_RANGE(nominal_msdu_size, 1, WMM_AC_MAX_NOMINAL_MSDU) ||
+	    !PARAM_IN_RANGE(mean_data_rate, 1, -1) ||
+	    !PARAM_IN_RANGE(minimum_phy_rate, 1, -1) ||
+	    !PARAM_IN_RANGE(surplus_bandwidth_allowance, WMM_AC_MIN_SBA_UNITY,
+			    -1))
+		return 0;
+#undef PARAM_IN_RANGE
+
+	if (!(params->direction == WMM_TSPEC_DIRECTION_UPLINK ||
+	      params->direction == WMM_TSPEC_DIRECTION_DOWNLINK ||
+	      params->direction == WMM_TSPEC_DIRECTION_BI_DIRECTIONAL)) {
+		wpa_printf(MSG_DEBUG, "WMM AC: invalid TS direction: %d",
+			   params->direction);
+		return 0;
+	}
+
+	req_ac = up_to_ac[params->user_priority];
+
+	/* Requested accesss category must have acm */
+	if (!wpa_s->wmm_ac_assoc_info->ac_params[req_ac].acm) {
+		wpa_printf(MSG_DEBUG, "WMM AC: AC %d is not ACM", req_ac);
+		return 0;
+	}
+
+	if (wmm_ac_should_replace_ts(wpa_s, params->tsid, req_ac,
+				     params->direction) < 0)
+		return 0;
+
+	return 1;
+}
+
+
+static struct wmm_ac_assoc_data *
+wmm_ac_process_param_elem(struct wpa_supplicant *wpa_s, const u8 *ies,
+			  size_t ies_len)
+{
+	struct ieee802_11_elems elems;
+	struct wmm_parameter_element *wmm_params;
+	struct wmm_ac_assoc_data *assoc_data;
+	int i;
+
+	/* Parsing WMM Parameter Element */
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "WMM AC: could not parse assoc ies");
+		return NULL;
+	}
+
+	if (!elems.wmm) {
+		wpa_printf(MSG_DEBUG, "WMM AC: No WMM IE");
+		return NULL;
+	}
+
+	if (elems.wmm_len != sizeof(*wmm_params)) {
+		wpa_printf(MSG_DEBUG, "WMM AC: Invalid WMM ie length");
+		return NULL;
+	}
+
+	wmm_params = (struct wmm_parameter_element *)(elems.wmm);
+
+	assoc_data = os_zalloc(sizeof(*assoc_data));
+	if (!assoc_data)
+		return NULL;
+
+	for (i = 0; i < WMM_AC_NUM; i++)
+		assoc_data->ac_params[i].acm =
+			!!(wmm_params->ac[i].aci_aifsn & WMM_AC_ACM);
+
+	wpa_printf(MSG_DEBUG,
+		   "WMM AC: AC mandatory: AC_BE=%u AC_BK=%u AC_VI=%u AC_VO=%u",
+		   assoc_data->ac_params[WMM_AC_BE].acm,
+		   assoc_data->ac_params[WMM_AC_BK].acm,
+		   assoc_data->ac_params[WMM_AC_VI].acm,
+		   assoc_data->ac_params[WMM_AC_VO].acm);
+
+	return assoc_data;
+}
+
+
+static int wmm_ac_init(struct wpa_supplicant *wpa_s, const u8 *ies,
+		       size_t ies_len, const struct wmm_params *wmm_params)
+{
+	struct wmm_ac_assoc_data *assoc_data;
+	u8 ac;
+
+	if (wpa_s->wmm_ac_assoc_info) {
+		wpa_printf(MSG_ERROR, "WMM AC: Already initialized");
+		return -1;
+	}
+
+	if (!ies) {
+		wpa_printf(MSG_ERROR, "WMM AC: Missing IEs");
+		return -1;
+	}
+
+	if (!(wmm_params->info_bitmap & WMM_PARAMS_UAPSD_QUEUES_INFO)) {
+		wpa_printf(MSG_DEBUG, "WMM AC: Missing U-APSD configuration");
+		return -1;
+	}
+
+	os_memset(wpa_s->tspecs, 0, sizeof(wpa_s->tspecs));
+	wpa_s->wmm_ac_last_dialog_token = 0;
+	wpa_s->addts_request = NULL;
+
+	assoc_data = wmm_ac_process_param_elem(wpa_s, ies, ies_len);
+	if (!assoc_data)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "WMM AC: U-APSD queues=0x%x",
+		   wmm_params->uapsd_queues);
+
+	for (ac = 0; ac < WMM_AC_NUM; ac++) {
+		assoc_data->ac_params[ac].uapsd =
+			!!(wmm_params->uapsd_queues & BIT(ac));
+	}
+
+	wpa_s->wmm_ac_assoc_info = assoc_data;
+	return 0;
+}
+
+
+static void wmm_ac_del_ts(struct wpa_supplicant *wpa_s, u8 ac, int dir_bitmap)
+{
+	enum ts_dir_idx idx;
+
+	for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+		if (!(dir_bitmap & BIT(idx)))
+			continue;
+
+		wmm_ac_del_ts_idx(wpa_s, ac, idx);
+	}
+}
+
+
+static void wmm_ac_deinit(struct wpa_supplicant *wpa_s)
+{
+	int i;
+
+	for (i = 0; i < WMM_AC_NUM; i++)
+		wmm_ac_del_ts(wpa_s, i, TS_DIR_IDX_ALL);
+
+	/* delete pending add_ts requset */
+	wmm_ac_del_req(wpa_s, 1);
+
+	os_free(wpa_s->wmm_ac_assoc_info);
+	wpa_s->wmm_ac_assoc_info = NULL;
+}
+
+
+void wmm_ac_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *ies,
+			 size_t ies_len, const struct wmm_params *wmm_params)
+{
+	if (wmm_ac_init(wpa_s, ies, ies_len, wmm_params))
+		return;
+
+	wpa_printf(MSG_DEBUG,
+		   "WMM AC: Valid WMM association, WMM AC is enabled");
+}
+
+
+void wmm_ac_notify_disassoc(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->wmm_ac_assoc_info)
+		return;
+
+	wmm_ac_deinit(wpa_s);
+	wpa_printf(MSG_DEBUG, "WMM AC: WMM AC is disabled");
+}
+
+
+int wpas_wmm_ac_delts(struct wpa_supplicant *wpa_s, u8 tsid)
+{
+	struct wmm_tspec_element tspec;
+	int ac;
+	enum ts_dir_idx dir;
+
+	if (!wpa_s->wmm_ac_assoc_info) {
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: Failed to delete TS, WMM AC is disabled");
+		return -1;
+	}
+
+	ac = wmm_ac_find_tsid(wpa_s, tsid, &dir);
+	if (ac < 0) {
+		wpa_printf(MSG_DEBUG, "WMM AC: TS does not exist");
+		return -1;
+	}
+
+	tspec = *wpa_s->tspecs[ac][dir];
+
+	wmm_ac_del_ts_idx(wpa_s, ac, dir);
+
+	wmm_ac_send_delts(wpa_s, &tspec, wpa_s->bssid);
+
+	return 0;
+}
+
+
+int wpas_wmm_ac_addts(struct wpa_supplicant *wpa_s,
+		      struct wmm_ac_ts_setup_params *params)
+{
+	struct wmm_ac_addts_request *addts_req;
+
+	if (!wpa_s->wmm_ac_assoc_info) {
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: Cannot add TS - missing assoc data");
+		return -1;
+	}
+
+	if (wpa_s->addts_request) {
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: can't add TS - ADDTS request is already pending");
+		return -1;
+	}
+
+	/*
+	 * we can setup downlink TS even without driver support.
+	 * however, we need driver support for the other directions.
+	 */
+	if (params->direction != WMM_AC_DIR_DOWNLINK &&
+	    !wpa_s->wmm_ac_supported) {
+		wpa_printf(MSG_DEBUG,
+			   "Cannot set uplink/bidi TS without driver support");
+		return -1;
+	}
+
+	if (!wmm_ac_ts_req_is_valid(wpa_s, params))
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "WMM AC: TS setup request (addr=" MACSTR
+		   " tsid=%u user priority=%u direction=%d)",
+		   MAC2STR(wpa_s->bssid), params->tsid,
+		   params->user_priority, params->direction);
+
+	addts_req = wmm_ac_build_addts_req(wpa_s, params, wpa_s->bssid);
+	if (!addts_req)
+		return -1;
+
+	if (wmm_ac_send_addts_request(wpa_s, addts_req))
+		goto err;
+
+	/* save as pending and set ADDTS resp timeout to 1 second */
+	wpa_s->addts_request = addts_req;
+	eloop_register_timeout(1, 0, wmm_ac_addts_req_timeout,
+			       wpa_s, addts_req);
+	return 0;
+err:
+	os_free(addts_req);
+	return -1;
+}
+
+
+static void wmm_ac_handle_delts(struct wpa_supplicant *wpa_s, const u8 *sa,
+				const struct wmm_tspec_element *tspec)
+{
+	int ac;
+	u8 tsid;
+	enum ts_dir_idx idx;
+
+	tsid = wmm_ac_get_tsid(tspec);
+
+	wpa_printf(MSG_DEBUG,
+		   "WMM AC: DELTS frame has been received TSID=%u addr="
+		   MACSTR, tsid, MAC2STR(sa));
+
+	ac = wmm_ac_find_tsid(wpa_s, tsid, &idx);
+	if (ac < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: Ignoring DELTS frame - TSID does not exist");
+		return;
+	}
+
+	wmm_ac_del_ts_idx(wpa_s, ac, idx);
+
+	wpa_printf(MSG_DEBUG,
+		   "TS was deleted successfully (tsid=%u address=" MACSTR ")",
+		   tsid, MAC2STR(sa));
+}
+
+
+static void wmm_ac_handle_addts_resp(struct wpa_supplicant *wpa_s, const u8 *sa,
+		const u8 resp_dialog_token, const u8 status_code,
+		const struct wmm_tspec_element *tspec)
+{
+	struct wmm_ac_addts_request *req = wpa_s->addts_request;
+	u8 ac, tsid, up, dir;
+	int replace_tspecs;
+
+	tsid = wmm_ac_get_tsid(tspec);
+	dir = wmm_ac_get_direction(tspec);
+	up = wmm_ac_get_user_priority(tspec);
+	ac = up_to_ac[up];
+
+	/* make sure we have a matching addts request */
+	if (!req || req->dialog_token != resp_dialog_token) {
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: no req with dialog=%u, ignoring frame",
+			   resp_dialog_token);
+		return;
+	}
+
+	/* make sure the params are the same */
+	if (os_memcmp(req->address, sa, ETH_ALEN) != 0 ||
+	    tsid != wmm_ac_get_tsid(&req->tspec) ||
+	    up != wmm_ac_get_user_priority(&req->tspec) ||
+	    dir != wmm_ac_get_direction(&req->tspec)) {
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: ADDTS params do not match, ignoring frame");
+		return;
+	}
+
+	/* delete pending request */
+	wmm_ac_del_req(wpa_s, 0);
+
+	wpa_printf(MSG_DEBUG,
+		   "ADDTS response status=%d tsid=%u up=%u direction=%u",
+		   status_code, tsid, up, dir);
+
+	if (status_code != WMM_ADDTS_STATUS_ADMISSION_ACCEPTED) {
+		wpa_printf(MSG_INFO, "WMM AC: ADDTS request was rejected");
+		goto err_msg;
+	}
+
+	replace_tspecs = wmm_ac_should_replace_ts(wpa_s, tsid, ac, dir);
+	if (replace_tspecs < 0)
+		goto err_delts;
+
+	wpa_printf(MSG_DEBUG, "ts idx replace bitmap: 0x%x", replace_tspecs);
+
+	/* when replacing tspecs - delete first */
+	wmm_ac_del_ts(wpa_s, ac, replace_tspecs);
+
+	/* Creating a new traffic stream */
+	wpa_printf(MSG_DEBUG,
+		   "WMM AC: adding a new TS with TSID=%u address="MACSTR
+		   " medium time=%u access category=%d dir=%d ",
+		   tsid, MAC2STR(sa),
+		   le_to_host16(tspec->medium_time), ac, dir);
+
+	if (wmm_ac_add_ts(wpa_s, sa, tspec))
+		goto err_delts;
+
+	return;
+
+err_delts:
+	/* ask the ap to delete the tspec */
+	wmm_ac_send_delts(wpa_s, tspec, sa);
+err_msg:
+	wpa_msg(wpa_s, MSG_INFO, WMM_AC_EVENT_TSPEC_REQ_FAILED "tsid=%u",
+		tsid);
+}
+
+
+void wmm_ac_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+			const u8 *sa, const u8 *data, size_t len)
+{
+	u8 action;
+	u8 dialog_token;
+	u8 status_code;
+	struct ieee802_11_elems elems;
+	struct wmm_tspec_element *tspec;
+
+	if (wpa_s->wmm_ac_assoc_info == NULL) {
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: WMM AC is disabled, ignoring action frame");
+		return;
+	}
+
+	action = data[0];
+
+	if (action != WMM_ACTION_CODE_ADDTS_RESP &&
+	    action != WMM_ACTION_CODE_DELTS) {
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: Unknown action (%d), ignoring action frame",
+			   action);
+		return;
+	}
+
+	/* WMM AC action frame */
+	if (os_memcmp(da, wpa_s->own_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WMM AC: frame destination addr="MACSTR
+			   " is other than ours, ignoring frame", MAC2STR(da));
+		return;
+	}
+
+	if (os_memcmp(sa, wpa_s->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WMM AC: ignore frame with sa " MACSTR
+			   " different other than our bssid", MAC2STR(da));
+		return;
+	}
+
+	if (len < 2 + sizeof(struct wmm_tspec_element)) {
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: Short ADDTS response ignored (len=%lu)",
+			   (unsigned long) len);
+		return;
+	}
+
+	data++;
+	len--;
+	dialog_token = data[0];
+	status_code = data[1];
+
+	if (ieee802_11_parse_elems(data + 2, len - 2, &elems, 1) != ParseOK) {
+		wpa_printf(MSG_DEBUG,
+			   "WMM AC: Could not parse WMM AC action from " MACSTR,
+			   MAC2STR(sa));
+		return;
+	}
+
+	/* the struct also contains the type and value, so decrease it */
+	if (elems.wmm_tspec_len != sizeof(struct wmm_tspec_element) - 2) {
+		wpa_printf(MSG_DEBUG, "WMM AC: missing or wrong length TSPEC");
+		return;
+	}
+
+	tspec = (struct wmm_tspec_element *)(elems.wmm_tspec - 2);
+
+	wpa_printf(MSG_DEBUG, "WMM AC: RX WMM AC Action from " MACSTR,
+		   MAC2STR(sa));
+	wpa_hexdump(MSG_MSGDUMP, "WMM AC: WMM AC Action content", data, len);
+
+	switch (action) {
+	case WMM_ACTION_CODE_ADDTS_RESP:
+		wmm_ac_handle_addts_resp(wpa_s, sa, dialog_token, status_code,
+					 tspec);
+		break;
+	case WMM_ACTION_CODE_DELTS:
+		wmm_ac_handle_delts(wpa_s, sa, tspec);
+		break;
+	default:
+		break;
+	}
+}
+
+
+static const char * get_ac_str(u8 ac)
+{
+	switch (ac) {
+	case WMM_AC_BE:
+		return "BE";
+	case WMM_AC_BK:
+		return "BK";
+	case WMM_AC_VI:
+		return "VI";
+	case WMM_AC_VO:
+		return "VO";
+	default:
+		return "N/A";
+	}
+}
+
+
+static const char * get_direction_str(u8 direction)
+{
+	switch (direction) {
+	case WMM_AC_DIR_DOWNLINK:
+		return "Downlink";
+	case WMM_AC_DIR_UPLINK:
+		return "Uplink";
+	case WMM_AC_DIR_BIDIRECTIONAL:
+		return "Bi-directional";
+	default:
+		return "N/A";
+	}
+}
+
+
+int wpas_wmm_ac_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+	struct wmm_ac_assoc_data *assoc_info = wpa_s->wmm_ac_assoc_info;
+	enum ts_dir_idx idx;
+	int pos = 0;
+	u8 ac, up;
+
+	if (!assoc_info) {
+		return wpa_scnprintf(buf, buflen - pos,
+				     "Not associated to a WMM AP, WMM AC is Disabled\n");
+	}
+
+	pos += wpa_scnprintf(buf + pos, buflen - pos, "WMM AC is Enabled\n");
+
+	for (ac = 0; ac < WMM_AC_NUM; ac++) {
+		int ts_count = 0;
+
+		pos += wpa_scnprintf(buf + pos, buflen - pos,
+				     "%s: acm=%d uapsd=%d\n",
+				     get_ac_str(ac),
+				     assoc_info->ac_params[ac].acm,
+				     assoc_info->ac_params[ac].uapsd);
+
+		for (idx = 0; idx < TS_DIR_IDX_COUNT; idx++) {
+			struct wmm_tspec_element *tspec;
+			u8 dir, tsid;
+			const char *dir_str;
+
+			tspec = wpa_s->tspecs[ac][idx];
+			if (!tspec)
+				continue;
+
+			ts_count++;
+
+			dir = wmm_ac_get_direction(tspec);
+			dir_str = get_direction_str(dir);
+			tsid = wmm_ac_get_tsid(tspec);
+			up = wmm_ac_get_user_priority(tspec);
+
+			pos += wpa_scnprintf(buf + pos, buflen - pos,
+					     "\tTSID=%u UP=%u\n"
+					     "\tAddress = "MACSTR"\n"
+					     "\tWMM AC dir = %s\n"
+					     "\tTotal admitted time = %u\n\n",
+					     tsid, up,
+					     MAC2STR(wpa_s->bssid),
+					     dir_str,
+					     le_to_host16(tspec->medium_time));
+		}
+
+		if (!ts_count) {
+			pos += wpa_scnprintf(buf + pos, buflen - pos,
+					     "\t(No Traffic Stream)\n\n");
+		}
+	}
+
+	return pos;
+}
+
+
+static u8 wmm_ac_get_tspecs_count(struct wpa_supplicant *wpa_s)
+{
+	int ac, dir, tspecs_count = 0;
+
+	for (ac = 0; ac < WMM_AC_NUM; ac++) {
+		for (dir = 0; dir < TS_DIR_IDX_COUNT; dir++) {
+			if (wpa_s->tspecs[ac][dir])
+				tspecs_count++;
+		}
+	}
+
+	return tspecs_count;
+}
+
+
+void wmm_ac_save_tspecs(struct wpa_supplicant *wpa_s)
+{
+	int ac, dir, tspecs_count;
+
+	wpa_printf(MSG_DEBUG, "WMM AC: Save last configured tspecs");
+
+	if (!wpa_s->wmm_ac_assoc_info)
+		return;
+
+	tspecs_count = wmm_ac_get_tspecs_count(wpa_s);
+	if (!tspecs_count) {
+		wpa_printf(MSG_DEBUG, "WMM AC: No configured TSPECs");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "WMM AC: Saving tspecs");
+
+	wmm_ac_clear_saved_tspecs(wpa_s);
+	wpa_s->last_tspecs = os_calloc(tspecs_count,
+				       sizeof(*wpa_s->last_tspecs));
+	if (!wpa_s->last_tspecs) {
+		wpa_printf(MSG_ERROR, "WMM AC: Failed to save tspecs!");
+		return;
+	}
+
+	for (ac = 0; ac < WMM_AC_NUM; ac++) {
+		for (dir = 0; dir < TS_DIR_IDX_COUNT; dir++) {
+			if (!wpa_s->tspecs[ac][dir])
+				continue;
+
+			wpa_s->last_tspecs[wpa_s->last_tspecs_count++] =
+				*wpa_s->tspecs[ac][dir];
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "WMM AC: Successfully saved %d TSPECs",
+		   wpa_s->last_tspecs_count);
+}
+
+
+void wmm_ac_clear_saved_tspecs(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->last_tspecs) {
+		wpa_printf(MSG_DEBUG, "WMM AC: Clear saved tspecs");
+		os_free(wpa_s->last_tspecs);
+		wpa_s->last_tspecs = NULL;
+		wpa_s->last_tspecs_count = 0;
+	}
+}
+
+
+int wmm_ac_restore_tspecs(struct wpa_supplicant *wpa_s)
+{
+	unsigned int i;
+
+	if (!wpa_s->wmm_ac_assoc_info || !wpa_s->last_tspecs_count)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "WMM AC: Restore %u saved tspecs",
+		   wpa_s->last_tspecs_count);
+
+	for (i = 0; i < wpa_s->last_tspecs_count; i++)
+		wmm_ac_add_ts(wpa_s, wpa_s->bssid, &wpa_s->last_tspecs[i]);
+
+	return 0;
+}
diff --git a/wpa_supplicant/wmm_ac.h b/wpa_supplicant/wmm_ac.h
new file mode 100644
index 0000000..5171b16
--- /dev/null
+++ b/wpa_supplicant/wmm_ac.h
@@ -0,0 +1,176 @@
+/*
+ * Wi-Fi Multimedia Admission Control (WMM-AC)
+ * Copyright(c) 2014, Intel Mobile Communication GmbH.
+ * Copyright(c) 2014, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WMM_AC_H
+#define WMM_AC_H
+
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+
+struct wpa_supplicant;
+
+#define WMM_AC_ACCESS_POLICY_EDCA 1
+#define WMM_AC_FIXED_MSDU_SIZE BIT(15)
+
+#define WMM_AC_MAX_TID 7
+#define WMM_AC_MAX_USER_PRIORITY 7
+#define WMM_AC_MIN_SBA_UNITY 0x2000
+#define WMM_AC_MAX_NOMINAL_MSDU 32767
+
+/**
+ * struct wmm_ac_assoc_data - WMM Admission Control Association Data
+ *
+ * This struct will store any relevant WMM association data needed by WMM AC.
+ * In case there is a valid WMM association, an instance of this struct will be
+ * created. In case there is no instance of this struct, the station is not
+ * associated to a valid WMM BSS and hence, WMM AC will not be used.
+ */
+struct wmm_ac_assoc_data {
+	struct {
+		/*
+		 * acm - Admission Control Mandatory
+		 * In case an access category is ACM, the traffic will have
+		 * to be admitted by WMM-AC's admission mechanism before use.
+		 */
+		unsigned int acm:1;
+
+		/*
+		 * uapsd_queues - Unscheduled Automatic Power Save Delivery
+		 *		  queues.
+		 * Indicates whether ACs are configured for U-APSD (or legacy
+		 * PS). Storing this value is necessary in order to set the
+		 * Power Save Bit (PSB) in ADDTS request Action frames (if not
+		 * given).
+		 */
+		unsigned int uapsd:1;
+	} ac_params[WMM_AC_NUM];
+};
+
+/**
+ * wmm_ac_dir - WMM Admission Control Direction
+ */
+enum wmm_ac_dir {
+	WMM_AC_DIR_UPLINK = 0,
+	WMM_AC_DIR_DOWNLINK = 1,
+	WMM_AC_DIR_BIDIRECTIONAL = 3
+};
+
+/**
+ * ts_dir_idx - indices of internally saved tspecs
+ *
+ * we can have multiple tspecs (downlink + uplink) per ac.
+ * save them in array, and use the enum to directly access
+ * the respective tspec slot (according to the direction).
+ */
+enum ts_dir_idx {
+	TS_DIR_IDX_UPLINK,
+	TS_DIR_IDX_DOWNLINK,
+	TS_DIR_IDX_BIDI,
+
+	TS_DIR_IDX_COUNT
+};
+#define TS_DIR_IDX_ALL (BIT(TS_DIR_IDX_COUNT) - 1)
+
+/**
+ * struct wmm_ac_addts_request - ADDTS Request Information
+ *
+ * The last sent ADDTS request(s) will be saved as element(s) of this struct in
+ * order to be compared with the received ADDTS response in ADDTS response
+ * action frame handling and should be stored until that point.
+ * In case a new traffic stream will be created/replaced/updated, only its
+ * relevant traffic stream information will be stored as a wmm_ac_ts struct.
+ */
+struct wmm_ac_addts_request {
+	/*
+	 * dialog token - Used to link the recived ADDTS response with this
+	 * saved ADDTS request when ADDTS response is being handled
+	 */
+	u8 dialog_token;
+
+	/*
+	 * address - The alleged traffic stream's receiver/transmitter address
+	 * Address and TID are used to identify the TS (TID is contained in
+	 * TSPEC)
+	 */
+	u8 address[ETH_ALEN];
+
+	/*
+	 * tspec - Traffic Stream Specification, will be used to compare the
+	 * sent TSPEC in ADDTS request to the received TSPEC in ADDTS response
+	 * and act accordingly in ADDTS response handling
+	 */
+	struct wmm_tspec_element tspec;
+};
+
+
+/**
+ * struct wmm_ac_ts_setup_params - TS setup parameters
+ *
+ * This struct holds parameters which should be provided
+ * to wmm_ac_ts_setup in order to setup a traffic stream
+ */
+struct wmm_ac_ts_setup_params {
+	/*
+	 * tsid - Traffic ID
+	 * TID and address are used to identify the TS
+	 */
+	int tsid;
+
+	/*
+	 * direction - Traffic Stream's direction
+	 */
+	enum wmm_ac_dir direction;
+
+	/*
+	 * user_priority - Traffic Stream's user priority
+	 */
+	int user_priority;
+
+	/*
+	 * nominal_msdu_size - Nominal MAC service data unit size
+	 */
+	int nominal_msdu_size;
+
+	/*
+	 * fixed_nominal_msdu - Whether the size is fixed
+	 * 0 = Nominal MSDU size is not fixed
+	 * 1 = Nominal MSDU size is fixed
+	 */
+	int fixed_nominal_msdu;
+
+	/*
+	 * surplus_bandwidth_allowance - Specifies excess time allocation
+	 */
+	int mean_data_rate;
+
+	/*
+	 * minimum_phy_rate - Specifies the minimum supported PHY rate in bps
+	 */
+	int minimum_phy_rate;
+
+	/*
+	 * surplus_bandwidth_allowance - Specifies excess time allocation
+	 */
+	int surplus_bandwidth_allowance;
+};
+
+void wmm_ac_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *ies,
+			 size_t ies_len, const struct wmm_params *wmm_params);
+void wmm_ac_notify_disassoc(struct wpa_supplicant *wpa_s);
+int wpas_wmm_ac_addts(struct wpa_supplicant *wpa_s,
+		      struct wmm_ac_ts_setup_params *params);
+int wpas_wmm_ac_delts(struct wpa_supplicant *wpa_s, u8 tsid);
+void wmm_ac_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+			const u8 *sa, const u8 *data, size_t len);
+int wpas_wmm_ac_status(struct wpa_supplicant *wpa_s, char *buf, size_t buflen);
+void wmm_ac_save_tspecs(struct wpa_supplicant *wpa_s);
+void wmm_ac_clear_saved_tspecs(struct wpa_supplicant *wpa_s);
+int wmm_ac_restore_tspecs(struct wpa_supplicant *wpa_s);
+
+#endif /* WMM_AC_H */
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 4a792c4..954de67 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 #include "common/wpa_ctrl.h"
 #include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
@@ -244,6 +245,7 @@
 	/* multiple TFS Resp IE (assuming consecutive) */
 	u8 *tfsresp_ie_start = NULL;
 	u8 *tfsresp_ie_end = NULL;
+	size_t left;
 
 	if (len < 3)
 		return;
@@ -251,11 +253,12 @@
 
 	wpa_printf(MSG_DEBUG, "WNM-Sleep Mode Response token=%u key_len_total=%d",
 		   frm[0], key_len_total);
-	pos += 3 + key_len_total;
-	if (pos > frm + len) {
+	left = len - 3;
+	if (key_len_total > left) {
 		wpa_printf(MSG_INFO, "WNM: Too short frame for Key Data field");
 		return;
 	}
+	pos += 3 + key_len_total;
 	while (pos - frm < len) {
 		u8 ie_len = *(pos + 1);
 		if (pos + 2 + ie_len > frm + len) {
@@ -309,13 +312,7 @@
 	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);
 	}
 
@@ -334,12 +331,9 @@
 			wpa_printf(MSG_DEBUG, "WNM: Too short TSF");
 			break;
 		}
-		os_free(rep->tsf_info);
-		rep->tsf_info = os_zalloc(sizeof(struct tsf_info));
-		if (rep->tsf_info == NULL)
-			break;
-		os_memcpy(rep->tsf_info->tsf_offset, pos, 2);
-		os_memcpy(rep->tsf_info->beacon_interval, pos + 2, 2);
+		rep->tsf_offset = WPA_GET_LE16(pos);
+		rep->beacon_int = WPA_GET_LE16(pos + 2);
+		rep->tsf_present = 1;
 		break;
 	case WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING:
 		if (elen < 2) {
@@ -347,12 +341,8 @@
 				   "country string");
 			break;
 		}
-		os_free(rep->con_coun_str);
-		rep->con_coun_str =
-			os_zalloc(sizeof(struct condensed_country_string));
-		if (rep->con_coun_str == NULL)
-			break;
-		os_memcpy(rep->con_coun_str->country_string, pos, 2);
+		os_memcpy(rep->country, pos, 2);
+		rep->country_present = 1;
 		break;
 	case WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE:
 		if (elen < 1) {
@@ -360,25 +350,13 @@
 				   "candidate");
 			break;
 		}
-		os_free(rep->bss_tran_can);
-		rep->bss_tran_can =
-			os_zalloc(sizeof(struct bss_transition_candidate));
-		if (rep->bss_tran_can == NULL)
-			break;
-		rep->bss_tran_can->preference = pos[0];
+		rep->preference = pos[0];
+		rep->preference_present = 1;
 		break;
 	case WNM_NEIGHBOR_BSS_TERMINATION_DURATION:
-		if (elen < 10) {
-			wpa_printf(MSG_DEBUG, "WNM: Too short BSS termination "
-				   "duration");
-			break;
-		}
-		os_free(rep->bss_term_dur);
-		rep->bss_term_dur =
-			os_zalloc(sizeof(struct bss_termination_duration));
-		if (rep->bss_term_dur == NULL)
-			break;
-		os_memcpy(rep->bss_term_dur->duration, pos, 10);
+		rep->bss_term_tsf = WPA_GET_LE64(pos);
+		rep->bss_term_dur = WPA_GET_LE16(pos + 8);
+		rep->bss_term_present = 1;
 		break;
 	case WNM_NEIGHBOR_BEARING:
 		if (elen < 8) {
@@ -386,11 +364,10 @@
 				   "bearing");
 			break;
 		}
-		os_free(rep->bearing);
-		rep->bearing = os_zalloc(sizeof(struct bearing));
-		if (rep->bearing == NULL)
-			break;
-		os_memcpy(rep->bearing->bearing, pos, 8);
+		rep->bearing = WPA_GET_LE16(pos);
+		rep->distance = WPA_GET_LE32(pos + 2);
+		rep->rel_height = WPA_GET_LE16(pos + 2 + 4);
+		rep->bearing_present = 1;
 		break;
 	case WNM_NEIGHBOR_MEASUREMENT_PILOT:
 		if (elen < 1) {
@@ -412,12 +389,8 @@
 				   "capabilities");
 			break;
 		}
-		os_free(rep->rrm_cap);
-		rep->rrm_cap =
-			os_zalloc(sizeof(struct rrm_enabled_capabilities));
-		if (rep->rrm_cap == NULL)
-			break;
-		os_memcpy(rep->rrm_cap->capabilities, pos, 5);
+		os_memcpy(rep->rm_capab, pos, 5);
+		rep->rm_capab_present = 1;
 		break;
 	case WNM_NEIGHBOR_MULTIPLE_BSSID:
 		if (elen < 1) {
@@ -436,6 +409,22 @@
 }
 
 
+static int wnm_nei_get_chan(struct wpa_supplicant *wpa_s, u8 op_class, u8 chan)
+{
+	struct wpa_bss *bss = wpa_s->current_bss;
+	const char *country = NULL;
+
+	if (bss) {
+		const u8 *elem = wpa_bss_get_ie(bss, WLAN_EID_COUNTRY);
+
+		if (elem && elem[1] >= 2)
+			country = (const char *) (elem + 2);
+	}
+
+	return ieee80211_chan_to_freq(country, op_class, chan);
+}
+
+
 static void wnm_parse_neighbor_report(struct wpa_supplicant *wpa_s,
 				      const u8 *pos, u8 len,
 				      struct neighbor_report *rep)
@@ -448,7 +437,7 @@
 	}
 
 	os_memcpy(rep->bssid, pos, ETH_ALEN);
-	os_memcpy(rep->bssid_information, pos + ETH_ALEN, 4);
+	rep->bssid_info = WPA_GET_LE32(pos + ETH_ALEN);
 	rep->regulatory_class = *(pos + 10);
 	rep->channel_number = *(pos + 11);
 	rep->phy_type = *(pos + 12);
@@ -472,47 +461,78 @@
 		left -= elen;
 		pos += elen;
 	}
+
+	rep->freq = wnm_nei_get_chan(wpa_s, rep->regulatory_class,
+				     rep->channel_number);
 }
 
 
-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)
+static struct wpa_bss *
+compare_scan_neighbor_results(struct wpa_supplicant *wpa_s)
 {
 
-	u8 i, j;
+	u8 i;
+	struct wpa_bss *bss = wpa_s->current_bss;
+	struct wpa_bss *target;
 
-	if (scan_res == NULL || num_neigh_rep == 0 || !wpa_s->current_bss)
+	if (!bss)
 		return 0;
 
 	wpa_printf(MSG_DEBUG, "WNM: Current BSS " MACSTR " RSSI %d",
-		   MAC2STR(wpa_s->bssid), wpa_s->current_bss->level);
+		   MAC2STR(wpa_s->bssid), bss->level);
 
-	for (i = 0; i < num_neigh_rep; i++) {
-		for (j = 0; j < scan_res->num; j++) {
-			/* Check for a better RSSI AP */
-			if (os_memcmp(scan_res->res[j]->bssid,
-				      neigh_rep[i].bssid, ETH_ALEN) == 0 &&
-			    scan_res->res[j]->level >
-			    wpa_s->current_bss->level) {
-				/* Got a BSSID with better RSSI value */
-				os_memcpy(bssid_to_connect, neigh_rep[i].bssid,
-					  ETH_ALEN);
-				wpa_printf(MSG_DEBUG, "Found a BSS " MACSTR
-					   " with better scan RSSI %d",
-					   MAC2STR(scan_res->res[j]->bssid),
-					   scan_res->res[j]->level);
-				return 1;
-			}
-			wpa_printf(MSG_DEBUG, "scan_res[%d] " MACSTR
-				   " RSSI %d", j,
-				   MAC2STR(scan_res->res[j]->bssid),
-				   scan_res->res[j]->level);
+	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+		struct neighbor_report *nei;
+
+		nei = &wpa_s->wnm_neighbor_report_elements[i];
+		if (nei->preference_present && nei->preference == 0) {
+			wpa_printf(MSG_DEBUG, "Skip excluded BSS " MACSTR,
+				   MAC2STR(nei->bssid));
+			continue;
 		}
+
+		target = wpa_bss_get_bssid(wpa_s, nei->bssid);
+		if (!target) {
+			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+				   " (pref %d) not found in scan results",
+				   MAC2STR(nei->bssid),
+				   nei->preference_present ? nei->preference :
+				   -1);
+			continue;
+		}
+
+		if (bss->ssid_len != target->ssid_len ||
+		    os_memcmp(bss->ssid, target->ssid, bss->ssid_len) != 0) {
+			/*
+			 * TODO: Could consider allowing transition to another
+			 * ESS if PMF was enabled for the association.
+			 */
+			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+				   " (pref %d) in different ESS",
+				   MAC2STR(nei->bssid),
+				   nei->preference_present ? nei->preference :
+				   -1);
+			continue;
+		}
+
+		if (target->level < bss->level && target->level < -80) {
+			wpa_printf(MSG_DEBUG, "Candidate BSS " MACSTR
+				   " (pref %d) does not have sufficient signal level (%d)",
+				   MAC2STR(nei->bssid),
+				   nei->preference_present ? nei->preference :
+				   -1,
+				   target->level);
+			continue;
+		}
+
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Found an acceptable preferred transition candidate BSS "
+			   MACSTR " (RSSI %d)",
+			   MAC2STR(nei->bssid), target->level);
+		return target;
 	}
 
-	return 0;
+	return NULL;
 }
 
 
@@ -524,10 +544,16 @@
 	u8 buf[1000], *pos;
 	struct ieee80211_mgmt *mgmt;
 	size_t len;
+	int res;
 
 	wpa_printf(MSG_DEBUG, "WNM: Send BSS Transition Management Response "
 		   "to " MACSTR " dialog_token=%u status=%u delay=%d",
 		   MAC2STR(wpa_s->bssid), dialog_token, status, delay);
+	if (!wpa_s->current_bss) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Current BSS not known - drop response");
+		return;
+	}
 
 	mgmt = (struct ieee80211_mgmt *) buf;
 	os_memset(&buf, 0, sizeof(buf));
@@ -557,62 +583,203 @@
 
 	len = pos - (u8 *) &mgmt->u.action.category;
 
-	wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
-			    wpa_s->own_addr, wpa_s->bssid,
-			    &mgmt->u.action.category, len, 0);
+	res = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				  wpa_s->own_addr, wpa_s->bssid,
+				  &mgmt->u.action.category, len, 0);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Failed to send BSS Transition Management Response");
+	}
 }
 
 
-void wnm_scan_response(struct wpa_supplicant *wpa_s,
-		       struct wpa_scan_results *scan_res)
+int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail)
 {
-	u8 bssid[ETH_ALEN];
+	struct wpa_bss *bss;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	enum bss_trans_mgmt_status_code status = WNM_BSS_TM_REJECT_UNSPECIFIED;
 
-	if (scan_res == NULL) {
-		wpa_printf(MSG_ERROR, "Scan result is NULL");
-		goto send_bss_resp_fail;
+	if (!wpa_s->wnm_neighbor_report_elements)
+		return 0;
+
+	if (os_reltime_before(&wpa_s->wnm_cand_valid_until,
+			      &wpa_s->scan_trigger_time)) {
+		wpa_printf(MSG_DEBUG, "WNM: Previously stored BSS transition candidate list is not valid anymore - drop it");
+		wnm_deallocate_memory(wpa_s);
+		return 0;
+	}
+
+	if (!wpa_s->current_bss ||
+	    os_memcmp(wpa_s->wnm_cand_from_bss, wpa_s->current_bss->bssid,
+		      ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "WNM: Stored BSS transition candidate list not from the current BSS - ignore it");
+		return 0;
 	}
 
 	/* 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 = compare_scan_neighbor_results(wpa_s);
+	if (!bss) {
+		wpa_printf(MSG_DEBUG, "WNM: No BSS transition candidate match found");
+		status = WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES;
+		goto send_bss_resp_fail;
+	}
 
-		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,
+	/* Associate to the network */
+	/* Send the BSS Management Response - Accept */
+	if (wpa_s->wnm_reply) {
+		wpa_s->wnm_reply = 0;
+		wnm_send_bss_transition_mgmt_resp(wpa_s,
 						  wpa_s->wnm_dialog_token,
 						  WNM_BSS_TM_ACCEPT,
-						  0, bssid);
-		}
+						  0, bss->bssid);
+	}
 
-		wpa_s->reassociate = 1;
-		wpa_supplicant_connect(wpa_s, bss, ssid);
-		wnm_deallocate_memory(wpa_s);
+	if (bss == wpa_s->current_bss) {
+		wpa_printf(MSG_DEBUG,
+			   "WNM: Already associated with the preferred candidate");
+		return 1;
+	}
+
+	wpa_s->reassociate = 1;
+	wpa_supplicant_connect(wpa_s, bss, ssid);
+	wnm_deallocate_memory(wpa_s);
+	return 1;
+
+send_bss_resp_fail:
+	if (!reply_on_fail)
+		return 0;
+
+	/* Send reject response for all the failures */
+
+	if (wpa_s->wnm_reply) {
+		wpa_s->wnm_reply = 0;
+		wnm_send_bss_transition_mgmt_resp(wpa_s,
+						  wpa_s->wnm_dialog_token,
+						  status, 0, NULL);
+	}
+	wnm_deallocate_memory(wpa_s);
+
+	return 0;
+}
+
+
+static int cand_pref_compar(const void *a, const void *b)
+{
+	const struct neighbor_report *aa = a;
+	const struct neighbor_report *bb = b;
+
+	if (!aa->preference_present && !bb->preference_present)
+		return 0;
+	if (!aa->preference_present)
+		return 1;
+	if (!bb->preference_present)
+		return -1;
+	if (bb->preference > aa->preference)
+		return 1;
+	if (bb->preference < aa->preference)
+		return -1;
+	return 0;
+}
+
+
+static void wnm_sort_cand_list(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->wnm_neighbor_report_elements)
+		return;
+	qsort(wpa_s->wnm_neighbor_report_elements,
+	      wpa_s->wnm_num_neighbor_report, sizeof(struct neighbor_report),
+	      cand_pref_compar);
+}
+
+
+static void wnm_dump_cand_list(struct wpa_supplicant *wpa_s)
+{
+	unsigned int i;
+
+	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Candidate List");
+	if (!wpa_s->wnm_neighbor_report_elements)
+		return;
+	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+		struct neighbor_report *nei;
+
+		nei = &wpa_s->wnm_neighbor_report_elements[i];
+		wpa_printf(MSG_DEBUG, "%u: " MACSTR
+			   " info=0x%x op_class=%u chan=%u phy=%u pref=%d freq=%d",
+			   i, MAC2STR(nei->bssid), nei->bssid_info,
+			   nei->regulatory_class,
+			   nei->channel_number, nei->phy_type,
+			   nei->preference_present ? nei->preference : -1,
+			   nei->freq);
+	}
+}
+
+
+static int chan_supported(struct wpa_supplicant *wpa_s, int freq)
+{
+	unsigned int i;
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		struct hostapd_hw_modes *mode = &wpa_s->hw.modes[i];
+		int j;
+
+		for (j = 0; j < mode->num_channels; j++) {
+			struct hostapd_channel_data *chan;
+
+			chan = &mode->channels[j];
+			if (chan->freq == freq &&
+			    !(chan->flag & HOSTAPD_CHAN_DISABLED))
+				return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+static void wnm_set_scan_freqs(struct wpa_supplicant *wpa_s)
+{
+	int *freqs;
+	int num_freqs = 0;
+	unsigned int i;
+
+	if (!wpa_s->wnm_neighbor_report_elements)
+		return;
+
+	if (wpa_s->hw.modes == NULL)
+		return;
+
+	os_free(wpa_s->next_scan_freqs);
+	wpa_s->next_scan_freqs = NULL;
+
+	freqs = os_calloc(wpa_s->wnm_num_neighbor_report + 1, sizeof(int));
+	if (freqs == NULL)
+		return;
+
+	for (i = 0; i < wpa_s->wnm_num_neighbor_report; i++) {
+		struct neighbor_report *nei;
+
+		nei = &wpa_s->wnm_neighbor_report_elements[i];
+		if (nei->freq <= 0) {
+			wpa_printf(MSG_DEBUG,
+				   "WNM: Unknown neighbor operating frequency for "
+				   MACSTR " - scan all channels",
+				   MAC2STR(nei->bssid));
+			os_free(freqs);
+			return;
+		}
+		if (chan_supported(wpa_s, nei->freq))
+			add_freq(freqs, &num_freqs, nei->freq);
+	}
+
+	if (num_freqs == 0) {
+		os_free(freqs);
 		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;
+	wpa_printf(MSG_DEBUG,
+		   "WNM: Scan %d frequencies based on transition candidate list",
+		   num_freqs);
+	wpa_s->next_scan_freqs = freqs;
 }
 
 
@@ -620,20 +787,28 @@
 					     const u8 *pos, const u8 *end,
 					     int reply)
 {
+	unsigned int beacon_int;
+	u8 valid_int;
+
 	if (pos + 5 > end)
 		return;
 
+	if (wpa_s->current_bss)
+		beacon_int = wpa_s->current_bss->beacon_int;
+	else
+		beacon_int = 100; /* best guess */
+
 	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];
+	valid_int = pos[4];
 	wpa_s->wnm_reply = reply;
 
 	wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Request: "
 		   "dialog_token=%u request_mode=0x%x "
 		   "disassoc_timer=%u validity_interval=%u",
 		   wpa_s->wnm_dialog_token, wpa_s->wnm_mode,
-		   wpa_s->wnm_dissoc_timer, wpa_s->wnm_validity_interval);
+		   wpa_s->wnm_dissoc_timer, valid_int);
 
 	pos += 5;
 
@@ -648,7 +823,6 @@
 
 	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 "
@@ -659,11 +833,6 @@
 		url[pos[0]] = '\0';
 		pos += 1 + pos[0];
 
-		if (wpa_s->current_bss)
-			beacon_int = wpa_s->current_bss->beacon_int;
-		else
-			beacon_int = 100; /* best guess */
-
 		wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
 			wpa_sm_pmf_enabled(wpa_s->wpa),
 			wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
@@ -681,11 +850,12 @@
 	}
 
 	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
+		unsigned int valid_ms;
+
 		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 *
+		wnm_deallocate_memory(wpa_s);
+		wpa_s->wnm_neighbor_report_elements = os_calloc(
+			WNM_MAX_NEIGHBOR_REPORT,
 			sizeof(struct neighbor_report));
 		if (wpa_s->wnm_neighbor_report_elements == NULL)
 			return;
@@ -712,8 +882,34 @@
 			pos += len;
 			wpa_s->wnm_num_neighbor_report++;
 		}
+		wnm_sort_cand_list(wpa_s);
+		wnm_dump_cand_list(wpa_s);
+		valid_ms = valid_int * beacon_int * 128 / 125;
+		wpa_printf(MSG_DEBUG, "WNM: Candidate list valid for %u ms",
+			   valid_ms);
+		os_get_reltime(&wpa_s->wnm_cand_valid_until);
+		wpa_s->wnm_cand_valid_until.sec += valid_ms / 1000;
+		wpa_s->wnm_cand_valid_until.usec += (valid_ms % 1000) * 1000;
+		wpa_s->wnm_cand_valid_until.sec +=
+			wpa_s->wnm_cand_valid_until.usec / 1000000;
+		wpa_s->wnm_cand_valid_until.usec %= 1000000;
+		os_memcpy(wpa_s->wnm_cand_from_bss, wpa_s->bssid, ETH_ALEN);
 
-		wpa_s->scan_res_handler = wnm_scan_response;
+		if (wpa_s->last_scan_res_used > 0) {
+			struct os_reltime now;
+
+			os_get_reltime(&now);
+			if (!os_reltime_expired(&now, &wpa_s->last_scan, 10)) {
+				wpa_printf(MSG_DEBUG,
+					   "WNM: Try to use recent scan results");
+				if (wnm_scan_process(wpa_s, 0) > 0)
+					return;
+				wpa_printf(MSG_DEBUG,
+					   "WNM: No match in previous scan results - try a new scan");
+			}
+		}
+
+		wnm_set_scan_freqs(wpa_s);
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
 	} else if (reply) {
 		enum bss_trans_mgmt_status_code status;
diff --git a/wpa_supplicant/wnm_sta.h b/wpa_supplicant/wnm_sta.h
index d2eb96d..8de4348 100644
--- a/wpa_supplicant/wnm_sta.h
+++ b/wpa_supplicant/wnm_sta.h
@@ -9,37 +9,12 @@
 #ifndef WNM_STA_H
 #define WNM_STA_H
 
-struct tsf_info {
-	u8 tsf_offset[2];
-	u8 beacon_interval[2];
-};
-
-struct condensed_country_string {
-	u8 country_string[2];
-};
-
-struct bss_transition_candidate {
-	u8 preference;
-};
-
-struct bss_termination_duration {
-	u8 duration[10];
-};
-
-struct bearing {
-	u8 bearing[8];
-};
-
 struct measurement_pilot {
 	u8 measurement_pilot;
 	u8 subelem_len;
 	u8 subelems[255];
 };
 
-struct rrm_enabled_capabilities {
-	u8 capabilities[5];
-};
-
 struct multiple_bssid {
 	u8 max_bssid_indicator;
 	u8 subelem_len;
@@ -48,18 +23,29 @@
 
 struct neighbor_report {
 	u8 bssid[ETH_ALEN];
-	u8 bssid_information[4];
+	u32 bssid_info;
 	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;
+	u8 preference; /* valid if preference_present=1 */
+	u16 tsf_offset; /* valid if tsf_present=1 */
+	u16 beacon_int; /* valid if tsf_present=1 */
+	char country[2]; /* valid if country_present=1 */
+	u8 rm_capab[5]; /* valid if rm_capab_present=1 */
+	u16 bearing; /* valid if bearing_present=1 */
+	u16 rel_height; /* valid if bearing_present=1 */
+	u32 distance; /* valid if bearing_present=1 */
+	u64 bss_term_tsf; /* valid if bss_term_present=1 */
+	u16 bss_term_dur; /* valid if bss_term_present=1 */
+	unsigned int preference_present:1;
+	unsigned int tsf_present:1;
+	unsigned int country_present:1;
+	unsigned int rm_capab_present:1;
+	unsigned int bearing_present:1;
+	unsigned int bss_term_present:1;
 	struct measurement_pilot *meas_pilot;
-	struct rrm_enabled_capabilities *rrm_cap;
 	struct multiple_bssid *mul_bssid;
+	int freq;
 };
 
 
@@ -69,11 +55,23 @@
 void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
 			      const struct ieee80211_mgmt *mgmt, size_t len);
 
-void wnm_scan_response(struct wpa_supplicant *wpa_s,
-		       struct wpa_scan_results *scan_res);
-
 int wnm_send_bss_transition_mgmt_query(struct wpa_supplicant *wpa_s,
 				       u8 query_reason);
 void wnm_deallocate_memory(struct wpa_supplicant *wpa_s);
 
+
+#ifdef CONFIG_WNM
+
+int wnm_scan_process(struct wpa_supplicant *wpa_s, int reply_on_fail);
+
+#else /* CONFIG_WNM */
+
+static inline int wnm_scan_process(struct wpa_supplicant *wpa_s,
+				   int reply_on_fail)
+{
+	return 0;
+}
+
+#endif /* CONFIG_WNM */
+
 #endif /* WNM_STA_H */
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index fe30b41..d2face0 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -333,7 +333,7 @@
 			return -1;
 		res = os_snprintf(cfile, flen, "%s/%s", ctrl_iface_dir,
 				  ifname);
-		if (res < 0 || res >= flen) {
+		if (os_snprintf_error(flen, res)) {
 			os_free(cfile);
 			return -1;
 		}
@@ -448,13 +448,13 @@
 	end = buf + buflen;
 
 	res = os_snprintf(pos, end - pos, "%s", cmd);
-	if (res < 0 || res >= end - pos)
+	if (os_snprintf_error(end - pos, res))
 		goto fail;
 	pos += res;
 
 	for (i = 0; i < argc; i++) {
 		res = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			goto fail;
 		pos += res;
 	}
@@ -584,7 +584,7 @@
 
 	if (argc == 1) {
 		res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
-		if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		if (os_snprintf_error(sizeof(cmd), res)) {
 			printf("Too long SET command.\n");
 			return -1;
 		}
@@ -610,7 +610,8 @@
 		/* 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",
+		"pkcs11_module_path", "openssl_ciphers",
+		"pcsc_reader", "pcsc_pin",
 		"driver_param", "dot11RSNAConfigPMKLifetime",
 		"dot11RSNAConfigPMKReauthThreshold",
 		"dot11RSNAConfigSATimeout",
@@ -732,7 +733,7 @@
 		res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH 0");
 	else
 		res = os_snprintf(cmd, sizeof(cmd), "BSS_FLUSH %s", argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+	if (os_snprintf_error(sizeof(cmd), res)) {
 		printf("Too long BSS_FLUSH command.\n");
 		return -1;
 	}
@@ -907,7 +908,7 @@
 		return -1;
 	}
 
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+	if (os_snprintf_error(sizeof(cmd), res)) {
 		printf("Too long WPS_REG command.\n");
 		return -1;
 	}
@@ -1032,7 +1033,7 @@
 		return -1;
 	}
 
-	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+	if (os_snprintf_error(sizeof(cmd), res)) {
 		printf("Too long WPS_ER_CONFIG command.\n");
 		return -1;
 	}
@@ -1084,14 +1085,14 @@
 	pos = cmd;
 	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "IDENTITY-%s:%s",
 			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
+	if (os_snprintf_error(end - pos, ret)) {
 		printf("Too long IDENTITY command.\n");
 		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			printf("Too long IDENTITY command.\n");
 			return -1;
 		}
@@ -1117,14 +1118,14 @@
 	pos = cmd;
 	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSWORD-%s:%s",
 			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
+	if (os_snprintf_error(end - pos, ret)) {
 		printf("Too long PASSWORD command.\n");
 		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			printf("Too long PASSWORD command.\n");
 			return -1;
 		}
@@ -1151,14 +1152,14 @@
 	pos = cmd;
 	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "NEW_PASSWORD-%s:%s",
 			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
+	if (os_snprintf_error(end - pos, ret)) {
 		printf("Too long NEW_PASSWORD command.\n");
 		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			printf("Too long NEW_PASSWORD command.\n");
 			return -1;
 		}
@@ -1184,14 +1185,14 @@
 	pos = cmd;
 	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PIN-%s:%s",
 			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
+	if (os_snprintf_error(end - pos, ret)) {
 		printf("Too long PIN command.\n");
 		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			printf("Too long PIN command.\n");
 			return -1;
 		}
@@ -1216,14 +1217,14 @@
 	pos = cmd;
 	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "OTP-%s:%s",
 			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
+	if (os_snprintf_error(end - pos, ret)) {
 		printf("Too long OTP command.\n");
 		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			printf("Too long OTP command.\n");
 			return -1;
 		}
@@ -1249,14 +1250,14 @@
 	pos = cmd;
 	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "SIM-%s:%s",
 			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
+	if (os_snprintf_error(end - pos, ret)) {
 		printf("Too long SIM command.\n");
 		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			printf("Too long SIM command.\n");
 			return -1;
 		}
@@ -1282,14 +1283,14 @@
 	pos = cmd;
 	ret = os_snprintf(pos, end - pos, WPA_CTRL_RSP "PASSPHRASE-%s:%s",
 			  argv[0], argv[1]);
-	if (ret < 0 || ret >= end - pos) {
+	if (os_snprintf_error(end - pos, ret)) {
 		printf("Too long PASSPHRASE command.\n");
 		return -1;
 	}
 	pos += ret;
 	for (i = 2; i < argc; i++) {
 		ret = os_snprintf(pos, end - pos, " %s", argv[i]);
-		if (ret < 0 || ret >= end - pos) {
+		if (os_snprintf_error(end - pos, ret)) {
 			printf("Too long PASSPHRASE command.\n");
 			return -1;
 		}
@@ -1625,7 +1626,7 @@
 			  argc > 1 ? argv[1] : "", argc > 2 ? argv[2] : "",
 			  argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : "",
 			  argc > 5 ? argv[5] : "");
-	if (res < 0 || (size_t) res >= sizeof(cmd))
+	if (os_snprintf_error(sizeof(cmd), res))
 		return -1;
 	cmd[sizeof(cmd) - 1] = '\0';
 	return wpa_ctrl_command(ctrl, cmd);
@@ -1751,6 +1752,31 @@
 }
 
 
+#ifdef CONFIG_MESH
+
+static int wpa_cli_cmd_mesh_interface_add(struct wpa_ctrl *ctrl, int argc,
+					  char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "MESH_INTERFACE_ADD", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mesh_group_add(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "MESH_GROUP_ADD", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_mesh_group_remove(struct wpa_ctrl *ctrl, int argc,
+					 char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "MESH_GROUP_REMOVE", 1, argc, argv);
+}
+
+#endif /* CONFIG_MESH */
+
+
 #ifdef CONFIG_P2P
 
 static int wpa_cli_cmd_p2p_find(struct wpa_ctrl *ctrl, int argc, char *argv[])
@@ -1914,7 +1940,7 @@
 
 	res = os_snprintf(cmd, sizeof(cmd), "P2P_SERV_DISC_RESP %s %s %s %s",
 			  argv[0], argv[1], argv[2], argv[3]);
-	if (res < 0 || (size_t) res >= sizeof(cmd))
+	if (os_snprintf_error(sizeof(cmd), res))
 		return -1;
 	cmd[sizeof(cmd) - 1] = '\0';
 	return wpa_ctrl_command(ctrl, cmd);
@@ -1962,7 +1988,7 @@
 		res = os_snprintf(cmd, sizeof(cmd),
 				  "P2P_SERVICE_ADD %s %s %s",
 				  argv[0], argv[1], argv[2]);
-	if (res < 0 || (size_t) res >= sizeof(cmd))
+	if (os_snprintf_error(sizeof(cmd), res))
 		return -1;
 	cmd[sizeof(cmd) - 1] = '\0';
 	return wpa_ctrl_command(ctrl, cmd);
@@ -1989,7 +2015,7 @@
 		res = os_snprintf(cmd, sizeof(cmd),
 				  "P2P_SERVICE_DEL %s %s",
 				  argv[0], argv[1]);
-	if (res < 0 || (size_t) res >= sizeof(cmd))
+	if (os_snprintf_error(sizeof(cmd), res))
 		return -1;
 	cmd[sizeof(cmd) - 1] = '\0';
 	return wpa_ctrl_command(ctrl, cmd);
@@ -2211,7 +2237,7 @@
 
 	res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_SET %s %s",
 			  argv[0], argc > 1 ? argv[1] : "");
-	if (res < 0 || (size_t) res >= sizeof(cmd))
+	if (os_snprintf_error(sizeof(cmd), res))
 		return -1;
 	cmd[sizeof(cmd) - 1] = '\0';
 	return wpa_ctrl_command(ctrl, cmd);
@@ -2232,7 +2258,7 @@
 
 	res = os_snprintf(cmd, sizeof(cmd), "WFD_SUBELEM_GET %s",
 			  argv[0]);
-	if (res < 0 || (size_t) res >= sizeof(cmd))
+	if (os_snprintf_error(sizeof(cmd), res))
 		return -1;
 	cmd[sizeof(cmd) - 1] = '\0';
 	return wpa_ctrl_command(ctrl, cmd);
@@ -2379,6 +2405,41 @@
 }
 
 
+static int wpa_cli_cmd_wmm_ac_addts(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "WMM_AC_ADDTS", 3, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wmm_ac_delts(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "WMM_AC_DELTS", 1, argc, argv);
+}
+
+
+static int wpa_cli_cmd_wmm_ac_status(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "WMM_AC_STATUS");
+}
+
+
+static int wpa_cli_cmd_tdls_chan_switch(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "TDLS_CHAN_SWITCH", 2, argc, argv);
+}
+
+
+static int wpa_cli_cmd_tdls_cancel_chan_switch(struct wpa_ctrl *ctrl, int argc,
+					       char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "TDLS_CANCEL_CHAN_SWITCH", 1, argc, argv);
+}
+
+
 static int wpa_cli_cmd_signal_poll(struct wpa_ctrl *ctrl, int argc,
 				   char *argv[])
 {
@@ -2463,6 +2524,26 @@
 }
 
 
+static int wpa_cli_cmd_neighbor_rep_request(struct wpa_ctrl *ctrl, int argc,
+					    char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "NEIGHBOR_REP_REQUEST", 0, argc, argv);
+}
+
+
+static int wpa_cli_cmd_erp_flush(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "ERP_FLUSH");
+}
+
+
+static int wpa_cli_cmd_mac_rand_scan(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	return wpa_cli_cmd(ctrl, "MAC_RAND_SCAN", 1, argc, argv);
+}
+
+
 enum wpa_cli_cmd_flags {
 	cli_cmd_flag_none		= 0x00,
 	cli_cmd_flag_sensitive		= 0x01
@@ -2780,6 +2861,17 @@
 	{ "roam", wpa_cli_cmd_roam, wpa_cli_complete_bss,
 	  cli_cmd_flag_none,
 	  "<addr> = roam to the specified BSS" },
+#ifdef CONFIG_MESH
+	{ "mesh_interface_add", wpa_cli_cmd_mesh_interface_add, NULL,
+	  cli_cmd_flag_none,
+	  "[ifname] = Create a new mesh interface" },
+	{ "mesh_group_add", wpa_cli_cmd_mesh_group_add, NULL,
+	  cli_cmd_flag_none,
+	  "<network id> = join a mesh network (disable others)" },
+	{ "mesh_group_remove", wpa_cli_cmd_mesh_group_remove, NULL,
+	  cli_cmd_flag_none,
+	  "<ifname> = Remove mesh group interface" },
+#endif /* CONFIG_MESH */
 #ifdef CONFIG_P2P
 	{ "p2p_find", wpa_cli_cmd_p2p_find, wpa_cli_complete_p2p_find,
 	  cli_cmd_flag_none,
@@ -2920,6 +3012,25 @@
 	{ "tdls_teardown", wpa_cli_cmd_tdls_teardown, NULL,
 	  cli_cmd_flag_none,
 	  "<addr> = tear down TDLS with <addr>" },
+	{ "wmm_ac_addts", wpa_cli_cmd_wmm_ac_addts, NULL,
+	  cli_cmd_flag_none,
+	  "<uplink/downlink/bidi> <tsid=0..7> <up=0..7> [nominal_msdu_size=#] "
+	  "[mean_data_rate=#] [min_phy_rate=#] [sba=#] [fixed_nominal_msdu] "
+	  "= add WMM-AC traffic stream" },
+	{ "wmm_ac_delts", wpa_cli_cmd_wmm_ac_delts, NULL,
+	  cli_cmd_flag_none,
+	  "<tsid> = delete WMM-AC traffic stream" },
+	{ "wmm_ac_status", wpa_cli_cmd_wmm_ac_status, NULL,
+	  cli_cmd_flag_none,
+	  "= show status for Wireless Multi-Media Admission-Control" },
+	{ "tdls_chan_switch", wpa_cli_cmd_tdls_chan_switch, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> <oper class> <freq> [sec_channel_offset=] [center_freq1=] "
+	  "[center_freq2=] [bandwidth=] [ht|vht] = enable channel switching "
+	  "with TDLS peer" },
+	{ "tdls_cancel_chan_switch", wpa_cli_cmd_tdls_cancel_chan_switch, NULL,
+	  cli_cmd_flag_none,
+	  "<addr> = disable channel switching with TDLS peer <addr>" },
 	{ "signal_poll", wpa_cli_cmd_signal_poll, NULL,
 	  cli_cmd_flag_none,
 	  "= get signal parameters" },
@@ -2952,6 +3063,18 @@
 	{ "vendor", wpa_cli_cmd_vendor, NULL, cli_cmd_flag_none,
 	  "<vendor id> <command id> [<hex formatted command argument>] = Send vendor command"
 	},
+	{ "neighbor_rep_request",
+	  wpa_cli_cmd_neighbor_rep_request, NULL, cli_cmd_flag_none,
+	  "[ssid=<SSID>] = Trigger request to AP for neighboring AP report "
+	  "(with optional given SSID, default: current SSID)"
+	},
+	{ "erp_flush", wpa_cli_cmd_erp_flush, NULL, cli_cmd_flag_none,
+	  "= flush ERP keys" },
+	{ "mac_rand_scan",
+	  wpa_cli_cmd_mac_rand_scan, NULL, cli_cmd_flag_none,
+	  "<scan|sched|pno|all> enable=<0/1> [addr=mac-address "
+	  "mask=mac-address-mask] = scan MAC randomization"
+	},
 	{ NULL, NULL, NULL, cli_cmd_flag_none, NULL }
 };
 
@@ -3245,6 +3368,14 @@
 			wpa_cli_connected = 0;
 			wpa_cli_exec(action_file, ifname, "DISCONNECTED");
 		}
+	} else if (str_match(pos, MESH_GROUP_STARTED)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, MESH_GROUP_REMOVED)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, MESH_PEER_CONNECTED)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, MESH_PEER_DISCONNECTED)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
 	} else if (str_match(pos, P2P_EVENT_GROUP_STARTED)) {
 		wpa_cli_exec(action_file, ifname, pos);
 	} else if (str_match(pos, P2P_EVENT_GROUP_REMOVED)) {
@@ -3594,7 +3725,7 @@
 			break;
 		*end = '\0';
 		ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos);
-		if (ret > 0 && ret < (int) sizeof(txt))
+		if (!os_snprintf_error(sizeof(txt), ret))
 			cli_txt_list_add(&ifnames, txt);
 		pos = end + 1;
 	}
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
index 6bba8d2..6276176 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -36,6 +36,7 @@
 	: QMainWindow(parent), app(_app)
 {
 	setupUi(this);
+	this->setWindowFlags(Qt::Dialog);
 
 #ifdef CONFIG_NATIVE_WINDOWS
 	fileStopServiceAction = new QAction(this);
@@ -129,6 +130,7 @@
 	udr = NULL;
 	tray_icon = NULL;
 	startInTray = false;
+	quietMode = false;
 	ctrl_iface = NULL;
 	ctrl_conn = NULL;
 	monitor_conn = NULL;
@@ -233,7 +235,7 @@
 {
 	int c;
 	for (;;) {
-		c = getopt(qApp->argc(), qApp->argv(), "i:p:t");
+		c = getopt(qApp->argc(), qApp->argv(), "i:p:tq");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -248,6 +250,9 @@
 		case 't':
 			startInTray = true;
 			break;
+		case 'q':
+			quietMode = true;
+			break;
 		}
 	}
 }
@@ -491,6 +496,7 @@
 		textSsid->clear();
 		textBssid->clear();
 		textIpAddress->clear();
+		updateTrayToolTip(tr("no status information"));
 
 #ifdef CONFIG_NATIVE_WINDOWS
 		static bool first = true;
@@ -538,6 +544,7 @@
 			} else if (strcmp(start, "ssid") == 0) {
 				ssid_updated = true;
 				textSsid->setText(pos);
+				updateTrayToolTip(pos + tr(" (associated)"));
 			} else if (strcmp(start, "ip_address") == 0) {
 				ipaddr_updated = true;
 				textIpAddress->setText(pos);
@@ -585,8 +592,10 @@
 		textStatus->clear();
 	if (!auth_updated)
 		textAuthentication->clear();
-	if (!ssid_updated)
+	if (!ssid_updated) {
 		textSsid->clear();
+		updateTrayToolTip(tr("(not-associated)"));
+	}
 	if (!bssid_updated)
 		textBssid->clear();
 	if (!ipaddr_updated)
@@ -1270,7 +1279,6 @@
 	QApplication::setQuitOnLastWindowClosed(false);
 
 	tray_icon = new QSystemTrayIcon(this);
-	tray_icon->setToolTip(qAppName() + tr(" - wpa_supplicant user interface"));
 	if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
 		tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg"));
 	else
@@ -1332,7 +1340,7 @@
 	if (!QSystemTrayIcon::supportsMessages())
 		return;
 
-	if (isVisible() || !tray_icon || !tray_icon->isVisible())
+	if (isVisible() || !tray_icon || !tray_icon->isVisible() || quietMode)
 		return;
 
 	tray_icon->showMessage(qAppName(), msg, type, sec * 1000);
@@ -1407,6 +1415,13 @@
 }
 
 
+void WpaGui::updateTrayToolTip(const QString &msg)
+{
+	if (tray_icon)
+		tray_icon->setToolTip(msg);
+}
+
+
 void WpaGui::closeEvent(QCloseEvent *event)
 {
 	if (eh) {
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.h b/wpa_supplicant/wpa_gui-qt4/wpagui.h
index 340286c..026eacb 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpagui.h
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.h
@@ -70,6 +70,7 @@
 	virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type,
 				     int sec, const QString &msg);
 	virtual void showTrayStatus();
+	virtual void updateTrayToolTip(const QString &msg);
 	virtual void wpsDialog();
 	virtual void peersDialog();
 	virtual void tabChanged(int index);
@@ -116,6 +117,7 @@
 	void createTrayIcon(bool);
 	bool ackTrayIcon;
 	bool startInTray;
+	bool quietMode;
 
 	int openCtrlConnection(const char *ifname);
 
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 5426177..ac38d69 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -202,7 +202,9 @@
 	if (assoc->ssid_len > 32)
 		return;
 	params.ssid_len = assoc->ssid_len;
-	params.freq = assoc->freq;
+	params.freq.mode = assoc->hwmode;
+	params.freq.freq = assoc->freq;
+	params.freq.channel = assoc->channel;
 	if (assoc->wpa_ie_len) {
 		params.wpa_ie = (u8 *) (assoc + 1);
 		params.wpa_ie_len = assoc->wpa_ie_len;
@@ -333,7 +335,7 @@
 	msg.msg_namelen = sizeof(iface->l2_addr);
 
 	if (sendmsg(iface->fd, &msg, 0) < 0) {
-		perror("sendmsg(l2 rx)");
+		wpa_printf(MSG_ERROR, "sendmsg(l2 rx): %s", strerror(errno));
 	}
 }
 
@@ -465,7 +467,7 @@
 	res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
 		       &fromlen);
 	if (res < 0) {
-		perror("recvfrom");
+		wpa_printf(MSG_ERROR, "recvfrom: %s", strerror(errno));
 		return;
 	}
 
@@ -613,7 +615,7 @@
 
 	iface->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (iface->fd < 0) {
-		perror("socket(PF_UNIX)");
+		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
 		wpa_priv_interface_deinit(iface);
 		return NULL;
 	}
@@ -631,15 +633,16 @@
 				   "allow connections - assuming it was "
 				   "leftover from forced program termination");
 			if (unlink(iface->sock_name) < 0) {
-				perror("unlink[ctrl_iface]");
-				wpa_printf(MSG_ERROR, "Could not unlink "
-					   "existing ctrl_iface socket '%s'",
-					   iface->sock_name);
+				wpa_printf(MSG_ERROR,
+					   "Could not unlink existing ctrl_iface socket '%s': %s",
+					   iface->sock_name, strerror(errno));
 				goto fail;
 			}
 			if (bind(iface->fd, (struct sockaddr *) &addr,
 				 sizeof(addr)) < 0) {
-				perror("wpa-priv-iface-init: bind(PF_UNIX)");
+				wpa_printf(MSG_ERROR,
+					   "wpa-priv-iface-init: bind(PF_UNIX): %s",
+					   strerror(errno));
 				goto fail;
 			}
 			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -654,7 +657,7 @@
 	}
 
 	if (chmod(iface->sock_name, S_IRWXU | S_IRWXG | S_IRWXO) < 0) {
-		perror("chmod");
+		wpa_printf(MSG_ERROR, "chmod: %s", strerror(errno));
 		goto fail;
 	}
 
@@ -686,7 +689,8 @@
 	msg.msg_namelen = sizeof(iface->drv_addr);
 
 	if (sendmsg(iface->fd, &msg, 0) < 0) {
-		perror("sendmsg(wpas_socket)");
+		wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
+			   strerror(errno));
 		return -1;
 	}
 
@@ -901,7 +905,8 @@
 	msg.msg_namelen = sizeof(iface->drv_addr);
 
 	if (sendmsg(iface->fd, &msg, 0) < 0)
-		perror("sendmsg(wpas_socket)");
+		wpa_printf(MSG_ERROR, "sendmsg(wpas_socket): %s",
+			   strerror(errno));
 }
 
 
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index eef3d21..e5dc43f 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -52,6 +52,7 @@
 #include "hs20_supplicant.h"
 #include "wnm_sta.h"
 #include "wpas_kay.h"
+#include "mesh.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
@@ -105,9 +106,6 @@
 "\n";
 #endif /* CONFIG_NO_STDOUT_DEBUG */
 
-struct wowlan_triggers *wpa_get_wowlan_triggers(const char *wowlan_triggers,
-						struct wpa_driver_capa *capa);
-
 /* Configure default/group WEP keys for static WEP */
 int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
 {
@@ -134,6 +132,7 @@
 	size_t keylen;
 	enum wpa_alg alg;
 	u8 seq[6] = { 0 };
+	int ret;
 
 	/* IBSS/WPA-None uses only one key (Group) for both receiving and
 	 * sending unicast and multicast packets. */
@@ -177,7 +176,9 @@
 	/* TODO: should actually remember the previously used seq#, both for TX
 	 * and RX from each STA.. */
 
-	return wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+	ret = wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+	os_memset(key, 0, sizeof(key));
+	return ret;
 }
 
 
@@ -300,11 +301,28 @@
 		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
 		wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
 	eapol_conf.external_sim = wpa_s->conf->external_sim;
-	eapol_conf.wps = wpa_s->key_mgmt == WPA_KEY_MGMT_WPS;
+
+#ifdef CONFIG_WPS
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
+		eapol_conf.wps |= EAPOL_LOCAL_WPS_IN_USE;
+		if (wpa_s->current_bss) {
+			struct wpabuf *ie;
+			ie = wpa_bss_get_vendor_ie_multi(wpa_s->current_bss,
+							 WPS_IE_VENDOR_TYPE);
+			if (ie) {
+				if (wps_is_20(ie))
+					eapol_conf.wps |=
+						EAPOL_PEER_IS_WPS20_AP;
+				wpabuf_free(ie);
+			}
+		}
+	}
+#endif /* CONFIG_WPS */
+
 	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
-#endif /* IEEE8021X_EAPOL */
 
 	ieee802_1x_alloc_kay_sm(wpa_s, ssid);
+#endif /* IEEE8021X_EAPOL */
 }
 
 
@@ -393,6 +411,10 @@
 		l2_packet_deinit(wpa_s->l2_br);
 		wpa_s->l2_br = NULL;
 	}
+#ifdef CONFIG_TESTING_OPTIONS
+	l2_packet_deinit(wpa_s->l2_test);
+	wpa_s->l2_test = NULL;
+#endif /* CONFIG_TESTING_OPTIONS */
 
 	if (wpa_s->conf != NULL) {
 		struct wpa_ssid *ssid;
@@ -416,6 +438,7 @@
 	wpa_tdls_deinit(wpa_s->wpa);
 #endif /* CONFIG_TDLS */
 
+	wmm_ac_clear_saved_tspecs(wpa_s);
 	pmksa_candidate_free(wpa_s->wpa);
 	wpa_sm_deinit(wpa_s->wpa);
 	wpa_s->wpa = NULL;
@@ -465,6 +488,8 @@
 	os_free(wpa_s->manual_sched_scan_freqs);
 	wpa_s->manual_sched_scan_freqs = NULL;
 
+	wpas_mac_addr_rand_scan_clear(wpa_s, MAC_ADDR_RAND_ALL);
+
 	gas_query_deinit(wpa_s->gas);
 	wpa_s->gas = NULL;
 
@@ -504,6 +529,8 @@
 		wpabuf_free(wpa_s->vendor_elem[i]);
 		wpa_s->vendor_elem[i] = NULL;
 	}
+
+	wmm_ac_notify_disassoc(wpa_s);
 }
 
 
@@ -736,6 +763,9 @@
 	if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
 		wpa_supplicant_start_autoscan(wpa_s);
 
+	if (old_state >= WPA_ASSOCIATED && wpa_s->wpa_state < WPA_ASSOCIATED)
+		wmm_ac_notify_disassoc(wpa_s);
+
 	if (wpa_s->wpa_state != old_state) {
 		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
 
@@ -845,7 +875,7 @@
 
 	/*
 	 * TODO: should notify EAPOL SM about changes in opensc_engine_path,
-	 * pkcs11_engine_path, pkcs11_module_path.
+	 * pkcs11_engine_path, pkcs11_module_path, openssl_ciphers.
 	 */
 	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
 		/*
@@ -982,7 +1012,7 @@
 		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
 		proto = WPA_PROTO_RSN;
 	} else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
-		   wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 &&
+		   wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie) == 0 &&
 		   (ie.group_cipher & ssid->group_cipher) &&
 		   (ie.pairwise_cipher & ssid->pairwise_cipher) &&
 		   (ie.key_mgmt & ssid->key_mgmt)) {
@@ -1000,6 +1030,40 @@
 #endif /* CONFIG_HS20 */
 	} else if (bss) {
 		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"WPA: ssid proto=0x%x pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+			ssid->proto, ssid->pairwise_cipher, ssid->group_cipher,
+			ssid->key_mgmt);
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: BSS " MACSTR " ssid='%s'%s%s%s",
+			MAC2STR(bss->bssid),
+			wpa_ssid_txt(bss->ssid, bss->ssid_len),
+			bss_wpa ? " WPA" : "",
+			bss_rsn ? " RSN" : "",
+			bss_osen ? " OSEN" : "");
+		if (bss_rsn) {
+			wpa_hexdump(MSG_DEBUG, "RSN", bss_rsn, 2 + bss_rsn[1]);
+			if (wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie)) {
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"Could not parse RSN element");
+			} else {
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"RSN: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+					ie.pairwise_cipher, ie.group_cipher,
+					ie.key_mgmt);
+			}
+		}
+		if (bss_wpa) {
+			wpa_hexdump(MSG_DEBUG, "WPA", bss_wpa, 2 + bss_wpa[1]);
+			if (wpa_parse_wpa_ie(bss_wpa, 2 + bss_wpa[1], &ie)) {
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"Could not parse WPA element");
+			} else {
+				wpa_dbg(wpa_s, MSG_DEBUG,
+					"WPA: pairwise_cipher=0x%x group_cipher=0x%x key_mgmt=0x%x",
+					ie.pairwise_cipher, ie.group_cipher,
+					ie.key_mgmt);
+			}
+		}
 		return -1;
 	} else {
 		if (ssid->proto & WPA_PROTO_OSEN)
@@ -1073,6 +1137,10 @@
 		sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
 #endif /* CONFIG_SAE */
 	if (0) {
+	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SUITE_B) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"WPA: using KEY_MGMT 802.1X with Suite B");
 #ifdef CONFIG_IEEE80211R
 	} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
 		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
@@ -1163,7 +1231,7 @@
 	}
 
 	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
-		wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
+		wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN, NULL);
 #ifndef CONFIG_NO_PBKDF2
 		if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
 		    ssid->passphrase) {
@@ -1172,7 +1240,8 @@
 				    4096, psk, PMK_LEN);
 		        wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
 					psk, PMK_LEN);
-			wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+			wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+			os_memset(psk, 0, sizeof(psk));
 		}
 #endif /* CONFIG_NO_PBKDF2 */
 #ifdef CONFIG_EXT_PASSWORD
@@ -1208,7 +1277,8 @@
 				wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
 						"external passphrase)",
 						psk, PMK_LEN);
-				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+				os_memset(psk, 0, sizeof(psk));
 			} else
 #endif /* CONFIG_NO_PBKDF2 */
 			if (wpabuf_len(pw) == 2 * PMK_LEN) {
@@ -1219,7 +1289,8 @@
 					ext_password_free(pw);
 					return -1;
 				}
-				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN, NULL);
+				os_memset(psk, 0, sizeof(psk));
 			} else {
 				wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
 					"PSK available");
@@ -1461,8 +1532,15 @@
 	else
 		rand_style = ssid->mac_addr;
 
+	wmm_ac_clear_saved_tspecs(wpa_s);
+	wpa_s->reassoc_same_bss = 0;
+
 	if (wpa_s->last_ssid == ssid) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Re-association to the same ESS");
+		if (wpa_s->current_bss && wpa_s->current_bss == bss) {
+			wmm_ac_save_tspecs(wpa_s);
+			wpa_s->reassoc_same_bss = 1;
+		}
 	} else if (rand_style > 0) {
 		if (wpas_update_random_addr(wpa_s, rand_style) < 0)
 			return;
@@ -1510,6 +1588,31 @@
 		return;
 	}
 
+	if (ssid->mode == WPAS_MODE_MESH) {
+#ifdef CONFIG_MESH
+		if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MESH)) {
+			wpa_msg(wpa_s, MSG_INFO,
+				"Driver does not support mesh mode");
+			return;
+		}
+		if (bss)
+			ssid->frequency = bss->freq;
+		if (wpa_supplicant_join_mesh(wpa_s, ssid) < 0) {
+			wpa_msg(wpa_s, MSG_ERROR, "Could not join mesh");
+			return;
+		}
+		wpa_s->current_bss = bss;
+		wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_STARTED
+			     "ssid=\"%s\" id=%d",
+			     wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+			     ssid->id);
+#else /* CONFIG_MESH */
+		wpa_msg(wpa_s, MSG_ERROR,
+			"mesh mode support not included in the build");
+#endif /* CONFIG_MESH */
+		return;
+	}
+
 #ifdef CONFIG_TDLS
 	if (bss)
 		wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
@@ -1593,7 +1696,8 @@
 	os_memset(&params, 0, sizeof(params));
 	wpa_s->reassociate = 0;
 	wpa_s->eap_expected_failure = 0;
-	if (bss && !wpas_driver_bss_selection(wpa_s)) {
+	if (bss &&
+	    (!wpas_driver_bss_selection(wpa_s) || wpas_wps_searching(wpa_s))) {
 #ifdef CONFIG_IEEE80211R
 		const u8 *ie, *md = NULL;
 #endif /* CONFIG_IEEE80211R */
@@ -1856,8 +1960,9 @@
 		params.fixed_bssid = 1;
 	}
 
-	if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
-	    params.freq.freq == 0) {
+	/* Initial frequency for IBSS/mesh */
+	if ((ssid->mode == WPAS_MODE_IBSS || ssid->mode == WPAS_MODE_MESH) &&
+	    ssid->frequency > 0 && params.freq.freq == 0) {
 		enum hostapd_hw_mode hw_mode;
 		u8 channel;
 
@@ -1906,6 +2011,23 @@
 			params.psk = ssid->psk;
 	}
 
+	if (wpa_s->conf->key_mgmt_offload) {
+		if (params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X ||
+		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SHA256 ||
+		    params.key_mgmt_suite == WPA_KEY_MGMT_IEEE8021X_SUITE_B)
+			params.req_key_mgmt_offload =
+				ssid->proactive_key_caching < 0 ?
+				wpa_s->conf->okc : ssid->proactive_key_caching;
+		else
+			params.req_key_mgmt_offload = 1;
+
+		if ((params.key_mgmt_suite == WPA_KEY_MGMT_PSK ||
+		     params.key_mgmt_suite == WPA_KEY_MGMT_PSK_SHA256 ||
+		     params.key_mgmt_suite == WPA_KEY_MGMT_FT_PSK) &&
+		    ssid->psk_set)
+			params.psk = ssid->psk;
+	}
+
 	params.drop_unencrypted = use_crypt;
 
 #ifdef CONFIG_IEEE80211W
@@ -2050,6 +2172,7 @@
 {
 	struct wpa_ssid *old_ssid;
 
+	wpas_connect_work_done(wpa_s);
 	wpa_clear_keys(wpa_s, addr);
 	old_ssid = wpa_s->current_ssid;
 	wpa_supplicant_mark_disassoc(wpa_s);
@@ -2102,6 +2225,14 @@
 	wpa_tdls_teardown_peers(wpa_s->wpa);
 #endif /* CONFIG_TDLS */
 
+#ifdef CONFIG_MESH
+	if (wpa_s->ifmsh) {
+		wpa_msg_ctrl(wpa_s, MSG_INFO, MESH_GROUP_REMOVED "%s",
+			     wpa_s->ifname);
+		wpa_supplicant_leave_mesh(wpa_s);
+	}
+#endif /* CONFIG_MESH */
+
 	if (addr) {
 		wpa_drv_deauthenticate(wpa_s, addr, reason_code);
 		os_memset(&event, 0, sizeof(event));
@@ -2267,12 +2398,17 @@
 	if (ssid) {
 		wpa_s->current_ssid = ssid;
 		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+		wpa_s->connect_without_scan =
+			(ssid->mode == WPAS_MODE_MESH) ? ssid : NULL;
+	} else {
+		wpa_s->connect_without_scan = NULL;
 	}
-	wpa_s->connect_without_scan = NULL;
+
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
 
-	if (wpa_supplicant_fast_associate(wpa_s) != 1)
+	if (wpa_s->connect_without_scan ||
+	    wpa_supplicant_fast_associate(wpa_s) != 1)
 		wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
 
 	if (ssid)
@@ -2742,15 +2878,9 @@
 
 int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
 {
-	if (wpa_s->driver->send_eapol) {
-		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->p2p_mgmt ||
-		    !(wpa_s->drv_flags &
-		      WPA_DRIVER_FLAGS_DEDICATED_P2P_DEVICE)) &&
-		   !(wpa_s->drv_flags &
-		     WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
+	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,
 					   wpa_drv_get_mac_addr(wpa_s),
@@ -2854,12 +2984,14 @@
 			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 			interface_count = 0;
 		}
+#ifndef ANDROID
 		if (!wpa_s->p2p_mgmt &&
 		    wpa_supplicant_delayed_sched_scan(wpa_s,
 						      interface_count % 3,
 						      100000))
 			wpa_supplicant_req_scan(wpa_s, interface_count % 3,
 						100000);
+#endif /* ANDROID */
 		interface_count++;
 	} else
 		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
@@ -3127,10 +3259,6 @@
 {
 	struct ieee80211_vht_capabilities *vhtcaps;
 	struct ieee80211_vht_capabilities *vhtcaps_mask;
-#ifdef CONFIG_HT_OVERRIDES
-	int max_ampdu;
-	const u32 max_ampdu_mask = VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX;
-#endif /* CONFIG_HT_OVERRIDES */
 
 	if (!ssid)
 		return;
@@ -3148,9 +3276,12 @@
 
 #ifdef CONFIG_HT_OVERRIDES
 	/* if max ampdu is <= 3, we have to make the HT cap the same */
-	if (ssid->vht_capa_mask & max_ampdu_mask) {
-		max_ampdu = (ssid->vht_capa & max_ampdu_mask) >>
-			find_first_bit(max_ampdu_mask);
+	if (ssid->vht_capa_mask & VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) {
+		int max_ampdu;
+
+		max_ampdu = (ssid->vht_capa &
+			     VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX) >>
+			VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT_MAX_SHIFT;
 
 		max_ampdu = max_ampdu < 3 ? max_ampdu : 3;
 		wpa_set_ampdu_factor(wpa_s,
@@ -3261,7 +3392,7 @@
 
 
 static int wpas_set_wowlan_triggers(struct wpa_supplicant *wpa_s,
-				    struct wpa_driver_capa *capa)
+				    const struct wpa_driver_capa *capa)
 {
 	struct wowlan_triggers *triggers;
 	int ret = 0;
@@ -3430,6 +3561,11 @@
 
 	if (dl_list_empty(&radio->work))
 		return;
+	if (wpa_s->ext_work_in_progress) {
+		wpa_printf(MSG_DEBUG,
+			   "External radio work in progress - delay start of pending item");
+		return;
+	}
 	eloop_cancel_timeout(radio_start_next_work, radio, NULL);
 	eloop_register_timeout(0, 0, radio_start_next_work, radio, NULL);
 }
@@ -3585,6 +3721,7 @@
 				     struct wpa_interface *iface)
 {
 	struct wpa_driver_capa capa;
+	int capa_res;
 
 	wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
 		   "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
@@ -3714,10 +3851,13 @@
 						      &wpa_s->hw.num_modes,
 						      &wpa_s->hw.flags);
 
-	if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+	capa_res = wpa_drv_get_capa(wpa_s, &capa);
+	if (capa_res == 0) {
 		wpa_s->drv_capa_known = 1;
 		wpa_s->drv_flags = capa.flags;
 		wpa_s->drv_enc = capa.enc;
+		wpa_s->drv_smps_modes = capa.smps_modes;
+		wpa_s->drv_rrm_flags = capa.rrm_flags;
 		wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
 		wpa_s->max_scan_ssids = capa.max_scan_ssids;
 		wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
@@ -3730,6 +3870,14 @@
 		wpa_s->extended_capa_len = capa.extended_capa_len;
 		wpa_s->num_multichan_concurrent =
 			capa.num_multichan_concurrent;
+		wpa_s->wmm_ac_supported = capa.wmm_ac_supported;
+
+		if (capa.mac_addr_rand_scan_supported)
+			wpa_s->mac_addr_rand_supported |= MAC_ADDR_RAND_SCAN;
+		if (wpa_s->sched_scan_supported &&
+		    capa.mac_addr_rand_sched_scan_supported)
+			wpa_s->mac_addr_rand_supported |=
+				(MAC_ADDR_RAND_SCHED_SCAN | MAC_ADDR_RAND_PNO);
 	}
 	if (wpa_s->max_remain_on_chan == 0)
 		wpa_s->max_remain_on_chan = 1000;
@@ -3804,7 +3952,7 @@
 	 * Note: We don't restore/remove the triggers on shutdown (it doesn't
 	 * have effect anyway when the interface is down).
 	 */
-	if (wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
+	if (capa_res == 0 && wpas_set_wowlan_triggers(wpa_s, &capa) < 0)
 		return -1;
 
 #ifdef CONFIG_EAP_PROXY
@@ -3828,6 +3976,8 @@
 	if (wpas_init_ext_pw(wpa_s) < 0)
 		return -1;
 
+	wpas_rrm_reset(wpa_s);
+
 	return 0;
 }
 
@@ -3835,6 +3985,26 @@
 static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
 					int notify, int terminate)
 {
+	struct wpa_global *global = wpa_s->global;
+	struct wpa_supplicant *iface, *prev;
+
+	if (wpa_s == wpa_s->parent)
+		wpas_p2p_group_remove(wpa_s, "*");
+
+	iface = global->ifaces;
+	while (iface) {
+		if (iface == wpa_s || iface->parent != wpa_s) {
+			iface = iface->next;
+			continue;
+		}
+		wpa_printf(MSG_DEBUG,
+			   "Remove remaining child interface %s from parent %s",
+			   iface->ifname, wpa_s->ifname);
+		prev = iface;
+		iface = iface->next;
+		wpa_supplicant_remove_iface(global, prev, terminate);
+	}
+
 	wpa_s->disconnected = 1;
 	if (wpa_s->drv_priv) {
 		wpa_supplicant_deauthenticate(wpa_s,
@@ -3864,6 +4034,13 @@
 		wpa_s->ctrl_iface = NULL;
 	}
 
+#ifdef CONFIG_MESH
+	if (wpa_s->ifmsh) {
+		wpa_supplicant_mesh_iface_deinit(wpa_s, wpa_s->ifmsh);
+		wpa_s->ifmsh = NULL;
+	}
+#endif /* CONFIG_MESH */
+
 	if (wpa_s->conf != NULL) {
 		wpa_config_free(wpa_s->conf);
 		wpa_s->conf = NULL;
@@ -3923,14 +4100,16 @@
 		return NULL;
 	}
 
-	/* Notify the control interfaces about new iface */
-	if (wpas_notify_iface_added(wpa_s)) {
-		wpa_supplicant_deinit_iface(wpa_s, 1, 0);
-		return NULL;
-	}
+	if (iface->p2p_mgmt == 0) {
+		/* Notify the control interfaces about new iface */
+		if (wpas_notify_iface_added(wpa_s)) {
+			wpa_supplicant_deinit_iface(wpa_s, 1, 0);
+			return NULL;
+		}
 
-	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
-		wpas_notify_network_added(wpa_s, ssid);
+		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+			wpas_notify_network_added(wpa_s, ssid);
+	}
 
 	wpa_s->next = global->ifaces;
 	global->ifaces = wpa_s;
@@ -3938,6 +4117,16 @@
 	wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
 	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 
+#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, iface->conf_p2p_dev) < 0) {
+		wpa_printf(MSG_INFO,
+			   "P2P: Failed to enable P2P Device interface");
+		/* Try to continue without. P2P will be disabled. */
+	}
+#endif /* CONFIG_P2P */
+
 	return wpa_s;
 }
 
@@ -3958,6 +4147,10 @@
 				int terminate)
 {
 	struct wpa_supplicant *prev;
+#ifdef CONFIG_MESH
+	unsigned int mesh_if_created = wpa_s->mesh_if_created;
+	char *ifname = NULL;
+#endif /* CONFIG_MESH */
 
 	/* Remove interface from the global list of interfaces */
 	prev = global->ifaces;
@@ -3973,12 +4166,30 @@
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
 
+#ifdef CONFIG_MESH
+	if (mesh_if_created) {
+		ifname = os_strdup(wpa_s->ifname);
+		if (ifname == NULL) {
+			wpa_dbg(wpa_s, MSG_ERROR,
+				"mesh: Failed to malloc ifname");
+			return -1;
+		}
+	}
+#endif /* CONFIG_MESH */
+
 	if (global->p2p_group_formation == wpa_s)
 		global->p2p_group_formation = NULL;
 	if (global->p2p_invite_group == wpa_s)
 		global->p2p_invite_group = NULL;
 	wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
 
+#ifdef CONFIG_MESH
+	if (mesh_if_created) {
+		wpa_drv_if_remove(global->ifaces, WPA_IF_MESH, ifname);
+		os_free(ifname);
+	}
+#endif /* CONFIG_MESH */
+
 	return 0;
 }
 
@@ -4063,7 +4274,10 @@
 	wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
 #endif /* CONFIG_NO_WPA_MSG */
 
-	wpa_debug_open_file(params->wpa_debug_file_path);
+	if (params->wpa_debug_file_path)
+		wpa_debug_open_file(params->wpa_debug_file_path);
+	else
+		wpa_debug_setup_stdout();
 	if (params->wpa_debug_syslog)
 		wpa_debug_open_syslog();
 	if (params->wpa_debug_tracing) {
@@ -4141,7 +4355,7 @@
 		wpa_supplicant_deinit(global);
 		return NULL;
 	}
-	global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
+	global->drv_priv = os_calloc(global->drv_count, sizeof(void *));
 	if (global->drv_priv == NULL) {
 		wpa_supplicant_deinit(global);
 		return NULL;
@@ -4279,7 +4493,7 @@
 }
 
 
-static void add_freq(int *freqs, int *num_freqs, int freq)
+void add_freq(int *freqs, int *num_freqs, int freq)
 {
 	int i;
 
@@ -4300,7 +4514,7 @@
 	int *freqs;
 	int num_freqs = 0;
 
-	freqs = os_zalloc(sizeof(int) * (max_freqs + 1));
+	freqs = os_calloc(max_freqs + 1, sizeof(int));
 	if (freqs == NULL)
 		return NULL;
 
@@ -4681,6 +4895,7 @@
 void wpas_request_connection(struct wpa_supplicant *wpa_s)
 {
 	wpa_s->normal_scans = 0;
+	wpa_s->scan_req = NORMAL_SCAN_REQ;
 	wpa_supplicant_reinit_autoscan(wpa_s);
 	wpa_s->extra_blacklist_count = 0;
 	wpa_s->disconnected = 0;
@@ -4785,3 +5000,261 @@
 
 	return num;
 }
+
+
+static void wpas_rrm_neighbor_rep_timeout_handler(void *data, void *user_ctx)
+{
+	struct rrm_data *rrm = data;
+
+	if (!rrm->notify_neighbor_rep) {
+		wpa_printf(MSG_ERROR,
+			   "RRM: Unexpected neighbor report timeout");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report - NONE");
+	rrm->notify_neighbor_rep(rrm->neighbor_rep_cb_ctx, NULL);
+
+	rrm->notify_neighbor_rep = NULL;
+	rrm->neighbor_rep_cb_ctx = NULL;
+}
+
+
+/*
+ * wpas_rrm_reset - Clear and reset all RRM data in wpa_supplicant
+ * @wpa_s: Pointer to wpa_supplicant
+ */
+void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->rrm.rrm_used = 0;
+
+	eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
+			     NULL);
+	if (wpa_s->rrm.notify_neighbor_rep)
+		wpas_rrm_neighbor_rep_timeout_handler(&wpa_s->rrm, NULL);
+	wpa_s->rrm.next_neighbor_rep_token = 1;
+}
+
+
+/*
+ * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
+ * @wpa_s: Pointer to wpa_supplicant
+ * @report: Neighbor report buffer, prefixed by a 1-byte dialog token
+ * @report_len: Length of neighbor report buffer
+ */
+void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
+				   const u8 *report, size_t report_len)
+{
+	struct wpabuf *neighbor_rep;
+
+	wpa_hexdump(MSG_DEBUG, "RRM: New Neighbor Report", report, report_len);
+	if (report_len < 1)
+		return;
+
+	if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Discarding neighbor report with token %d (expected %d)",
+			   report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
+		return;
+	}
+
+	eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
+			     NULL);
+
+	if (!wpa_s->rrm.notify_neighbor_rep) {
+		wpa_printf(MSG_ERROR, "RRM: Unexpected neighbor report");
+		return;
+	}
+
+	/* skipping the first byte, which is only an id (dialog token) */
+	neighbor_rep = wpabuf_alloc(report_len - 1);
+	if (neighbor_rep == NULL)
+		return;
+	wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
+	wpa_printf(MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
+		   report[0]);
+	wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
+				       neighbor_rep);
+	wpa_s->rrm.notify_neighbor_rep = NULL;
+	wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
+}
+
+
+/**
+ * wpas_rrm_send_neighbor_rep_request - Request a neighbor report from our AP
+ * @wpa_s: Pointer to wpa_supplicant
+ * @ssid: if not null, this is sent in the request. Otherwise, no SSID IE
+ *	  is sent in the request.
+ * @cb: Callback function to be called once the requested report arrives, or
+ *	timed out after RRM_NEIGHBOR_REPORT_TIMEOUT seconds.
+ *	In the former case, 'neighbor_rep' is a newly allocated wpabuf, and it's
+ *	the requester's responsibility to free it.
+ *	In the latter case NULL will be sent in 'neighbor_rep'.
+ * @cb_ctx: Context value to send the callback function
+ * Returns: 0 in case of success, negative error code otherwise
+ *
+ * In case there is a previous request which has not been answered yet, the
+ * new request fails. The caller may retry after RRM_NEIGHBOR_REPORT_TIMEOUT.
+ * Request must contain a callback function.
+ */
+int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
+				       const struct wpa_ssid *ssid,
+				       void (*cb)(void *ctx,
+						  struct wpabuf *neighbor_rep),
+				       void *cb_ctx)
+{
+	struct wpabuf *buf;
+	const u8 *rrm_ie;
+
+	if (wpa_s->wpa_state != WPA_COMPLETED || wpa_s->current_ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "RRM: No connection, no RRM.");
+		return -ENOTCONN;
+	}
+
+	if (!wpa_s->rrm.rrm_used) {
+		wpa_printf(MSG_DEBUG, "RRM: No RRM in current connection.");
+		return -EOPNOTSUPP;
+	}
+
+	rrm_ie = wpa_bss_get_ie(wpa_s->current_bss,
+				WLAN_EID_RRM_ENABLED_CAPABILITIES);
+	if (!rrm_ie || !(wpa_s->current_bss->caps & IEEE80211_CAP_RRM) ||
+	    !(rrm_ie[2] & WLAN_RRM_CAPS_NEIGHBOR_REPORT)) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: No network support for Neighbor Report.");
+		return -EOPNOTSUPP;
+	}
+
+	if (!cb) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Neighbor Report request must provide a callback.");
+		return -EINVAL;
+	}
+
+	/* Refuse if there's a live request */
+	if (wpa_s->rrm.notify_neighbor_rep) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Currently handling previous Neighbor Report.");
+		return -EBUSY;
+	}
+
+	/* 3 = action category + action code + dialog token */
+	buf = wpabuf_alloc(3 + (ssid ? 2 + ssid->ssid_len : 0));
+	if (buf == NULL) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Failed to allocate Neighbor Report Request");
+		return -ENOMEM;
+	}
+
+	wpa_printf(MSG_DEBUG, "RRM: Neighbor report request (for %s), token=%d",
+		   (ssid ? wpa_ssid_txt(ssid->ssid, ssid->ssid_len) : ""),
+		   wpa_s->rrm.next_neighbor_rep_token);
+
+	wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+	wpabuf_put_u8(buf, WLAN_RRM_NEIGHBOR_REPORT_REQUEST);
+	wpabuf_put_u8(buf, wpa_s->rrm.next_neighbor_rep_token);
+	if (ssid) {
+		wpabuf_put_u8(buf, WLAN_EID_SSID);
+		wpabuf_put_u8(buf, ssid->ssid_len);
+		wpabuf_put_data(buf, ssid->ssid, ssid->ssid_len);
+	}
+
+	wpa_s->rrm.next_neighbor_rep_token++;
+
+	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
+				wpa_s->own_addr, wpa_s->bssid,
+				wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
+		wpa_printf(MSG_DEBUG,
+			   "RRM: Failed to send Neighbor Report Request");
+		wpabuf_free(buf);
+		return -ECANCELED;
+	}
+
+	wpa_s->rrm.neighbor_rep_cb_ctx = cb_ctx;
+	wpa_s->rrm.notify_neighbor_rep = cb;
+	eloop_register_timeout(RRM_NEIGHBOR_REPORT_TIMEOUT, 0,
+			       wpas_rrm_neighbor_rep_timeout_handler,
+			       &wpa_s->rrm, NULL);
+
+	wpabuf_free(buf);
+	return 0;
+}
+
+
+void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
+					      const u8 *src,
+					      const u8 *frame, size_t len,
+					      int rssi)
+{
+	struct wpabuf *buf;
+	const struct rrm_link_measurement_request *req;
+	struct rrm_link_measurement_report report;
+
+	if (wpa_s->wpa_state != WPA_COMPLETED) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Ignoring link measurement request. Not associated");
+		return;
+	}
+
+	if (!wpa_s->rrm.rrm_used) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Ignoring link measurement request. Not RRM network");
+		return;
+	}
+
+	if (!(wpa_s->drv_rrm_flags & WPA_DRIVER_FLAGS_TX_POWER_INSERTION)) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Measurement report failed. TX power insertion not supported");
+		return;
+	}
+
+	req = (const struct rrm_link_measurement_request *) frame;
+	if (len < sizeof(*req)) {
+		wpa_printf(MSG_INFO,
+			   "RRM: Link measurement report failed. Request too short");
+		return;
+	}
+
+	os_memset(&report, 0, sizeof(report));
+	report.tpc.eid = WLAN_EID_TPC_REPORT;
+	report.tpc.len = 2;
+	report.rsni = 255; /* 255 indicates that RSNI is not available */
+	report.dialog_token = req->dialog_token;
+
+	/*
+	 * It's possible to estimate RCPI based on RSSI in dBm. This
+	 * calculation will not reflect the correct value for high rates,
+	 * but it's good enough for Action frames which are transmitted
+	 * with up to 24 Mbps rates.
+	 */
+	if (!rssi)
+		report.rcpi = 255; /* not available */
+	else if (rssi < -110)
+		report.rcpi = 0;
+	else if (rssi > 0)
+		report.rcpi = 220;
+	else
+		report.rcpi = (rssi + 110) * 2;
+
+	/* action_category + action_code */
+	buf = wpabuf_alloc(2 + sizeof(report));
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR,
+			   "RRM: Link measurement report failed. Buffer allocation failed");
+		return;
+	}
+
+	wpabuf_put_u8(buf, WLAN_ACTION_RADIO_MEASUREMENT);
+	wpabuf_put_u8(buf, WLAN_RRM_LINK_MEASUREMENT_REPORT);
+	wpabuf_put_data(buf, &report, sizeof(report));
+	wpa_hexdump(MSG_DEBUG, "RRM: Link measurement report:",
+		    wpabuf_head(buf), wpabuf_len(buf));
+
+	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, src,
+				wpa_s->own_addr, wpa_s->bssid,
+				wpabuf_head(buf), wpabuf_len(buf), 0)) {
+		wpa_printf(MSG_ERROR,
+			   "RRM: Link measurement report failed. Send action failed");
+	}
+	wpabuf_free(buf);
+}
diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf
index 89da0da..e78c0dd 100644
--- a/wpa_supplicant/wpa_supplicant.conf
+++ b/wpa_supplicant/wpa_supplicant.conf
@@ -114,6 +114,19 @@
 # networks are found, a new IBSS or AP mode network is created.
 ap_scan=1
 
+# MPM residency
+# By default, wpa_supplicant implements the mesh peering manager (MPM) for an
+# open mesh. However, if the driver can implement the MPM, you may set this to
+# 0 to use the driver version. When AMPE is enabled, the wpa_supplicant MPM is
+# always used.
+# 0: MPM lives in the driver
+# 1: wpa_supplicant provides an MPM which handles peering (default)
+#user_mpm=1
+
+# Maximum number of peer links (0-255; default: 99)
+# Maximum number of mesh peering currently maintained by the STA.
+#max_peer_links=99
+
 # EAP fast re-authentication
 # By default, fast re-authentication is enabled for all EAP methods that
 # support it. This variable can be used to disable fast re-authentication.
@@ -132,6 +145,16 @@
 # configure the path to the pkcs11 module required by the pkcs11 engine
 #pkcs11_module_path=/usr/lib/pkcs11/opensc-pkcs11.so
 
+# OpenSSL cipher string
+#
+# This is an OpenSSL specific configuration option for configuring the default
+# ciphers. If not set, "DEFAULT:!EXP:!LOW" is used as the default.
+# See https://www.openssl.org/docs/apps/ciphers.html for OpenSSL documentation
+# on cipher suite configuration. This is applicable only if wpa_supplicant is
+# built to use OpenSSL.
+#openssl_ciphers=DEFAULT:!EXP:!LOW
+
+
 # Dynamic EAP methods
 # If EAP methods were built dynamically as shared object files, they need to be
 # loaded here before being used in the network blocks. By default, EAP methods
@@ -932,6 +955,12 @@
 #	1 = try to use OCSP stapling, but not require response
 #	2 = require valid OCSP stapling response
 #
+# openssl_ciphers: OpenSSL specific cipher configuration
+#	This can be used to override the global openssl_ciphers configuration
+#	parameter (see above).
+#
+# erp: Whether EAP Re-authentication Protocol (ERP) is enabled
+#
 # 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
@@ -1310,6 +1339,23 @@
 	psk="secret passphrase"
 }
 
+# open mesh network
+network={
+	ssid="test mesh"
+	mode=5
+	frequency=2437
+	key_mgmt=NONE
+}
+
+# secure (SAE + AMPE) network
+network={
+	ssid="secure mesh"
+	mode=5
+	frequency=2437
+	key_mgmt=SAE
+	psk="very secret passphrase"
+}
+
 
 # Catch all example that allows more or less all configuration modes
 network={
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index ae9dddd..c541ccb 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -15,6 +15,7 @@
 #include "common/wpa_ctrl.h"
 #include "wps/wps_defs.h"
 #include "config_ssid.h"
+#include "wmm_ac.h"
 
 extern const char *wpa_supplicant_version;
 extern const char *wpa_supplicant_license;
@@ -273,6 +274,7 @@
 	} conc_pref;
 	unsigned int p2p_per_sta_psk:1;
 	unsigned int p2p_fail_on_wps_complete:1;
+	unsigned int p2p_24ghz_social_channels:1;
 
 #ifdef CONFIG_WIFI_DISPLAY
 	int wifi_display;
@@ -376,6 +378,31 @@
 	unsigned int flags;
 };
 
+#define RRM_NEIGHBOR_REPORT_TIMEOUT 1 /* 1 second for AP to send a report */
+
+/*
+ * struct rrm_data - Data used for managing RRM features
+ */
+struct rrm_data {
+	/* rrm_used - indication regarding the current connection */
+	unsigned int rrm_used:1;
+
+	/*
+	 * notify_neighbor_rep - Callback for notifying report requester
+	 */
+	void (*notify_neighbor_rep)(void *ctx, struct wpabuf *neighbor_rep);
+
+	/*
+	 * neighbor_rep_cb_ctx - Callback context
+	 * Received in the callback registration, and sent to the callback
+	 * function as a parameter.
+	 */
+	void *neighbor_rep_cb_ctx;
+
+	/* next_neighbor_rep_token - Next request's dialog token */
+	u8 next_neighbor_rep_token;
+};
+
 /**
  * struct wpa_supplicant - Internal data for wpa_supplicant interface
  *
@@ -417,6 +444,7 @@
 	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
 				     * field contains the target BSSID. */
 	int reassociate; /* reassociation requested */
+	int reassoc_same_bss; /* reassociating to the same bss */
 	int disconnected; /* all connections disabled; i.e., do no reassociate
 			   * before this has been cleared */
 	struct wpa_ssid *current_ssid;
@@ -573,8 +601,10 @@
 	int scan_id[MAX_SCAN_ID];
 	unsigned int scan_id_count;
 
-	unsigned int drv_flags;
+	u64 drv_flags;
 	unsigned int drv_enc;
+	unsigned int drv_smps_modes;
+	unsigned int drv_rrm_flags;
 
 	/*
 	 * A bitmap of supported protocols for probe response offload. See
@@ -646,6 +676,9 @@
 					* SA Query transaction identifiers */
 		struct os_reltime sa_query_start;
 		struct os_reltime last_unprot_disconnect;
+		enum { HT_SEC_CHAN_UNKNOWN,
+		       HT_SEC_CHAN_ABOVE,
+		       HT_SEC_CHAN_BELOW } ht_sec_chan;
 		u8 sched_obss_scan;
 		u16 obss_scan_int;
 		u16 bss_max_idle_period;
@@ -653,6 +686,7 @@
 		struct sae_data sae;
 		struct wpabuf *sae_token;
 		int sae_group_index;
+		unsigned int sae_pmksa_caching:1;
 #endif /* CONFIG_SAE */
 	} sme;
 #endif /* CONFIG_SME */
@@ -664,6 +698,13 @@
 	void *ap_configured_cb_data;
 #endif /* CONFIG_AP */
 
+	struct hostapd_iface *ifmsh;
+#ifdef CONFIG_MESH
+	struct mesh_rsn *mesh_rsn;
+	int mesh_if_idx;
+	unsigned int mesh_if_created:1;
+#endif /* CONFIG_MESH */
+
 	unsigned int off_channel_freq;
 	struct wpabuf *pending_action_tx;
 	u8 pending_action_src[ETH_ALEN];
@@ -685,6 +726,7 @@
 	int p2p_mgmt;
 
 #ifdef CONFIG_P2P
+	struct wpa_supplicant *p2p_dev;
 	struct p2p_go_neg_results *go_params;
 	int create_p2p_iface;
 	u8 pending_interface_addr[ETH_ALEN];
@@ -755,6 +797,7 @@
 	unsigned int p2p_go_vht:1;
 	unsigned int user_initiated_pd:1;
 	unsigned int p2p_go_group_formation_completed:1;
+	unsigned int group_formation_reported:1;
 	unsigned int waiting_presence_resp;
 	int p2p_first_connection_timeout;
 	unsigned int p2p_nfc_tag_enabled:1;
@@ -775,6 +818,10 @@
 					* formation */
 	u8 p2p_peer_oob_pubkey_hash[WPS_OOB_PUBKEY_HASH_LEN];
 	u8 p2p_ip_addr_info[3 * 4];
+
+	/* group common frequencies */
+	int *p2p_group_common_freqs;
+	unsigned int p2p_group_common_freqs_num;
 #endif /* CONFIG_P2P */
 
 	struct wpa_ssid *bgscan_ssid;
@@ -811,6 +858,7 @@
 	unsigned int auto_network_select:1;
 	unsigned int fetch_all_anqp:1;
 	unsigned int fetch_osu_info:1;
+	unsigned int fetch_osu_waiting_scan:1;
 	unsigned int fetch_osu_icon_in_progress:1;
 	struct wpa_bss *interworking_gas_bss;
 	unsigned int osu_icon_id;
@@ -845,6 +893,23 @@
 
 	unsigned int no_keep_alive:1;
 	unsigned int ext_mgmt_frame_handling:1;
+	unsigned int ext_eapol_frame_io:1;
+	unsigned int wmm_ac_supported:1;
+	unsigned int ext_work_in_progress:1;
+
+#define MAC_ADDR_RAND_SCAN       BIT(0)
+#define MAC_ADDR_RAND_SCHED_SCAN BIT(1)
+#define MAC_ADDR_RAND_PNO        BIT(2)
+#define MAC_ADDR_RAND_ALL        (MAC_ADDR_RAND_SCAN | \
+				  MAC_ADDR_RAND_SCHED_SCAN | \
+				  MAC_ADDR_RAND_PNO)
+	unsigned int mac_addr_rand_supported;
+	unsigned int mac_addr_rand_enable;
+
+	/* MAC Address followed by mask (2 * ETH_ALEN) */
+	u8 *mac_addr_scan;
+	u8 *mac_addr_sched_scan;
+	u8 *mac_addr_pno;
 
 #ifdef CONFIG_WNM
 	u8 wnm_dialog_token;
@@ -852,9 +917,10 @@
 	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;
+	struct os_reltime wnm_cand_valid_until;
+	u8 wnm_cand_from_bss[ETH_ALEN];
 #endif /* CONFIG_WNM */
 
 #ifdef CONFIG_TESTING_GET_GTK
@@ -868,6 +934,20 @@
 	unsigned int ext_work_id;
 
 	struct wpabuf *vendor_elem[NUM_VENDOR_ELEM_FRAMES];
+
+#ifdef CONFIG_TESTING_OPTIONS
+	struct l2_packet_data *l2_test;
+	unsigned int extra_roc_dur;
+#endif /* CONFIG_TESTING_OPTIONS */
+
+	struct wmm_ac_assoc_data *wmm_ac_assoc_info;
+	struct wmm_tspec_element *tspecs[WMM_AC_NUM][TS_DIR_IDX_COUNT];
+	struct wmm_ac_addts_request *addts_request;
+	u8 wmm_ac_last_dialog_token;
+	struct wmm_tspec_element *last_tspecs;
+	u8 last_tspecs_count;
+
+	struct rrm_data rrm;
 };
 
 
@@ -964,6 +1044,20 @@
 int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf, size_t buflen);
 int wpas_update_random_addr(struct wpa_supplicant *wpa_s, int style);
 int wpas_update_random_addr_disassoc(struct wpa_supplicant *wpa_s);
+void add_freq(int *freqs, int *num_freqs, int freq);
+
+void wpas_rrm_reset(struct wpa_supplicant *wpa_s);
+void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
+				   const u8 *report, size_t report_len);
+int wpas_rrm_send_neighbor_rep_request(struct wpa_supplicant *wpa_s,
+				       const struct wpa_ssid *ssid,
+				       void (*cb)(void *ctx,
+						  struct wpabuf *neighbor_rep),
+				       void *cb_ctx);
+void wpas_rrm_handle_link_measurement_request(struct wpa_supplicant *wpa_s,
+					      const u8 *src,
+					      const u8 *frame, size_t len,
+					      int rssi);
 
 /**
  * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
@@ -991,8 +1085,6 @@
 int wpa_supplicant_fast_associate(struct wpa_supplicant *wpa_s);
 struct wpa_bss * wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
 					     struct wpa_ssid **selected_ssid);
-int ht_supported(const struct hostapd_hw_modes *mode);
-int vht_supported(const struct hostapd_hw_modes *mode);
 
 /* eap_register.c */
 int eap_register_methods(void);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 38279b1..3098058 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -96,11 +96,26 @@
 static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
 			  u16 proto, const u8 *buf, size_t len)
 {
+#ifdef CONFIG_TESTING_OPTIONS
+	if (wpa_s->ext_eapol_frame_io && proto == ETH_P_EAPOL) {
+		size_t hex_len = 2 * len + 1;
+		char *hex = os_malloc(hex_len);
+
+		if (hex == NULL)
+			return -1;
+		wpa_snprintf_hex(hex, hex_len, buf, len);
+		wpa_msg(wpa_s, MSG_INFO, "EAPOL-TX " MACSTR " %s",
+			MAC2STR(dest), hex);
+		os_free(hex);
+		return 0;
+	}
+#endif /* CONFIG_TESTING_OPTIONS */
+
 	if (wpa_s->l2) {
 		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
 	}
 
-	return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+	return -1;
 }
 #endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */
 
@@ -528,7 +543,44 @@
 					 const u8 *ies, size_t ies_len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-	return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len);
+	int ret;
+	u8 *data, *pos;
+	size_t data_len;
+
+	if (action != 1) {
+		wpa_printf(MSG_ERROR, "Unsupported send_ft_action action %d",
+			   action);
+		return -1;
+	}
+
+	/*
+	 * Action frame payload:
+	 * Category[1] = 6 (Fast BSS Transition)
+	 * Action[1] = 1 (Fast BSS Transition Request)
+	 * STA Address
+	 * Target AP Address
+	 * FT IEs
+	 */
+
+	data_len = 2 + 2 * ETH_ALEN + ies_len;
+	data = os_malloc(data_len);
+	if (data == NULL)
+		return -1;
+	pos = data;
+	*pos++ = 0x06; /* FT Action category */
+	*pos++ = action;
+	os_memcpy(pos, wpa_s->own_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, target_ap, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, ies, ies_len);
+
+	ret = wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0,
+				  wpa_s->bssid, wpa_s->own_addr, wpa_s->bssid,
+				  data, data_len, 0);
+	os_free(data);
+
+	return ret;
 }
 
 
@@ -557,12 +609,14 @@
 #ifdef CONFIG_TDLS
 
 static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
-					int *tdls_ext_setup)
+					int *tdls_ext_setup,
+					int *tdls_chan_switch)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
 	*tdls_supported = 0;
 	*tdls_ext_setup = 0;
+	*tdls_chan_switch = 0;
 
 	if (!wpa_s->drv_capa_known)
 		return -1;
@@ -573,6 +627,9 @@
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP)
 		*tdls_ext_setup = 1;
 
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_CHANNEL_SWITCH)
+		*tdls_chan_switch = 1;
+
 	return 0;
 }
 
@@ -640,6 +697,25 @@
 	return wpa_drv_sta_add(wpa_s, &params);
 }
 
+
+static int wpa_supplicant_tdls_enable_channel_switch(
+	void *ctx, const u8 *addr, u8 oper_class,
+	const struct hostapd_freq_params *params)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	return wpa_drv_tdls_enable_channel_switch(wpa_s, addr, oper_class,
+						  params);
+}
+
+
+static int wpa_supplicant_tdls_disable_channel_switch(void *ctx, const u8 *addr)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	return wpa_drv_tdls_disable_channel_switch(wpa_s, addr);
+}
+
 #endif /* CONFIG_TDLS */
 
 #endif /* CONFIG_NO_WPA */
@@ -748,7 +824,7 @@
 	len = os_snprintf(buf, buflen,
 			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
 			  field_name, ssid->id, txt);
-	if (len < 0 || (size_t) len >= buflen) {
+	if (os_snprintf_error(buflen, len)) {
 		os_free(buf);
 		return;
 	}
@@ -866,6 +942,7 @@
 	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
 	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
 	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+	ctx->openssl_ciphers = wpa_s->conf->openssl_ciphers;
 	ctx->wps = wpa_s->wps;
 	ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
 	ctx->port_cb = wpa_supplicant_port_cb;
@@ -899,6 +976,19 @@
 #endif /* CONFIG_NO_WPA */
 
 
+static int wpa_supplicant_key_mgmt_set_pmk(void *ctx, const u8 *pmk,
+					   size_t pmk_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	if (wpa_s->conf->key_mgmt_offload)
+		return wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0,
+				       NULL, 0, pmk, pmk_len);
+	else
+		return 0;
+}
+
+
 int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
 {
 #ifndef CONFIG_NO_WPA
@@ -938,8 +1028,13 @@
 	ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
 	ctx->tdls_oper = wpa_supplicant_tdls_oper;
 	ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset;
+	ctx->tdls_enable_channel_switch =
+		wpa_supplicant_tdls_enable_channel_switch;
+	ctx->tdls_disable_channel_switch =
+		wpa_supplicant_tdls_disable_channel_switch;
 #endif /* CONFIG_TDLS */
 	ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
+	ctx->key_mgmt_set_pmk = wpa_supplicant_key_mgmt_set_pmk;
 
 	wpa_s->wpa = wpa_sm_init(ctx);
 	if (wpa_s->wpa == NULL) {
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 40a5c69..b1266c6 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -286,7 +286,9 @@
 		/* compare security parameters */
 		if (ssid->auth_alg != new_ssid->auth_alg ||
 		    ssid->key_mgmt != new_ssid->key_mgmt ||
-		    ssid->group_cipher != new_ssid->group_cipher)
+		    (ssid->group_cipher != new_ssid->group_cipher &&
+		     !(ssid->group_cipher & new_ssid->group_cipher &
+		       WPA_CIPHER_CCMP)))
 			continue;
 
 		/*
@@ -337,6 +339,8 @@
 		/* Remove the duplicated older network entry. */
 		wpa_printf(MSG_DEBUG, "Remove duplicate network %d", ssid->id);
 		wpas_notify_network_removed(wpa_s, ssid);
+		if (wpa_s->current_ssid == ssid)
+			wpa_s->current_ssid = NULL;
 		wpa_config_remove_network(wpa_s->conf, ssid->id);
 	}
 }
@@ -471,6 +475,11 @@
 		break;
 	case WPS_ENCR_AES:
 		ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+		if (wpa_s->drv_capa_known &&
+		    (wpa_s->drv_enc & WPA_DRIVER_CAPA_ENC_GCMP)) {
+			ssid->pairwise_cipher |= WPA_CIPHER_GCMP;
+			ssid->group_cipher |= WPA_CIPHER_GCMP;
+		}
 		break;
 	}
 
@@ -1082,6 +1091,14 @@
 		       int p2p_group)
 {
 	struct wpa_ssid *ssid;
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		wpa_printf(MSG_DEBUG,
+			   "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+		return -1;
+	}
+#endif /* CONFIG_AP */
 	wpas_clear_wps(wpa_s);
 	ssid = wpas_wps_add_network(wpa_s, 0, NULL, bssid);
 	if (ssid == NULL)
@@ -1122,6 +1139,13 @@
 	unsigned int rpin = 0;
 	char hash[2 * WPS_OOB_PUBKEY_HASH_LEN + 10];
 
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		wpa_printf(MSG_DEBUG,
+			   "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+		return -1;
+	}
+#endif /* CONFIG_AP */
 	wpas_clear_wps(wpa_s);
 	if (bssid && is_zero_ether_addr(bssid))
 		bssid = NULL;
@@ -1235,6 +1259,13 @@
 	char *pos, *end;
 	int res;
 
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		wpa_printf(MSG_DEBUG,
+			   "WPS: Reject request to start Registrar(as station) operation while AP mode is enabled");
+		return -1;
+	}
+#endif /* CONFIG_AP */
 	if (!pin)
 		return -1;
 	wpas_clear_wps(wpa_s);
@@ -1245,7 +1276,7 @@
 	pos = val;
 	end = pos + sizeof(val);
 	res = os_snprintf(pos, end - pos, "\"pin=%s", pin);
-	if (res < 0 || res >= end - pos)
+	if (os_snprintf_error(end - pos, res))
 		return -1;
 	pos += res;
 	if (settings) {
@@ -1253,12 +1284,12 @@
 				  "new_encr=%s new_key=%s",
 				  settings->ssid_hex, settings->auth,
 				  settings->encr, settings->key_hex);
-		if (res < 0 || res >= end - pos)
+		if (os_snprintf_error(end - pos, res))
 			return -1;
 		pos += res;
 	}
 	res = os_snprintf(pos, end - pos, "\"");
-	if (res < 0 || res >= end - pos)
+	if (os_snprintf_error(end - pos, res))
 		return -1;
 	if (wpa_config_set(ssid, "phase1", val, 0) < 0)
 		return -1;
@@ -1309,7 +1340,7 @@
 			  dev->model_number, dev->serial_number,
 			  wps_dev_type_bin2str(dev->pri_dev_type, devtype,
 					       sizeof(devtype)));
-	if (len > 0 && len < (int) sizeof(txt))
+	if (!os_snprintf_error(sizeof(txt), len))
 		wpa_printf(MSG_INFO, "%s", txt);
 }
 
@@ -1697,6 +1728,10 @@
 		uuid = wps_get_uuid_e(ie);
 		wpa_hexdump(MSG_DEBUG, "WPS: UUID of the other BSS",
 			    uuid, UUID_LEN);
+		if (os_memcmp(selected->bssid, bss->bssid, ETH_ALEN) == 0) {
+			wpabuf_free(ie);
+			continue;
+		}
 		if (sel_uuid == NULL || uuid == NULL ||
 		    os_memcmp(sel_uuid, uuid, UUID_LEN) != 0) {
 			ret = 1; /* PBC overlap */
@@ -1800,13 +1835,12 @@
 }
 
 
-int wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
+void wpas_wps_er_stop(struct wpa_supplicant *wpa_s)
 {
 #ifdef CONFIG_WPS_ER
 	wps_er_deinit(wpa_s->wps_er, NULL, NULL);
 	wpa_s->wps_er = NULL;
 #endif /* CONFIG_WPS_ER */
-	return 0;
 }
 
 
@@ -1907,6 +1941,7 @@
 	u8 addr[ETH_ALEN], *use_addr = NULL;
 	struct wpa_ssid *ssid;
 	struct wps_credential cred;
+	int ret;
 
 	if (uuid_str2bin(uuid, u) == 0)
 		use_uuid = u;
@@ -1920,7 +1955,9 @@
 
 	if (wpas_wps_network_to_cred(ssid, &cred) < 0)
 		return -1;
-	return wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
+	ret = wps_er_set_config(wpa_s->wps_er, use_uuid, use_addr, &cred);
+	os_memset(&cred, 0, sizeof(cred));
+	return ret;
 }
 
 
diff --git a/wpa_supplicant/wps_supplicant.h b/wpa_supplicant/wps_supplicant.h
index 2263512..683bd50 100644
--- a/wpa_supplicant/wps_supplicant.h
+++ b/wpa_supplicant/wps_supplicant.h
@@ -47,7 +47,7 @@
 int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *pos,
 			      char *end);
 int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter);
-int wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
+void wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
 int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
 			const char *uuid, const char *pin);
 int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid);