Update to new version 0.8.16 from BRCM

Sync with main tree commit b8349523e460493fa0b4de36c689595109e45e91
Author: Neeraj Kumar Garg <neerajkg@broadcom.com>
Date:   Tue Dec 27 23:21:45 2011 +0200
    P2P: Reject p2p_group_add if forced frequency is not acceptable

Change-Id: Icb4541a371b05c270e80440d7a7fdea7f33ff61e
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/CleanSpec.mk b/CleanSpec.mk
index d01a378..0d97a21 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -54,3 +54,6 @@
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_cli_intermediates/*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_supplicant_intermediates/*)
 $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/hostapd_intermediates/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_cli_intermediates/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_supplicant_intermediates/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/hostapd_intermediates/*)
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index 4f555a0..255c802 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -19,7 +19,7 @@
 L_CFLAGS += -DANDROID_LOG_NAME=\"hostapd\"
 
 ifeq ($(BOARD_WLAN_DEVICE), bcmdhd)
-L_CFLAGS += -DANDROID_BRCM_P2P_PATCH
+L_CFLAGS += -DANDROID_P2P
 endif
 
 # To force sizeof(enum) = 4
@@ -79,6 +79,8 @@
 OBJS += src/ap/wpa_auth_ie.c
 OBJS += src/ap/preauth_auth.c
 OBJS += src/ap/pmksa_cache_auth.c
+OBJS += src/ap/ieee802_11_shared.c
+OBJS += src/ap/beacon.c
 OBJS_d =
 OBJS_p =
 LIBS =
@@ -756,7 +758,6 @@
 endif
 
 ifdef NEED_AP_MLME
-OBJS += src/ap/beacon.c
 OBJS += src/ap/wmm.c
 OBJS += src/ap/ap_list.c
 OBJS += src/ap/ieee802_11.c
@@ -772,6 +773,8 @@
 OBJS += src/ap/p2p_hostapd.c
 endif
 
+OBJS += src/drivers/driver_common.c
+
 ifdef CONFIG_NO_STDOUT_DEBUG
 L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
 endif
@@ -785,9 +788,15 @@
 endif
 
 OBJS_c = hostapd_cli.c src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
+OBJS_c += src/utils/eloop.c
 ifdef CONFIG_WPA_TRACE
 OBJS_c += src/utils/trace.c
+endif
 OBJS_c += src/utils/wpa_debug.c
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += src/utils/edit.c
+else
+OBJS_c += src/utils/edit_simple.c
 endif
 
 ########################
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index a8417d6..47f2423 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -82,7 +82,7 @@
 	* updated management frame protection to use IEEE Std 802.11w-2009
 	* fixed number of small WPS issues and added workarounds to
 	  interoperate with common deployed broken implementations
-	* added some IEEE 802.11n co-existance rules to disable 40 MHz channels
+	* added some IEEE 802.11n co-existence rules to disable 40 MHz channels
 	  or modify primary/secondary channels if needed based on neighboring
 	  networks
 	* added support for NFC out-of-band mechanism with WPS
diff --git a/hostapd/Makefile b/hostapd/Makefile
index d05975b..22c09c1 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -51,6 +51,10 @@
 OBJS += ../src/ap/wpa_auth_ie.o
 OBJS += ../src/ap/preauth_auth.o
 OBJS += ../src/ap/pmksa_cache_auth.o
+OBJS += ../src/ap/ieee802_11_shared.o
+OBJS += ../src/ap/beacon.o
+
+OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
 
 NEED_RC4=y
 NEED_AES=y
@@ -74,9 +78,14 @@
 endif
 endif
 
-OBJS += ../src/utils/eloop.o
+ifndef CONFIG_ELOOP
+CONFIG_ELOOP=eloop
+endif
+OBJS += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
 OBJS += ../src/utils/common.o
 OBJS += ../src/utils/wpa_debug.o
+OBJS_c += ../src/utils/wpa_debug.o
 OBJS += ../src/utils/wpabuf.o
 OBJS += ../src/utils/os_$(CONFIG_OS).o
 OBJS += ../src/utils/ip_addr.o
@@ -427,6 +436,15 @@
 CONFIG_TLS=openssl
 endif
 
+ifdef CONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
 ifeq ($(CONFIG_TLS), openssl)
 ifdef TLS_FUNCS
 OBJS += ../src/crypto/tls_openssl.o
@@ -445,10 +463,6 @@
 ifdef TLS_FUNCS
 OBJS += ../src/crypto/tls_gnutls.o
 LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
 endif
 OBJS += ../src/crypto/crypto_gnutls.o
 HOBJS += ../src/crypto/crypto_gnutls.o
@@ -510,6 +524,9 @@
 NEED_SHA256=y
 NEED_BASE64=y
 NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
 NEED_MODEXP=y
 NEED_CIPHER=y
 CFLAGS += -DCONFIG_TLS_INTERNAL
@@ -669,10 +686,14 @@
 endif
 
 ifdef NEED_SHA256
+CFLAGS += -DCONFIG_SHA256
 OBJS += ../src/crypto/sha256.o
 ifdef CONFIG_INTERNAL_SHA256
 OBJS += ../src/crypto/sha256-internal.o
 endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += ../src/crypto/sha256-tlsprf.o
+endif
 endif
 
 ifdef NEED_DH_GROUPS
@@ -692,6 +713,7 @@
 else
 OBJS += ../src/crypto/random.o
 HOBJS += ../src/crypto/random.o
+HOBJS += ../src/utils/eloop.o
 HOBJS += $(SHA1OBJS)
 HOBJS += ../src/crypto/md5.o
 endif
@@ -720,7 +742,6 @@
 endif
 
 ifdef NEED_AP_MLME
-OBJS += ../src/ap/beacon.o
 OBJS += ../src/ap/wmm.o
 OBJS += ../src/ap/ap_list.o
 OBJS += ../src/ap/ieee802_11.o
@@ -736,6 +757,18 @@
 OBJS += ../src/ap/p2p_hostapd.o
 endif
 
+ifdef CONFIG_INTERWORKING
+CFLAGS += -DCONFIG_INTERWORKING
+endif
+
+OBJS += ../src/drivers/driver_common.o
+
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += ../src/utils/edit.o
+else
+OBJS_c += ../src/utils/edit_simple.o
+endif
+
 ifdef CONFIG_NO_STDOUT_DEBUG
 CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
 endif
@@ -784,10 +817,8 @@
 	$(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
 	@$(E) "  LD " $@
 
-OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
 ifdef CONFIG_WPA_TRACE
 OBJS_c += ../src/utils/trace.o
-OBJS_c += ../src/utils/wpa_debug.o
 endif
 hostapd_cli: $(OBJS_c)
 	$(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index bfd4809..467d39f 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -330,7 +330,7 @@
 			}
 
 			num_methods++;
-			if (num_methods >= EAP_USER_MAX_METHODS)
+			if (num_methods >= EAP_MAX_METHODS)
 				break;
 		skip_eap:
 			if (pos3 == NULL)
@@ -1050,9 +1050,18 @@
 		return -1;
 	}
 
+	if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+	    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+		wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
+			   "RADIUS checking (macaddr_acl=2) enabled.");
+		return -1;
+	}
+
 	if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
 	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
-	    bss->ssid.wpa_psk_file == NULL) {
+	    bss->ssid.wpa_psk_file == NULL &&
+	    (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
+	     bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
 		wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
 			   "is not configured.");
 		return -1;
@@ -1075,8 +1084,7 @@
 	}
 
 #ifdef CONFIG_IEEE80211R
-	if ((bss->wpa_key_mgmt &
-	     (WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X)) &&
+	if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
 	    (bss->nas_identifier == NULL ||
 	     os_strlen(bss->nas_identifier) < 1 ||
 	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
@@ -1142,6 +1150,40 @@
 }
 
 
+#ifdef CONFIG_INTERWORKING
+static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
+				    int line)
+{
+	size_t len = os_strlen(pos);
+	u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+
+	struct hostapd_roaming_consortium *rc;
+
+	if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN ||
+	    hexstr2bin(pos, oi, len / 2)) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium "
+			   "'%s'", line, pos);
+		return -1;
+	}
+	len /= 2;
+
+	rc = os_realloc(bss->roaming_consortium,
+			sizeof(struct hostapd_roaming_consortium) *
+			(bss->roaming_consortium_count + 1));
+	if (rc == NULL)
+		return -1;
+
+	os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len);
+	rc[bss->roaming_consortium_count].len = len;
+
+	bss->roaming_consortium = rc;
+	bss->roaming_consortium_count++;
+
+	return 0;
+}
+#endif /* CONFIG_INTERWORKING */
+
+
 /**
  * hostapd_config_read - Read and parse a configuration file
  * @fname: Configuration file name (including path, if needed)
@@ -1292,6 +1334,8 @@
 			bss->isolate = atoi(pos);
 		} else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
 			bss->ap_max_inactivity = atoi(pos);
+		} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
+			bss->skip_inactivity_poll = atoi(pos);
 		} else if (os_strcmp(buf, "country_code") == 0) {
 			os_memcpy(conf->country, pos, 2);
 			/* FIX: make this configurable */
@@ -1596,6 +1640,16 @@
 				hostapd_config_parse_key_mgmt(line, pos);
 			if (bss->wpa_key_mgmt == -1)
 				errors++;
+		} else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
+			bss->wpa_psk_radius = atoi(pos);
+			if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+			    bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
+			    bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
+				wpa_printf(MSG_ERROR, "Line %d: unknown "
+					   "wpa_psk_radius %d",
+					   line, bss->wpa_psk_radius);
+				errors++;
+			}
 		} else if (os_strcmp(buf, "wpa_pairwise") == 0) {
 			bss->wpa_pairwise =
 				hostapd_config_parse_cipher(line, pos);
@@ -1735,6 +1789,21 @@
 					   "hw_mode '%s'", line, pos);
 				errors++;
 			}
+		} else if (os_strcmp(buf, "wps_rf_bands") == 0) {
+			if (os_strcmp(pos, "a") == 0)
+				bss->wps_rf_bands = WPS_RF_50GHZ;
+			else if (os_strcmp(pos, "g") == 0 ||
+				 os_strcmp(pos, "b") == 0)
+				bss->wps_rf_bands = WPS_RF_24GHZ;
+			else if (os_strcmp(pos, "ag") == 0 ||
+				 os_strcmp(pos, "ga") == 0)
+				bss->wps_rf_bands =
+					WPS_RF_24GHZ | WPS_RF_50GHZ;
+			else {
+				wpa_printf(MSG_ERROR, "Line %d: unknown "
+					   "wps_rf_band '%s'", line, pos);
+				errors++;
+			}
 		} else if (os_strcmp(buf, "channel") == 0) {
 			conf->channel = atoi(pos);
 		} else if (os_strcmp(buf, "beacon_int") == 0) {
@@ -2058,6 +2127,60 @@
 			extern int rsn_testing;
 			rsn_testing = atoi(pos);
 #endif /* CONFIG_RSN_TESTING */
+		} else if (os_strcmp(buf, "time_advertisement") == 0) {
+			bss->time_advertisement = atoi(pos);
+		} else if (os_strcmp(buf, "time_zone") == 0) {
+			size_t tz_len = os_strlen(pos);
+			if (tz_len < 4 || tz_len > 255) {
+				wpa_printf(MSG_DEBUG, "Line %d: invalid "
+					   "time_zone", line);
+				errors++;
+				continue;
+			}
+			os_free(bss->time_zone);
+			bss->time_zone = os_strdup(pos);
+			if (bss->time_zone == NULL)
+				errors++;
+#ifdef CONFIG_INTERWORKING
+		} else if (os_strcmp(buf, "interworking") == 0) {
+			bss->interworking = atoi(pos);
+		} else if (os_strcmp(buf, "access_network_type") == 0) {
+			bss->access_network_type = atoi(pos);
+			if (bss->access_network_type < 0 ||
+			    bss->access_network_type > 15) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "access_network_type", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "internet") == 0) {
+			bss->internet = atoi(pos);
+		} else if (os_strcmp(buf, "asra") == 0) {
+			bss->asra = atoi(pos);
+		} else if (os_strcmp(buf, "esr") == 0) {
+			bss->esr = atoi(pos);
+		} else if (os_strcmp(buf, "uesa") == 0) {
+			bss->uesa = atoi(pos);
+		} else if (os_strcmp(buf, "venue_group") == 0) {
+			bss->venue_group = atoi(pos);
+			bss->venue_info_set = 1;
+		} else if (os_strcmp(buf, "venue_type") == 0) {
+			bss->venue_type = atoi(pos);
+			bss->venue_info_set = 1;
+		} else if (os_strcmp(buf, "hessid") == 0) {
+			if (hwaddr_aton(pos, bss->hessid)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "hessid", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "roaming_consortium") == 0) {
+			if (parse_roaming_consortium(bss, pos, line) < 0)
+				errors++;
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_RADIUS_TEST
+		} else if (os_strcmp(buf, "dump_msk_file") == 0) {
+			os_free(bss->dump_msk_file);
+			bss->dump_msk_file = os_strdup(pos);
+#endif /* CONFIG_RADIUS_TEST */
 		} else {
 			wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
 				   "item '%s'", line, buf);
@@ -2099,12 +2222,29 @@
 		} else if (bss->wpa) {
 			bss->ssid.security_policy = SECURITY_WPA_PSK;
 		} else if (bss->ieee802_1x) {
+			int cipher = WPA_CIPHER_NONE;
 			bss->ssid.security_policy = SECURITY_IEEE_802_1X;
 			bss->ssid.wep.default_len = bss->default_wep_key_len;
-		} else if (bss->ssid.wep.keys_set)
+			if (bss->default_wep_key_len)
+				cipher = bss->default_wep_key_len >= 13 ?
+					WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+			bss->wpa_group = cipher;
+			bss->wpa_pairwise = cipher;
+			bss->rsn_pairwise = cipher;
+		} else if (bss->ssid.wep.keys_set) {
+			int cipher = WPA_CIPHER_WEP40;
+			if (bss->ssid.wep.len[0] >= 13)
+				cipher = WPA_CIPHER_WEP104;
 			bss->ssid.security_policy = SECURITY_STATIC_WEP;
-		else
+			bss->wpa_group = cipher;
+			bss->wpa_pairwise = cipher;
+			bss->rsn_pairwise = cipher;
+		} else {
 			bss->ssid.security_policy = SECURITY_PLAINTEXT;
+			bss->wpa_group = WPA_CIPHER_NONE;
+			bss->wpa_pairwise = WPA_CIPHER_NONE;
+			bss->rsn_pairwise = WPA_CIPHER_NONE;
+		}
 	}
 
 	if (hostapd_config_check(conf))
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 195b8a7..a38d77c 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -32,7 +32,6 @@
 #include "ap/wpa_auth.h"
 #include "ap/ieee802_11.h"
 #include "ap/sta_info.h"
-#include "ap/accounting.h"
 #include "ap/wps_hostapd.h"
 #include "ap/ctrl_iface_ap.h"
 #include "ap/ap_drv_ops.h"
@@ -174,9 +173,9 @@
 	if (mgmt == NULL)
 		return -1;
 
-	wpa_printf(MSG_DEBUG, "P2P: Disconnect STA " MACSTR " with minor "
-		   "reason code %u (stype=%u)",
-		   MAC2STR(addr), minor_reason_code, stype);
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
+		" with minor reason code %u (stype=%u)",
+		MAC2STR(addr), minor_reason_code, stype);
 
 	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
 	os_memcpy(mgmt->da, addr, ETH_ALEN);
@@ -219,7 +218,8 @@
 	struct sta_info *sta;
 	const char *pos;
 
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s", txtaddr);
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
+		txtaddr);
 
 	if (hwaddr_aton(txtaddr, addr))
 		return -1;
@@ -275,7 +275,8 @@
 	struct sta_info *sta;
 	const char *pos;
 
-	wpa_printf(MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s", txtaddr);
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
+		txtaddr);
 
 	if (hwaddr_aton(txtaddr, addr))
 		return -1;
@@ -526,6 +527,57 @@
 #endif /* CONFIG_WPS */
 
 
+static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
+					   const char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	const char *url;
+	u8 buf[1000], *pos;
+	struct ieee80211_mgmt *mgmt;
+	size_t url_len;
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+	url = cmd + 17;
+	if (*url != ' ')
+		return -1;
+	url++;
+	url_len = os_strlen(url);
+	if (url_len > 255)
+		return -1;
+
+	os_memset(buf, 0, sizeof(buf));
+	mgmt = (struct ieee80211_mgmt *) buf;
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt->da, addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+	mgmt->u.action.u.bss_tm_req.req_mode =
+		WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+	mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
+	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+
+	pos = mgmt->u.action.u.bss_tm_req.variable;
+
+	/* Session Information URL */
+	*pos++ = url_len;
+	os_memcpy(pos, url, url_len);
+	pos += url_len;
+
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+			   "Management Request frame");
+		return -1;
+	}
+
+	return 0;
+}
+
+
 static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
 					 char *buf, size_t buflen)
 {
@@ -879,6 +931,9 @@
 		if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
 			reply_len = -1;
 #endif /* CONFIG_WPS */
+	} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
+		if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
+			reply_len = -1;
 	} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
 		reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
 							  reply_size);
diff --git a/hostapd/defconfig b/hostapd/defconfig
index 26be2a8..bae5ba2 100644
--- a/hostapd/defconfig
+++ b/hostapd/defconfig
@@ -208,3 +208,40 @@
 # considered for builds that are known to be used on devices that meet the
 # requirements described above.
 #CONFIG_NO_RANDOM_POOL=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+#CONFIG_TLS=openssl
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used.
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms.
+#CONFIG_TLSV12=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks.
+#CONFIG_INTERWORKING=y
diff --git a/hostapd/dump_state.c b/hostapd/dump_state.c
index 73aa93d..110cedc 100644
--- a/hostapd/dump_state.c
+++ b/hostapd/dump_state.c
@@ -13,6 +13,7 @@
  */
 
 #include "utils/includes.h"
+#include <time.h>
 
 #include "utils/common.h"
 #include "radius/radius_client.h"
@@ -106,7 +107,8 @@
 		fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
 
 		fprintf(f,
-			"  AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n"
+			"  AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
+			"\n"
 			"  capability=0x%x listen_interval=%d\n",
 			sta->aid,
 			sta->flags,
@@ -127,6 +129,7 @@
 			(sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
 			(sta->flags & WLAN_STA_WDS ? "[WDS]" : ""),
 			(sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
+			(sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
 			sta->capability,
 			sta->listen_interval);
 
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 3b1548c..4e6202b 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -99,19 +99,18 @@
 
 # Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
 # Default: IEEE 802.11b
-hw_mode=a
+hw_mode=g
 
 # Channel number (IEEE 802.11)
 # (default: 0, i.e., not set)
-# Please note that some drivers (e.g., madwifi) do not use this value from
-# hostapd and the channel will need to be configuration separately with
-# iwconfig.
-channel=60
+# Please note that some drivers do not use this value from hostapd and the
+# channel will need to be configured separately with iwconfig.
+channel=1
 
 # Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
 beacon_int=100
 
-# DTIM (delivery trafic information message) period (range 1..255):
+# DTIM (delivery traffic information message) period (range 1..255):
 # number of beacons between DTIMs (1 = every beacon includes DTIM element)
 # (default: 2)
 dtim_period=2
@@ -340,6 +339,12 @@
 # the STA with a data frame.
 # default: 300 (i.e., 5 minutes)
 #ap_max_inactivity=300
+#
+# The inactivity polling can be disabled to disconnect stations based on
+# inactivity timeout so that idle stations are more likely to be disconnected
+# even if they are still in range of the AP. This can be done by setting
+# skip_inactivity_poll to 1 (default 0).
+#skip_inactivity_poll=0
 
 # Disassociate stations based on excessive transmission failures or other
 # indications of connection loss. This depends on the driver capabilities and
@@ -511,6 +516,10 @@
 # Fragment size for EAP methods
 #fragment_size=1400
 
+# Finite cyclic group for EAP-pwd. Number maps to group of domain parameters
+# using the IANA repository for IKE (RFC 2409).
+#pwd_group=19
+
 # Configuration data for EAP-SIM database/authentication gateway interface.
 # This is a text string in implementation specific format. The example
 # implementation in eap_sim_db.c uses this as the UNIX domain socket name for
@@ -673,6 +682,7 @@
 # Enable WPA. Setting this variable configures the AP to require WPA (either
 # WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
 # wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice.
 # For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
 # RADIUS authentication server must be configured, and WPA-EAP must be included
 # in wpa_key_mgmt.
@@ -697,6 +707,15 @@
 # configuration reloads.
 #wpa_psk_file=/etc/hostapd.wpa_psk
 
+# Optionally, WPA passphrase can be received from RADIUS authentication server
+# This requires macaddr_acl to be set to 2 (RADIUS)
+# 0 = disabled (default)
+# 1 = optional; use default passphrase/psk if RADIUS server does not include
+#	Tunnel-Password
+# 2 = required; reject authentication if RADIUS server does not include
+#	Tunnel-Password
+#wpa_psk_radius=0
+
 # Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
 # entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
 # added to enable SHA256-based stronger algorithms.
@@ -1008,6 +1027,12 @@
 # 12-digit, all-numeric code that identifies the consumer package.
 #upc=123456789012
 
+# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band)
+# This value should be set according to RF band(s) supported by the AP if
+# hw_mode is not set. For dual band dual concurrent devices, this needs to be
+# set to ag to allow both RF bands to be advertized.
+#wps_rf_bands=ag
+
 ##### Wi-Fi Direct (P2P) ######################################################
 
 # Enable P2P Device management
@@ -1024,6 +1049,75 @@
 # Prohibit use of TDLS Channel Switching in this BSS
 #tdls_prohibit_chan_switch=1
 
+##### IEEE 802.11v-2011 #######################################################
+
+# Time advertisement
+# 0 = disabled (default)
+# 2 = UTC time at which the TSF timer is 0
+#time_advertisement=2
+
+# Local time zone as specified in 8.3 of IEEE Std 1003.1-2004:
+# stdoffset[dst[offset][,start[/time],end[/time]]]
+#time_zone=EST5
+
+##### IEEE 802.11u-2011 #######################################################
+
+# Enable Interworking service
+#interworking=1
+
+# Access Network Type
+# 0 = Private network
+# 1 = Private network with guest access
+# 2 = Chargeable public network
+# 3 = Free public network
+# 4 = Personal device network
+# 5 = Emergency services only network
+# 14 = Test or experimental
+# 15 = Wildcard
+#access_network_type=0
+
+# Whether the network provides connectivity to the Internet
+# 0 = Unspecified
+# 1 = Network provides connectivity to the Internet
+#internet=1
+
+# Additional Step Required for Access
+# Note: This is only used with open network, i.e., ASRA shall ne set to 0 if
+# RSN is used.
+#asra=0
+
+# Emergency services reachable
+#esr=0
+
+# Unauthenticated emergency service accessible
+#uesa=0
+
+# Venue Info (optional)
+# The available values are defined in IEEE Std 802.11u-2011, 7.3.1.34.
+# Example values (group,type):
+# 0,0 = Unspecified
+# 1,7 = Convention Center
+# 1,13 = Coffee Shop
+# 2,0 = Unspecified Business
+# 7,1  Private Residence
+#venue_group=7
+#venue_type=1
+
+# Homogeneous ESS identifier (optional; dot11HESSID)
+# If set, this shall be identifical to one of the BSSIDs in the homogeneous
+# ESS and this shall be set to the same value across all BSSs in homogeneous
+# ESS.
+#hessid=02:03:04:05:06:07
+
+# Roaming Consortium List
+# Arbitrary number of Roaming Consortium OIs can be configured with each line
+# adding a new OI to the list. The first three entries are available through
+# Beacon and Probe Response frames. Any additional entry will be available only
+# through ANQP queries. Each OI is between 3 and 15 octets and is configured a
+# a hexstring.
+#roaming_consortium=021122
+#roaming_consortium=2233445566
+
 ##### Multiple BSSID support ##################################################
 #
 # Above configuration is using the default interface (wlan#, or multi-SSID VLAN
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index a48d773..527860c 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -16,7 +16,9 @@
 #include <dirent.h>
 
 #include "common/wpa_ctrl.h"
-#include "common.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/edit.h"
 #include "common/version.h"
 
 
@@ -113,6 +115,7 @@
 static const char *pid_file = NULL;
 static const char *action_file = NULL;
 static int ping_interval = 5;
+static int interactive = 0;
 
 
 static void usage(void)
@@ -512,6 +515,26 @@
 #endif /* CONFIG_WPS */
 
 
+static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	char buf[300];
+	int res;
+
+	if (argc < 2) {
+		printf("Invalid 'ess_disassoc' command - two arguments (STA "
+		       "addr and URL) are needed\n");
+		return -1;
+	}
+
+	res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
+			  argv[0], argv[1]);
+	if (res < 0 || res >= (int) sizeof(buf))
+		return -1;
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
 static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
 				      char *argv[])
 {
@@ -588,6 +611,8 @@
 static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	hostapd_cli_quit = 1;
+	if (interactive)
+		eloop_terminate();
 	return 0;
 }
 
@@ -723,6 +748,7 @@
 	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
 	{ "wps_config", hostapd_cli_cmd_wps_config },
 #endif /* CONFIG_WPS */
+	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
 	{ "get_config", hostapd_cli_cmd_get_config },
 	{ "help", hostapd_cli_cmd_help },
 	{ "interface", hostapd_cli_cmd_interface },
@@ -801,70 +827,39 @@
 }
 
 
-static void hostapd_cli_interactive(void)
+#define max_args 10
+
+static int tokenize_cmd(char *cmd, char *argv[])
 {
-	const int max_args = 10;
-	char cmd[256], *res, *argv[max_args], *pos;
-	int argc;
+	char *pos;
+	int argc = 0;
 
-	printf("\nInteractive mode\n\n");
-
-	do {
-		hostapd_cli_recv_pending(ctrl_conn, 0, 0);
-		printf("> ");
-		alarm(ping_interval);
-		res = fgets(cmd, sizeof(cmd), stdin);
-		alarm(0);
-		if (res == NULL)
-			break;
-		pos = cmd;
-		while (*pos != '\0') {
-			if (*pos == '\n') {
-				*pos = '\0';
-				break;
-			}
+	pos = cmd;
+	for (;;) {
+		while (*pos == ' ')
 			pos++;
+		if (*pos == '\0')
+			break;
+		argv[argc] = pos;
+		argc++;
+		if (argc == max_args)
+			break;
+		if (*pos == '"') {
+			char *pos2 = os_strrchr(pos, '"');
+			if (pos2)
+				pos = pos2 + 1;
 		}
-		argc = 0;
-		pos = cmd;
-		for (;;) {
-			while (*pos == ' ')
-				pos++;
-			if (*pos == '\0')
-				break;
-			argv[argc] = pos;
-			argc++;
-			if (argc == max_args)
-				break;
-			while (*pos != '\0' && *pos != ' ')
-				pos++;
-			if (*pos == ' ')
-				*pos++ = '\0';
-		}
-		if (argc)
-			wpa_request(ctrl_conn, argc, argv);
-	} while (!hostapd_cli_quit);
+		while (*pos != '\0' && *pos != ' ')
+			pos++;
+		if (*pos == ' ')
+			*pos++ = '\0';
+	}
+
+	return argc;
 }
 
 
-static void hostapd_cli_cleanup(void)
-{
-	hostapd_cli_close_connection();
-	if (pid_file)
-		os_daemonize_terminate(pid_file);
-
-	os_program_deinit();
-}
-
-
-static void hostapd_cli_terminate(int sig)
-{
-	hostapd_cli_cleanup();
-	exit(0);
-}
-
-
-static void hostapd_cli_alarm(int sig)
+static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
 {
 	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
 		printf("Connection to hostapd lost - trying to reconnect\n");
@@ -884,7 +879,55 @@
 	}
 	if (ctrl_conn)
 		hostapd_cli_recv_pending(ctrl_conn, 1, 0);
-	alarm(ping_interval);
+	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
+}
+
+
+static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
+{
+	eloop_terminate();
+}
+
+
+static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
+{
+	char *argv[max_args];
+	int argc;
+	argc = tokenize_cmd(cmd, argv);
+	if (argc)
+		wpa_request(ctrl_conn, argc, argv);
+}
+
+
+static void hostapd_cli_edit_eof_cb(void *ctx)
+{
+	eloop_terminate();
+}
+
+
+static void hostapd_cli_interactive(void)
+{
+	printf("\nInteractive mode\n\n");
+
+	eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
+	edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
+		  NULL, NULL, NULL);
+	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
+
+	eloop_run();
+
+	edit_deinit(NULL, NULL);
+	eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
+}
+
+
+static void hostapd_cli_cleanup(void)
+{
+	hostapd_cli_close_connection();
+	if (pid_file)
+		os_daemonize_terminate(pid_file);
+
+	os_program_deinit();
 }
 
 
@@ -927,7 +970,6 @@
 
 int main(int argc, char *argv[])
 {
-	int interactive;
 	int warning_displayed = 0;
 	int c;
 	int daemonize = 0;
@@ -975,6 +1017,9 @@
 		       hostapd_cli_license);
 	}
 
+	if (eloop_init())
+		return -1;
+
 	for (;;) {
 		if (ctrl_ifname == NULL) {
 			struct dirent *dent;
@@ -1014,10 +1059,6 @@
 		continue;
 	}
 
-	signal(SIGINT, hostapd_cli_terminate);
-	signal(SIGTERM, hostapd_cli_terminate);
-	signal(SIGALRM, hostapd_cli_alarm);
-
 	if (interactive || action_file) {
 		if (wpa_ctrl_attach(ctrl_conn) == 0) {
 			hostapd_cli_attached = 1;
@@ -1039,6 +1080,7 @@
 		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
 
 	os_free(ctrl_ifname);
+	eloop_destroy();
 	hostapd_cli_cleanup();
 	return 0;
 }
diff --git a/hostapd/main.c b/hostapd/main.c
index 01ad826..da8135b 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -37,6 +37,16 @@
 extern int wpa_debug_show_keys;
 extern int wpa_debug_timestamp;
 
+extern struct wpa_driver_ops *wpa_drivers[];
+
+
+struct hapd_global {
+	void **drv_priv;
+	size_t drv_count;
+};
+
+static struct hapd_global global;
+
 
 struct hapd_interfaces {
 	size_t count;
@@ -246,6 +256,24 @@
 		b = NULL;
 
 	os_memset(&params, 0, sizeof(params));
+	for (i = 0; wpa_drivers[i]; i++) {
+		if (wpa_drivers[i] != hapd->driver)
+			continue;
+
+		if (global.drv_priv[i] == NULL &&
+		    wpa_drivers[i]->global_init) {
+			global.drv_priv[i] = wpa_drivers[i]->global_init();
+			if (global.drv_priv[i] == NULL) {
+				wpa_printf(MSG_ERROR, "Failed to initialize "
+					   "driver '%s'",
+					   wpa_drivers[i]->name);
+				return -1;
+			}
+		}
+
+		params.global_priv = global.drv_priv[i];
+		break;
+	}
 	params.bssid = b;
 	params.ifname = hapd->conf->iface;
 	params.ssid = (const u8 *) hapd->conf->ssid.ssid;
@@ -275,8 +303,10 @@
 	}
 
 	if (hapd->driver->get_capa &&
-	    hapd->driver->get_capa(hapd->drv_priv, &capa) == 0)
+	    hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
 		iface->drv_flags = capa.flags;
+		iface->probe_resp_offloads = capa.probe_resp_offloads;
+	}
 
 	return 0;
 }
@@ -372,6 +402,10 @@
 static int hostapd_global_init(struct hapd_interfaces *interfaces,
 			       const char *entropy_file)
 {
+	int i;
+
+	os_memset(&global, 0, sizeof(global));
+
 	hostapd_logger_register_cb(hostapd_logger_cb);
 
 	if (eap_server_register_methods()) {
@@ -396,12 +430,32 @@
 	openlog("hostapd", 0, LOG_DAEMON);
 #endif /* CONFIG_NATIVE_WINDOWS */
 
+	for (i = 0; wpa_drivers[i]; i++)
+		global.drv_count++;
+	if (global.drv_count == 0) {
+		wpa_printf(MSG_ERROR, "No drivers enabled");
+		return -1;
+	}
+	global.drv_priv = os_zalloc(global.drv_count * sizeof(void *));
+	if (global.drv_priv == NULL)
+		return -1;
+
 	return 0;
 }
 
 
 static void hostapd_global_deinit(const char *pid_file)
 {
+	int i;
+
+	for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
+		if (!global.drv_priv[i])
+			continue;
+		wpa_drivers[i]->global_deinit(global.drv_priv[i]);
+	}
+	os_free(global.drv_priv);
+	global.drv_priv = NULL;
+
 #ifdef EAP_SERVER_TNC
 	tncs_global_deinit();
 #endif /* EAP_SERVER_TNC */
diff --git a/src/ap/accounting.c b/src/ap/accounting.c
index dbfb058..03421b3 100644
--- a/src/ap/accounting.c
+++ b/src/ap/accounting.c
@@ -236,6 +236,7 @@
 void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
 {
 	struct radius_msg *msg;
+	struct os_time t;
 	int interval;
 
 	if (sta->acct_session_started)
@@ -247,7 +248,8 @@
 		       "starting accounting session %08X-%08X",
 		       sta->acct_session_id_hi, sta->acct_session_id_lo);
 
-	time(&sta->acct_session_start);
+	os_get_time(&t);
+	sta->acct_session_start = t.sec;
 	sta->last_rx_bytes = sta->last_tx_bytes = 0;
 	sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
 	hostapd_drv_sta_clear_stats(hapd, sta->addr);
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index e77716b..b24cd90 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -426,6 +426,8 @@
 		ssid->dyn_vlan_keys = NULL;
 	}
 
+	os_free(conf->time_zone);
+
 #ifdef CONFIG_IEEE80211R
 	{
 		struct ft_remote_r0kh *r0kh, *r0kh_prev;
@@ -467,6 +469,12 @@
 	os_free(conf->model_url);
 	os_free(conf->upc);
 #endif /* CONFIG_WPS */
+
+	os_free(conf->roaming_consortium);
+
+#ifdef CONFIG_RADIUS_TEST
+	os_free(conf->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
 }
 
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 09eed5a..485092d 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -104,7 +104,6 @@
 	u8 addr[ETH_ALEN];
 };
 
-#define EAP_USER_MAX_METHODS 8
 struct hostapd_eap_user {
 	struct hostapd_eap_user *next;
 	u8 *identity;
@@ -112,7 +111,7 @@
 	struct {
 		int vendor;
 		u32 method;
-	} methods[EAP_USER_MAX_METHODS];
+	} methods[EAP_MAX_METHODS];
 	u8 *password;
 	size_t password_len;
 	int phase2;
@@ -142,6 +141,13 @@
 };
 
 
+#define MAX_ROAMING_CONSORTIUM_LEN 15
+
+struct hostapd_roaming_consortium {
+	u8 len;
+	u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+};
+
 /**
  * struct hostapd_bss_config - Per-BSS configuration
  */
@@ -213,6 +219,11 @@
 	/* dot11AssociationSAQueryRetryTimeout (in TUs) */
 	int assoc_sa_query_retry_timeout;
 #endif /* CONFIG_IEEE80211W */
+	enum {
+		PSK_RADIUS_IGNORED = 0,
+		PSK_RADIUS_ACCEPTED = 1,
+		PSK_RADIUS_REQUIRED = 2
+	} wpa_psk_radius;
 	int wpa_pairwise;
 	int wpa_group;
 	int wpa_group_rekey;
@@ -329,11 +340,38 @@
 	int p2p;
 
 	int disassoc_low_ack;
+	int skip_inactivity_poll;
 
 #define TDLS_PROHIBIT BIT(0)
 #define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
 	int tdls;
 	int disable_11n;
+
+	/* IEEE 802.11v */
+	int time_advertisement;
+	char *time_zone;
+
+	/* IEEE 802.11u - Interworking */
+	int interworking;
+	int access_network_type;
+	int internet;
+	int asra;
+	int esr;
+	int uesa;
+	int venue_info_set;
+	u8 venue_group;
+	u8 venue_type;
+	u8 hessid[ETH_ALEN];
+
+	/* IEEE 802.11u - Roaming Consortium list */
+	unsigned int roaming_consortium_count;
+	struct hostapd_roaming_consortium *roaming_consortium;
+
+	u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
+
+#ifdef CONFIG_RADIUS_TEST
+	char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 };
 
 
@@ -354,12 +392,6 @@
 		LONG_PREAMBLE = 0,
 		SHORT_PREAMBLE = 1
 	} preamble;
-	enum {
-		CTS_PROTECTION_AUTOMATIC = 0,
-		CTS_PROTECTION_FORCE_ENABLED = 1,
-		CTS_PROTECTION_FORCE_DISABLED = 2,
-		CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
-	} cts_protection_type;
 
 	int *supported_rates;
 	int *basic_rates;
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 0b6836c..429c187 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -41,117 +41,159 @@
 }
 
 
-int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf **beacon_ret,
+			       struct wpabuf **proberesp_ret,
+			       struct wpabuf **assocresp_ret)
 {
-	struct wpabuf *beacon, *proberesp, *assocresp = NULL;
-	int ret;
+	struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL;
+	u8 buf[200], *pos;
 
-	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
-		return 0;
+	*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
 
-	beacon = hapd->wps_beacon_ie;
-	proberesp = hapd->wps_probe_resp_ie;
-
-#ifdef CONFIG_P2P
-	if (hapd->wps_beacon_ie == NULL && hapd->p2p_beacon_ie == NULL)
-		beacon = NULL;
-	else {
-		beacon = wpabuf_alloc((hapd->wps_beacon_ie ?
-				       wpabuf_len(hapd->wps_beacon_ie) : 0) +
-				      (hapd->p2p_beacon_ie ?
-				       wpabuf_len(hapd->p2p_beacon_ie) : 0));
-		if (beacon == NULL)
-			return -1;
-		if (hapd->wps_beacon_ie)
-			wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
-		if (hapd->p2p_beacon_ie)
-			wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
+	pos = buf;
+	pos = hostapd_eid_time_adv(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&beacon, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(beacon, buf, pos - buf);
+	}
+	pos = hostapd_eid_time_zone(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&proberesp, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(proberesp, buf, pos - buf);
 	}
 
-	if (hapd->wps_probe_resp_ie == NULL && hapd->p2p_probe_resp_ie == NULL)
-		proberesp = NULL;
-	else {
-		proberesp = wpabuf_alloc(
-			(hapd->wps_probe_resp_ie ?
-			 wpabuf_len(hapd->wps_probe_resp_ie) : 0) +
-			(hapd->p2p_probe_resp_ie ?
-			 wpabuf_len(hapd->p2p_probe_resp_ie) : 0));
-		if (proberesp == NULL) {
-			wpabuf_free(beacon);
-			return -1;
-		}
-		if (hapd->wps_probe_resp_ie)
-			wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
-		if (hapd->p2p_probe_resp_ie)
-			wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
+	pos = buf;
+	pos = hostapd_eid_ext_capab(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&assocresp, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(assocresp, buf, pos - buf);
+	}
+	pos = hostapd_eid_interworking(hapd, pos);
+	pos = hostapd_eid_adv_proto(hapd, pos);
+	pos = hostapd_eid_roaming_consortium(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&beacon, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(beacon, buf, pos - buf);
+
+		if (wpabuf_resize(&proberesp, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(proberesp, buf, pos - buf);
+	}
+
+	if (hapd->wps_beacon_ie) {
+		if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
+		    0)
+			goto fail;
+		wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
+	}
+
+	if (hapd->wps_probe_resp_ie) {
+		if (wpabuf_resize(&proberesp,
+				  wpabuf_len(hapd->wps_probe_resp_ie)) < 0)
+			goto fail;
+		wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
+	}
+
+#ifdef CONFIG_P2P
+	if (hapd->p2p_beacon_ie) {
+		if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) <
+		    0)
+			goto fail;
+		wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
+	}
+
+	if (hapd->p2p_probe_resp_ie) {
+		if (wpabuf_resize(&proberesp,
+				  wpabuf_len(hapd->p2p_probe_resp_ie)) < 0)
+			goto fail;
+		wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
 	}
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_P2P_MANAGER
 	if (hapd->conf->p2p & P2P_MANAGE) {
-		struct wpabuf *a;
-
-		a = wpabuf_alloc(100 + (beacon ? wpabuf_len(beacon) : 0));
-		if (a) {
+		if (wpabuf_resize(&beacon, 100) == 0) {
 			u8 *start, *p;
-			if (beacon)
-				wpabuf_put_buf(a, beacon);
-			if (beacon != hapd->wps_beacon_ie)
-				wpabuf_free(beacon);
-			start = wpabuf_put(a, 0);
+			start = wpabuf_put(beacon, 0);
 			p = hostapd_eid_p2p_manage(hapd, start);
-			wpabuf_put(a, p - start);
-			beacon = a;
+			wpabuf_put(beacon, p - start);
 		}
 
-		a = wpabuf_alloc(100 + (proberesp ? wpabuf_len(proberesp) :
-					0));
-		if (a) {
+		if (wpabuf_resize(&proberesp, 100) == 0) {
 			u8 *start, *p;
-			if (proberesp)
-				wpabuf_put_buf(a, proberesp);
-			if (proberesp != hapd->wps_probe_resp_ie)
-				wpabuf_free(proberesp);
-			start = wpabuf_put(a, 0);
+			start = wpabuf_put(proberesp, 0);
 			p = hostapd_eid_p2p_manage(hapd, start);
-			wpabuf_put(a, p - start);
-			proberesp = a;
+			wpabuf_put(proberesp, p - start);
 		}
 	}
 #endif /* CONFIG_P2P_MANAGER */
 
 #ifdef CONFIG_WPS2
-	if (hapd->conf->wps_state)
-		assocresp = wps_build_assoc_resp_ie();
+	if (hapd->conf->wps_state) {
+		struct wpabuf *a = wps_build_assoc_resp_ie();
+		if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
+			wpabuf_put_buf(assocresp, a);
+		wpabuf_free(a);
+	}
 #endif /* CONFIG_WPS2 */
 
 #ifdef CONFIG_P2P_MANAGER
 	if (hapd->conf->p2p & P2P_MANAGE) {
-		struct wpabuf *a;
-		a = wpabuf_alloc(100 + (assocresp ? wpabuf_len(assocresp) :
-					0));
-		if (a) {
+		if (wpabuf_resize(&assocresp, 100) == 0) {
 			u8 *start, *p;
-			start = wpabuf_put(a, 0);
+			start = wpabuf_put(assocresp, 0);
 			p = hostapd_eid_p2p_manage(hapd, start);
-			wpabuf_put(a, p - start);
-			if (assocresp) {
-				wpabuf_put_buf(a, assocresp);
-				wpabuf_free(assocresp);
-			}
-			assocresp = a;
+			wpabuf_put(assocresp, p - start);
 		}
 	}
 #endif /* CONFIG_P2P_MANAGER */
 
+	*beacon_ret = beacon;
+	*proberesp_ret = proberesp;
+	*assocresp_ret = assocresp;
+
+	return 0;
+
+fail:
+	wpabuf_free(beacon);
+	wpabuf_free(proberesp);
+	wpabuf_free(assocresp);
+	return -1;
+}
+
+
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf *beacon,
+			       struct wpabuf *proberesp,
+			       struct wpabuf *assocresp)
+{
+	wpabuf_free(beacon);
+	wpabuf_free(proberesp);
+	wpabuf_free(assocresp);
+}
+
+
+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
+{
+	struct wpabuf *beacon, *proberesp, *assocresp;
+	int ret;
+
+	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
+		return 0;
+
+	if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
+	    0)
+		return -1;
+
 	ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
 					  assocresp);
 
-	if (beacon != hapd->wps_beacon_ie)
-		wpabuf_free(beacon);
-	if (proberesp != hapd->wps_probe_resp_ie)
-		wpabuf_free(proberesp);
-	wpabuf_free(assocresp);
+	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
 
 	return ret;
 }
@@ -211,74 +253,6 @@
 }
 
 
-static int hostapd_set_ap_isolate(struct hostapd_data *hapd, int value)
-{
-	if (hapd->driver == NULL || hapd->driver->set_intra_bss == NULL)
-		return 0;
-	return hapd->driver->set_intra_bss(hapd->drv_priv, !value);
-}
-
-
-int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection)
-{
-	int ret = 0;
-	int preamble;
-#ifdef CONFIG_IEEE80211N
-	u8 buf[60], *ht_capab, *ht_oper, *pos;
-
-	pos = buf;
-	ht_capab = pos;
-	pos = hostapd_eid_ht_capabilities(hapd, pos);
-	ht_oper = pos;
-	pos = hostapd_eid_ht_operation(hapd, pos);
-	if (pos > ht_oper && ht_oper > ht_capab &&
-	    hostapd_set_ht_params(hapd, ht_capab + 2, ht_capab[1],
-				  ht_oper + 2, ht_oper[1])) {
-		wpa_printf(MSG_ERROR, "Could not set HT capabilities "
-			   "for kernel driver");
-		ret = -1;
-	}
-
-#endif /* CONFIG_IEEE80211N */
-
-	if (hostapd_set_cts_protect(hapd, use_protection)) {
-		wpa_printf(MSG_ERROR, "Failed to set CTS protect in kernel "
-			   "driver");
-		ret = -1;
-	}
-
-	if (hapd->iface->current_mode &&
-	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
-	    hostapd_set_short_slot_time(hapd,
-					hapd->iface->num_sta_no_short_slot_time
-					> 0 ? 0 : 1)) {
-		wpa_printf(MSG_ERROR, "Failed to set Short Slot Time option "
-			   "in kernel driver");
-		ret = -1;
-	}
-
-	if (hapd->iface->num_sta_no_short_preamble == 0 &&
-	    hapd->iconf->preamble == SHORT_PREAMBLE)
-		preamble = SHORT_PREAMBLE;
-	else
-		preamble = LONG_PREAMBLE;
-	if (hostapd_set_preamble(hapd, preamble)) {
-		wpa_printf(MSG_ERROR, "Could not set preamble for kernel "
-			   "driver");
-		ret = -1;
-	}
-
-	if (hostapd_set_ap_isolate(hapd, hapd->conf->isolate) &&
-	    hapd->conf->isolate) {
-		wpa_printf(MSG_ERROR, "Could not enable AP isolation in "
-			   "kernel driver");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-
 int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
 {
 	char force_ifname[IFNAMSIZ];
@@ -310,11 +284,41 @@
 }
 
 
+int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+			 u16 auth_alg)
+{
+	if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
+		return 0;
+	return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
+}
+
+
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+		     u16 seq, u16 status, const u8 *ie, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
+		return 0;
+	return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr,
+				      seq, status, ie, len);
+}
+
+
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+		      int reassoc, u16 status, const u8 *ie, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_assoc == NULL)
+		return 0;
+	return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr,
+				       reassoc, status, ie, len);
+}
+
+
 int hostapd_sta_add(struct hostapd_data *hapd,
 		    const u8 *addr, u16 aid, u16 capability,
 		    const u8 *supp_rates, size_t supp_rates_len,
 		    u16 listen_interval,
-		    const struct ieee80211_ht_capabilities *ht_capab)
+		    const struct ieee80211_ht_capabilities *ht_capab,
+		    u32 flags, u8 qosinfo)
 {
 	struct hostapd_sta_add_params params;
 
@@ -331,10 +335,22 @@
 	params.supp_rates_len = supp_rates_len;
 	params.listen_interval = listen_interval;
 	params.ht_capabilities = ht_capab;
+	params.flags = hostapd_sta_flags_to_drv(flags);
+	params.qosinfo = qosinfo;
 	return hapd->driver->sta_add(hapd->drv_priv, &params);
 }
 
 
+int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
+		      u8 *tspec_ie, size_t tspec_ielen)
+{
+	if (hapd->driver == NULL || hapd->driver->add_tspec == NULL)
+		return 0;
+	return hapd->driver->add_tspec(hapd->drv_priv, addr, tspec_ie,
+				       tspec_ielen);
+}
+
+
 int hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
 {
 	if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
@@ -460,16 +476,6 @@
 }
 
 
-int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
-			  int *basic_rates, int mode)
-{
-	if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
-		return 0;
-	return hapd->driver->set_rate_sets(hapd->drv_priv, supp_rates,
-					   basic_rates, mode);
-}
-
-
 int hostapd_set_country(struct hostapd_data *hapd, const char *country)
 {
 	if (hapd->driver == NULL ||
@@ -479,30 +485,6 @@
 }
 
 
-int hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
-{
-	if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
-		return 0;
-	return hapd->driver->set_cts_protect(hapd->drv_priv, value);
-}
-
-
-int hostapd_set_preamble(struct hostapd_data *hapd, int value)
-{
-	if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
-		return 0;
-	return hapd->driver->set_preamble(hapd->drv_priv, value);
-}
-
-
-int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
-{
-	if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
-		return 0;
-	return hapd->driver->set_short_slot_time(hapd->drv_priv, value);
-}
-
-
 int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
 				int cw_min, int cw_max, int burst_time)
 {
@@ -513,15 +495,6 @@
 }
 
 
-int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
-			   const u8 *mask)
-{
-	if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
-		return 1;
-	return hapd->driver->valid_bss_mask(hapd->drv_priv, addr, mask);
-}
-
-
 struct hostapd_hw_modes *
 hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
 			    u16 *flags)
@@ -542,19 +515,6 @@
 }
 
 
-int hostapd_set_ht_params(struct hostapd_data *hapd,
-			  const u8 *ht_capab, size_t ht_capab_len,
-			  const u8 *ht_oper, size_t ht_oper_len)
-{
-	if (hapd->driver == NULL || hapd->driver->set_ht_params == NULL ||
-	    ht_capab == NULL || ht_oper == NULL)
-		return 0;
-	return hapd->driver->set_ht_params(hapd->drv_priv,
-					   ht_capab, ht_capab_len,
-					   ht_oper, ht_oper_len);
-}
-
-
 int hostapd_drv_none(struct hostapd_data *hapd)
 {
 	return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
@@ -604,11 +564,11 @@
 
 
 int hostapd_drv_send_mlme(struct hostapd_data *hapd,
-			  const void *msg, size_t len)
+			  const void *msg, size_t len, int noack)
 {
 	if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
 		return 0;
-	return hapd->driver->send_mlme(hapd->drv_priv, msg, len);
+	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
 }
 
 
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index f6076af..835cdde 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -21,13 +21,19 @@
 struct ieee80211_ht_capabilities;
 
 u32 hostapd_sta_flags_to_drv(u32 flags);
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf **beacon,
+			       struct wpabuf **proberesp,
+			       struct wpabuf **assocresp);
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
+			       struct wpabuf *proberesp,
+			       struct wpabuf *assocresp);
 int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
 int hostapd_set_authorized(struct hostapd_data *hapd,
 			   struct sta_info *sta, int authorized);
 int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
 int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
 			      int enabled);
-int hostapd_set_bss_params(struct hostapd_data *hapd, int use_protection);
 int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
 int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
 int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
@@ -36,7 +42,8 @@
 		    const u8 *addr, u16 aid, u16 capability,
 		    const u8 *supp_rates, size_t supp_rates_len,
 		    u16 listen_interval,
-		    const struct ieee80211_ht_capabilities *ht_capab);
+		    const struct ieee80211_ht_capabilities *ht_capab,
+		    u32 flags, u8 qosinfo);
 int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
 int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
 			     size_t elem_len);
@@ -59,23 +66,13 @@
 int hostapd_set_frag(struct hostapd_data *hapd, int frag);
 int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
 			  int total_flags, int flags_or, int flags_and);
-int hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
-			  int *basic_rates, int mode);
 int hostapd_set_country(struct hostapd_data *hapd, const char *country);
-int hostapd_set_cts_protect(struct hostapd_data *hapd, int value);
-int hostapd_set_preamble(struct hostapd_data *hapd, int value);
-int hostapd_set_short_slot_time(struct hostapd_data *hapd, int value);
 int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
 				int cw_min, int cw_max, int burst_time);
-int hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
-			   const u8 *mask);
 struct hostapd_hw_modes *
 hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
 			    u16 *flags);
 int hostapd_driver_commit(struct hostapd_data *hapd);
-int hostapd_set_ht_params(struct hostapd_data *hapd,
-			  const u8 *ht_capab, size_t ht_capab_len,
-			  const u8 *ht_oper, size_t ht_oper_len);
 int hostapd_drv_none(struct hostapd_data *hapd);
 int hostapd_driver_scan(struct hostapd_data *hapd,
 			struct wpa_driver_scan_params *params);
@@ -90,11 +87,19 @@
 			const u8 *seq, size_t seq_len,
 			const u8 *key, size_t key_len);
 int hostapd_drv_send_mlme(struct hostapd_data *hapd,
-			  const void *msg, size_t len);
+			  const void *msg, size_t len, int noack);
 int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
 			   const u8 *addr, int reason);
 int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
 			     const u8 *addr, int reason);
+int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+			 u16 auth_alg);
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+		     u16 seq, u16 status, const u8 *ie, size_t len);
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+		      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);
 
 
 #include "drivers/driver.h"
@@ -163,16 +168,12 @@
 	return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
 }
 
-static inline int hostapd_drv_set_beacon(struct hostapd_data *hapd,
-					 const u8 *head, size_t head_len,
-					 const u8 *tail, size_t tail_len,
-					 int dtim_period, int beacon_int)
+static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
+				     struct wpa_driver_ap_params *params)
 {
-	if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
+	if (hapd->driver == NULL || hapd->driver->set_ap == NULL)
 		return 0;
-	return hapd->driver->set_beacon(hapd->drv_priv,
-					head, head_len, tail, tail_len,
-					dtim_period, beacon_int);
+	return hapd->driver->set_ap(hapd->drv_priv, params);
 }
 
 static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd,
@@ -202,4 +203,13 @@
 	return hapd->driver->set_authmode(hapd->drv_priv, auth_algs);
 }
 
+static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
+					   const u8 *own_addr, const u8 *addr,
+					   int qos)
+{
+	if (hapd->driver == NULL || hapd->driver->poll_client == NULL)
+		return;
+	hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
+}
+
 #endif /* AP_DRV_OPS */
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index 7c87fde..6f56c95 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -60,7 +60,7 @@
 				       struct eap_user *user)
 {
 	const struct hostapd_eap_user *eap_user;
-	int i, count;
+	int i;
 
 	eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
 	if (eap_user == NULL)
@@ -70,10 +70,7 @@
 		return 0;
 
 	os_memset(user, 0, sizeof(*user));
-	count = EAP_USER_MAX_METHODS;
-	if (count > EAP_MAX_METHODS)
-		count = EAP_MAX_METHODS;
-	for (i = 0; i < count; i++) {
+	for (i = 0; i < EAP_MAX_METHODS; i++) {
 		user->methods[i].vendor = eap_user->methods[i].vendor;
 		user->methods[i].method = eap_user->methods[i].method;
 	}
@@ -120,6 +117,9 @@
 	srv.eap_req_id_text = conf->eap_req_id_text;
 	srv.eap_req_id_text_len = conf->eap_req_id_text_len;
 	srv.pwd_group = conf->pwd_group;
+#ifdef CONFIG_RADIUS_TEST
+	srv.dump_msk_file = conf->dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 
 	hapd->radius_srv = radius_server_init(&srv);
 	if (hapd->radius_srv == NULL) {
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 0091064..4d8b277 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -35,6 +35,8 @@
 #include "beacon.h"
 
 
+#ifdef NEED_AP_MLME
+
 static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
 {
 	u8 erp = 0;
@@ -43,23 +45,11 @@
 	    hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
 		return 0;
 
-	switch (hapd->iconf->cts_protection_type) {
-	case CTS_PROTECTION_FORCE_ENABLED:
-		erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
-		break;
-	case CTS_PROTECTION_FORCE_DISABLED:
-		erp = 0;
-		break;
-	case CTS_PROTECTION_AUTOMATIC:
-		if (hapd->iface->olbc)
-			erp |= ERP_INFO_USE_PROTECTION;
-		/* continue */
-	case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
-		if (hapd->iface->num_sta_non_erp > 0) {
-			erp |= ERP_INFO_NON_ERP_PRESENT |
-				ERP_INFO_USE_PROTECTION;
-		}
-		break;
+	if (hapd->iface->olbc)
+		erp |= ERP_INFO_USE_PROTECTION;
+	if (hapd->iface->num_sta_non_erp > 0) {
+		erp |= ERP_INFO_NON_ERP_PRESENT |
+			ERP_INFO_USE_PROTECTION;
 	}
 	if (hapd->iface->num_sta_no_short_preamble > 0 ||
 	    hapd->iconf->preamble == LONG_PREAMBLE)
@@ -182,8 +172,7 @@
 }
 
 
-static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
-			    struct sta_info *sta)
+static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
 {
 	const u8 *ie;
 	size_t ielen;
@@ -197,30 +186,134 @@
 }
 
 
+static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+				   struct sta_info *sta,
+				   const struct ieee80211_mgmt *req,
+				   int is_p2p, size_t *resp_len)
+{
+	struct ieee80211_mgmt *resp;
+	u8 *pos, *epos;
+	size_t buflen;
+
+#define MAX_PROBERESP_LEN 768
+	buflen = MAX_PROBERESP_LEN;
+#ifdef CONFIG_WPS
+	if (hapd->wps_probe_resp_ie)
+		buflen += wpabuf_len(hapd->wps_probe_resp_ie);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	if (hapd->p2p_probe_resp_ie)
+		buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
+#endif /* CONFIG_P2P */
+	resp = os_zalloc(buflen);
+	if (resp == NULL)
+		return NULL;
+
+	epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
+
+	resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_PROBE_RESP);
+	if (req)
+		os_memcpy(resp->da, req->sa, ETH_ALEN);
+	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+
+	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+	resp->u.probe_resp.beacon_int =
+		host_to_le16(hapd->iconf->beacon_int);
+
+	/* hardware or low-level driver will setup seq_ctrl and timestamp */
+	resp->u.probe_resp.capab_info =
+		host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
+
+	pos = resp->u.probe_resp.variable;
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = hapd->conf->ssid.ssid_len;
+	os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len);
+	pos += hapd->conf->ssid.ssid_len;
+
+	/* Supported rates */
+	pos = hostapd_eid_supp_rates(hapd, pos);
+
+	/* DS Params */
+	pos = hostapd_eid_ds_params(hapd, pos);
+
+	pos = hostapd_eid_country(hapd, pos, epos - pos);
+
+	/* ERP Information element */
+	pos = hostapd_eid_erp_info(hapd, pos);
+
+	/* Extended supported rates */
+	pos = hostapd_eid_ext_supp_rates(hapd, pos);
+
+	/* RSN, MDIE, WPA */
+	pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+
+#ifdef CONFIG_IEEE80211N
+	pos = hostapd_eid_ht_capabilities(hapd, pos);
+	pos = hostapd_eid_ht_operation(hapd, pos);
+#endif /* CONFIG_IEEE80211N */
+
+	pos = hostapd_eid_ext_capab(hapd, pos);
+
+	pos = hostapd_eid_time_adv(hapd, pos);
+	pos = hostapd_eid_time_zone(hapd, pos);
+
+	pos = hostapd_eid_interworking(hapd, pos);
+	pos = hostapd_eid_adv_proto(hapd, pos);
+	pos = hostapd_eid_roaming_consortium(hapd, pos);
+
+	/* Wi-Fi Alliance WMM */
+	pos = hostapd_eid_wmm(hapd, pos);
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
+		os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
+			  wpabuf_len(hapd->wps_probe_resp_ie));
+		pos += wpabuf_len(hapd->wps_probe_resp_ie);
+	}
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p &&
+	    hapd->p2p_probe_resp_ie) {
+		os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
+			  wpabuf_len(hapd->p2p_probe_resp_ie));
+		pos += wpabuf_len(hapd->p2p_probe_resp_ie);
+	}
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_P2P_MANAGER
+	if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
+	    P2P_MANAGE)
+		pos = hostapd_eid_p2p_manage(hapd, pos);
+#endif /* CONFIG_P2P_MANAGER */
+
+	*resp_len = pos - (u8 *) resp;
+	return (u8 *) resp;
+}
+
+
 void handle_probe_req(struct hostapd_data *hapd,
 		      const struct ieee80211_mgmt *mgmt, size_t len)
 {
-	struct ieee80211_mgmt *resp;
+	u8 *resp;
 	struct ieee802_11_elems elems;
-	char *ssid;
-	u8 *pos, *epos;
 	const u8 *ie;
-	size_t ssid_len, ie_len;
+	size_t ie_len;
 	struct sta_info *sta = NULL;
-	size_t buflen;
-	size_t i;
+	size_t i, resp_len;
+	int noack;
 
 	ie = mgmt->u.probe_req.variable;
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
 		return;
 	ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
 
-#ifndef ANDROID_BRCM_P2P_PATCH
 	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
 		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
-					    mgmt->sa, ie, ie_len) > 0)
+					    mgmt->sa, mgmt->da, mgmt->bssid,
+					    ie, ie_len) > 0)
 			return;
-#endif
+
 	if (!hapd->iconf->send_probe_response)
 		return;
 
@@ -230,9 +323,6 @@
 		return;
 	}
 
-	ssid = NULL;
-	ssid_len = 0;
-
 	if ((!elems.ssid || !elems.supp_rates)) {
 		wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
 			   "without SSID or supported rates element",
@@ -277,13 +367,9 @@
 	    (elems.ssid_len == hapd->conf->ssid.ssid_len &&
 	     os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) ==
 	     0)) {
-		ssid = hapd->conf->ssid.ssid;
-		ssid_len = hapd->conf->ssid.ssid_len;
 		if (sta)
 			sta->ssid_probe = &hapd->conf->ssid;
-	}
-
-	if (!ssid) {
+	} else {
 		if (!(mgmt->da[0] & 0x01)) {
 			char ssid_txt[33];
 			ieee802_11_print_ssid(ssid_txt, elems.ssid,
@@ -296,92 +382,51 @@
 		return;
 	}
 
+#ifdef CONFIG_INTERWORKING
+	if (elems.interworking && elems.interworking_len >= 1) {
+		u8 ant = elems.interworking[0] & 0x0f;
+		if (ant != INTERWORKING_ANT_WILDCARD &&
+		    ant != hapd->conf->access_network_type) {
+			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+				   " for mismatching ANT %u ignored",
+				   MAC2STR(mgmt->sa), ant);
+			return;
+		}
+	}
+
+	if (elems.interworking &&
+	    (elems.interworking_len == 7 || elems.interworking_len == 9)) {
+		const u8 *hessid;
+		if (elems.interworking_len == 7)
+			hessid = elems.interworking + 1;
+		else
+			hessid = elems.interworking + 1 + 2;
+		if (!is_broadcast_ether_addr(hessid) &&
+		    os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) {
+			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+				   " for mismatching HESSID " MACSTR
+				   " ignored",
+				   MAC2STR(mgmt->sa), MAC2STR(hessid));
+			return;
+		}
+	}
+#endif /* CONFIG_INTERWORKING */
+
 	/* TODO: verify that supp_rates contains at least one matching rate
 	 * with AP configuration */
-#define MAX_PROBERESP_LEN 768
-	buflen = MAX_PROBERESP_LEN;
-#ifdef CONFIG_WPS
-	if (hapd->wps_probe_resp_ie)
-		buflen += wpabuf_len(hapd->wps_probe_resp_ie);
-#endif /* CONFIG_WPS */
-#ifdef CONFIG_P2P
-	if (hapd->p2p_probe_resp_ie)
-		buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
-#endif /* CONFIG_P2P */
-	resp = os_zalloc(buflen);
+
+	resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
+				      &resp_len);
 	if (resp == NULL)
 		return;
-	epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
 
-	resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_PROBE_RESP);
-	os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
-	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+	/*
+	 * If this is a broadcast probe request, apply no ack policy to avoid
+	 * excessive retries.
+	 */
+	noack = !!(elems.ssid_len == 0 && is_broadcast_ether_addr(mgmt->da));
 
-	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
-	resp->u.probe_resp.beacon_int =
-		host_to_le16(hapd->iconf->beacon_int);
-
-	/* hardware or low-level driver will setup seq_ctrl and timestamp */
-	resp->u.probe_resp.capab_info =
-		host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
-
-	pos = resp->u.probe_resp.variable;
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = ssid_len;
-	os_memcpy(pos, ssid, ssid_len);
-	pos += ssid_len;
-
-	/* Supported rates */
-	pos = hostapd_eid_supp_rates(hapd, pos);
-
-	/* DS Params */
-	pos = hostapd_eid_ds_params(hapd, pos);
-
-	pos = hostapd_eid_country(hapd, pos, epos - pos);
-
-	/* ERP Information element */
-	pos = hostapd_eid_erp_info(hapd, pos);
-
-	/* Extended supported rates */
-	pos = hostapd_eid_ext_supp_rates(hapd, pos);
-
-	/* RSN, MDIE, WPA */
-	pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
-
-#ifdef CONFIG_IEEE80211N
-	pos = hostapd_eid_ht_capabilities(hapd, pos);
-	pos = hostapd_eid_ht_operation(hapd, pos);
-#endif /* CONFIG_IEEE80211N */
-
-	pos = hostapd_eid_ext_capab(hapd, pos);
-
-	/* Wi-Fi Alliance WMM */
-	pos = hostapd_eid_wmm(hapd, pos);
-
-#ifdef CONFIG_WPS
-	if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
-		os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
-			  wpabuf_len(hapd->wps_probe_resp_ie));
-		pos += wpabuf_len(hapd->wps_probe_resp_ie);
-	}
-#endif /* CONFIG_WPS */
-
-#ifdef CONFIG_P2P
-	if ((hapd->conf->p2p & P2P_ENABLED) && elems.p2p &&
-	    hapd->p2p_probe_resp_ie) {
-		os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
-			  wpabuf_len(hapd->p2p_probe_resp_ie));
-		pos += wpabuf_len(hapd->p2p_probe_resp_ie);
-	}
-#endif /* CONFIG_P2P */
-#ifdef CONFIG_P2P_MANAGER
-	if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
-	    P2P_MANAGE)
-		pos = hostapd_eid_p2p_manage(hapd, pos);
-#endif /* CONFIG_P2P_MANAGER */
-
-	if (hostapd_drv_send_mlme(hapd, resp, pos - (u8 *) resp) < 0)
+	if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
 		perror("handle_probe_req: send");
 
 	os_free(resp);
@@ -392,17 +437,61 @@
 }
 
 
-void ieee802_11_set_beacon(struct hostapd_data *hapd)
+static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
+					size_t *resp_len)
 {
-	struct ieee80211_mgmt *head;
-	u8 *pos, *tail, *tailpos;
-	u16 capab_info;
-	size_t head_len, tail_len;
+	/* check probe response offloading caps and print warnings */
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD))
+		return NULL;
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_probe_resp_ie &&
+	    (!(hapd->iface->probe_resp_offloads &
+	       (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS |
+		WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2))))
+		wpa_printf(MSG_WARNING, "Device is trying to offload WPS "
+			   "Probe Response while not supporting this");
+#endif /* CONFIG_WPS */
 
 #ifdef CONFIG_P2P
-	if ((hapd->conf->p2p & (P2P_ENABLED | P2P_GROUP_OWNER)) == P2P_ENABLED)
-		goto no_beacon;
-#endif /* CONFIG_P2P */
+	if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie &&
+	    !(hapd->iface->probe_resp_offloads &
+	      WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P))
+		wpa_printf(MSG_WARNING, "Device is trying to offload P2P "
+			   "Probe Response while not supporting this");
+#endif  /* CONFIG_P2P */
+
+	if (hapd->conf->interworking &&
+	    !(hapd->iface->probe_resp_offloads &
+	      WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING))
+		wpa_printf(MSG_WARNING, "Device is trying to offload "
+			   "Interworking Probe Response while not supporting "
+			   "this");
+
+	/* Generate a Probe Response template for the non-P2P case */
+	return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len);
+}
+
+#endif /* NEED_AP_MLME */
+
+
+void ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+	struct ieee80211_mgmt *head = NULL;
+	u8 *tail = NULL;
+	size_t head_len = 0, tail_len = 0;
+	u8 *resp = NULL;
+	size_t resp_len = 0;
+	struct wpa_driver_ap_params params;
+	struct wpabuf *beacon, *proberesp, *assocresp;
+#ifdef NEED_AP_MLME
+	u16 capab_info;
+	u8 *pos, *tailpos;
+#endif /* NEED_AP_MLME */
+
+	hapd->beacon_set_done = 1;
+
+#ifdef NEED_AP_MLME
 
 #define BEACON_HEAD_BUF_SIZE 256
 #define BEACON_TAIL_BUF_SIZE 512
@@ -474,7 +563,7 @@
 
 	/* RSN, MDIE, WPA */
 	tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
-				  tailpos, NULL);
+				  tailpos);
 
 #ifdef CONFIG_IEEE80211N
 	tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
@@ -483,6 +572,16 @@
 
 	tailpos = hostapd_eid_ext_capab(hapd, tailpos);
 
+	/*
+	 * TODO: Time Advertisement element should only be included in some
+	 * DTIM Beacon frames.
+	 */
+	tailpos = hostapd_eid_time_adv(hapd, tailpos);
+
+	tailpos = hostapd_eid_interworking(hapd, tailpos);
+	tailpos = hostapd_eid_adv_proto(hapd, tailpos);
+	tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
+
 	/* Wi-Fi Alliance WMM */
 	tailpos = hostapd_eid_wmm(hapd, tailpos);
 
@@ -509,20 +608,75 @@
 
 	tail_len = tailpos > tail ? tailpos - tail : 0;
 
-	if (hostapd_drv_set_beacon(hapd, (u8 *) head, head_len,
-				   tail, tail_len, hapd->conf->dtim_period,
-				   hapd->iconf->beacon_int))
-		wpa_printf(MSG_ERROR, "Failed to set beacon head/tail or DTIM "
-			   "period");
+	resp = hostapd_probe_resp_offloads(hapd, &resp_len);
+#endif /* NEED_AP_MLME */
+
+	os_memset(&params, 0, sizeof(params));
+	params.head = (u8 *) head;
+	params.head_len = head_len;
+	params.tail = tail;
+	params.tail_len = tail_len;
+	params.proberesp = resp;
+	params.proberesp_len = resp_len;
+	params.dtim_period = hapd->conf->dtim_period;
+	params.beacon_int = hapd->iconf->beacon_int;
+	params.basic_rates = hapd->iconf->basic_rates;
+	params.ssid = (u8 *) hapd->conf->ssid.ssid;
+	params.ssid_len = hapd->conf->ssid.ssid_len;
+	params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
+		hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
+	params.group_cipher = hapd->conf->wpa_group;
+	params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
+	params.auth_algs = hapd->conf->auth_algs;
+	params.wpa_version = hapd->conf->wpa;
+	params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+		(hapd->conf->ieee802_1x &&
+		 (hapd->conf->default_wep_key_len ||
+		  hapd->conf->individual_wep_key_len));
+	switch (hapd->conf->ignore_broadcast_ssid) {
+	case 0:
+		params.hide_ssid = NO_SSID_HIDING;
+		break;
+	case 1:
+		params.hide_ssid = HIDDEN_SSID_ZERO_LEN;
+		break;
+	case 2:
+		params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
+		break;
+	}
+	hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
+	params.beacon_ies = beacon;
+	params.proberesp_ies = proberesp;
+	params.assocresp_ies = assocresp;
+	params.isolate = hapd->conf->isolate;
+#ifdef NEED_AP_MLME
+	params.cts_protect = !!(ieee802_11_erp_info(hapd) &
+				ERP_INFO_USE_PROTECTION);
+	params.preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
+		hapd->iconf->preamble == SHORT_PREAMBLE;
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+		params.short_slot_time =
+			hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
+	else
+		params.short_slot_time = -1;
+	if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+		params.ht_opmode = -1;
+	else
+		params.ht_opmode = hapd->iface->ht_op_mode;
+#endif /* NEED_AP_MLME */
+	params.interworking = hapd->conf->interworking;
+	if (hapd->conf->interworking &&
+	    !is_zero_ether_addr(hapd->conf->hessid))
+		params.hessid = hapd->conf->hessid;
+	params.access_network_type = hapd->conf->access_network_type;
+	if (hostapd_drv_set_ap(hapd, &params))
+		wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
+	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
 
 	os_free(tail);
 	os_free(head);
-
-#ifdef CONFIG_P2P
-no_beacon:
-#endif /* CONFIG_P2P */
-	hostapd_set_bss_params(hapd, !!(ieee802_11_erp_info(hapd) &
-					ERP_INFO_USE_PROTECTION));
+	os_free(resp);
 }
 
 
diff --git a/src/ap/beacon.h b/src/ap/beacon.h
index c1510e1..a944f5f 100644
--- a/src/ap/beacon.h
+++ b/src/ap/beacon.h
@@ -20,17 +20,7 @@
 
 void handle_probe_req(struct hostapd_data *hapd,
 		      const struct ieee80211_mgmt *mgmt, size_t len);
-#ifdef NEED_AP_MLME
 void ieee802_11_set_beacon(struct hostapd_data *hapd);
 void ieee802_11_set_beacons(struct hostapd_iface *iface);
-#else /* NEED_AP_MLME */
-static inline void ieee802_11_set_beacon(struct hostapd_data *hapd)
-{
-}
-
-static inline void ieee802_11_set_beacons(struct hostapd_iface *iface)
-{
-}
-#endif /* NEED_AP_MLME */
 
 #endif /* BEACON_H */
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 10e3af9..b7febdc 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -19,7 +19,6 @@
 #include "drivers/driver.h"
 #include "common/ieee802_11_defs.h"
 #include "common/ieee802_11_common.h"
-#include "common/wpa_ctrl.h"
 #include "crypto/random.h"
 #include "p2p/p2p.h"
 #include "wps/wps.h"
@@ -28,25 +27,22 @@
 #include "sta_info.h"
 #include "accounting.h"
 #include "tkip_countermeasures.h"
-#include "iapp.h"
 #include "ieee802_1x.h"
 #include "wpa_auth.h"
-#include "wmm.h"
 #include "wps_hostapd.h"
 #include "ap_drv_ops.h"
 #include "ap_config.h"
 
 
 int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
-			const u8 *ie, size_t ielen, int reassoc)
+			const u8 *req_ies, size_t req_ies_len, int reassoc)
 {
 	struct sta_info *sta;
 	int new_assoc, res;
 	struct ieee802_11_elems elems;
-#ifdef CONFIG_P2P
-	const u8 *all_ies = ie;
-	size_t all_ies_len = ielen;
-#endif /* CONFIG_P2P */
+	const u8 *ie;
+	size_t ielen;
+	u16 reason = WLAN_REASON_UNSPECIFIED;
 
 	if (addr == NULL) {
 		/*
@@ -65,7 +61,7 @@
 	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO, "associated");
 
-	ieee802_11_parse_elems(ie, ielen, &elems, 0);
+	ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
 	if (elems.wps_ie) {
 		ie = elems.wps_ie - 2;
 		ielen = elems.wps_ie_len + 2;
@@ -93,18 +89,19 @@
 		if (sta == NULL)
 			return -1;
 	}
-	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
 
 #ifdef CONFIG_P2P
 	if (elems.p2p) {
 		wpabuf_free(sta->p2p_ie);
-		sta->p2p_ie = ieee802_11_vendor_ie_concat(all_ies, all_ies_len,
+		sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
 							  P2P_IE_VENDOR_TYPE);
 	}
 #endif /* CONFIG_P2P */
 
 	if (hapd->conf->wpa) {
 		if (ie == NULL || ielen == 0) {
+#ifdef CONFIG_WPS
 			if (hapd->conf->wps_state) {
 				wpa_printf(MSG_DEBUG, "STA did not include "
 					   "WPA/RSN IE in (Re)Association "
@@ -112,15 +109,29 @@
 				sta->flags |= WLAN_STA_MAYBE_WPS;
 				goto skip_wpa_check;
 			}
+#endif /* CONFIG_WPS */
 
 			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
 			return -1;
 		}
+#ifdef CONFIG_WPS
 		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
 		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+			struct wpabuf *wps;
 			sta->flags |= WLAN_STA_WPS;
+			wps = ieee802_11_vendor_ie_concat(ie, ielen,
+							  WPS_IE_VENDOR_TYPE);
+			if (wps) {
+				if (wps_is_20(wps)) {
+					wpa_printf(MSG_DEBUG, "WPS: STA "
+						   "supports WPS 2.0");
+					sta->flags |= WLAN_STA_WPS2;
+				}
+				wpabuf_free(wps);
+			}
 			goto skip_wpa_check;
 		}
+#endif /* CONFIG_WPS */
 
 		if (sta->wpa_sm == NULL)
 			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
@@ -133,52 +144,55 @@
 		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
 					  ie, ielen, NULL, 0);
 		if (res != WPA_IE_OK) {
-			int resp;
 			wpa_printf(MSG_DEBUG, "WPA/RSN information element "
 				   "rejected? (res %u)", res);
 			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
 			if (res == WPA_INVALID_GROUP)
-				resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
 			else if (res == WPA_INVALID_PAIRWISE)
-				resp = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+				reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
 			else if (res == WPA_INVALID_AKMP)
-				resp = WLAN_REASON_AKMP_NOT_VALID;
+				reason = WLAN_REASON_AKMP_NOT_VALID;
 #ifdef CONFIG_IEEE80211W
 			else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
-				resp = WLAN_REASON_INVALID_IE;
+				reason = WLAN_REASON_INVALID_IE;
 			else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
-				resp = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
 #endif /* CONFIG_IEEE80211W */
 			else
-				resp = WLAN_REASON_INVALID_IE;
-			hostapd_drv_sta_disassoc(hapd, sta->addr, resp);
-			ap_free_sta(hapd, sta);
-			return -1;
+				reason = WLAN_REASON_INVALID_IE;
+			goto fail;
 		}
 	} else if (hapd->conf->wps_state) {
-#ifdef CONFIG_WPS_STRICT
-		if (ie) {
-			struct wpabuf *wps;
-			wps = ieee802_11_vendor_ie_concat(ie, ielen,
+#ifdef CONFIG_WPS
+		struct wpabuf *wps;
+		if (req_ies)
+			wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
 							  WPS_IE_VENDOR_TYPE);
-			if (wps && wps_validate_assoc_req(wps) < 0) {
-				hostapd_drv_sta_disassoc(
-					hapd, sta->addr,
-					WLAN_REASON_INVALID_IE);
-				ap_free_sta(hapd, sta);
-				wpabuf_free(wps);
-				return -1;
-			}
+		else
+			wps = NULL;
+#ifdef CONFIG_WPS_STRICT
+		if (wps && wps_validate_assoc_req(wps) < 0) {
+			reason = WLAN_REASON_INVALID_IE;
 			wpabuf_free(wps);
+			goto fail;
 		}
 #endif /* CONFIG_WPS_STRICT */
-		if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
-		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+		if (wps) {
 			sta->flags |= WLAN_STA_WPS;
+			if (wps_is_20(wps)) {
+				wpa_printf(MSG_DEBUG, "WPS: STA supports "
+					   "WPS 2.0");
+				sta->flags |= WLAN_STA_WPS2;
+			}
 		} else
 			sta->flags |= WLAN_STA_MAYBE_WPS;
+		wpabuf_free(wps);
+#endif /* CONFIG_WPS */
 	}
+#ifdef CONFIG_WPS
 skip_wpa_check:
+#endif /* CONFIG_WPS */
 
 	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
 	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
@@ -189,11 +203,18 @@
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
 
 #ifdef CONFIG_P2P
-	p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
-			      all_ies, all_ies_len);
+	if (req_ies) {
+		p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
+				      req_ies, req_ies_len);
+	}
 #endif /* CONFIG_P2P */
 
 	return 0;
+
+fail:
+	hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
+	ap_free_sta(hapd, sta);
+	return -1;
 }
 
 
@@ -224,14 +245,8 @@
 		return;
 	}
 
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-		MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if(hapd->msg_ctx_parent)
-		wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-			MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
 	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
 	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
@@ -255,8 +270,8 @@
 }
 
 
-int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
-			 const u8 *ie, size_t ie_len)
+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)
 {
 	size_t i;
 	int ret = 0;
@@ -267,7 +282,7 @@
 	random_add_randomness(sa, ETH_ALEN);
 	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
 		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
-					    sa, ie, ie_len) > 0) {
+					    sa, da, bssid, ie, ie_len) > 0) {
 			ret = 1;
 			break;
 		}
@@ -280,46 +295,6 @@
 
 #ifdef NEED_AP_MLME
 
-static const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
-{
-	u16 fc, type, stype;
-
-	/*
-	 * PS-Poll frames are 16 bytes. All other frames are
-	 * 24 bytes or longer.
-	 */
-	if (len < 16)
-		return NULL;
-
-	fc = le_to_host16(hdr->frame_control);
-	type = WLAN_FC_GET_TYPE(fc);
-	stype = WLAN_FC_GET_STYPE(fc);
-
-	switch (type) {
-	case WLAN_FC_TYPE_DATA:
-		if (len < 24)
-			return NULL;
-		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
-		case WLAN_FC_FROMDS | WLAN_FC_TODS:
-		case WLAN_FC_TODS:
-			return hdr->addr1;
-		case WLAN_FC_FROMDS:
-			return hdr->addr2;
-		default:
-			return NULL;
-		}
-	case WLAN_FC_TYPE_CTRL:
-		if (stype != WLAN_FC_STYPE_PSPOLL)
-			return NULL;
-		return hdr->addr1;
-	case WLAN_FC_TYPE_MGMT:
-		return hdr->addr3;
-	default:
-		return NULL;
-	}
-}
-
-
 #define HAPD_BROADCAST ((struct hostapd_data *) -1)
 
 static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
@@ -343,17 +318,14 @@
 
 
 static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
-					const u8 *frame, size_t len)
+					const u8 *bssid, const u8 *addr,
+					int wds)
 {
-	const struct ieee80211_hdr *hdr = (const struct ieee80211_hdr *) frame;
-	u16 fc = le_to_host16(hdr->frame_control);
-	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
+	hapd = get_hapd_bssid(hapd->iface, bssid);
 	if (hapd == NULL || hapd == HAPD_BROADCAST)
 		return;
 
-	ieee802_11_rx_from_unknown(hapd, hdr->addr2,
-				   (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
-				   (WLAN_FC_TODS | WLAN_FC_FROMDS));
+	ieee802_11_rx_from_unknown(hapd, addr, wds);
 }
 
 
@@ -497,6 +469,23 @@
 			  union wpa_event_data *data)
 {
 	struct hostapd_data *hapd = ctx;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	int level = MSG_DEBUG;
+
+	if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
+	    data->rx_mgmt.frame_len >= 24) {
+		const struct ieee80211_hdr *hdr;
+		u16 fc;
+		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+		fc = le_to_host16(hdr->frame_control);
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+			level = MSG_EXCESSIVE;
+	}
+
+	wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
+		event_to_string(event), event);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
 
 	switch (event) {
 	case EVENT_MICHAEL_MIC_FAILURE:
@@ -532,9 +521,19 @@
 			break;
 		}
 		break;
+	case EVENT_EAPOL_TX_STATUS:
+		hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
+					data->eapol_tx_status.data,
+					data->eapol_tx_status.data_len,
+					data->eapol_tx_status.ack);
+		break;
+	case EVENT_DRIVER_CLIENT_POLL_OK:
+		hostapd_client_poll_ok(hapd, data->client_poll.addr);
+		break;
 	case EVENT_RX_FROM_UNKNOWN:
-		hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.frame,
-					    data->rx_from_unknown.len);
+		hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
+					    data->rx_from_unknown.addr,
+					    data->rx_from_unknown.wds);
 		break;
 	case EVENT_RX_MGMT:
 		hostapd_mgmt_rx(hapd, &data->rx_mgmt);
@@ -545,6 +544,8 @@
 		    data->rx_probe_req.ie == NULL)
 			break;
 		hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
+				     data->rx_probe_req.da,
+				     data->rx_probe_req.bssid,
 				     data->rx_probe_req.ie,
 				     data->rx_probe_req.ie_len);
 		break;
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index f00a544..0c5ee2e 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -61,9 +61,11 @@
 	else
 		hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
 
-	if (hapd->conf->wpa && hapd->wpa_auth == NULL)
+	if (hapd->conf->wpa && hapd->wpa_auth == NULL) {
 		hostapd_setup_wpa(hapd);
-	else if (hapd->conf->wpa) {
+		if (hapd->wpa_auth)
+			wpa_init_keys(hapd->wpa_auth);
+	} else if (hapd->conf->wpa) {
 		const u8 *wpa_ie;
 		size_t wpa_ie_len;
 		hostapd_reconfig_wpa(hapd);
@@ -259,6 +261,8 @@
 	wpabuf_free(hapd->p2p_probe_resp_ie);
 	hapd->p2p_probe_resp_ie = NULL;
 #endif /* CONFIG_P2P */
+
+	wpabuf_free(hapd->time_adv);
 }
 
 
@@ -287,6 +291,8 @@
 	iface->hw_features = NULL;
 	os_free(iface->current_rates);
 	iface->current_rates = NULL;
+	os_free(iface->basic_rates);
+	iface->basic_rates = NULL;
 	ap_list_deinit(iface);
 	hostapd_config_free(iface->conf);
 	iface->conf = NULL;
@@ -341,12 +347,13 @@
 	if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
 		return 0;
 
-	wpa_printf(MSG_DEBUG, "Flushing old station entries");
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries");
 	if (hostapd_flush(hapd)) {
-		wpa_printf(MSG_WARNING, "Could not connect to kernel driver.");
+		wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to "
+			"kernel driver");
 		ret = -1;
 	}
-	wpa_printf(MSG_DEBUG, "Deauthenticate all stations");
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
 	os_memset(addr, 0xff, ETH_ALEN);
 	hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
 	hostapd_free_stas(hapd);
@@ -367,7 +374,6 @@
 	u8 mask[ETH_ALEN] = { 0 };
 	struct hostapd_data *hapd = iface->bss[0];
 	unsigned int i = iface->conf->num_bss, bits = 0, j;
-	int res;
 	int auto_addr = 0;
 
 	if (hostapd_drv_none(hapd))
@@ -431,17 +437,6 @@
 	wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
 		   (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
 
-	res = hostapd_valid_bss_mask(hapd, hapd->own_addr, mask);
-	if (res == 0)
-		return 0;
-
-	if (res < 0) {
-		wpa_printf(MSG_ERROR, "Driver did not accept BSSID mask "
-			   MACSTR " for start address " MACSTR ".",
-			   MAC2STR(mask), MAC2STR(hapd->own_addr));
-		return -1;
-	}
-
 	if (!auto_addr)
 		return 0;
 
@@ -639,6 +634,9 @@
 
 	ieee802_11_set_beacon(hapd);
 
+	if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
+		return -1;
+
 	if (hapd->driver && hapd->driver->set_operstate)
 		hapd->driver->set_operstate(hapd->drv_priv, 1);
 
@@ -746,7 +744,7 @@
 	}
 
 	if (iface->current_mode) {
-		if (hostapd_prepare_rates(hapd, iface->current_mode)) {
+		if (hostapd_prepare_rates(iface, iface->current_mode)) {
 			wpa_printf(MSG_ERROR, "Failed to prepare rates "
 				   "table.");
 			hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 3764be4..c6f6205 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -31,7 +31,8 @@
 union wps_event_data;
 
 struct hostapd_probereq_cb {
-	int (*cb)(void *ctx, const u8 *sa, const u8 *ie, size_t ie_len);
+	int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
+		  const u8 *ie, size_t ie_len);
 	void *ctx;
 };
 
@@ -81,10 +82,7 @@
 				 struct sta_info *sta, int reassoc);
 
 	void *msg_ctx; /* ctx for wpa_msg() calls */
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/* Sending the event to parent is required as SSL listens on parent ctrl iface */
-	void *msg_ctx_parent; /* ctx for wpa_msg() calls */
-#endif /*ANDROID_BRCM_P2P_PATCH*/
+	void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */
 
 	struct radius_client_data *radius;
 	u32 acct_session_id_hi, acct_session_id_lo;
@@ -111,6 +109,10 @@
 
 	int parameter_set_count;
 
+	/* Time Advertisement */
+	u8 time_update_counter;
+	struct wpabuf *time_adv;
+
 #ifdef CONFIG_FULL_DYNAMIC_VLAN
 	struct full_dynamic_vlan *full_dynamic_vlan;
 #endif /* CONFIG_FULL_DYNAMIC_VLAN */
@@ -118,6 +120,7 @@
 	struct l2_packet_data *l2;
 	struct wps_context *wps;
 
+	int beacon_set_done;
 	struct wpabuf *wps_beacon_ie;
 	struct wpabuf *wps_probe_resp_ie;
 #ifdef CONFIG_WPS
@@ -146,7 +149,7 @@
 	void *wps_event_cb_ctx;
 
 	void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
-				  int authorized);
+				  int authorized, const u8 *p2p_dev_addr);
 	void *sta_authorized_cb_ctx;
 
 	void (*setup_complete_cb)(void *ctx);
@@ -189,6 +192,13 @@
 	struct ap_info *ap_iter_list;
 
 	unsigned int drv_flags;
+
+	/*
+	 * A bitmap of supported protocols for probe response offload. See
+	 * struct wpa_driver_capa in driver.h
+	 */
+	unsigned int probe_resp_offloads;
+
 	struct hostapd_hw_modes *hw_features;
 	int num_hw_features;
 	struct hostapd_hw_modes *current_mode;
@@ -196,6 +206,7 @@
 	 * current_mode->channels */
 	int num_rates;
 	struct hostapd_rate_data *current_rates;
+	int *basic_rates;
 	int freq;
 
 	u16 hw_flags;
@@ -251,6 +262,7 @@
 /* utils.c */
 int hostapd_register_probereq_cb(struct hostapd_data *hapd,
 				 int (*cb)(void *ctx, const u8 *sa,
+					   const u8 *da, const u8 *bssid,
 					   const u8 *ie, size_t ie_len),
 				 void *ctx);
 void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
@@ -260,7 +272,7 @@
 			const u8 *ie, size_t ielen, int reassoc);
 void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
 void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
-int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa,
-			 const u8 *ie, size_t ie_len);
+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);
 
 #endif /* HOSTAPD_H */
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 86f6811..8c6fef2 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -2,7 +2,7 @@
  * hostapd / Hardware feature query and different modes
  * Copyright 2002-2003, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
- * Copyright (c) 2008-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -101,7 +101,7 @@
 }
 
 
-int hostapd_prepare_rates(struct hostapd_data *hapd,
+int hostapd_prepare_rates(struct hostapd_iface *iface,
 			  struct hostapd_hw_modes *mode)
 {
 	int i, num_basic_rates = 0;
@@ -110,8 +110,8 @@
 	int basic_rates_g[] = { 10, 20, 55, 110, -1 };
 	int *basic_rates;
 
-	if (hapd->iconf->basic_rates)
-		basic_rates = hapd->iconf->basic_rates;
+	if (iface->conf->basic_rates)
+		basic_rates = iface->conf->basic_rates;
 	else switch (mode->mode) {
 	case HOSTAPD_MODE_IEEE80211A:
 		basic_rates = basic_rates_a;
@@ -126,18 +126,20 @@
 		return -1;
 	}
 
-	if (hostapd_set_rate_sets(hapd, hapd->iconf->supported_rates,
-				  basic_rates, mode->mode)) {
-		wpa_printf(MSG_ERROR, "Failed to update rate sets in kernel "
-			   "module");
-	}
+	i = 0;
+	while (basic_rates[i] >= 0)
+		i++;
+	os_free(iface->basic_rates);
+	iface->basic_rates = os_malloc(i * sizeof(int));
+	if (iface->basic_rates)
+		os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int));
 
-	os_free(hapd->iface->current_rates);
-	hapd->iface->num_rates = 0;
+	os_free(iface->current_rates);
+	iface->num_rates = 0;
 
-	hapd->iface->current_rates =
+	iface->current_rates =
 		os_zalloc(mode->num_rates * sizeof(struct hostapd_rate_data));
-	if (!hapd->iface->current_rates) {
+	if (!iface->current_rates) {
 		wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
 			   "table.");
 		return -1;
@@ -146,27 +148,27 @@
 	for (i = 0; i < mode->num_rates; i++) {
 		struct hostapd_rate_data *rate;
 
-		if (hapd->iconf->supported_rates &&
-		    !hostapd_rate_found(hapd->iconf->supported_rates,
+		if (iface->conf->supported_rates &&
+		    !hostapd_rate_found(iface->conf->supported_rates,
 					mode->rates[i]))
 			continue;
 
-		rate = &hapd->iface->current_rates[hapd->iface->num_rates];
+		rate = &iface->current_rates[iface->num_rates];
 		rate->rate = mode->rates[i];
 		if (hostapd_rate_found(basic_rates, rate->rate)) {
 			rate->flags |= HOSTAPD_RATE_BASIC;
 			num_basic_rates++;
 		}
 		wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
-			   hapd->iface->num_rates, rate->rate, rate->flags);
-		hapd->iface->num_rates++;
+			   iface->num_rates, rate->rate, rate->flags);
+		iface->num_rates++;
 	}
 
-	if ((hapd->iface->num_rates == 0 || num_basic_rates == 0) &&
-	    (!hapd->iconf->ieee80211n || !hapd->iconf->require_ht)) {
+	if ((iface->num_rates == 0 || num_basic_rates == 0) &&
+	    (!iface->conf->ieee80211n || !iface->conf->require_ht)) {
 		wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
 			   "rate sets (%d,%d).",
-			   hapd->iface->num_rates, num_basic_rates);
+			   iface->num_rates, num_basic_rates);
 		return -1;
 	}
 
@@ -407,20 +409,6 @@
 }
 
 
-static void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-	size_t i;
-
-	if (res == NULL)
-		return;
-
-	for (i = 0; i < res->num; i++)
-		os_free(res->res[i]);
-	os_free(res->res);
-	os_free(res);
-}
-
-
 static void ieee80211n_check_scan(struct hostapd_iface *iface)
 {
 	struct wpa_scan_results *scan_res;
@@ -630,7 +618,8 @@
 		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_WARNING,
 			       "Hardware does not support configured mode "
-			       "(%d)", (int) iface->conf->hw_mode);
+			       "(%d) (hw_mode in hostapd.conf)",
+			       (int) iface->conf->hw_mode);
 		return -2;
 	}
 
@@ -642,8 +631,15 @@
 			if (chan->flag & HOSTAPD_CHAN_DISABLED) {
 				wpa_printf(MSG_ERROR,
 					   "channel [%i] (%i) is disabled for "
-					   "use in AP mode, flags: 0x%x",
-					   j, chan->chan, chan->flag);
+					   "use in AP mode, flags: 0x%x%s%s%s",
+					   j, chan->chan, chan->flag,
+					   chan->flag & HOSTAPD_CHAN_NO_IBSS ?
+					   " NO-IBSS" : "",
+					   chan->flag &
+					   HOSTAPD_CHAN_PASSIVE_SCAN ?
+					   " PASSIVE-SCAN" : "",
+					   chan->flag & HOSTAPD_CHAN_RADAR ?
+					   " RADAR" : "");
 			} else {
 				ok = 1;
 				break;
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index b84bca6..abadcd1 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -2,6 +2,7 @@
  * hostapd / Hardware feature query and different modes
  * Copyright 2002-2003, Instant802 Networks, Inc.
  * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -25,7 +26,7 @@
 int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
 int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
 int hostapd_check_ht_capab(struct hostapd_iface *iface);
-int hostapd_prepare_rates(struct hostapd_data *hapd,
+int hostapd_prepare_rates(struct hostapd_iface *iface,
 			  struct hostapd_hw_modes *mode);
 #else /* NEED_AP_MLME */
 static inline void
@@ -59,7 +60,7 @@
 	return 0;
 }
 
-static inline int hostapd_prepare_rates(struct hostapd_data *hapd,
+static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
 					struct hostapd_hw_modes *mode)
 {
 	return 0;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index e0a3a36..a1a7270 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-2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -163,59 +163,6 @@
 }
 
 
-u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
-{
-	u8 *pos = eid;
-
-	if ((hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH)) ==
-	    0)
-		return eid;
-
-	*pos++ = WLAN_EID_EXT_CAPAB;
-	*pos++ = 5;
-	*pos++ = 0x00;
-	*pos++ = 0x00;
-	*pos++ = 0x00;
-	*pos++ = 0x00;
-	*pos = 0x00;
-	if (hapd->conf->tdls & TDLS_PROHIBIT)
-		*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
-	if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
-		*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
-	pos++;
-
-	return pos;
-}
-
-
-#ifdef CONFIG_IEEE80211W
-static u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
-					    struct sta_info *sta, u8 *eid)
-{
-	u8 *pos = eid;
-	u32 timeout, tu;
-	struct os_time now, passed;
-
-	*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
-	*pos++ = 5;
-	*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
-	os_get_time(&now);
-	os_time_sub(&now, &sta->sa_query_start, &passed);
-	tu = (passed.sec * 1000000 + passed.usec) / 1024;
-	if (hapd->conf->assoc_sa_query_max_timeout > tu)
-		timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
-	else
-		timeout = 0;
-	if (timeout < hapd->conf->assoc_sa_query_max_timeout)
-		timeout++; /* add some extra time for local timers */
-	WPA_PUT_LE32(pos, timeout);
-	pos += 4;
-
-	return pos;
-}
-#endif /* CONFIG_IEEE80211W */
-
-
 void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
 {
 	int i;
@@ -322,7 +269,7 @@
 		   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
 		   MAC2STR(dst), auth_alg, auth_transaction,
 		   resp, (unsigned long) ies_len);
-	if (hostapd_drv_send_mlme(hapd, reply, rlen) < 0)
+	if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
 		perror("send_auth_reply: send");
 
 	os_free(buf);
@@ -366,6 +313,8 @@
 	const u8 *challenge = NULL;
 	u32 session_timeout, acct_interim_interval;
 	int vlan_id = 0;
+	u8 psk[PMK_LEN];
+	int has_psk = 0;
 	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
 	size_t resp_ies_len = 0;
 
@@ -400,9 +349,7 @@
 	if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
 	       auth_alg == WLAN_AUTH_OPEN) ||
 #ifdef CONFIG_IEEE80211R
-	      (hapd->conf->wpa &&
-	       (hapd->conf->wpa_key_mgmt &
-		(WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) &&
+	      (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
 	       auth_alg == WLAN_AUTH_FT) ||
 #endif /* CONFIG_IEEE80211R */
 	      ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
@@ -430,7 +377,9 @@
 
 	res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
 				      &session_timeout,
-				      &acct_interim_interval, &vlan_id);
+				      &acct_interim_interval, &vlan_id,
+				      psk, &has_psk);
+
 	if (res == HOSTAPD_ACL_REJECT) {
 		printf("Station " MACSTR " not allowed to authenticate.\n",
 		       MAC2STR(mgmt->sa));
@@ -468,6 +417,16 @@
 			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
 	}
 
+	if (has_psk && hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+		os_free(sta->psk);
+		sta->psk = os_malloc(PMK_LEN);
+		if (sta->psk)
+			os_memcpy(sta->psk, psk, PMK_LEN);
+	} else {
+		os_free(sta->psk);
+		sta->psk = NULL;
+	}
+
 	sta->flags &= ~WLAN_STA_PREAUTH;
 	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
 
@@ -592,15 +551,22 @@
 		     const u8 *wmm_ie, size_t wmm_ie_len)
 {
 	sta->flags &= ~WLAN_STA_WMM;
+	sta->qosinfo = 0;
 	if (wmm_ie && hapd->conf->wmm_enabled) {
-		if (hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len))
+		struct wmm_information_element *wmm;
+
+		if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
 			hostapd_logger(hapd, sta->addr,
 				       HOSTAPD_MODULE_WPA,
 				       HOSTAPD_LEVEL_DEBUG,
 				       "invalid WMM element in association "
 				       "request");
-		else
-			sta->flags |= WLAN_STA_WMM;
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+
+		sta->flags |= WLAN_STA_WMM;
+		wmm = (struct wmm_information_element *) wmm_ie;
+		sta->qosinfo = wmm->qos_info;
 	}
 	return WLAN_STATUS_SUCCESS;
 }
@@ -701,7 +667,7 @@
 	}
 
 #ifdef CONFIG_WPS
-	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
 	if (hapd->conf->wps_state && elems.wps_ie) {
 		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
 			   "Request - assume WPS is used");
@@ -709,6 +675,10 @@
 		wpabuf_free(sta->wps_ie);
 		sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
 							  WPS_IE_VENDOR_TYPE);
+		if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
+			wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
+			sta->flags |= WLAN_STA_WPS2;
+		}
 		wpa_ie = NULL;
 		wpa_ie_len = 0;
 		if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
@@ -854,7 +824,7 @@
 	send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
 	reply.u.deauth.reason_code = host_to_le16(reason_code);
 
-	if (hostapd_drv_send_mlme(hapd, &reply, send_len) < 0)
+	if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
 		wpa_printf(MSG_INFO, "Failed to send deauth: %s",
 			   strerror(errno));
 }
@@ -917,7 +887,8 @@
 		p = hostapd_eid_wmm(hapd, p);
 
 #ifdef CONFIG_WPS
-	if (sta->flags & WLAN_STA_WPS) {
+	if ((sta->flags & WLAN_STA_WPS) ||
+	    ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) {
 		struct wpabuf *wps = wps_build_assoc_resp_ie();
 		if (wps) {
 			os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
@@ -959,7 +930,7 @@
 
 	send_len += p - reply->u.assoc_resp.variable;
 
-	if (hostapd_drv_send_mlme(hapd, reply, send_len) < 0)
+	if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
 		wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
 			   strerror(errno));
 }
@@ -1160,15 +1131,8 @@
 		return;
 	}
 
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
-	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-		MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if(hapd->msg_ctx_parent)
-		wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-			MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
-
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_INFO, "disassociated");
@@ -1199,32 +1163,26 @@
 	struct sta_info *sta;
 
 	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
-		wpa_msg(hapd, MSG_DEBUG, "handle_deauth - too short payload "
-			"(len=%lu)", (unsigned long) len);
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
+			"payload (len=%lu)", (unsigned long) len);
 		return;
 	}
 
-	wpa_msg(hapd, MSG_DEBUG, "deauthentication: STA=" MACSTR
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
 		" reason_code=%d",
 		MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
 
 	sta = ap_get_sta(hapd, mgmt->sa);
 	if (sta == NULL) {
-		wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " trying to "
-			"deauthenticate, but it is not authenticated",
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
+			"to deauthenticate, but it is not authenticated",
 			MAC2STR(mgmt->sa));
 		return;
 	}
 
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
 			WLAN_STA_ASSOC_REQ_OK);
-	wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-		MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if(hapd->msg_ctx_parent)
-		wpa_msg(hapd->msg_ctx_parent, MSG_INFO, AP_STA_DISCONNECTED MACSTR,
-			MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
 	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
 	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 		       HOSTAPD_LEVEL_DEBUG, "deauthenticated");
@@ -1259,81 +1217,11 @@
 
 #ifdef CONFIG_IEEE80211W
 
-/* MLME-SAQuery.request */
-void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
-				  const u8 *addr, const u8 *trans_id)
-{
-	struct ieee80211_mgmt mgmt;
-	u8 *end;
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
-		   MACSTR, MAC2STR(addr));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
-
-	os_memset(&mgmt, 0, sizeof(mgmt));
-	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_ACTION);
-	os_memcpy(mgmt.da, addr, ETH_ALEN);
-	os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
-	mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
-	mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
-	os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
-		  WLAN_SA_QUERY_TR_ID_LEN);
-	end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
-	if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt) < 0)
-		perror("ieee802_11_send_sa_query_req: send");
-}
-
-
-static void hostapd_sa_query_request(struct hostapd_data *hapd,
-				     const struct ieee80211_mgmt *mgmt)
-{
-	struct sta_info *sta;
-	struct ieee80211_mgmt resp;
-	u8 *end;
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
-		   MACSTR, MAC2STR(mgmt->sa));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    mgmt->u.action.u.sa_query_resp.trans_id,
-		    WLAN_SA_QUERY_TR_ID_LEN);
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
-			   "from unassociated STA " MACSTR, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
-		   MACSTR, MAC2STR(mgmt->sa));
-
-	os_memset(&resp, 0, sizeof(resp));
-	resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					  WLAN_FC_STYPE_ACTION);
-	os_memcpy(resp.da, mgmt->sa, ETH_ALEN);
-	os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
-	os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
-	resp.u.action.category = WLAN_ACTION_SA_QUERY;
-	resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
-	os_memcpy(resp.u.action.u.sa_query_req.trans_id,
-		  mgmt->u.action.u.sa_query_req.trans_id,
-		  WLAN_SA_QUERY_TR_ID_LEN);
-	end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
-	if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp) < 0)
-		perror("hostapd_sa_query_request: send");
-}
-
-
 static void hostapd_sa_query_action(struct hostapd_data *hapd,
 				    const struct ieee80211_mgmt *mgmt,
 				    size_t len)
 {
-	struct sta_info *sta;
 	const u8 *end;
-	int i;
 
 	end = mgmt->u.action.u.sa_query_resp.trans_id +
 		WLAN_SA_QUERY_TR_ID_LEN;
@@ -1343,50 +1231,9 @@
 		return;
 	}
 
-	if (mgmt->u.action.u.sa_query_resp.action == WLAN_SA_QUERY_REQUEST) {
-		hostapd_sa_query_request(hapd, mgmt);
-		return;
-	}
-
-	if (mgmt->u.action.u.sa_query_resp.action != WLAN_SA_QUERY_RESPONSE) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
-			   "Action %d", mgmt->u.action.u.sa_query_resp.action);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
-		   MACSTR, MAC2STR(mgmt->sa));
-	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
-		    mgmt->u.action.u.sa_query_resp.trans_id,
-		    WLAN_SA_QUERY_TR_ID_LEN);
-
-	/* MLME-SAQuery.confirm */
-
-	sta = ap_get_sta(hapd, mgmt->sa);
-	if (sta == NULL || sta->sa_query_trans_id == NULL) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
-			   "pending SA Query request found");
-		return;
-	}
-
-	for (i = 0; i < sta->sa_query_count; i++) {
-		if (os_memcmp(sta->sa_query_trans_id +
-			      i * WLAN_SA_QUERY_TR_ID_LEN,
-			      mgmt->u.action.u.sa_query_resp.trans_id,
-			      WLAN_SA_QUERY_TR_ID_LEN) == 0)
-			break;
-	}
-
-	if (i >= sta->sa_query_count) {
-		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
-			   "transaction identifier found");
-		return;
-	}
-
-	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
-		       HOSTAPD_LEVEL_DEBUG,
-		       "Reply to pending SA Query received");
-	ap_sta_stop_sa_query(hapd, sta);
+	ieee802_11_sa_query_action(hapd, mgmt->sa,
+				   mgmt->u.action.u.sa_query_resp.action,
+				   mgmt->u.action.u.sa_query_resp.trans_id);
 }
 
 
@@ -1401,7 +1248,10 @@
 static void handle_action(struct hostapd_data *hapd,
 			  const struct ieee80211_mgmt *mgmt, size_t len)
 {
+#if defined(CONFIG_IEEE80211W) || defined(CONFIG_IEEE80211R)
 	struct sta_info *sta;
+	sta = ap_get_sta(hapd, mgmt->sa);
+#endif /* CONFIG_IEEE80211W || CONFIG_IEEE80211R */
 
 	if (len < IEEE80211_HDRLEN + 1) {
 		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
@@ -1411,7 +1261,6 @@
 		return;
 	}
 
-	sta = ap_get_sta(hapd, mgmt->sa);
 #ifdef CONFIG_IEEE80211W
 	if (sta && (sta->flags & WLAN_STA_MFP) &&
 	    !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
@@ -1493,7 +1342,7 @@
 		os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
 		resp->u.action.category |= 0x80;
 
-		hostapd_drv_send_mlme(hapd, resp, len);
+		hostapd_drv_send_mlme(hapd, resp, len, 0);
 		os_free(resp);
 	}
 }
@@ -1536,6 +1385,11 @@
 		mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
 
 	if (!broadcast &&
+#ifdef CONFIG_P2P
+	    /* Invitation responses can be sent with the peer MAC as BSSID */
+	    !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+	      stype == WLAN_FC_STYPE_ACTION) &&
+#endif /* CONFIG_P2P */
 	    os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
 		printf("MGMT: BSSID=" MACSTR " not our address\n",
 		       MAC2STR(mgmt->bssid));
@@ -1574,7 +1428,7 @@
 		handle_disassoc(hapd, mgmt, len);
 		break;
 	case WLAN_FC_STYPE_DEAUTH:
-		wpa_msg(hapd, MSG_DEBUG, "mgmt::deauth");
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
 		handle_deauth(hapd, mgmt, len);
 		break;
 	case WLAN_FC_STYPE_ACTION:
@@ -1688,14 +1542,6 @@
 		 * step.
 		 */
 		ap_sta_set_authorized(hapd, sta, 1);
-		wpa_msg(hapd->msg_ctx, MSG_INFO,
-			AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-		/* Sending the event to parent is required as SSL listens on parent ctrl iface */
-		if(hapd->msg_ctx_parent)
-			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-				AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
 	}
 
 	if (reassoc)
@@ -1722,10 +1568,16 @@
 	if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
 			    sta->supported_rates, sta->supported_rates_len,
 			    sta->listen_interval,
-			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL)) {
+			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+			    sta->flags, sta->qosinfo)) {
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_NOTICE,
 			       "Could not add STA to kernel driver");
+
+		ap_sta_disconnect(hapd, sta, sta->addr,
+				  WLAN_REASON_DISASSOC_AP_BUSY);
+
+		goto fail;
 	}
 
 	if (sta->flags & WLAN_STA_WDS)
@@ -1764,6 +1616,54 @@
 }
 
 
+static void handle_deauth_cb(struct hostapd_data *hapd,
+			     const struct ieee80211_mgmt *mgmt,
+			     size_t len, int ok)
+{
+	struct sta_info *sta;
+	if (mgmt->da[0] & 0x01)
+		return;
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
+			   " not found", MAC2STR(mgmt->da));
+		return;
+	}
+	if (ok)
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
+			   MAC2STR(sta->addr));
+	else
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+			   "deauth", MAC2STR(sta->addr));
+
+	ap_sta_deauth_cb(hapd, sta);
+}
+
+
+static void handle_disassoc_cb(struct hostapd_data *hapd,
+			       const struct ieee80211_mgmt *mgmt,
+			       size_t len, int ok)
+{
+	struct sta_info *sta;
+	if (mgmt->da[0] & 0x01)
+		return;
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
+			   " not found", MAC2STR(mgmt->da));
+		return;
+	}
+	if (ok)
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
+			   MAC2STR(sta->addr));
+	else
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+			   "disassoc", MAC2STR(sta->addr));
+
+	ap_sta_disassoc_cb(hapd, sta);
+}
+
+
 /**
  * ieee802_11_mgmt_cb - Process management frame TX status callback
  * @hapd: hostapd BSS data structure (the BSS from which the management frame
@@ -1796,7 +1696,12 @@
 		wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
 		break;
 	case WLAN_FC_STYPE_DEAUTH:
-		/* ignore */
+		wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
+		handle_deauth_cb(hapd, mgmt, len, ok);
+		break;
+	case WLAN_FC_STYPE_DISASSOC:
+		wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
+		handle_disassoc_cb(hapd, mgmt, len, ok);
 		break;
 	case WLAN_FC_STYPE_ACTION:
 		wpa_printf(MSG_DEBUG, "mgmt::action cb");
@@ -1853,6 +1758,55 @@
 }
 
 
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+			     const u8 *data, size_t len, int ack)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, dst);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, dst);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL)
+		return;
+
+	ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
+}
+
+
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, addr);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL)
+		return;
+	if (!(sta->flags & WLAN_STA_PENDING_POLL))
+		return;
+
+	wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
+		   "activity poll", MAC2STR(sta->addr));
+	sta->flags &= ~WLAN_STA_PENDING_POLL;
+}
+
+
 void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
 				int wds)
 {
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 157198c..43042a5 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -62,7 +62,21 @@
 void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
 void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
 		       const u8 *buf, size_t len, int ack);
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+			     const u8 *data, size_t len, int ack);
 void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
 				int wds);
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+				     struct sta_info *sta, u8 *eid);
+void ieee802_11_sa_query_action(struct hostapd_data *hapd,
+				const u8 *sa, const u8 action_type,
+				const u8 *trans_id);
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
+int hostapd_update_time_adv(struct hostapd_data *hapd);
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
 
 #endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_auth.c b/src/ap/ieee802_11_auth.c
index b933263..f3f313d 100644
--- a/src/ap/ieee802_11_auth.c
+++ b/src/ap/ieee802_11_auth.c
@@ -21,6 +21,7 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "crypto/sha1.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "hostapd.h"
@@ -40,6 +41,8 @@
 	u32 session_timeout;
 	u32 acct_interim_interval;
 	int vlan_id;
+	int has_psk;
+	u8 psk[PMK_LEN];
 };
 
 
@@ -68,7 +71,8 @@
 
 static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
 				 u32 *session_timeout,
-				 u32 *acct_interim_interval, int *vlan_id)
+				 u32 *acct_interim_interval, int *vlan_id,
+				 u8 *psk, int *has_psk)
 {
 	struct hostapd_cached_radius_acl *entry;
 	struct os_time now;
@@ -89,6 +93,10 @@
 					entry->acct_interim_interval;
 			if (vlan_id)
 				*vlan_id = entry->vlan_id;
+			if (psk)
+				os_memcpy(psk, entry->psk, PMK_LEN);
+			if (has_psk)
+				*has_psk = entry->has_psk;
 			return entry->accepted;
 		}
 
@@ -210,11 +218,14 @@
  * @session_timeout: Buffer for returning session timeout (from RADIUS)
  * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
  * @vlan_id: Buffer for returning VLAN ID
+ * @psk: Buffer for returning WPA PSK
+ * @has_psk: Buffer for indicating whether psk was filled
  * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
  */
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 			    const u8 *msg, size_t len, u32 *session_timeout,
-			    u32 *acct_interim_interval, int *vlan_id)
+			    u32 *acct_interim_interval, int *vlan_id,
+			    u8 *psk, int *has_psk)
 {
 	if (session_timeout)
 		*session_timeout = 0;
@@ -222,6 +233,10 @@
 		*acct_interim_interval = 0;
 	if (vlan_id)
 		*vlan_id = 0;
+	if (has_psk)
+		*has_psk = 0;
+	if (psk)
+		os_memset(psk, 0, PMK_LEN);
 
 	if (hostapd_maclist_found(hapd->conf->accept_mac,
 				  hapd->conf->num_accept_mac, addr, vlan_id))
@@ -241,11 +256,12 @@
 		return HOSTAPD_ACL_REJECT;
 #else /* CONFIG_NO_RADIUS */
 		struct hostapd_acl_query_data *query;
+		struct os_time t;
 
 		/* Check whether ACL cache has an entry for this station */
 		int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
 						acct_interim_interval,
-						vlan_id);
+						vlan_id, psk, has_psk);
 		if (res == HOSTAPD_ACL_ACCEPT ||
 		    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
 			return res;
@@ -271,7 +287,8 @@
 			wpa_printf(MSG_ERROR, "malloc for query data failed");
 			return HOSTAPD_ACL_REJECT;
 		}
-		time(&query->timestamp);
+		os_get_time(&t);
+		query->timestamp = t.sec;
 		os_memcpy(query->addr, addr, ETH_ALEN);
 		if (hostapd_radius_acl_query(hapd, addr, query)) {
 			wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
@@ -397,6 +414,7 @@
 	struct hostapd_acl_query_data *query, *prev;
 	struct hostapd_cached_radius_acl *cache;
 	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+	struct os_time t;
 
 	query = hapd->acl_queries;
 	prev = NULL;
@@ -431,9 +449,13 @@
 		wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
 		goto done;
 	}
-	time(&cache->timestamp);
+	os_get_time(&t);
+	cache->timestamp = t.sec;
 	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
 	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
+		int passphraselen;
+		char *passphrase;
+
 		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
 					      &cache->session_timeout) == 0)
 			cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
@@ -452,6 +474,32 @@
 		}
 
 		cache->vlan_id = radius_msg_get_vlanid(msg);
+
+		passphrase = radius_msg_get_tunnel_password(
+			msg, &passphraselen,
+			hapd->conf->radius->auth_server->shared_secret,
+			hapd->conf->radius->auth_server->shared_secret_len,
+			req);
+		cache->has_psk = passphrase != NULL;
+		if (passphrase != NULL) {
+			/* passphrase does not contain the NULL termination.
+			 * Add it here as pbkdf2_sha1 requires it. */
+			char *strpassphrase = os_zalloc(passphraselen + 1);
+			if (strpassphrase) {
+				os_memcpy(strpassphrase, passphrase,
+					  passphraselen);
+				pbkdf2_sha1(strpassphrase,
+					    hapd->conf->ssid.ssid,
+					    hapd->conf->ssid.ssid_len, 4096,
+					    cache->psk, PMK_LEN);
+				os_free(strpassphrase);
+			}
+			os_free(passphrase);
+		}
+
+		if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
+		    cache->psk == NULL)
+			cache->accepted = HOSTAPD_ACL_REJECT;
 	} else
 		cache->accepted = HOSTAPD_ACL_REJECT;
 	cache->next = hapd->acl_cache;
diff --git a/src/ap/ieee802_11_auth.h b/src/ap/ieee802_11_auth.h
index b2971e5..a90571f 100644
--- a/src/ap/ieee802_11_auth.h
+++ b/src/ap/ieee802_11_auth.h
@@ -24,7 +24,8 @@
 
 int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
 			    const u8 *msg, size_t len, u32 *session_timeout,
-			    u32 *acct_interim_interval, int *vlan_id);
+			    u32 *acct_interim_interval, int *vlan_id,
+			    u8 *psk, int *has_psk);
 int hostapd_acl_init(struct hostapd_data *hapd);
 void hostapd_acl_deinit(struct hostapd_data *hapd);
 
diff --git a/src/ap/ieee802_11_shared.c b/src/ap/ieee802_11_shared.c
new file mode 100644
index 0000000..8503fce
--- /dev/null
+++ b/src/ap/ieee802_11_shared.c
@@ -0,0 +1,405 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "ieee802_11.h"
+
+
+#ifdef CONFIG_IEEE80211W
+
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+				     struct sta_info *sta, u8 *eid)
+{
+	u8 *pos = eid;
+	u32 timeout, tu;
+	struct os_time now, passed;
+
+	*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+	*pos++ = 5;
+	*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
+	os_get_time(&now);
+	os_time_sub(&now, &sta->sa_query_start, &passed);
+	tu = (passed.sec * 1000000 + passed.usec) / 1024;
+	if (hapd->conf->assoc_sa_query_max_timeout > tu)
+		timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
+	else
+		timeout = 0;
+	if (timeout < hapd->conf->assoc_sa_query_max_timeout)
+		timeout++; /* add some extra time for local timers */
+	WPA_PUT_LE32(pos, timeout);
+	pos += 4;
+
+	return pos;
+}
+
+
+/* MLME-SAQuery.request */
+void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
+				  const u8 *addr, const u8 *trans_id)
+{
+	struct ieee80211_mgmt mgmt;
+	u8 *end;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
+		   MACSTR, MAC2STR(addr));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	os_memset(&mgmt, 0, sizeof(mgmt));
+	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt.da, addr, ETH_ALEN);
+	os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+	mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
+	mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+	os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
+		  WLAN_SA_QUERY_TR_ID_LEN);
+	end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+	if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
+		perror("ieee802_11_send_sa_query_req: send");
+}
+
+
+static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
+					  const u8 *sa, const u8 *trans_id)
+{
+	struct sta_info *sta;
+	struct ieee80211_mgmt resp;
+	u8 *end;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
+		   MACSTR, MAC2STR(sa));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	sta = ap_get_sta(hapd, sa);
+	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
+			   "from unassociated STA " MACSTR, MAC2STR(sa));
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
+		   MACSTR, MAC2STR(sa));
+
+	os_memset(&resp, 0, sizeof(resp));
+	resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	os_memcpy(resp.da, sa, ETH_ALEN);
+	os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
+	resp.u.action.category = WLAN_ACTION_SA_QUERY;
+	resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
+	os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
+		  WLAN_SA_QUERY_TR_ID_LEN);
+	end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+	if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
+		perror("ieee80211_mgmt_sa_query_request: send");
+}
+
+
+void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
+				const u8 action_type, const u8 *trans_id)
+{
+	struct sta_info *sta;
+	int i;
+
+	if (action_type == WLAN_SA_QUERY_REQUEST) {
+		ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
+		return;
+	}
+
+	if (action_type != WLAN_SA_QUERY_RESPONSE) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
+			   "Action %d", action_type);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
+		   MACSTR, MAC2STR(sa));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	/* MLME-SAQuery.confirm */
+
+	sta = ap_get_sta(hapd, sa);
+	if (sta == NULL || sta->sa_query_trans_id == NULL) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
+			   "pending SA Query request found");
+		return;
+	}
+
+	for (i = 0; i < sta->sa_query_count; i++) {
+		if (os_memcmp(sta->sa_query_trans_id +
+			      i * WLAN_SA_QUERY_TR_ID_LEN,
+			      trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0)
+			break;
+	}
+
+	if (i >= sta->sa_query_count) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
+			   "transaction identifier found");
+		return;
+	}
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "Reply to pending SA Query received");
+	ap_sta_stop_sa_query(hapd, sta);
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
+u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	u8 len = 0;
+
+	if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
+		len = 5;
+	if (len < 4 && hapd->conf->interworking)
+		len = 4;
+	if (len == 0)
+		return eid;
+
+	*pos++ = WLAN_EID_EXT_CAPAB;
+	*pos++ = len;
+	*pos++ = 0x00;
+	*pos++ = 0x00;
+	*pos++ = 0x00;
+
+	*pos = 0x00;
+	if (hapd->conf->time_advertisement == 2)
+		*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
+	if (hapd->conf->interworking)
+		*pos |= 0x80; /* Bit 31 - Interworking */
+	pos++;
+
+	if (len < 5)
+		return pos;
+	*pos = 0x00;
+	if (hapd->conf->tdls & TDLS_PROHIBIT)
+		*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+	if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
+		*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
+	pos++;
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+	u8 *len;
+
+	if (!hapd->conf->interworking)
+		return eid;
+
+	*pos++ = WLAN_EID_INTERWORKING;
+	len = pos++;
+
+	*pos = hapd->conf->access_network_type;
+	if (hapd->conf->internet)
+		*pos |= INTERWORKING_ANO_INTERNET;
+	if (hapd->conf->asra)
+		*pos |= INTERWORKING_ANO_ASRA;
+	if (hapd->conf->esr)
+		*pos |= INTERWORKING_ANO_ESR;
+	if (hapd->conf->uesa)
+		*pos |= INTERWORKING_ANO_UESA;
+	pos++;
+
+	if (hapd->conf->venue_info_set) {
+		*pos++ = hapd->conf->venue_group;
+		*pos++ = hapd->conf->venue_type;
+	}
+
+	if (!is_zero_ether_addr(hapd->conf->hessid)) {
+		os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
+		pos += ETH_ALEN;
+	}
+
+	*len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+
+	/* TODO: Separate configuration for ANQP? */
+	if (!hapd->conf->interworking)
+		return eid;
+
+	*pos++ = WLAN_EID_ADV_PROTO;
+	*pos++ = 2;
+	*pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */
+	*pos++ = ACCESS_NETWORK_QUERY_PROTOCOL;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+	u8 *len;
+	unsigned int i, count;
+
+	if (!hapd->conf->interworking ||
+	    hapd->conf->roaming_consortium == NULL ||
+	    hapd->conf->roaming_consortium_count == 0)
+		return eid;
+
+	*pos++ = WLAN_EID_ROAMING_CONSORTIUM;
+	len = pos++;
+
+	/* Number of ANQP OIs (in addition to the max 3 listed here) */
+	if (hapd->conf->roaming_consortium_count > 3 + 255)
+		*pos++ = 255;
+	else if (hapd->conf->roaming_consortium_count > 3)
+		*pos++ = hapd->conf->roaming_consortium_count - 3;
+	else
+		*pos++ = 0;
+
+	/* OU #1 and #2 Lengths */
+	*pos = hapd->conf->roaming_consortium[0].len;
+	if (hapd->conf->roaming_consortium_count > 1)
+		*pos |= hapd->conf->roaming_consortium[1].len << 4;
+	pos++;
+
+	if (hapd->conf->roaming_consortium_count > 3)
+		count = 3;
+	else
+		count = hapd->conf->roaming_consortium_count;
+
+	for (i = 0; i < count; i++) {
+		os_memcpy(pos, hapd->conf->roaming_consortium[i].oi,
+			  hapd->conf->roaming_consortium[i].len);
+		pos += hapd->conf->roaming_consortium[i].len;
+	}
+
+	*len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid)
+{
+	if (hapd->conf->time_advertisement != 2)
+		return eid;
+
+	if (hapd->time_adv == NULL &&
+	    hostapd_update_time_adv(hapd) < 0)
+		return eid;
+
+	if (hapd->time_adv == NULL)
+		return eid;
+
+	os_memcpy(eid, wpabuf_head(hapd->time_adv),
+		  wpabuf_len(hapd->time_adv));
+	eid += wpabuf_len(hapd->time_adv);
+
+	return eid;
+}
+
+
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
+{
+	size_t len;
+
+	if (hapd->conf->time_advertisement != 2)
+		return eid;
+
+	len = os_strlen(hapd->conf->time_zone);
+
+	*eid++ = WLAN_EID_TIME_ZONE;
+	*eid++ = len;
+	os_memcpy(eid, hapd->conf->time_zone, len);
+	eid += len;
+
+	return eid;
+}
+
+
+int hostapd_update_time_adv(struct hostapd_data *hapd)
+{
+	const int elen = 2 + 1 + 10 + 5 + 1;
+	struct os_time t;
+	struct os_tm tm;
+	u8 *pos;
+
+	if (hapd->conf->time_advertisement != 2)
+		return 0;
+
+	if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0)
+		return -1;
+
+	if (!hapd->time_adv) {
+		hapd->time_adv = wpabuf_alloc(elen);
+		if (hapd->time_adv == NULL)
+			return -1;
+		pos = wpabuf_put(hapd->time_adv, elen);
+	} else
+		pos = wpabuf_mhead_u8(hapd->time_adv);
+
+	*pos++ = WLAN_EID_TIME_ADVERTISEMENT;
+	*pos++ = 1 + 10 + 5 + 1;
+
+	*pos++ = 2; /* UTC time at which the TSF timer is 0 */
+
+	/* Time Value at TSF 0 */
+	/* FIX: need to calculate this based on the current TSF value */
+	WPA_PUT_LE16(pos, tm.year); /* Year */
+	pos += 2;
+	*pos++ = tm.month; /* Month */
+	*pos++ = tm.day; /* Day of month */
+	*pos++ = tm.hour; /* Hours */
+	*pos++ = tm.min; /* Minutes */
+	*pos++ = tm.sec; /* Seconds */
+	WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */
+	pos += 2;
+	*pos++ = 0; /* Reserved */
+
+	/* Time Error */
+	/* TODO: fill in an estimate on the error */
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+
+	*pos++ = hapd->time_update_counter++;
+
+	return 0;
+}
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index 49eba69..153b271 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -20,13 +20,13 @@
 #include "crypto/crypto.h"
 #include "crypto/random.h"
 #include "common/ieee802_11_defs.h"
-#include "common/wpa_ctrl.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "eap_server/eap.h"
 #include "eap_common/eap_wsc_common.h"
 #include "eapol_auth/eapol_auth_sm.h"
 #include "eapol_auth/eapol_auth_sm_i.h"
+#include "p2p/p2p.h"
 #include "hostapd.h"
 #include "accounting.h"
 #include "sta_info.h"
@@ -36,9 +36,6 @@
 #include "ap_config.h"
 #include "ap_drv_ops.h"
 #include "ieee802_1x.h"
-#ifdef ANDROID_BRCM_P2P_PATCH
-#include "p2p/p2p_i.h"
-#endif
 
 
 static void ieee802_1x_finished(struct hostapd_data *hapd,
@@ -87,53 +84,16 @@
 				   struct sta_info *sta, int authorized)
 {
 	int res;
-#ifdef ANDROID_BRCM_P2P_PATCH
-	u8 *dev_addr = NULL;
-#endif
 
 	if (sta->flags & WLAN_STA_PREAUTH)
 		return;
 
 	if (authorized) {
-		if (!ap_sta_is_authorized(sta)) {
-#if defined(ANDROID_BRCM_P2P_PATCH) && defined(CONFIG_P2P)
-			if((dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr)))
-				wpa_msg(hapd->msg_ctx, MSG_INFO,
-					AP_STA_CONNECTED MACSTR " dev_addr="MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
-			else
-#endif /*ANDROID_BRCM_P2P_PATCH*/
-				wpa_msg(hapd->msg_ctx, MSG_INFO,
-					AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
-
-#ifdef ANDROID_BRCM_P2P_PATCH
-			/* Sending the event to parent is required as SSL listens on parent ctrl iface */
-			if(hapd->msg_ctx_parent) {
-				if(dev_addr)
-					wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-						AP_STA_CONNECTED MACSTR " dev_addr="MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
-				else
-					wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-						AP_STA_CONNECTED MACSTR , MAC2STR(sta->addr));
-			}
-#endif /* ANDROID_BRCM_P2P_PATCH */
-		}
-
 		ap_sta_set_authorized(hapd, sta, 1);
 		res = hostapd_set_authorized(hapd, sta, 1);
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_DEBUG, "authorizing port");
 	} else {
-		if (ap_sta_is_authorized(sta) && (sta->flags & WLAN_STA_ASSOC)) {
-			wpa_msg(hapd->msg_ctx, MSG_INFO,
-				AP_STA_DISCONNECTED MACSTR,
-				MAC2STR(sta->addr));
-#ifdef ANDROID_BRCM_P2P_PATCH
-			if(hapd->msg_ctx_parent)
-				wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
-					AP_STA_DISCONNECTED MACSTR,
-					MAC2STR(sta->addr));
-#endif /* ANDROID_BRCM_P2P_PATCH */
-		}
 		ap_sta_set_authorized(hapd, sta, 0);
 		res = hostapd_set_authorized(hapd, sta, 0);
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
@@ -722,7 +682,8 @@
 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
 		   (unsigned long) len, MAC2STR(sa));
 	sta = ap_get_sta(hapd, sa);
-	if (!sta || !(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH))) {
+	if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
+		     !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
 		wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
 			   "associated/Pre-authenticating STA");
 		return;
@@ -785,14 +746,24 @@
 			return;
 
 #ifdef CONFIG_WPS
-		if (!hapd->conf->ieee802_1x &&
-		    ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
-		     WLAN_STA_MAYBE_WPS)) {
-			/*
-			 * Delay EAPOL frame transmission until a possible WPS
-			 * STA initiates the handshake with EAPOL-Start.
-			 */
-			sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+		if (!hapd->conf->ieee802_1x) {
+			u32 wflags = sta->flags & (WLAN_STA_WPS |
+						   WLAN_STA_WPS2 |
+						   WLAN_STA_MAYBE_WPS);
+			if (wflags == WLAN_STA_MAYBE_WPS ||
+			    wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) {
+				/*
+				 * Delay EAPOL frame transmission until a
+				 * possible WPS STA initiates the handshake
+				 * with EAPOL-Start. Only allow the wait to be
+				 * skipped if the STA is known to support WPS
+				 * 2.0.
+				 */
+				wpa_printf(MSG_DEBUG, "WPS: Do not start "
+					   "EAPOL until EAPOL-Start is "
+					   "received");
+				sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+			}
 		}
 #endif /* CONFIG_WPS */
 
@@ -921,11 +892,14 @@
 
 #ifdef CONFIG_WPS
 	sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
-	if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS)) {
+	if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) {
 		/*
-		 * Delay EAPOL frame transmission until a possible WPS
-		 * initiates the handshake with EAPOL-Start.
+		 * Delay EAPOL frame transmission until a possible WPS STA
+		 * initiates the handshake with EAPOL-Start. Only allow the
+		 * wait to be skipped if the STA is known to support WPS 2.0.
 		 */
+		wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
+			   "EAPOL-Start is received");
 		sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
 	}
 #endif /* CONFIG_WPS */
@@ -1443,6 +1417,9 @@
 		 * request and we cannot continue EAP processing (EAP-Failure
 		 * could only be sent if the EAP peer actually replied).
 		 */
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
+			MAC2STR(sta->addr));
+
 		sm->eap_if->portEnabled = FALSE;
 		ap_sta_disconnect(hapd, sta, sta->addr,
 				  WLAN_REASON_PREV_AUTH_NOT_VALID);
@@ -1595,7 +1572,7 @@
 {
 	struct hostapd_data *hapd = ctx;
 	const struct hostapd_eap_user *eap_user;
-	int i, count;
+	int i;
 
 	eap_user = hostapd_get_eap_user(hapd->conf, identity,
 					identity_len, phase2);
@@ -1604,10 +1581,7 @@
 
 	os_memset(user, 0, sizeof(*user));
 	user->phase2 = phase2;
-	count = EAP_USER_MAX_METHODS;
-	if (count > EAP_MAX_METHODS)
-		count = EAP_MAX_METHODS;
-	for (i = 0; i < count; i++) {
+	for (i = 0; i < EAP_MAX_METHODS; i++) {
 		user->methods[i].vendor = eap_user->methods[i].vendor;
 		user->methods[i].method = eap_user->methods[i].method;
 	}
@@ -1619,6 +1593,7 @@
 		os_memcpy(user->password, eap_user->password,
 			  eap_user->password_len);
 		user->password_len = eap_user->password_len;
+		user->password_hash = eap_user->password_hash;
 	}
 	user->force_version = eap_user->force_version;
 	user->ttls_auth = eap_user->ttls_auth;
@@ -1795,15 +1770,13 @@
 			 const u8 *buf, size_t len, int ack)
 {
 	struct ieee80211_hdr *hdr;
-	struct ieee802_1x_hdr *xhdr;
-	struct ieee802_1x_eapol_key *key;
 	u8 *pos;
 	const unsigned char rfc1042_hdr[ETH_ALEN] =
 		{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 
 	if (sta == NULL)
 		return -1;
-	if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2 + sizeof(*xhdr))
+	if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
 		return 0;
 
 	hdr = (struct ieee80211_hdr *) buf;
@@ -1815,16 +1788,30 @@
 		return 0;
 	pos += 2;
 
-	xhdr = (struct ieee802_1x_hdr *) pos;
-	pos += sizeof(*xhdr);
+	return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos,
+					  ack);
+}
 
+
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			       const u8 *buf, int len, int ack)
+{
+	const struct ieee802_1x_hdr *xhdr =
+		(const struct ieee802_1x_hdr *) buf;
+	const u8 *pos = buf + sizeof(*xhdr);
+	struct ieee802_1x_eapol_key *key;
+
+	if (len < (int) sizeof(*xhdr))
+		return 0;
 	wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
 		   "type=%d length=%d - ack=%d",
 		   MAC2STR(sta->addr), xhdr->version, xhdr->type,
 		   be_to_host16(xhdr->length), ack);
 
-	if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
-	    pos + sizeof(struct wpa_eapol_key) <= buf + len) {
+	if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
+		return 0;
+
+	if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
 		const struct wpa_eapol_key *wpa;
 		wpa = (const struct wpa_eapol_key *) pos;
 		if (wpa->type == EAPOL_KEY_TYPE_RSN ||
@@ -1835,11 +1822,10 @@
 
 	/* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
 	 * or Authenticator state machines, but EAPOL-Key packets are not
-	 * retransmitted in case of failure. Try to re-sent failed EAPOL-Key
+	 * retransmitted in case of failure. Try to re-send failed EAPOL-Key
 	 * packets couple of times because otherwise STA keys become
 	 * unsynchronized with AP. */
-	if (xhdr->type == IEEE802_1X_TYPE_EAPOL_KEY && !ack &&
-	    pos + sizeof(*key) <= buf + len) {
+	if (!ack && pos + sizeof(*key) <= buf + len) {
 		key = (struct ieee802_1x_eapol_key *) pos;
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
 			       HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
@@ -1943,6 +1929,7 @@
 {
 	int len = 0, ret;
 	struct eapol_state_machine *sm = sta->eapol_sm;
+	struct os_time t;
 
 	if (sm == NULL)
 		return 0;
@@ -2057,6 +2044,7 @@
 	len += ret;
 
 	/* dot1xAuthSessionStatsTable */
+	os_get_time(&t);
 	ret = os_snprintf(buf + len, buflen - len,
 			  /* TODO: dot1xAuthSessionOctetsRx */
 			  /* TODO: dot1xAuthSessionOctetsTx */
@@ -2071,8 +2059,7 @@
 			  (wpa_key_mgmt_wpa_ieee8021x(
 				   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
 			  1 : 2,
-			  (unsigned int) (time(NULL) -
-					  sta->acct_session_start),
+			  (unsigned int) (t.sec - sta->acct_session_start),
 			  sm->identity);
 	if (ret < 0 || (size_t) ret >= buflen - len)
 		return len;
@@ -2099,22 +2086,25 @@
 			       "Added PMKSA cache entry (IEEE 802.1X)");
 	}
 
-#ifdef CONFIG_WPS
-	if (!success && (sta->flags & WLAN_STA_WPS)) {
+	if (!success) {
 		/*
 		 * Many devices require deauthentication after WPS provisioning
 		 * and some may not be be able to do that themselves, so
-		 * disconnect the client here.
+		 * disconnect the client here. In addition, this may also
+		 * benefit IEEE 802.1X/EAPOL authentication cases, too since
+		 * the EAPOL PAE state machine would remain in HELD state for
+		 * considerable amount of time and some EAP methods, like
+		 * EAP-FAST with anonymous provisioning, may require another
+		 * EAPOL authentication to be started to complete connection.
 		 */
-		wpa_printf(MSG_DEBUG, "WPS: Force disconnection after "
-			   "EAP-Failure");
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
+			"disconnection after EAP-Failure");
 		/* Add a small sleep to increase likelihood of previously
 		 * requested EAP-Failure TX getting out before this should the
 		 * driver reorder operations.
 		 */
 		os_sleep(0, 10000);
 		ap_sta_disconnect(hapd, sta, sta->addr,
-				  WLAN_REASON_PREV_AUTH_NOT_VALID);
+				  WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
 	}
-#endif /* CONFIG_WPS */
 }
diff --git a/src/ap/ieee802_1x.h b/src/ap/ieee802_1x.h
index 1a4d2eb..267e22a 100644
--- a/src/ap/ieee802_1x.h
+++ b/src/ap/ieee802_1x.h
@@ -68,6 +68,8 @@
 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);
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			       const u8 *data, int len, int ack);
 u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
 u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
 				 int idx);
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index e829447..972a723 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / Station table
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "radius/radius.h"
 #include "radius/radius_client.h"
 #include "drivers/driver.h"
@@ -38,9 +39,12 @@
 static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
 				       struct sta_info *sta);
 static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
 #ifdef CONFIG_IEEE80211W
 static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
 #endif /* CONFIG_IEEE80211W */
+static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
 
 int ap_for_each_sta(struct hostapd_data *hapd,
 		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
@@ -198,6 +202,8 @@
 
 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
 	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
 
 	ieee802_1x_free_station(sta);
 	wpa_auth_sta_deinit(sta->wpa_sm);
@@ -222,6 +228,7 @@
 	wpabuf_free(sta->p2p_ie);
 
 	os_free(sta->ht_capabilities);
+	os_free(sta->psk);
 
 	os_free(sta);
 }
@@ -275,31 +282,37 @@
 		int inactive_sec;
 		inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
 		if (inactive_sec == -1) {
-			wpa_msg(hapd, MSG_DEBUG, "Check inactivity: Could not "
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Check inactivity: Could not "
 				"get station info rom kernel driver for "
 				MACSTR, MAC2STR(sta->addr));
 		} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
 			   sta->flags & WLAN_STA_ASSOC) {
 			/* station activity detected; reset timeout state */
-			wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
-				"active %is ago",
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Station " MACSTR " has been active %is ago",
 				MAC2STR(sta->addr), inactive_sec);
 			sta->timeout_next = STA_NULLFUNC;
 			next_time = hapd->conf->ap_max_inactivity -
 				inactive_sec;
 		} else {
-			wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has been "
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Station " MACSTR " has been "
 				"inactive too long: %d sec, max allowed: %d",
 				MAC2STR(sta->addr), inactive_sec,
 				hapd->conf->ap_max_inactivity);
+
+			if (hapd->conf->skip_inactivity_poll)
+				sta->timeout_next = STA_DISASSOC;
 		}
 	}
 
 	if ((sta->flags & WLAN_STA_ASSOC) &&
 	    sta->timeout_next == STA_DISASSOC &&
-	    !(sta->flags & WLAN_STA_PENDING_POLL)) {
-		wpa_msg(hapd, MSG_DEBUG, "Station " MACSTR " has ACKed data "
-			"poll", MAC2STR(sta->addr));
+	    !(sta->flags & WLAN_STA_PENDING_POLL) &&
+	    !hapd->conf->skip_inactivity_poll) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
+			" has ACKed data poll", MAC2STR(sta->addr));
 		/* data nullfunc frame poll did not produce TX errors; assume
 		 * station ACKed it */
 		sta->timeout_next = STA_NULLFUNC;
@@ -314,46 +327,17 @@
 
 	if (sta->timeout_next == STA_NULLFUNC &&
 	    (sta->flags & WLAN_STA_ASSOC)) {
-#ifndef CONFIG_NATIVE_WINDOWS
-		/* send data frame to poll STA and check whether this frame
-		 * is ACKed */
-		struct ieee80211_hdr hdr;
-
-		wpa_printf(MSG_DEBUG, "  Polling STA with data frame");
+		wpa_printf(MSG_DEBUG, "  Polling STA");
 		sta->flags |= WLAN_STA_PENDING_POLL;
-
-		os_memset(&hdr, 0, sizeof(hdr));
-		if (hapd->driver &&
-		    os_strcmp(hapd->driver->name, "hostap") == 0) {
-			/*
-			 * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
-			 * but it is apparently not retried so TX Exc events
-			 * are not received for it.
-			 */
-			hdr.frame_control =
-				IEEE80211_FC(WLAN_FC_TYPE_DATA,
-					     WLAN_FC_STYPE_DATA);
-		} else {
-			hdr.frame_control =
-				IEEE80211_FC(WLAN_FC_TYPE_DATA,
-					     WLAN_FC_STYPE_NULLFUNC);
-		}
-
-		hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
-		os_memcpy(hdr.IEEE80211_DA_FROMDS, sta->addr, ETH_ALEN);
-		os_memcpy(hdr.IEEE80211_BSSID_FROMDS, hapd->own_addr,
-			  ETH_ALEN);
-		os_memcpy(hdr.IEEE80211_SA_FROMDS, hapd->own_addr, ETH_ALEN);
-
-		if (hostapd_drv_send_mlme(hapd, &hdr, sizeof(hdr)) < 0)
-			perror("ap_handle_timer: send");
-#endif /* CONFIG_NATIVE_WINDOWS */
+		hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
+					sta->flags & WLAN_STA_WMM);
 	} else if (sta->timeout_next != STA_REMOVE) {
 		int deauth = sta->timeout_next == STA_DEAUTH;
 
-		wpa_printf(MSG_DEBUG, "Sending %s info to STA " MACSTR,
-			   deauth ? "deauthentication" : "disassociation",
-			   MAC2STR(sta->addr));
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+			"Timeout, sending %s info to STA " MACSTR,
+			deauth ? "deauthentication" : "disassociation",
+			MAC2STR(sta->addr));
 
 		if (deauth) {
 			hostapd_drv_sta_deauth(
@@ -373,6 +357,7 @@
 				       hapd, sta);
 		break;
 	case STA_DISASSOC:
+		ap_sta_set_authorized(hapd, sta, 0);
 		sta->flags &= ~WLAN_STA_ASSOC;
 		ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
 		if (!sta->acct_terminate_cause)
@@ -393,7 +378,7 @@
 	case STA_REMOVE:
 		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
 			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
-			       "inactivity");
+			       "inactivity (timer DEAUTH/REMOVE)");
 		if (!sta->acct_terminate_cause)
 			sta->acct_terminate_cause =
 				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
@@ -525,13 +510,23 @@
 }
 
 
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+
+	ap_sta_remove(hapd, sta);
+	mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
+}
+
+
 void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
 			 u16 reason)
 {
 	wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
 		   hapd->conf->iface, MAC2STR(sta->addr));
 	sta->flags &= ~WLAN_STA_ASSOC;
-	ap_sta_remove(hapd, sta);
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->timeout_next = STA_DEAUTH;
 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
 	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
@@ -539,7 +534,22 @@
 	accounting_sta_stop(hapd, sta);
 	ieee802_1x_free_station(sta);
 
-	mlme_disassociate_indication(hapd, sta, reason);
+	sta->disassoc_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_disassoc_cb_timeout, hapd, sta);
+}
+
+
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+
+	ap_sta_remove(hapd, sta);
+	mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
 }
 
 
@@ -549,7 +559,7 @@
 	wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
 		   hapd->conf->iface, MAC2STR(sta->addr));
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
-	ap_sta_remove(hapd, sta);
+	ap_sta_set_authorized(hapd, sta, 0);
 	sta->timeout_next = STA_REMOVE;
 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
 	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
@@ -557,7 +567,12 @@
 	accounting_sta_stop(hapd, sta);
 	ieee802_1x_free_station(sta);
 
-	mlme_deauthenticate_indication(hapd, sta, reason);
+	sta->deauth_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_deauth_cb_timeout, hapd, sta);
 }
 
 
@@ -762,17 +777,58 @@
 void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
 			   int authorized)
 {
+	const u8 *dev_addr = NULL;
 	if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
 		return;
 
-	if (authorized)
+#ifdef CONFIG_P2P
+	dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
+#endif /* CONFIG_P2P */
+
+	if (authorized) {
+		if (dev_addr)
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+				MACSTR " p2p_dev_addr=" MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+				MACSTR, MAC2STR(sta->addr));
+		if (hapd->msg_ctx_parent &&
+		    hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_CONNECTED MACSTR " p2p_dev_addr="
+				MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else if (hapd->msg_ctx_parent &&
+			 hapd->msg_ctx_parent != hapd->msg_ctx)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
+
 		sta->flags |= WLAN_STA_AUTHORIZED;
-	else
+	} else {
+		if (dev_addr)
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+				MACSTR " p2p_dev_addr=" MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+				MACSTR, MAC2STR(sta->addr));
+		if (hapd->msg_ctx_parent &&
+		    hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_DISCONNECTED MACSTR " p2p_dev_addr="
+				MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else if (hapd->msg_ctx_parent &&
+			 hapd->msg_ctx_parent != hapd->msg_ctx)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_DISCONNECTED MACSTR,
+				MAC2STR(sta->addr));
 		sta->flags &= ~WLAN_STA_AUTHORIZED;
+	}
 
 	if (hapd->sta_authorized_cb)
 		hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
-					sta->addr, authorized);
+					sta->addr, authorized, dev_addr);
 }
 
 
@@ -791,6 +847,38 @@
 	ap_sta_set_authorized(hapd, sta, 0);
 	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
 	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-	eloop_register_timeout(0, 0, ap_handle_timer, hapd, sta);
+	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
+			       ap_handle_timer, hapd, sta);
 	sta->timeout_next = STA_REMOVE;
+
+	sta->deauth_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_deauth_cb_timeout, hapd, sta);
+}
+
+
+void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) {
+		wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame");
+		return;
+	}
+	sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	ap_sta_deauth_cb_timeout(hapd, sta);
+}
+
+
+void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) {
+		wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame");
+		return;
+	}
+	sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB;
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+	ap_sta_disassoc_cb_timeout(hapd, sta);
 }
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 9ec4fe3..daa96bf 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -1,6 +1,6 @@
 /*
  * hostapd / Station table
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -32,6 +32,9 @@
 #define WLAN_STA_MAYBE_WPS BIT(13)
 #define WLAN_STA_WDS BIT(14)
 #define WLAN_STA_ASSOC_REQ_OK BIT(15)
+#define WLAN_STA_WPS2 BIT(16)
+#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
+#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
 #define WLAN_STA_NONERP BIT(31)
 
 /* Maximum number of supported rates (from both Supported Rates and Extended
@@ -49,6 +52,7 @@
 	u16 listen_interval; /* or beacon_int for APs */
 	u8 supported_rates[WLAN_SUPP_RATES_MAX];
 	int supported_rates_len;
+	u8 qosinfo; /* Valid when WLAN_STA_WMM is set */
 
 	unsigned int nonerp_set:1;
 	unsigned int no_short_slot_time_set:1;
@@ -65,6 +69,9 @@
 		STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
 	} timeout_next;
 
+	u16 deauth_reason;
+	u16 disassoc_reason;
+
 	/* IEEE 802.1X related data */
 	struct eapol_state_machine *eapol_sm;
 
@@ -92,6 +99,7 @@
 	struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
 
 	int vlan_id;
+	u8 *psk; /* PSK from RADIUS authentication server */
 
 	struct ieee80211_ht_capabilities *ht_capabilities;
 
@@ -114,7 +122,7 @@
  * passed since last received frame from the station, a nullfunc data frame is
  * sent to the station. If this frame is not acknowledged and no other frames
  * have been received, the station will be disassociated after
- * AP_DISASSOC_DELAY seconds. Similarily, the station will be deauthenticated
+ * AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated
  * after AP_DEAUTH_DELAY seconds has passed after disassociation. */
 #define AP_MAX_INACTIVITY (5 * 60)
 #define AP_DISASSOC_DELAY (1)
@@ -162,4 +170,7 @@
 	return sta->flags & WLAN_STA_AUTHORIZED;
 }
 
+void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
+
 #endif /* STA_INFO_H */
diff --git a/src/ap/tkip_countermeasures.c b/src/ap/tkip_countermeasures.c
index 1925217..fac7f4b 100644
--- a/src/ap/tkip_countermeasures.c
+++ b/src/ap/tkip_countermeasures.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / TKIP countermeasures
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -60,9 +60,15 @@
 }
 
 
+void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
+{
+	eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
+}
+
+
 void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
 {
-	time_t now;
+	struct os_time now;
 
 	if (addr && local) {
 		struct sta_info *sta = ap_get_sta(hapd, addr);
@@ -82,13 +88,13 @@
 		}
 	}
 
-	time(&now);
-	if (now > hapd->michael_mic_failure + 60) {
+	os_get_time(&now);
+	if (now.sec > hapd->michael_mic_failure + 60) {
 		hapd->michael_mic_failures = 1;
 	} else {
 		hapd->michael_mic_failures++;
 		if (hapd->michael_mic_failures > 1)
 			ieee80211_tkip_countermeasures_start(hapd);
 	}
-	hapd->michael_mic_failure = now;
+	hapd->michael_mic_failure = now.sec;
 }
diff --git a/src/ap/tkip_countermeasures.h b/src/ap/tkip_countermeasures.h
index 5a1afce..a8ffd16 100644
--- a/src/ap/tkip_countermeasures.h
+++ b/src/ap/tkip_countermeasures.h
@@ -1,6 +1,6 @@
 /*
  * hostapd / TKIP countermeasures
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,5 +16,6 @@
 #define TKIP_COUNTERMEASURES_H
 
 void michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
+void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd);
 
 #endif /* TKIP_COUNTERMEASURES_H */
diff --git a/src/ap/utils.c b/src/ap/utils.c
index 0ff48ae..09bc32f 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -22,6 +22,7 @@
 
 int hostapd_register_probereq_cb(struct hostapd_data *hapd,
 				 int (*cb)(void *ctx, const u8 *sa,
+					   const u8 *da, const u8 *bssid,
 					   const u8 *ie, size_t ie_len),
 				 void *ctx)
 {
diff --git a/src/ap/wmm.c b/src/ap/wmm.c
index a6d9b89..d21c82f 100644
--- a/src/ap/wmm.c
+++ b/src/ap/wmm.c
@@ -72,7 +72,8 @@
 	wmm->version = WMM_VERSION;
 	wmm->qos_info = hapd->parameter_set_count & 0xf;
 
-	if (hapd->conf->wmm_uapsd)
+	if (hapd->conf->wmm_uapsd &&
+	    (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
 		wmm->qos_info |= 0x80;
 
 	wmm->reserved = 0;
@@ -97,9 +98,11 @@
 }
 
 
-/* This function is called when a station sends an association request with
- * WMM info element. The function returns zero on success or non-zero on any
- * error in WMM element. eid does not include Element ID and Length octets. */
+/*
+ * This function is called when a station sends an association request with
+ * WMM info element. The function returns 1 on success or 0 on any error in WMM
+ * element. eid does not include Element ID and Length octets.
+ */
 int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
 {
 	struct wmm_information_element *wmm;
@@ -109,7 +112,7 @@
 	if (len < sizeof(struct wmm_information_element)) {
 		wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)",
 			   (unsigned long) len);
-		return -1;
+		return 0;
 	}
 
 	wmm = (struct wmm_information_element *) eid;
@@ -120,10 +123,10 @@
 	if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT ||
 	    wmm->version != WMM_VERSION) {
 		wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version");
-		return -1;
+		return 0;
 	}
 
-	return 0;
+	return 1;
 }
 
 
@@ -153,7 +156,7 @@
 	os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
 	len = ((u8 *) (t + 1)) - buf;
 
-	if (hostapd_drv_send_mlme(hapd, m, len) < 0)
+	if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
 		perror("wmm_send_action: send");
 }
 
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 0836887..adc69e2 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
 /*
- * hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * IEEE 802.11 RSN / WPA Authenticator
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -52,6 +52,7 @@
 static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
 static const u32 eapol_key_timeout_first = 100; /* ms */
 static const u32 eapol_key_timeout_subseq = 1000; /* ms */
+static const u32 eapol_key_timeout_first_group = 500; /* ms */
 
 /* TODO: make these configurable */
 static const int dot11RSNAConfigPMKLifetime = 43200;
@@ -194,6 +195,7 @@
 {
 	if (wpa_auth->cb.disconnect == NULL)
 		return;
+	wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr));
 	wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
 				WLAN_REASON_PREV_AUTH_NOT_VALID);
 }
@@ -332,7 +334,7 @@
 
 
 static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
-					 int vlan_id)
+					 int vlan_id, int delay_init)
 {
 	struct wpa_group *group;
 
@@ -349,10 +351,6 @@
 		wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
 			   "for secure operations - update keys later when "
 			   "the first station connects");
-#ifdef ANDROID_BRCM_P2P_PATCH
-		os_free(group);
-		return NULL;
-#endif
 	}
 
 	/*
@@ -369,9 +367,15 @@
 	}
 
 	group->GInit = TRUE;
-	wpa_group_sm_step(wpa_auth, group);
-	group->GInit = FALSE;
-	wpa_group_sm_step(wpa_auth, group);
+	if (delay_init) {
+		wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
+			   "until Beacon frames have been configured");
+		/* Initialization is completed in wpa_init_keys(). */
+	} else {
+		wpa_group_sm_step(wpa_auth, group);
+		group->GInit = FALSE;
+		wpa_group_sm_step(wpa_auth, group);
+	}
 
 	return group;
 }
@@ -403,7 +407,7 @@
 		return NULL;
 	}
 
-	wpa_auth->group = wpa_group_init(wpa_auth, 0);
+	wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
 	if (wpa_auth->group == NULL) {
 		os_free(wpa_auth->wpa_ie);
 		os_free(wpa_auth);
@@ -444,6 +448,19 @@
 }
 
 
+int wpa_init_keys(struct wpa_authenticator *wpa_auth)
+{
+	struct wpa_group *group = wpa_auth->group;
+
+	wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
+		   "keys");
+	wpa_group_sm_step(wpa_auth, group);
+	group->GInit = FALSE;
+	wpa_group_sm_step(wpa_auth, group);
+	return 0;
+}
+
+
 /**
  * wpa_deinit - Deinitialize WPA authenticator
  * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
@@ -695,6 +712,37 @@
 #endif /* CONFIG_IEEE80211R */
 
 
+static void wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
+				     struct wpa_state_machine *sm, int group)
+{
+	/* Supplicant reported a Michael MIC error */
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+			 "received EAPOL-Key Error Request "
+			 "(STA detected Michael MIC failure (group=%d))",
+			 group);
+
+	if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"ignore Michael MIC failure report since "
+				"group cipher is not TKIP");
+	} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"ignore Michael MIC failure report since "
+				"pairwise cipher is not TKIP");
+	} else {
+		wpa_auth_mic_failure_report(wpa_auth, sm->addr);
+		sm->dot11RSNAStatsTKIPRemoteMICFailures++;
+		wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
+	}
+
+	/*
+	 * Error report is not a request for a new key handshake, but since
+	 * Authenticator may do it, let's change the keys now anyway.
+	 */
+	wpa_request_new_ptk(sm);
+}
+
+
 void wpa_receive(struct wpa_authenticator *wpa_auth,
 		 struct wpa_state_machine *sm,
 		 u8 *data, size_t data_len)
@@ -720,6 +768,9 @@
 	key = (struct wpa_eapol_key *) (hdr + 1);
 	key_info = WPA_GET_BE16(key->key_info);
 	key_data_length = WPA_GET_BE16(key->key_data_length);
+	wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
+		   " key_info=0x%x type=%u key_data_length=%u",
+		   MAC2STR(sm->addr), key_info, key->type, key_data_length);
 	if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
 		wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
 			   "key_data overflow (%d > %lu)",
@@ -819,7 +870,7 @@
 	if (!(key_info & WPA_KEY_INFO_REQUEST) &&
 	    !wpa_replay_counter_valid(sm, key->replay_counter)) {
 		int i;
-		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
 				 "received EAPOL-Key %s with unexpected "
 				 "replay counter", msgtxt);
 		for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
@@ -1000,17 +1051,9 @@
 #endif /* CONFIG_PEERKEY */
 			return;
 		} else if (key_info & WPA_KEY_INFO_ERROR) {
-			/* Supplicant reported a Michael MIC error */
-			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
-					"received EAPOL-Key Error Request "
-					"(STA detected Michael MIC failure)");
-			wpa_auth_mic_failure_report(wpa_auth, sm->addr);
-			sm->dot11RSNAStatsTKIPRemoteMICFailures++;
-			wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
-			/* Error report is not a request for a new key
-			 * handshake, but since Authenticator may do it, let's
-			 * change the keys now anyway. */
-			wpa_request_new_ptk(sm);
+			wpa_receive_error_report(
+				wpa_auth, sm,
+				!(key_info & WPA_KEY_INFO_KEY_TYPE));
 		} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"received EAPOL-Key Request for new "
@@ -1028,9 +1071,6 @@
 			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
 					"received EAPOL-Key Request for GTK "
 					"rekeying");
-			/* FIX: why was this triggering PTK rekeying for the
-			 * STA that requested Group Key rekeying?? */
-			/* wpa_request_new_ptk(sta->wpa_sm); */
 			eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
 			wpa_rekey_gtk(wpa_auth, NULL);
 		}
@@ -1057,6 +1097,7 @@
 	os_memcpy(sm->last_rx_eapol_key, data, data_len);
 	sm->last_rx_eapol_key_len = data_len;
 
+	sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
 	sm->EAPOLKeyReceived = TRUE;
 	sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
 	sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
@@ -1293,7 +1334,8 @@
 
 	ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
 	if (ctr == 1 && wpa_auth->conf.tx_status)
-		timeout_ms = eapol_key_timeout_first;
+		timeout_ms = pairwise ? eapol_key_timeout_first :
+			eapol_key_timeout_first_group;
 	else
 		timeout_ms = eapol_key_timeout_subseq;
 	if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
@@ -1844,6 +1886,20 @@
 		gtk_len = 0;
 		keyidx = 0;
 		_rsc = NULL;
+		if (sm->rx_eapol_key_secure) {
+			/*
+			 * It looks like Windows 7 supplicant tries to use
+			 * Secure bit in msg 2/4 after having reported Michael
+			 * MIC failure and it then rejects the 4-way handshake
+			 * if msg 3/4 does not set Secure bit. Work around this
+			 * by setting the Secure bit here even in the case of
+			 * WPA if the supplicant used it first.
+			 */
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+					"STA used Secure bit in WPA msg 2/4 - "
+					"set Secure for 3/4 as workaround");
+			secure = 1;
+		}
 	}
 
 	kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
@@ -2469,6 +2525,7 @@
 		group->GN_igtk = tmp;
 #endif /* CONFIG_IEEE80211W */
 		wpa_gtk_update(wpa_auth, group);
+		wpa_group_config_group_keys(wpa_auth, group);
 	}
 }
 
@@ -2771,7 +2828,7 @@
 
 	wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
 		   vlan_id);
-	group = wpa_group_init(wpa_auth, vlan_id);
+	group = wpa_group_init(wpa_auth, vlan_id, 0);
 	if (group == NULL)
 		return NULL;
 
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index e533a14..ce2751e 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -208,6 +208,7 @@
 struct wpa_authenticator * wpa_init(const u8 *addr,
 				    struct wpa_auth_config *conf,
 				    struct wpa_auth_callbacks *cb);
+int wpa_init_keys(struct wpa_authenticator *wpa_auth);
 void wpa_deinit(struct wpa_authenticator *wpa_auth);
 int wpa_reconfig(struct wpa_authenticator *wpa_auth,
 		 struct wpa_auth_config *conf);
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index 65f5f4c..2d1bbe4 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -24,33 +24,10 @@
 #include "wmm.h"
 #include "wpa_auth.h"
 #include "wpa_auth_i.h"
-#include "wpa_auth_ie.h"
 
 
 #ifdef CONFIG_IEEE80211R
 
-struct wpa_ft_ies {
-	const u8 *mdie;
-	size_t mdie_len;
-	const u8 *ftie;
-	size_t ftie_len;
-	const u8 *r1kh_id;
-	const u8 *gtk;
-	size_t gtk_len;
-	const u8 *r0kh_id;
-	size_t r0kh_id_len;
-	const u8 *rsn;
-	size_t rsn_len;
-	const u8 *rsn_pmkid;
-	const u8 *ric;
-	size_t ric_len;
-};
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse);
-
-
 static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
 			   const u8 *data, size_t data_len)
 {
@@ -728,143 +705,6 @@
 }
 
 
-static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
-			     struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-
-	parse->ftie = ie;
-	parse->ftie_len = ie_len;
-
-	pos = ie + sizeof(struct rsn_ftie);
-	end = ie + ie_len;
-
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		case FTIE_SUBELEM_R1KH_ID:
-			if (pos[1] != FT_R1KH_ID_LEN) {
-				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
-					   "length in FTIE: %d", pos[1]);
-				return -1;
-			}
-			parse->r1kh_id = pos + 2;
-			break;
-		case FTIE_SUBELEM_GTK:
-			parse->gtk = pos + 2;
-			parse->gtk_len = pos[1];
-			break;
-		case FTIE_SUBELEM_R0KH_ID:
-			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
-				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
-					   "length in FTIE: %d", pos[1]);
-				return -1;
-			}
-			parse->r0kh_id = pos + 2;
-			parse->r0kh_id_len = pos[1];
-			break;
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	return 0;
-}
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-	struct wpa_ie_data data;
-	int ret;
-	const struct rsn_ftie *ftie;
-	int prot_ie_count = 0;
-
-	os_memset(parse, 0, sizeof(*parse));
-	if (ies == NULL)
-		return 0;
-
-	pos = ies;
-	end = ies + ies_len;
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		case WLAN_EID_RSN:
-			parse->rsn = pos + 2;
-			parse->rsn_len = pos[1];
-			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
-						   parse->rsn_len + 2,
-						   &data);
-			if (ret < 0) {
-				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
-					   "RSN IE: %d", ret);
-				return -1;
-			}
-			if (data.num_pmkid == 1 && data.pmkid)
-				parse->rsn_pmkid = data.pmkid;
-			break;
-		case WLAN_EID_MOBILITY_DOMAIN:
-			parse->mdie = pos + 2;
-			parse->mdie_len = pos[1];
-			break;
-		case WLAN_EID_FAST_BSS_TRANSITION:
-			if (pos[1] < sizeof(*ftie))
-				return -1;
-			ftie = (const struct rsn_ftie *) (pos + 2);
-			prot_ie_count = ftie->mic_control[1];
-			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
-				return -1;
-			break;
-		case WLAN_EID_RIC_DATA:
-			if (parse->ric == NULL)
-				parse->ric = pos;
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	if (prot_ie_count == 0)
-		return 0; /* no MIC */
-
-	/*
-	 * Check that the protected IE count matches with IEs included in the
-	 * frame.
-	 */
-	if (parse->rsn)
-		prot_ie_count--;
-	if (parse->mdie)
-		prot_ie_count--;
-	if (parse->ftie)
-		prot_ie_count--;
-	if (prot_ie_count < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
-			   "the protected IE count");
-		return -1;
-	}
-
-	if (prot_ie_count == 0 && parse->ric) {
-		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
-			   "included in protected IE count");
-		return -1;
-	}
-
-	/* Determine the end of the RIC IE(s) */
-	pos = parse->ric;
-	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
-	       prot_ie_count) {
-		prot_ie_count--;
-		pos += 2 + pos[1];
-	}
-	parse->ric_len = pos - parse->ric;
-	if (prot_ie_count) {
-		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
-			   "frame", (int) prot_ie_count);
-		return -1;
-	}
-
-	return 0;
-}
-
-
 static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
 				   int vlan_id,
 				   enum wpa_alg alg, const u8 *addr, int idx,
@@ -1207,7 +1047,7 @@
 
 	count = 3;
 	if (parse.ric)
-		count++;
+		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
 	if (ftie->mic_control[1] != count) {
 		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
 			   "Control: received %u expected %u",
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 0e3cb31..56bab23 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -29,11 +29,13 @@
 #include "ap_drv_ops.h"
 #include "ap_config.h"
 #include "wpa_auth.h"
+#include "wpa_auth_glue.h"
 
 
 static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
 				  struct wpa_auth_config *wconf)
 {
+	os_memset(wconf, 0, sizeof(*wconf));
 	wconf->wpa = conf->wpa;
 	wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
 	wconf->wpa_pairwise = conf->wpa_pairwise;
@@ -184,6 +186,9 @@
 					   const u8 *prev_psk)
 {
 	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	if (sta && sta->psk)
+		return sta->psk;
 	return hostapd_get_psk(hapd->conf, addr, prev_psk);
 }
 
@@ -384,7 +389,7 @@
 	ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf,
 			     sizeof(*buf) + data_len);
 	os_free(buf);
-	return -1;
+	return ret;
 }
 
 
@@ -414,7 +419,7 @@
 	os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
 	os_memcpy(&m->u, data, data_len);
 
-	res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen);
+	res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
 	os_free(m);
 	return res;
 }
@@ -547,6 +552,7 @@
 
 void hostapd_deinit_wpa(struct hostapd_data *hapd)
 {
+	ieee80211_tkip_countermeasures_deinit(hapd);
 	rsn_preauth_iface_deinit(hapd);
 	if (hapd->wpa_auth) {
 		wpa_deinit(hapd->wpa_auth);
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 67a5c3b..d82192a 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -86,6 +86,7 @@
 	unsigned int pending_deinit:1;
 	unsigned int started:1;
 	unsigned int mgmt_frame_prot:1;
+	unsigned int rx_eapol_key_secure:1;
 #ifdef CONFIG_IEEE80211R
 	unsigned int ft_completed:1;
 	unsigned int pmk_r1_name_valid:1;
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index 9d4aa67..4db04bb 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -253,19 +253,10 @@
 		capab |= WPA_CAPABILITY_PREAUTH;
 	if (conf->peerkey)
 		capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
-#ifdef ANDROID_BRCM_P2P_PATCH 
-    /* WAR: we should make an get_wpa_rsnie_cap() to get the cap of peer supp 
-	 * Temporally we force tp set replay counter tp 0x3 
-	 * as if wmm is enable in all of supp device
-     */
-    capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2); 
-#else
 	if (conf->wmm_enabled) {
 		/* 4 PTKSA replay counters when using WMM */
 		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
 	}
-#endif /* ANDROID_BRCM_P2P_PATCH */
-
 #ifdef CONFIG_IEEE80211W
 	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
 		capab |= WPA_CAPABILITY_MFPC;
@@ -350,8 +341,7 @@
 		pos += res;
 	}
 #ifdef CONFIG_IEEE80211R
-	if (wpa_auth->conf.wpa_key_mgmt &
-	    (WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK)) {
+	if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
 		res = wpa_write_mdie(&wpa_auth->conf, pos,
 				     buf + sizeof(buf) - pos);
 		if (res < 0)
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 640e8cd..817012e 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -41,7 +41,8 @@
 static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
 #endif /* CONFIG_WPS_UPNP */
 
-static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
+				    const u8 *bssid,
 				    const u8 *ie, size_t ie_len);
 static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
 
@@ -140,7 +141,8 @@
 	hapd->wps_beacon_ie = beacon_ie;
 	wpabuf_free(hapd->wps_probe_resp_ie);
 	hapd->wps_probe_resp_ie = probe_resp_ie;
-	ieee802_11_set_beacon(hapd);
+	if (hapd->beacon_set_done)
+		ieee802_11_set_beacon(hapd);
 	return hostapd_set_ap_wps_ie(hapd);
 }
 
@@ -184,11 +186,26 @@
 }
 
 
+struct wps_stop_reg_data {
+	struct hostapd_data *current_hapd;
+	const u8 *uuid_e;
+};
+
+static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_stop_reg_data *data = ctx;
+	if (hapd != data->current_hapd && hapd->wps != NULL)
+		wps_registrar_complete(hapd->wps->registrar, data->uuid_e);
+	return 0;
+}
+
+
 static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
 				       const u8 *uuid_e)
 {
 	struct hostapd_data *hapd = ctx;
 	char uuid[40];
+	struct wps_stop_reg_data data;
 	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
 		return;
 	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
@@ -196,6 +213,9 @@
 	if (hapd->wps_reg_success_cb)
 		hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx,
 					 mac_addr, uuid_e);
+	data.current_hapd = hapd;
+	data.uuid_e = uuid_e;
+	hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
 }
 
 
@@ -240,6 +260,20 @@
 }
 
 
+static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
+			      size_t attr_len)
+{
+	size_t blen = attr_len * 2 + 1;
+	char *buf = os_malloc(blen);
+	if (buf) {
+		wpa_snprintf_hex(buf, blen, attr, attr_len);
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			WPS_EVENT_NEW_AP_SETTINGS "%s", buf);
+		os_free(buf);
+	}
+}
+
+
 static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
 {
 	const struct wps_credential *cred = ctx;
@@ -269,15 +303,15 @@
 
 	if ((hapd->conf->wps_cred_processing == 1 ||
 	     hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
-		size_t blen = cred->cred_attr_len * 2 + 1;
-		char *_buf = os_malloc(blen);
-		if (_buf) {
-			wpa_snprintf_hex(_buf, blen,
-					 cred->cred_attr, cred->cred_attr_len);
-			wpa_msg(hapd->msg_ctx, MSG_INFO, "%s%s",
-				WPS_EVENT_NEW_AP_SETTINGS, _buf);
-			os_free(_buf);
-		}
+		hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len);
+	} else if (hapd->conf->wps_cred_processing == 1 ||
+		   hapd->conf->wps_cred_processing == 2) {
+		struct wpabuf *attr;
+		attr = wpabuf_alloc(200);
+		if (attr && wps_build_credential_wrap(attr, cred) == 0)
+			hapd_new_ap_event(hapd, wpabuf_head_u8(attr),
+					  wpabuf_len(attr));
+		wpabuf_free(attr);
 	} else
 		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
 
@@ -565,18 +599,22 @@
 
 	switch (event) {
 	case WPS_EV_M2D:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D);
 		break;
 	case WPS_EV_FAIL:
 		hostapd_wps_event_fail(hapd, &data->fail);
 		break;
 	case WPS_EV_SUCCESS:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS);
 		break;
 	case WPS_EV_PWD_AUTH_FAIL:
 		hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
 		break;
 	case WPS_EV_PBC_OVERLAP:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP);
 		break;
 	case WPS_EV_PBC_TIMEOUT:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT);
 		break;
 	case WPS_EV_ER_AP_ADD:
 		break;
@@ -762,8 +800,14 @@
 	}
 
 	wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
-	wps->dev.rf_bands = hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
-		WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+
+	if (conf->wps_rf_bands) {
+		wps->dev.rf_bands = conf->wps_rf_bands;
+	} else {
+		wps->dev.rf_bands =
+			hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
+			WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+	}
 
 	if (conf->wpa & WPA_PROTO_RSN) {
 		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
@@ -1076,7 +1120,8 @@
 #endif /* CONFIG_WPS_OOB */
 
 
-static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr,
+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
+				    const u8 *bssid,
 				    const u8 *ie, size_t ie_len)
 {
 	struct hostapd_data *hapd = ctx;
@@ -1175,7 +1220,7 @@
 	}
 #endif /* CONFIG_WPS_STRICT */
 
-	if (!sta) {
+	if (!sta || !(sta->flags & WLAN_STA_WPS)) {
 		wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
 		return 0;
 	}
@@ -1240,6 +1285,7 @@
 	struct hostapd_data *hapd = eloop_data;
 	wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
 	hostapd_wps_ap_pin_disable(hapd);
+	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED);
 }
 
 
@@ -1304,7 +1350,7 @@
 	struct wps_ap_pin_data data;
 
 	pin = wps_generate_pin();
-	os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%u", pin);
+	os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
 	data.timeout = timeout;
 	hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
 	return hapd->conf->ap_pin;
diff --git a/src/common/defs.h b/src/common/defs.h
index 8abec07..6082053 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -76,6 +76,11 @@
 		wpa_key_mgmt_wpa_psk(akm);
 }
 
+static inline int wpa_key_mgmt_wpa_any(int akm)
+{
+	return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
+}
+
 
 #define WPA_PROTO_WPA BIT(0)
 #define WPA_PROTO_RSN BIT(1)
@@ -267,4 +272,21 @@
 	NUM_HOSTAPD_MODES
 };
 
+/**
+ * enum wpa_ctrl_req_type - Control interface request types
+ */
+enum wpa_ctrl_req_type {
+	WPA_CTRL_REQ_UNKNOWN,
+	WPA_CTRL_REQ_EAP_IDENTITY,
+	WPA_CTRL_REQ_EAP_PASSWORD,
+	WPA_CTRL_REQ_EAP_NEW_PASSWORD,
+	WPA_CTRL_REQ_EAP_PIN,
+	WPA_CTRL_REQ_EAP_OTP,
+	WPA_CTRL_REQ_EAP_PASSPHRASE,
+	NUM_WPA_CTRL_REQS
+};
+
+/* Maximum number of EAP methods to store for EAP server user information */
+#define EAP_MAX_METHODS 8
+
 #endif /* DEFS_H */
diff --git a/src/common/gas.c b/src/common/gas.c
new file mode 100644
index 0000000..babdaa3
--- /dev/null
+++ b/src/common/gas.c
@@ -0,0 +1,279 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "ieee802_11_defs.h"
+#include "gas.h"
+
+
+static struct wpabuf *
+gas_build_req(u8 action, u8 dialog_token, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(100 + size);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, action);
+	wpabuf_put_u8(buf, dialog_token);
+
+	return buf;
+}
+
+
+static struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
+{
+	return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
+			     size);
+}
+
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token)
+{
+	return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
+}
+
+
+static struct wpabuf *
+gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
+	       u8 more, u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(100 + size);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, action);
+	wpabuf_put_u8(buf, dialog_token);
+	wpabuf_put_le16(buf, status_code);
+	if (action == WLAN_PA_GAS_COMEBACK_RESP)
+		wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
+	wpabuf_put_le16(buf, comeback_delay);
+
+	return buf;
+}
+
+
+struct wpabuf *
+gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
+		       size_t size)
+{
+	return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
+			      status_code, 0, 0, comeback_delay, size);
+}
+
+
+static struct wpabuf *
+gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
+			u16 comeback_delay, size_t size)
+{
+	return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
+			      status_code, frag_id, more, comeback_delay,
+			      size);
+}
+
+
+/**
+ * gas_add_adv_proto_anqp - Add an Advertisement Protocol element
+ * @buf: Buffer to which the element is added
+ * @query_resp_len_limit: Query Response Length Limit in units of 256 octets
+ * @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
+ *
+ *
+ * @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
+ * that the maximum limit is determined by the maximum allowable number of
+ * fragments in the GAS Query Response Fragment ID.
+ */
+static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
+				   u8 pame_bi)
+{
+	/* Advertisement Protocol IE */
+	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+	wpabuf_put_u8(buf, 2); /* Length */
+	wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
+		      (pame_bi ? 0x80 : 0));
+	/* Advertisement Protocol */
+	wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
+}
+
+
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_initial_req(dialog_token, 4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0, 0);
+
+	wpabuf_put(buf, 2); /* Query Request Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+					    u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
+				     4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+	wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+						u16 status_code,
+						u16 comeback_delay,
+						struct wpabuf *payload)
+{
+	struct wpabuf *buf;
+
+	buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+					  comeback_delay,
+					  payload ? wpabuf_len(payload) : 0);
+	if (buf == NULL)
+		return NULL;
+
+	if (payload)
+		wpabuf_put_buf(buf, payload);
+
+	gas_anqp_set_len(buf);
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+					     u8 frag_id, u8 more,
+					     u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_comeback_resp(dialog_token, status_code,
+				      frag_id, more, comeback_delay, 4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+	wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+						 u16 status_code,
+						 u8 frag_id, u8 more,
+						 u16 comeback_delay,
+						 struct wpabuf *payload)
+{
+	struct wpabuf *buf;
+
+	buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+					   more, comeback_delay,
+					   payload ? wpabuf_len(payload) : 0);
+	if (buf == NULL)
+		return NULL;
+
+	if (payload)
+		wpabuf_put_buf(buf, payload);
+
+	gas_anqp_set_len(buf);
+
+	return buf;
+}
+
+
+/**
+ * gas_anqp_set_len - Set Query Request/Response Length
+ * @buf: GAS message
+ *
+ * This function is used to update the Query Request/Response Length field once
+ * the payload has been filled.
+ */
+void gas_anqp_set_len(struct wpabuf *buf)
+{
+	u8 action;
+	size_t offset;
+	u8 *len;
+
+	if (buf == NULL || wpabuf_len(buf) < 2)
+		return;
+
+	action = *(wpabuf_head_u8(buf) + 1);
+	switch (action) {
+	case WLAN_PA_GAS_INITIAL_REQ:
+		offset = 3 + 4;
+		break;
+	case WLAN_PA_GAS_INITIAL_RESP:
+		offset = 7 + 4;
+		break;
+	case WLAN_PA_GAS_COMEBACK_RESP:
+		offset = 8 + 4;
+		break;
+	default:
+		return;
+	}
+
+	if (wpabuf_len(buf) < offset + 2)
+		return;
+
+	len = wpabuf_mhead_u8(buf) + offset;
+	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+}
+
+
+/**
+ * gas_anqp_add_element - Add ANQP element header
+ * @buf: GAS message
+ * @info_id: ANQP Info ID
+ * Returns: Pointer to the Length field for gas_anqp_set_element_len()
+ */
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
+{
+	wpabuf_put_le16(buf, info_id);
+	return wpabuf_put(buf, 2); /* Length to be filled */
+}
+
+
+/**
+ * gas_anqp_set_element_len - Update ANQP element Length field
+ * @buf: GAS message
+ * @len_pos: Length field position from gas_anqp_add_element()
+ *
+ * This function is called after the ANQP element payload has been added to the
+ * buffer.
+ */
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
+{
+	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+}
diff --git a/src/common/gas.h b/src/common/gas.h
new file mode 100644
index 0000000..2f8d2cb
--- /dev/null
+++ b/src/common/gas.h
@@ -0,0 +1,42 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef GAS_H
+#define GAS_H
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token);
+struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code,
+				       u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+					    u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+						u16 status_code,
+						u16 comeback_delay,
+						struct wpabuf *payload);
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+					     u8 frag_id, u8 more,
+					     u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+						 u16 status_code,
+						 u8 frag_id, u8 more,
+						 u16 comeback_delay,
+						 struct wpabuf *payload);
+void gas_anqp_set_len(struct wpabuf *buf);
+
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id);
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos);
+
+#endif /* GAS_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index ee41b3a..43cb2c6 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -259,6 +259,10 @@
 				break;
 			elems->link_id = pos;
 			break;
+		case WLAN_EID_INTERWORKING:
+			elems->interworking = pos;
+			elems->interworking_len = elen;
+			break;
 		default:
 			unknown++;
 			if (!show_errors)
@@ -345,3 +349,43 @@
 
 	return buf;
 }
+
+
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
+{
+	u16 fc, type, stype;
+
+	/*
+	 * PS-Poll frames are 16 bytes. All other frames are
+	 * 24 bytes or longer.
+	 */
+	if (len < 16)
+		return NULL;
+
+	fc = le_to_host16(hdr->frame_control);
+	type = WLAN_FC_GET_TYPE(fc);
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	switch (type) {
+	case WLAN_FC_TYPE_DATA:
+		if (len < 24)
+			return NULL;
+		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
+		case WLAN_FC_FROMDS | WLAN_FC_TODS:
+		case WLAN_FC_TODS:
+			return hdr->addr1;
+		case WLAN_FC_FROMDS:
+			return hdr->addr2;
+		default:
+			return NULL;
+		}
+	case WLAN_FC_TYPE_CTRL:
+		if (stype != WLAN_FC_STYPE_PSPOLL)
+			return NULL;
+		return hdr->addr1;
+	case WLAN_FC_TYPE_MGMT:
+		return hdr->addr3;
+	default:
+		return NULL;
+	}
+}
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 0c90fa4..60f0974 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -42,6 +42,7 @@
 	const u8 *vendor_ht_cap;
 	const u8 *p2p;
 	const u8 *link_id;
+	const u8 *interworking;
 
 	u8 ssid_len;
 	u8 supp_rates_len;
@@ -67,6 +68,7 @@
 	u8 ht_operation_len;
 	u8 vendor_ht_cap_len;
 	u8 p2p_len;
+	u8 interworking_len;
 };
 
 typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
@@ -77,5 +79,7 @@
 int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
 					    u32 oui_type);
+struct ieee80211_hdr;
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len);
 
 #endif /* IEEE802_11_COMMON_H */
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 86868c0..66801fd 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -153,7 +153,17 @@
 #define WLAN_STATUS_INVALID_PMKID 53
 #define WLAN_STATUS_INVALID_MDIE 54
 #define WLAN_STATUS_INVALID_FTIE 55
+#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59
+#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60
+#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61
+#define WLAN_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62
+#define WLAN_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63
+#define WLAN_STATUS_REQ_REFUSED_HOME 64
+#define WLAN_STATUS_ADV_SRV_UNREACHABLE 65
+#define WLAN_STATUS_REQ_REFUSED_SSPN 67
+#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
 #define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_TRANSMISSION_FAILURE 79
 
 /* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
 #define WLAN_REASON_UNSPECIFIED 1
@@ -219,12 +229,16 @@
 #define WLAN_EID_RIC_DATA 57
 #define WLAN_EID_HT_OPERATION 61
 #define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_TIME_ADVERTISEMENT 69
 #define WLAN_EID_20_40_BSS_COEXISTENCE 72
 #define WLAN_EID_20_40_BSS_INTOLERANT 73
 #define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
 #define WLAN_EID_MMIE 76
+#define WLAN_EID_TIME_ZONE 98
 #define WLAN_EID_LINK_ID 101
+#define WLAN_EID_INTERWORKING 107
 #define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_ROAMING_CONSORTIUM 111
 #define WLAN_EID_EXT_CAPAB 127
 #define WLAN_EID_VENDOR_SPECIFIC 221
 
@@ -239,6 +253,8 @@
 #define WLAN_ACTION_FT 6
 #define WLAN_ACTION_HT 7
 #define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_WNM 10
+#define WLAN_ACTION_UNPROTECTED_WNM 11
 #define WLAN_ACTION_TDLS 12
 #define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
 #define WLAN_ACTION_VENDOR_SPECIFIC 127
@@ -249,6 +265,7 @@
 #define WLAN_PA_GAS_INITIAL_RESP 11
 #define WLAN_PA_GAS_COMEBACK_REQ 12
 #define WLAN_PA_GAS_COMEBACK_RESP 13
+#define WLAN_TDLS_DISCOVERY_RESPONSE 14
 
 /* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
 #define WLAN_SA_QUERY_REQUEST 0
@@ -274,33 +291,81 @@
 #define WLAN_TIMEOUT_KEY_LIFETIME 2
 #define WLAN_TIMEOUT_ASSOC_COMEBACK 3
 
-/* Advertisement Protocol ID definitions (IEEE 802.11u) */
+/* Interworking element (IEEE 802.11u) - Access Network Options */
+#define INTERWORKING_ANO_ACCESS_NETWORK_MASK 0x0f
+#define INTERWORKING_ANO_INTERNET 0x10
+#define INTERWORKING_ANO_ASRA 0x20
+#define INTERWORKING_ANO_ESR 0x40
+#define INTERWORKING_ANO_UESA 0x80
+
+#define INTERWORKING_ANT_PRIVATE 0
+#define INTERWORKING_ANT_PRIVATE_WITH_GUEST 1
+#define INTERWORKING_ANT_CHARGEABLE_PUBLIC 2
+#define INTERWORKING_ANT_FREE_PUBLIC 3
+#define INTERWORKING_ANT_PERSONAL_DEVICE 4
+#define INTERWORKING_ANT_EMERGENCY_SERVICES 5
+#define INTERWORKING_ANT_TEST 6
+#define INTERWORKING_ANT_WILDCARD 15
+
+/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */
 enum adv_proto_id {
-	NATIVE_QUERY_PROTOCOL = 0,
+	ACCESS_NETWORK_QUERY_PROTOCOL = 0,
 	MIH_INFO_SERVICE = 1,
 	MIH_CMD_AND_EVENT_DISCOVERY = 2,
 	EMERGENCY_ALERT_SYSTEM = 3,
-	LOCATION_TO_SERVICE = 4,
 	ADV_PROTO_VENDOR_SPECIFIC = 221
 };
 
-/* Native Query Protocol info ID definitions (IEEE 802.11u) */
-enum nqp_info_id {
-	NQP_CAPABILITY_LIST = 256,
-	NQP_VENUE_NAME = 257,
-	NQP_EMERGENCY_CALL_NUMBER = 258,
-	NQP_NETWORK_AUTH_TYPE = 259,
-	NQP_ROAMING_CONSORTIUM = 260,
-	NQP_IP_ADDR_TYPE_AVAILABILITY = 261,
-	NQP_NAI_REALM = 262,
-	NQP_3GPP_CELLULAR_NETWORK = 263,
-	NQP_AP_GEOSPATIAL_LOCATION = 264,
-	NQP_AP_CIVIC_LOCATION = 265,
-	NQP_DOMAIN_NAME = 266,
-	NQP_EMERGENCY_ALERT_URI = 267,
-	NQP_VENDOR_SPECIFIC = 56797
+/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */
+enum anqp_info_id {
+	ANQP_QUERY_LIST = 256,
+	ANQP_CAPABILITY_LIST = 257,
+	ANQP_VENUE_NAME = 258,
+	ANQP_EMERGENCY_CALL_NUMBER = 259,
+	ANQP_NETWORK_AUTH_TYPE = 260,
+	ANQP_ROAMING_CONSORTIUM = 261,
+	ANQP_IP_ADDR_TYPE_AVAILABILITY = 262,
+	ANQP_NAI_REALM = 263,
+	ANQP_3GPP_CELLULAR_NETWORK = 264,
+	ANQP_AP_GEOSPATIAL_LOCATION = 265,
+	ANQP_AP_CIVIC_LOCATION = 266,
+	ANQP_AP_LOCATION_PUBLIC_URI = 267,
+	ANQP_DOMAIN_NAME = 268,
+	ANQP_EMERGENCY_ALERT_URI = 269,
+	ANQP_EMERGENCY_NAI = 271,
+	ANQP_VENDOR_SPECIFIC = 56797
 };
 
+/* NAI Realm list - EAP Method subfield - Authentication Parameter ID */
+enum nai_realm_eap_auth_param {
+	NAI_REALM_EAP_AUTH_EXPANDED_EAP_METHOD = 1,
+	NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH = 2,
+	NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD = 3,
+	NAI_REALM_EAP_AUTH_EXPANDED_INNER_EAP_METHOD = 4,
+	NAI_REALM_EAP_AUTH_CRED_TYPE = 5,
+	NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE = 6,
+	NAI_REALM_EAP_AUTH_VENDOR_SPECIFIC = 221
+};
+
+enum nai_realm_eap_auth_inner_non_eap {
+	NAI_REALM_INNER_NON_EAP_PAP = 1,
+	NAI_REALM_INNER_NON_EAP_CHAP = 2,
+	NAI_REALM_INNER_NON_EAP_MSCHAP = 3,
+	NAI_REALM_INNER_NON_EAP_MSCHAPV2 = 4
+};
+
+enum nai_realm_eap_cred_type {
+	NAI_REALM_CRED_TYPE_SIM = 1,
+	NAI_REALM_CRED_TYPE_USIM = 2,
+	NAI_REALM_CRED_TYPE_NFC_SECURE_ELEMENT = 3,
+	NAI_REALM_CRED_TYPE_HARDWARE_TOKEN = 4,
+	NAI_REALM_CRED_TYPE_SOFTOKEN = 5,
+	NAI_REALM_CRED_TYPE_CERTIFICATE = 6,
+	NAI_REALM_CRED_TYPE_USERNAME_PASSWORD = 7,
+	NAI_REALM_CRED_TYPE_NONE = 8,
+	NAI_REALM_CRED_TYPE_ANONYMOUS = 9,
+	NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
+};
 
 #ifdef _MSC_VER
 #pragma pack(push, 1)
@@ -436,6 +501,18 @@
 					/* Vendor-specific content */
 					u8 variable[0];
 				} STRUCT_PACKED vs_public_action;
+				struct {
+					u8 action; /* 7 */
+					u8 dialog_token;
+					u8 req_mode;
+					le16 disassoc_timer;
+					u8 validity_interval;
+					/* BSS Termination Duration (optional),
+					 * Session Information URL (optional),
+					 * BSS Transition Candidate List
+					 * Entries */
+					u8 variable[0];
+				} STRUCT_PACKED bss_tm_req;
 			} u;
 		} STRUCT_PACKED action;
 	} u;
@@ -541,7 +618,7 @@
 #define OP_MODE_MIXED                   3
 
 #define HT_INFO_OPERATION_MODE_OP_MODE_MASK	\
-		((le16) (0x0001 | 0x0002))
+		(0x0001 | 0x0002)
 #define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET		0
 #define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT	((u8) BIT(2))
 #define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT	((u8) BIT(3))
@@ -600,6 +677,10 @@
 
 } STRUCT_PACKED;
 
+#define WMM_QOSINFO_STA_AC_MASK 0x0f
+#define WMM_QOSINFO_STA_SP_MASK 0x03
+#define WMM_QOSINFO_STA_SP_SHIFT 5
+
 #define WMM_AC_AIFSN_MASK 0x0f
 #define WMM_AC_AIFNS_SHIFT 0
 #define WMM_AC_ACM 0x10
@@ -628,7 +709,7 @@
 	u8 oui_type; /* 2 */
 	u8 oui_subtype; /* 1 */
 	u8 version; /* 1 for WMM version 1.0 */
-	u8 qos_info; /* AP/STA specif QoS info */
+	u8 qos_info; /* AP/STA specific QoS info */
 	u8 reserved; /* 0 */
 	struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
 
@@ -797,4 +878,44 @@
 #define WLAN_AKM_SUITE_8021X		0x000FAC01
 #define WLAN_AKM_SUITE_PSK		0x000FAC02
 
+
+/* IEEE 802.11v - WNM Action field values */
+enum wnm_action {
+	WNM_EVENT_REQ = 0,
+	WNM_EVENT_REPORT = 1,
+	WNM_DIAGNOSTIC_REQ = 2,
+	WNM_DIAGNOSTIC_REPORT = 3,
+	WNM_LOCATION_CFG_REQ = 4,
+	WNM_LOCATION_CFG_RESP = 5,
+	WNM_BSS_TRANS_MGMT_QUERY = 6,
+	WNM_BSS_TRANS_MGMT_REQ = 7,
+	WNM_BSS_TRANS_MGMT_RESP = 8,
+	WNM_FMS_REQ = 9,
+	WNM_FMS_RESP = 10,
+	WNM_COLLOCATED_INTERFERENCE_REQ = 11,
+	WNM_COLLOCATED_INTERFERENCE_REPORT = 12,
+	WNM_TFS_REQ = 13,
+	WNM_TFS_RESP = 14,
+	WNM_TFS_NOTIFY = 15,
+	WNM_SLEEP_MODE_REQ = 16,
+	WNM_SLEEP_MODE_RESP = 17,
+	WNM_TIM_BROADCAST_REQ = 18,
+	WNM_TIM_BROADCAST_RESP = 19,
+	WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20,
+	WNM_CHANNEL_USAGE_REQ = 21,
+	WNM_CHANNEL_USAGE_RESP = 22,
+	WNM_DMS_REQ = 23,
+	WNM_DMS_RESP = 24,
+	WNM_TIMING_MEASUREMENT_REQ = 25,
+	WNM_NOTIFICATION_REQ = 26,
+	WNM_NOTIFICATION_RESP = 27
+};
+
+/* IEEE 802.11v - BSS Transition Management Request - Request Mode */
+#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0)
+#define WNM_BSS_TM_REQ_ABRIDGED BIT(1)
+#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2)
+#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
+#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+
 #endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/version.h b/src/common/version.h
index ba2d2c0..7afba48 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 "0.8.x" VERSION_STR_POSTFIX
+#define VERSION_STR "2.0-devel" VERSION_STR_POSTFIX
 
 #endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index eb2745e..24a61e4 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -188,6 +188,154 @@
 
 	return 0;
 }
+
+
+static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
+			     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+
+	parse->ftie = ie;
+	parse->ftie_len = ie_len;
+
+	pos = ie + sizeof(struct rsn_ftie);
+	end = ie + ie_len;
+
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		case FTIE_SUBELEM_R1KH_ID:
+			if (pos[1] != FT_R1KH_ID_LEN) {
+				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
+					   "length in FTIE: %d", pos[1]);
+				return -1;
+			}
+			parse->r1kh_id = pos + 2;
+			break;
+		case FTIE_SUBELEM_GTK:
+			parse->gtk = pos + 2;
+			parse->gtk_len = pos[1];
+			break;
+		case FTIE_SUBELEM_R0KH_ID:
+			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
+				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
+					   "length in FTIE: %d", pos[1]);
+				return -1;
+			}
+			parse->r0kh_id = pos + 2;
+			parse->r0kh_id_len = pos[1];
+			break;
+#ifdef CONFIG_IEEE80211W
+		case FTIE_SUBELEM_IGTK:
+			parse->igtk = pos + 2;
+			parse->igtk_len = pos[1];
+			break;
+#endif /* CONFIG_IEEE80211W */
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	return 0;
+}
+
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
+		     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+	struct wpa_ie_data data;
+	int ret;
+	const struct rsn_ftie *ftie;
+	int prot_ie_count = 0;
+
+	os_memset(parse, 0, sizeof(*parse));
+	if (ies == NULL)
+		return 0;
+
+	pos = ies;
+	end = ies + ies_len;
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		case WLAN_EID_RSN:
+			parse->rsn = pos + 2;
+			parse->rsn_len = pos[1];
+			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
+						   parse->rsn_len + 2,
+						   &data);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
+					   "RSN IE: %d", ret);
+				return -1;
+			}
+			if (data.num_pmkid == 1 && data.pmkid)
+				parse->rsn_pmkid = data.pmkid;
+			break;
+		case WLAN_EID_MOBILITY_DOMAIN:
+			parse->mdie = pos + 2;
+			parse->mdie_len = pos[1];
+			break;
+		case WLAN_EID_FAST_BSS_TRANSITION:
+			if (pos[1] < sizeof(*ftie))
+				return -1;
+			ftie = (const struct rsn_ftie *) (pos + 2);
+			prot_ie_count = ftie->mic_control[1];
+			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
+				return -1;
+			break;
+		case WLAN_EID_TIMEOUT_INTERVAL:
+			parse->tie = pos + 2;
+			parse->tie_len = pos[1];
+			break;
+		case WLAN_EID_RIC_DATA:
+			if (parse->ric == NULL)
+				parse->ric = pos;
+			break;
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	if (prot_ie_count == 0)
+		return 0; /* no MIC */
+
+	/*
+	 * Check that the protected IE count matches with IEs included in the
+	 * frame.
+	 */
+	if (parse->rsn)
+		prot_ie_count--;
+	if (parse->mdie)
+		prot_ie_count--;
+	if (parse->ftie)
+		prot_ie_count--;
+	if (prot_ie_count < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
+			   "the protected IE count");
+		return -1;
+	}
+
+	if (prot_ie_count == 0 && parse->ric) {
+		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
+			   "included in protected IE count");
+		return -1;
+	}
+
+	/* Determine the end of the RIC IE(s) */
+	pos = parse->ric;
+	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
+	       prot_ie_count) {
+		prot_ie_count--;
+		pos += 2 + pos[1];
+	}
+	parse->ric_len = pos - parse->ric;
+	if (prot_ie_count) {
+		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
+			   "frame", (int) prot_ie_count);
+		return -1;
+	}
+
+	return 0;
+}
 #endif /* CONFIG_IEEE80211R */
 
 
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index fe79cee..69437a7 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -358,4 +358,27 @@
 		       const u8 *ie2, size_t ie2len);
 int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
 
+struct wpa_ft_ies {
+	const u8 *mdie;
+	size_t mdie_len;
+	const u8 *ftie;
+	size_t ftie_len;
+	const u8 *r1kh_id;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *r0kh_id;
+	size_t r0kh_id_len;
+	const u8 *rsn;
+	size_t rsn_len;
+	const u8 *rsn_pmkid;
+	const u8 *tie;
+	size_t tie_len;
+	const u8 *igtk;
+	size_t igtk_len;
+	const u8 *ric;
+	size_t ric_len;
+};
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
+
 #endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index 88d3a02..3b25f77 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -21,6 +21,7 @@
 #endif /* CONFIG_CTRL_IFACE_UNIX */
 
 #ifdef ANDROID
+#include <dirent.h>
 #include <cutils/sockets.h>
 #include "private/android_filesystem_config.h"
 #endif /* ANDROID */
@@ -175,6 +176,56 @@
 	os_free(ctrl);
 }
 
+
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void)
+{
+	DIR *dir;
+	struct dirent entry;
+	struct dirent *result;
+	size_t dirnamelen;
+	int prefixlen = os_strlen(CONFIG_CTRL_IFACE_CLIENT_PREFIX);
+	size_t maxcopy;
+	char pathname[PATH_MAX];
+	char *namep;
+
+	if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
+		return;
+
+	dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
+					  CONFIG_CTRL_IFACE_CLIENT_DIR);
+	if (dirnamelen >= sizeof(pathname)) {
+		closedir(dir);
+		return;
+	}
+	namep = pathname + dirnamelen;
+	maxcopy = PATH_MAX - dirnamelen;
+	while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
+		if (os_strncmp(entry.d_name, CONFIG_CTRL_IFACE_CLIENT_PREFIX,
+			       prefixlen) == 0) {
+			if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+				unlink(pathname);
+		}
+	}
+	closedir(dir);
+}
+#endif /* ANDROID */
+
+#else /* CONFIG_CTRL_IFACE_UNIX */
+
+#ifdef ANDROID
+void wpa_ctrl_cleanup(void)
+{
+}
+#endif /* ANDROID */
+
 #endif /* CONFIG_CTRL_IFACE_UNIX */
 
 
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
old mode 100644
new mode 100755
index 35e5e3d..d13ba02
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -100,10 +100,8 @@
 /** P2P device found */
 #define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
 
-#ifdef ANDROID_BRCM_P2P_PATCH
 /** P2P device lost */
 #define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST "
-#endif
 
 /** A P2P device requested GO negotiation, but we were not ready to start the
  * negotiation */
@@ -130,6 +128,10 @@
 #define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
 #define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
 #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
+#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
+
+#define INTERWORKING_AP "INTERWORKING-AP "
+#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
 
 /* hostapd control interface - fixed message prefixes */
 #define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
@@ -267,6 +269,17 @@
  */
 int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
 
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void);
+#endif /* ANDROID */
+
 #ifdef CONFIG_CTRL_IFACE_UDP
 #define WPA_CTRL_IFACE_PORT 9877
 #define WPA_GLOBAL_CTRL_IFACE_PORT 9878
diff --git a/src/crypto/Makefile b/src/crypto/Makefile
index 69aa16a..b221dd4 100644
--- a/src/crypto/Makefile
+++ b/src/crypto/Makefile
@@ -12,6 +12,7 @@
 CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
 CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
 #CFLAGS += -DALL_DH_GROUPS
+CFLAGS += -DCONFIG_SHA256
 
 LIB_OBJS= \
 	aes-cbc.o \
@@ -40,6 +41,7 @@
 	sha1-tlsprf.o \
 	sha1-tprf.o \
 	sha256.o \
+	sha256-tlsprf.o \
 	sha256-internal.o
 
 LIB_OBJS += crypto_internal.o
@@ -48,6 +50,7 @@
 LIB_OBJS += crypto_internal-rsa.o
 LIB_OBJS += tls_internal.o
 LIB_OBJS += fips_prf_internal.o
+LIB_OBJS += random.o
 
 
 libcrypto.a: $(LIB_OBJS)
diff --git a/src/crypto/aes-internal-dec.c b/src/crypto/aes-internal-dec.c
index 2d32c03..a0fc45b 100644
--- a/src/crypto/aes-internal-dec.c
+++ b/src/crypto/aes-internal-dec.c
@@ -32,7 +32,7 @@
  *
  * @return	the number of rounds for the given cipher key size.
  */
-void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
+static void rijndaelKeySetupDec(u32 rk[/*44*/], const u8 cipherKey[])
 {
 	int Nr = 10, i, j;
 	u32 temp;
diff --git a/src/crypto/aes-internal-enc.c b/src/crypto/aes-internal-enc.c
index 2f19826..8726aa7 100644
--- a/src/crypto/aes-internal-enc.c
+++ b/src/crypto/aes-internal-enc.c
@@ -27,7 +27,7 @@
 #include "crypto.h"
 #include "aes_i.h"
 
-void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
+static void rijndaelEncrypt(const u32 rk[/*44*/], const u8 pt[16], u8 ct[16])
 {
 	u32 s0, s1, s2, s3, t0, t1, t2, t3;
 	const int Nr = 10;
diff --git a/src/crypto/crypto.h b/src/crypto/crypto.h
index 587b5a9..6dca191 100644
--- a/src/crypto/crypto.h
+++ b/src/crypto/crypto.h
@@ -155,7 +155,8 @@
 
 enum crypto_hash_alg {
 	CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
-	CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1
+	CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,
+	CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
 };
 
 struct crypto_hash;
diff --git a/src/crypto/crypto_internal-rsa.c b/src/crypto/crypto_internal-rsa.c
index 205042c..7f0a5cf 100644
--- a/src/crypto/crypto_internal-rsa.c
+++ b/src/crypto/crypto_internal-rsa.c
@@ -17,7 +17,6 @@
 #include "common.h"
 #include "crypto.h"
 #include "tls/rsa.h"
-#include "tls/bignum.h"
 #include "tls/pkcs1.h"
 #include "tls/pkcs8.h"
 
diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c
index 8fdba65..9362fe1 100644
--- a/src/crypto/crypto_internal.c
+++ b/src/crypto/crypto_internal.c
@@ -1,6 +1,6 @@
 /*
  * Crypto wrapper for internal crypto implementation
- * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,6 +16,7 @@
 
 #include "common.h"
 #include "crypto.h"
+#include "sha256_i.h"
 #include "sha1_i.h"
 #include "md5_i.h"
 
@@ -24,6 +25,9 @@
 	union {
 		struct MD5Context md5;
 		struct SHA1Context sha1;
+#ifdef CONFIG_SHA256
+		struct sha256_state sha256;
+#endif /* CONFIG_SHA256 */
 	} u;
 	u8 key[64];
 	size_t key_len;
@@ -35,7 +39,7 @@
 {
 	struct crypto_hash *ctx;
 	u8 k_pad[64];
-	u8 tk[20];
+	u8 tk[32];
 	size_t i;
 
 	ctx = os_zalloc(sizeof(*ctx));
@@ -51,6 +55,11 @@
 	case CRYPTO_HASH_ALG_SHA1:
 		SHA1Init(&ctx->u.sha1);
 		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+		sha256_init(&ctx->u.sha256);
+		break;
+#endif /* CONFIG_SHA256 */
 	case CRYPTO_HASH_ALG_HMAC_MD5:
 		if (key_len > sizeof(k_pad)) {
 			MD5Init(&ctx->u.md5);
@@ -63,7 +72,8 @@
 		ctx->key_len = key_len;
 
 		os_memcpy(k_pad, key, key_len);
-		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
 		for (i = 0; i < sizeof(k_pad); i++)
 			k_pad[i] ^= 0x36;
 		MD5Init(&ctx->u.md5);
@@ -81,12 +91,34 @@
 		ctx->key_len = key_len;
 
 		os_memcpy(k_pad, key, key_len);
-		os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
 		for (i = 0; i < sizeof(k_pad); i++)
 			k_pad[i] ^= 0x36;
 		SHA1Init(&ctx->u.sha1);
 		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
 		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		if (key_len > sizeof(k_pad)) {
+			sha256_init(&ctx->u.sha256);
+			sha256_process(&ctx->u.sha256, key, key_len);
+			sha256_done(&ctx->u.sha256, tk);
+			key = tk;
+			key_len = 32;
+		}
+		os_memcpy(ctx->key, key, key_len);
+		ctx->key_len = key_len;
+
+		os_memcpy(k_pad, key, key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x36;
+		sha256_init(&ctx->u.sha256);
+		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+		break;
+#endif /* CONFIG_SHA256 */
 	default:
 		os_free(ctx);
 		return NULL;
@@ -110,6 +142,14 @@
 	case CRYPTO_HASH_ALG_HMAC_SHA1:
 		SHA1Update(&ctx->u.sha1, data, len);
 		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		sha256_process(&ctx->u.sha256, data, len);
+		break;
+#endif /* CONFIG_SHA256 */
+	default:
+		break;
 	}
 }
 
@@ -146,6 +186,17 @@
 		*len = 20;
 		SHA1Final(mac, &ctx->u.sha1);
 		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+		if (*len < 32) {
+			*len = 32;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 32;
+		sha256_done(&ctx->u.sha256, mac);
+		break;
+#endif /* CONFIG_SHA256 */
 	case CRYPTO_HASH_ALG_HMAC_MD5:
 		if (*len < 16) {
 			*len = 16;
@@ -186,6 +237,31 @@
 		SHA1Update(&ctx->u.sha1, mac, 20);
 		SHA1Final(mac, &ctx->u.sha1);
 		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		if (*len < 32) {
+			*len = 32;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 32;
+
+		sha256_done(&ctx->u.sha256, mac);
+
+		os_memcpy(k_pad, ctx->key, ctx->key_len);
+		os_memset(k_pad + ctx->key_len, 0,
+			  sizeof(k_pad) - ctx->key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x5c;
+		sha256_init(&ctx->u.sha256);
+		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+		sha256_process(&ctx->u.sha256, mac, 32);
+		sha256_done(&ctx->u.sha256, mac);
+		break;
+#endif /* CONFIG_SHA256 */
+	default:
+		os_free(ctx);
+		return -1;
 	}
 
 	os_free(ctx);
diff --git a/src/crypto/dh_group5.c b/src/crypto/dh_group5.c
index 8c475bf..2a67d99 100644
--- a/src/crypto/dh_group5.c
+++ b/src/crypto/dh_group5.c
@@ -22,7 +22,7 @@
 void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
 {
 	*publ = dh_init(dh_groups_get(5), priv);
-	if (*publ == 0)
+	if (*publ == NULL)
 		return NULL;
 	return (void *) 1;
 }
diff --git a/src/crypto/fips_prf_internal.c b/src/crypto/fips_prf_internal.c
index a85cb14..1e0c453 100644
--- a/src/crypto/fips_prf_internal.c
+++ b/src/crypto/fips_prf_internal.c
@@ -28,13 +28,14 @@
 	u8 *xpos = x;
 	u32 carry;
 
-	if (seed_len > sizeof(xkey))
+	if (seed_len < sizeof(xkey))
+		os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+	else
 		seed_len = sizeof(xkey);
 
 	/* FIPS 186-2 + change notice 1 */
 
 	os_memcpy(xkey, seed, seed_len);
-	os_memset(xkey + seed_len, 0, 64 - seed_len);
 	t[0] = 0x67452301;
 	t[1] = 0xEFCDAB89;
 	t[2] = 0x98BADCFE;
diff --git a/src/crypto/md5-internal.c b/src/crypto/md5-internal.c
index f8692a9..137ad91 100644
--- a/src/crypto/md5-internal.c
+++ b/src/crypto/md5-internal.c
@@ -188,7 +188,7 @@
     MD5Transform(ctx->buf, (u32 *) ctx->in);
     byteReverse((unsigned char *) ctx->buf, 4);
     os_memcpy(digest, ctx->buf, 16);
-    os_memset(ctx, 0, sizeof(ctx));	/* In case it's sensitive */
+    os_memset(ctx, 0, sizeof(*ctx));	/* In case it's sensitive */
 }
 
 /* The four core functions - F1 is optimized somewhat */
diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c
index dae15ab..c439ae9 100644
--- a/src/crypto/ms_funcs.c
+++ b/src/crypto/ms_funcs.c
@@ -19,6 +19,60 @@
 #include "ms_funcs.h"
 #include "crypto.h"
 
+/**
+ * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
+ * @utf8_string: UTF-8 string (IN)
+ * @utf8_string_len: Length of utf8_string (IN)
+ * @ucs2_buffer: UCS-2 buffer (OUT)
+ * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
+ * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
+ * Returns: 0 on success, -1 on failure
+ */
+static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
+                        u8 *ucs2_buffer, size_t ucs2_buffer_size,
+                        size_t *ucs2_string_size)
+{
+	size_t i, j;
+
+	for (i = 0, j = 0; i < utf8_string_len; i++) {
+		u8 c = utf8_string[i];
+		if (j >= ucs2_buffer_size) {
+			/* input too long */
+			return -1;
+		}
+		if (c <= 0x7F) {
+			WPA_PUT_LE16(ucs2_buffer + j, c);
+			j += 2;
+		} else if (i == utf8_string_len - 1 ||
+			   j >= ucs2_buffer_size - 1) {
+			/* incomplete surrogate */
+			return -1;
+		} else {
+			u8 c2 = utf8_string[++i];
+			if ((c & 0xE0) == 0xC0) {
+				/* two-byte encoding */
+				WPA_PUT_LE16(ucs2_buffer + j,
+					     ((c & 0x1F) << 6) | (c2 & 0x3F));
+				j += 2;
+			} else if (i == utf8_string_len ||
+				   j >= ucs2_buffer_size - 1) {
+				/* incomplete surrogate */
+				return -1;
+			} else {
+				/* three-byte encoding */
+				u8 c3 = utf8_string[++i];
+				WPA_PUT_LE16(ucs2_buffer + j,
+					     ((c & 0xF) << 12) |
+					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
+			}
+		}
+	}
+
+	if (ucs2_string_size)
+		*ucs2_string_size = j / 2;
+	return 0;
+}
+
 
 /**
  * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
@@ -53,7 +107,7 @@
 
 /**
  * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @password_hash: 16-octet PasswordHash (OUT)
  * Returns: 0 on success, -1 on failure
@@ -62,18 +116,13 @@
 		      u8 *password_hash)
 {
 	u8 buf[512], *pos;
-	size_t i, len;
+	size_t len, max_len;
 
-	if (password_len > 256)
-		password_len = 256;
+	max_len = sizeof(buf);
+	if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
+		return -1;
 
-	/* Convert password into unicode */
-	for (i = 0; i < password_len; i++) {
-		buf[2 * i] = password[i];
-		buf[2 * i + 1] = 0;
-	}
-
-	len = password_len * 2;
+	len *= 2;
 	pos = buf;
 	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
 }
@@ -117,7 +166,7 @@
  * @peer_challenge: 16-octet PeerChallenge (IN)
  * @username: 0-to-256-char UserName (IN)
  * @username_len: Length of username
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @response: 24-octet Response (OUT)
  * Returns: 0 on success, -1 on failure
@@ -225,7 +274,7 @@
 
 /**
  * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @nt_response: 24-octet NT-Response (IN)
  * @peer_challenge: 16-octet PeerChallenge (IN)
@@ -254,7 +303,7 @@
 /**
  * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
  * @challenge: 8-octet Challenge (IN)
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @response: 24-octet Response (OUT)
  * Returns: 0 on success, -1 on failure
@@ -375,7 +424,7 @@
 
 /**
  * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
- * @password: 0-to-256-unicode-char Password (IN; ASCII)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
  * @password_len: Length of password
  * @password_hash: 16-octet PasswordHash (IN)
  * @pw_block: 516-byte PwBlock (OUT)
@@ -385,18 +434,23 @@
 	const u8 *password, size_t password_len,
 	const u8 *password_hash, u8 *pw_block)
 {
-	size_t i, offset;
+	size_t ucs2_len, offset;
 	u8 *pos;
 
-	if (password_len > 256)
+	os_memset(pw_block, 0, PWBLOCK_LEN);
+
+	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
 		return -1;
 
-	os_memset(pw_block, 0, PWBLOCK_LEN);
-	offset = (256 - password_len) * 2;
-	if (os_get_random(pw_block, offset) < 0)
+	if (ucs2_len > 256)
 		return -1;
-	for (i = 0; i < password_len; i++)
-		pw_block[offset + i * 2] = password[i];
+
+	offset = (256 - ucs2_len) * 2;
+	if (offset != 0) {
+		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
+		if (os_get_random(pw_block, offset) < 0)
+			return -1;
+	}
 	/*
 	 * PasswordLength is 4 octets, but since the maximum password length is
 	 * 256, only first two (in little endian byte order) can be non-zero.
@@ -410,9 +464,9 @@
 
 /**
  * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
- * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
  * @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
  * @old_password_len: Length of old_password
  * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
  * Returns: 0 on success, -1 on failure
@@ -450,9 +504,9 @@
 
 /**
  * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
- * @new_password: 0-to-256-unicode-char NewPassword (IN; ASCII)
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
  * @new_password_len: Length of new_password
- * @old_password: 0-to-256-unicode-char OldPassword (IN; ASCII)
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
  * @old_password_len: Length of old_password
  * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
  * Returns: 0 on success, -1 on failure
diff --git a/src/crypto/random.c b/src/crypto/random.c
index f545917..a54e197 100644
--- a/src/crypto/random.c
+++ b/src/crypto/random.c
@@ -354,23 +354,31 @@
 	char buf[RANDOM_ENTROPY_SIZE];
 	FILE *f;
 	u8 opr;
+	int fail = 0;
 
 	if (!random_entropy_file)
 		return;
 
-	random_get_bytes(buf, RANDOM_ENTROPY_SIZE);
+	if (random_get_bytes(buf, RANDOM_ENTROPY_SIZE) < 0)
+		return;
 
 	f = fopen(random_entropy_file, "wb");
 	if (f == NULL) {
-		wpa_printf(MSG_ERROR, "random: Could not write %s",
-			   random_entropy_file);
+		wpa_printf(MSG_ERROR, "random: Could not open entropy file %s "
+			   "for writing", random_entropy_file);
 		return;
 	}
 
 	opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
-	fwrite(&opr, 1, 1, f);
-	fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f);
+	if (fwrite(&opr, 1, 1, f) != 1 ||
+	    fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f) != 1)
+		fail = 1;
 	fclose(f);
+	if (fail) {
+		wpa_printf(MSG_ERROR, "random: Could not write entropy data "
+			   "to %s", random_entropy_file);
+		return;
+	}
 
 	wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
 		   "(own_pool_ready=%u)",
diff --git a/src/crypto/sha1-pbkdf2.c b/src/crypto/sha1-pbkdf2.c
index 11323de..9dac977 100644
--- a/src/crypto/sha1-pbkdf2.c
+++ b/src/crypto/sha1-pbkdf2.c
@@ -16,8 +16,6 @@
 
 #include "common.h"
 #include "sha1.h"
-#include "md5.h"
-#include "crypto.h"
 
 static int pbkdf2_sha1_f(const char *passphrase, const char *ssid,
 			 size_t ssid_len, int iterations, unsigned int count,
diff --git a/src/crypto/sha1-tlsprf.c b/src/crypto/sha1-tlsprf.c
index 2c8c029..f98fd65 100644
--- a/src/crypto/sha1-tlsprf.c
+++ b/src/crypto/sha1-tlsprf.c
@@ -17,11 +17,10 @@
 #include "common.h"
 #include "sha1.h"
 #include "md5.h"
-#include "crypto.h"
 
 
 /**
- * tls_prf - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
+ * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
  * @secret: Key for PRF
  * @secret_len: Length of the key in bytes
  * @label: A unique label for each purpose of the PRF
@@ -34,8 +33,8 @@
  * This function is used to derive new, cryptographically separate keys from a
  * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
  */
-int tls_prf(const u8 *secret, size_t secret_len, const char *label,
-	    const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
+		     const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
 {
 	size_t L_S1, L_S2, i;
 	const u8 *S1, *S2;
diff --git a/src/crypto/sha1.h b/src/crypto/sha1.h
index c1a6233..f0c1a5f 100644
--- a/src/crypto/sha1.h
+++ b/src/crypto/sha1.h
@@ -25,9 +25,9 @@
 	     const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
 int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
 	       const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len);
-int __must_check tls_prf(const u8 *secret, size_t secret_len,
-			 const char *label, const u8 *seed, size_t seed_len,
-			 u8 *out, size_t outlen);
+int __must_check tls_prf_sha1_md5(const u8 *secret, size_t secret_len,
+				  const char *label, const u8 *seed,
+				  size_t seed_len, u8 *out, size_t outlen);
 int pbkdf2_sha1(const char *passphrase, const char *ssid, size_t ssid_len,
 		int iterations, u8 *buf, size_t buflen);
 #endif /* SHA1_H */
diff --git a/src/crypto/sha256-internal.c b/src/crypto/sha256-internal.c
index b061373..ef5751d 100644
--- a/src/crypto/sha256-internal.c
+++ b/src/crypto/sha256-internal.c
@@ -1,6 +1,6 @@
 /*
  * SHA-256 hash implementation and interface functions
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -16,19 +16,9 @@
 
 #include "common.h"
 #include "sha256.h"
+#include "sha256_i.h"
 #include "crypto.h"
 
-struct sha256_state {
-	u64 length;
-	u32 state[8], curlen;
-	u8 buf[64];
-};
-
-static void sha256_init(struct sha256_state *md);
-static int sha256_process(struct sha256_state *md, const unsigned char *in,
-			  unsigned long inlen);
-static int sha256_done(struct sha256_state *md, unsigned char *out);
-
 
 /**
  * sha256_vector - SHA256 hash for data vector
@@ -137,7 +127,7 @@
 
 
 /* Initialize the hash state */
-static void sha256_init(struct sha256_state *md)
+void sha256_init(struct sha256_state *md)
 {
 	md->curlen = 0;
 	md->length = 0;
@@ -158,32 +148,31 @@
    @param inlen  The length of the data (octets)
    @return CRYPT_OK if successful
 */
-static int sha256_process(struct sha256_state *md, const unsigned char *in,
-			  unsigned long inlen)
+int sha256_process(struct sha256_state *md, const unsigned char *in,
+		   unsigned long inlen)
 {
 	unsigned long n;
-#define block_size 64
 
-	if (md->curlen > sizeof(md->buf))
+	if (md->curlen >= sizeof(md->buf))
 		return -1;
 
 	while (inlen > 0) {
-		if (md->curlen == 0 && inlen >= block_size) {
+		if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) {
 			if (sha256_compress(md, (unsigned char *) in) < 0)
 				return -1;
-			md->length += block_size * 8;
-			in += block_size;
-			inlen -= block_size;
+			md->length += SHA256_BLOCK_SIZE * 8;
+			in += SHA256_BLOCK_SIZE;
+			inlen -= SHA256_BLOCK_SIZE;
 		} else {
-			n = MIN(inlen, (block_size - md->curlen));
+			n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen));
 			os_memcpy(md->buf + md->curlen, in, n);
 			md->curlen += n;
 			in += n;
 			inlen -= n;
-			if (md->curlen == block_size) {
+			if (md->curlen == SHA256_BLOCK_SIZE) {
 				if (sha256_compress(md, md->buf) < 0)
 					return -1;
-				md->length += 8 * block_size;
+				md->length += 8 * SHA256_BLOCK_SIZE;
 				md->curlen = 0;
 			}
 		}
@@ -199,7 +188,7 @@
    @param out [out] The destination of the hash (32 bytes)
    @return CRYPT_OK if successful
 */
-static int sha256_done(struct sha256_state *md, unsigned char *out)
+int sha256_done(struct sha256_state *md, unsigned char *out)
 {
 	int i;
 
@@ -217,14 +206,14 @@
 	 * encoding like normal.
 	 */
 	if (md->curlen > 56) {
-		while (md->curlen < 64) {
+		while (md->curlen < SHA256_BLOCK_SIZE) {
 			md->buf[md->curlen++] = (unsigned char) 0;
 		}
 		sha256_compress(md, md->buf);
 		md->curlen = 0;
 	}
 
-	/* pad upto 56 bytes of zeroes */
+	/* pad up to 56 bytes of zeroes */
 	while (md->curlen < 56) {
 		md->buf[md->curlen++] = (unsigned char) 0;
 	}
diff --git a/src/crypto/sha256-tlsprf.c b/src/crypto/sha256-tlsprf.c
new file mode 100644
index 0000000..6763c96
--- /dev/null
+++ b/src/crypto/sha256-tlsprf.c
@@ -0,0 +1,72 @@
+/*
+ * TLS PRF P_SHA256
+ * Copyright (c) 2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+
+
+/**
+ * tls_prf_sha256 - Pseudo-Random Function for TLS v1.2 (P_SHA256, RFC 5246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @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 TLS. This PRF is defined in RFC 2246, Chapter 5.
+ */
+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)
+{
+	size_t clen;
+	u8 A[SHA256_MAC_LEN];
+	u8 P[SHA256_MAC_LEN];
+	size_t pos;
+	const unsigned char *addr[3];
+	size_t len[3];
+
+	addr[0] = A;
+	len[0] = SHA256_MAC_LEN;
+	addr[1] = (unsigned char *) label;
+	len[1] = os_strlen(label);
+	addr[2] = seed;
+	len[2] = seed_len;
+
+	/*
+	 * RFC 5246, Chapter 5
+	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+	 * PRF(secret, label, seed) = P_SHA256(secret, label + seed)
+	 */
+
+	hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A);
+
+	pos = 0;
+	while (pos < outlen) {
+		hmac_sha256_vector(secret, secret_len, 3, addr, len, P);
+		hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A);
+
+		clen = outlen - pos;
+		if (clen > SHA256_MAC_LEN)
+			clen = SHA256_MAC_LEN;
+		os_memcpy(out + pos, P, clen);
+		pos += clen;
+	}
+}
diff --git a/src/crypto/sha256.h b/src/crypto/sha256.h
index dc597f0..b1ce6af 100644
--- a/src/crypto/sha256.h
+++ b/src/crypto/sha256.h
@@ -1,6 +1,6 @@
 /*
  * SHA256 hash implementation and interface functions
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -23,5 +23,8 @@
 		 size_t data_len, u8 *mac);
 void sha256_prf(const u8 *key, size_t key_len, const char *label,
 	      const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+void tls_prf_sha256(const u8 *secret, size_t secret_len,
+		    const char *label, const u8 *seed, size_t seed_len,
+		    u8 *out, size_t outlen);
 
 #endif /* SHA256_H */
diff --git a/src/crypto/sha256_i.h b/src/crypto/sha256_i.h
new file mode 100644
index 0000000..20ae488
--- /dev/null
+++ b/src/crypto/sha256_i.h
@@ -0,0 +1,31 @@
+/*
+ * SHA-256 internal definitions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef SHA256_I_H
+#define SHA256_I_H
+
+#define SHA256_BLOCK_SIZE 64
+
+struct sha256_state {
+	u64 length;
+	u32 state[8], curlen;
+	u8 buf[SHA256_BLOCK_SIZE];
+};
+
+void sha256_init(struct sha256_state *md);
+int sha256_process(struct sha256_state *md, const unsigned char *in,
+		   unsigned long inlen);
+int sha256_done(struct sha256_state *md, unsigned char *out);
+
+#endif /* SHA256_I_H */
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index 0928b5b..d9d88cb 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -24,8 +24,6 @@
 	size_t client_random_len;
 	const u8 *server_random;
 	size_t server_random_len;
-	const u8 *inner_secret; /* TLS/IA inner secret */
-	size_t inner_secret_len;
 };
 
 enum tls_event {
@@ -72,6 +70,7 @@
 	const char *pkcs11_engine_path;
 	const char *pkcs11_module_path;
 	int fips_mode;
+	int cert_in_cb;
 
 	void (*event_cb)(void *ctx, enum tls_event ev,
 			 union tls_event_data *data);
@@ -114,7 +113,6 @@
  * specific for now)
  * @cert_id: the certificate's id when using engine
  * @ca_cert_id: the CA certificate's id when using engine
- * @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
  * @flags: Parameter options (TLS_CONN_*)
  *
  * TLS connection parameters to be configured with tls_connection_set_params()
@@ -142,7 +140,6 @@
 	const char *dh_file;
 	const u8 *dh_blob;
 	size_t dh_blob_len;
-	int tls_ia;
 
 	/* OpenSSL specific variables */
 	int engine;
@@ -282,20 +279,6 @@
 					   int verify_peer);
 
 /**
- * tls_connection_set_ia - Set TLS/IA parameters
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @tls_ia: 1 = enable TLS/IA
- * Returns: 0 on success, -1 on failure
- *
- * This function is used to configure TLS/IA in server mode where
- * tls_connection_set_params() is not used.
- */
-int __must_check tls_connection_set_ia(void *tls_ctx,
-				       struct tls_connection *conn,
-				       int tls_ia);
-
-/**
  * tls_connection_get_keys - Get master key and random data from TLS connection
  * @tls_ctx: TLS context data from tls_init()
  * @conn: Connection context data from tls_connection_init()
@@ -322,7 +305,7 @@
  * not exported from the TLS library, tls_connection_prf() is required so that
  * further keying material can be derived from the master secret. If not
  * implemented, the function will still need to be defined, but it can just
- * return -1. Example implementation of this function is in tls_prf() function
+ * return -1. Example implementation of this function is in tls_prf_sha1_md5()
  * when it is called with seed set to client_random|server_random (or
  * server_random|client_random).
  */
@@ -364,6 +347,12 @@
 					 const struct wpabuf *in_data,
 					 struct wpabuf **appl_data);
 
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+					  struct tls_connection *conn,
+					  const struct wpabuf *in_data,
+					  struct wpabuf **appl_data,
+					  int *more_data_needed);
+
 /**
  * tls_connection_server_handshake - Process TLS handshake (server side)
  * @tls_ctx: TLS context data from tls_init()
@@ -409,6 +398,11 @@
 				       struct tls_connection *conn,
 				       const struct wpabuf *in_data);
 
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+					struct tls_connection *conn,
+					const struct wpabuf *in_data,
+					int *more_data_needed);
+
 /**
  * tls_connection_resumed - Was session resumption used
  * @tls_ctx: TLS context data from tls_init()
@@ -514,7 +508,6 @@
 int tls_connection_get_keyblock_size(void *tls_ctx,
 				     struct tls_connection *conn);
 
-#define TLS_CAPABILITY_IA 0x0001 /* TLS Inner Application (TLS/IA) */
 /**
  * tls_capabilities - Get supported TLS capabilities
  * @tls_ctx: TLS context data from tls_init()
@@ -522,42 +515,6 @@
  */
 unsigned int tls_capabilities(void *tls_ctx);
 
-/**
- * tls_connection_ia_send_phase_finished - Send a TLS/IA PhaseFinished message
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @final: 1 = FinalPhaseFinished, 0 = IntermediatePhaseFinished
- * Returns: Encrypted TLS/IA data, %NULL on failure
- *
- * This function is used to send the TLS/IA end phase message, e.g., when the
- * EAP server completes EAP-TTLSv1.
- */
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final);
-
-/**
- * tls_connection_ia_final_phase_finished - Has final phase been completed
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * Returns: 1 if valid FinalPhaseFinished has been received, 0 if not, or -1
- * on failure
- */
-int __must_check tls_connection_ia_final_phase_finished(
-	void *tls_ctx, struct tls_connection *conn);
-
-/**
- * tls_connection_ia_permute_inner_secret - Permute TLS/IA inner secret
- * @tls_ctx: TLS context data from tls_init()
- * @conn: Connection context data from tls_connection_init()
- * @key: Session key material (session_key vectors with 2-octet length), or
- * %NULL if no session key was generating in the current phase
- * @key_len: Length of session key material
- * Returns: 0 on success, -1 on failure
- */
-int __must_check tls_connection_ia_permute_inner_secret(
-	void *tls_ctx, struct tls_connection *conn,
-	const u8 *key, size_t key_len);
-
 typedef int (*tls_session_ticket_cb)
 (void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
  const u8 *server_random, u8 *master_secret);
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index c3a7358..afa5268 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -1,6 +1,6 @@
 /*
  * SSL/TLS interface functions for GnuTLS
- * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -19,28 +19,12 @@
 #include <gnutls/pkcs12.h>
 #endif /* PKCS12_FUNCS */
 
-#ifdef CONFIG_GNUTLS_EXTRA
-#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
-#define GNUTLS_IA
-#include <gnutls/extra.h>
-#if LIBGNUTLS_VERSION_NUMBER == 0x010302
-/* This function is not included in the current gnutls/extra.h even though it
- * should be, so define it here as a workaround for the time being. */
-int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
-#endif /* LIBGNUTLS_VERSION_NUMBER == 0x010302 */
-#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
-#endif /* CONFIG_GNUTLS_EXTRA */
-
 #include "common.h"
 #include "tls.h"
 
 
-#ifndef TLS_RANDOM_SIZE
-#define TLS_RANDOM_SIZE 32
-#endif
-#ifndef TLS_MASTER_SIZE
-#define TLS_MASTER_SIZE 48
-#endif
+#define WPA_TLS_RANDOM_SIZE 32
+#define WPA_TLS_MASTER_SIZE 48
 
 
 #if LIBGNUTLS_VERSION_NUMBER < 0x010302
@@ -77,9 +61,9 @@
 	gnutls_mac_algorithm_t write_mac_algorithm;
 	gnutls_compression_method_t write_compression_algorithm;
 	cipher_suite_st current_cipher_suite;
-	opaque master_secret[TLS_MASTER_SIZE];
-	opaque client_random[TLS_RANDOM_SIZE];
-	opaque server_random[TLS_RANDOM_SIZE];
+	opaque master_secret[WPA_TLS_MASTER_SIZE];
+	opaque client_random[WPA_TLS_RANDOM_SIZE];
+	opaque server_random[WPA_TLS_RANDOM_SIZE];
 	/* followed by stuff we are not interested in */
 } security_parameters_st;
 
@@ -118,21 +102,6 @@
 
 	int params_set;
 	gnutls_certificate_credentials_t xcred;
-
-	int tls_ia;
-	int final_phase_finished;
-
-#ifdef GNUTLS_IA
-	gnutls_ia_server_credentials_t iacred_srv;
-	gnutls_ia_client_credentials_t iacred_cli;
-
-	/* Session keys generated in the current phase for inner secret
-	 * permutation before generating/verifying PhaseFinished. */
-	u8 *session_keys;
-	size_t session_keys_len;
-
-	u8 inner_secret[TLS_MASTER_SIZE];
-#endif /* GNUTLS_IA */
 };
 
 
@@ -285,8 +254,12 @@
 static int tls_gnutls_init_session(struct tls_global *global,
 				   struct tls_connection *conn)
 {
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+	const char *err;
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
 	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
 	const int protos[2] = { GNUTLS_TLS1, 0 };
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
 	int ret;
 
 	ret = gnutls_init(&conn->session,
@@ -301,6 +274,15 @@
 	if (ret < 0)
 		goto fail;
 
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
+					 &err);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
+			   "'%s'", err);
+		goto fail;
+	}
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
 	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
 	if (ret < 0)
 		goto fail;
@@ -308,6 +290,7 @@
 	ret = gnutls_protocol_set_priority(conn->session, protos);
 	if (ret < 0)
 		goto fail;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
 
 	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
 	gnutls_transport_set_push_function(conn->session, tls_push_func);
@@ -364,17 +347,6 @@
 	if (conn == NULL)
 		return;
 
-#ifdef GNUTLS_IA
-	if (conn->iacred_srv)
-		gnutls_ia_free_server_credentials(conn->iacred_srv);
-	if (conn->iacred_cli)
-		gnutls_ia_free_client_credentials(conn->iacred_cli);
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-#endif /* GNUTLS_IA */
-
 	gnutls_certificate_free_credentials(conn->xcred);
 	gnutls_deinit(conn->session);
 	os_free(conn->pre_shared_secret);
@@ -407,14 +379,6 @@
 	wpabuf_free(conn->push_buf);
 	conn->push_buf = NULL;
 	conn->established = 0;
-	conn->final_phase_finished = 0;
-#ifdef GNUTLS_IA
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-	conn->session_keys_len = 0;
-#endif /* GNUTLS_IA */
 
 	gnutls_deinit(conn->session);
 	if (tls_gnutls_init_session(global, conn)) {
@@ -597,11 +561,13 @@
 				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
 		}
 
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
 		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
 			gnutls_certificate_set_verify_flags(
 				conn->xcred,
 				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
 		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
 	}
 
 	if (params->client_cert && params->private_key) {
@@ -646,7 +612,6 @@
 		}
 	}
 
-	conn->tls_ia = params->tls_ia;
 	conn->params_set = 1;
 
 	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
@@ -656,28 +621,6 @@
 			   gnutls_strerror(ret));
 	}
 
-#ifdef GNUTLS_IA
-	if (conn->iacred_cli)
-		gnutls_ia_free_client_credentials(conn->iacred_cli);
-
-	ret = gnutls_ia_allocate_client_credentials(&conn->iacred_cli);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
-			   gnutls_strerror(ret));
-		return -1;
-	}
-
-	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
-				     conn->iacred_cli);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
-			   gnutls_strerror(ret));
-		gnutls_ia_free_client_credentials(conn->iacred_cli);
-		conn->iacred_cli = NULL;
-		return -1;
-	}
-#endif /* GNUTLS_IE */
-
 	return ret;
 }
 
@@ -729,11 +672,13 @@
 				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
 		}
 
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
 		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
 			gnutls_certificate_set_verify_flags(
 				global->xcred,
 				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
 		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
 	}
 
 	if (params->client_cert && params->private_key) {
@@ -822,10 +767,11 @@
 
 	os_memset(keys, 0, sizeof(*keys));
 
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
 #ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
 	sec = &conn->session->security_parameters;
 	keys->master_key = sec->master_secret;
-	keys->master_key_len = TLS_MASTER_SIZE;
+	keys->master_key_len = WPA_TLS_MASTER_SIZE;
 	keys->client_random = sec->client_random;
 	keys->server_random = sec->server_random;
 #else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
@@ -835,16 +781,12 @@
 		(u8 *) gnutls_session_get_server_random(conn->session);
 	/* No access to master_secret */
 #endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
 
-#ifdef GNUTLS_IA
-	gnutls_ia_extract_inner_secret(conn->session,
-				       (char *) conn->inner_secret);
-	keys->inner_secret = conn->inner_secret;
-	keys->inner_secret_len = TLS_MASTER_SIZE;
-#endif /* GNUTLS_IA */
-
-	keys->client_random_len = TLS_RANDOM_SIZE;
-	keys->server_random_len = TLS_RANDOM_SIZE;
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
+	keys->client_random_len = WPA_TLS_RANDOM_SIZE;
+	keys->server_random_len = WPA_TLS_RANDOM_SIZE;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
 
 	return 0;
 }
@@ -883,11 +825,13 @@
 
 	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
 		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
+		*err = GNUTLS_A_INTERNAL_ERROR;
 		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
 			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
 				   "algorithm");
 			*err = GNUTLS_A_INSUFFICIENT_SECURITY;
 		}
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
 		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
 			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
 				   "activated");
@@ -897,6 +841,7 @@
 			wpa_printf(MSG_INFO, "TLS: Certificate expired");
 			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
 		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
 		return -1;
 	}
 
@@ -988,7 +933,7 @@
 				 wpabuf_size(ad));
 	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
 	if (res < 0) {
-		wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
+		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
 			   "(%s)", __func__, (int) res,
 			   gnutls_strerror(res));
 		wpabuf_free(ad);
@@ -1062,20 +1007,7 @@
 			goto out;
 		}
 
-#ifdef CONFIG_GNUTLS_EXTRA
-		if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
-			wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
-			conn->failed++;
-			return NULL;
-		}
-#endif /* CONFIG_GNUTLS_EXTRA */
-
-		if (conn->tls_ia)
-			wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
-		else {
-			wpa_printf(MSG_DEBUG, "TLS: Handshake completed "
-				   "successfully");
-		}
+		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
 		conn->established = 1;
 		if (conn->push_buf == NULL) {
 			/* Need to return something to get final TLS ACK. */
@@ -1122,12 +1054,6 @@
 	ssize_t res;
 	struct wpabuf *buf;
 
-#ifdef GNUTLS_IA
-	if (conn->tls_ia)
-		res = gnutls_ia_send(conn->session, wpabuf_head(in_data),
-				     wpabuf_len(in_data));
-	else
-#endif /* GNUTLS_IA */
 	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
 				 wpabuf_len(in_data));
 	if (res < 0) {
@@ -1170,65 +1096,6 @@
 	if (out == NULL)
 		return NULL;
 
-#ifdef GNUTLS_IA
-	if (conn->tls_ia) {
-		res = gnutls_ia_recv(conn->session, wpabuf_mhead(out),
-				     wpabuf_size(out));
-		if (res == GNUTLS_E_WARNING_IA_IPHF_RECEIVED ||
-		    res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED) {
-			int final = res == GNUTLS_E_WARNING_IA_FPHF_RECEIVED;
-			wpa_printf(MSG_DEBUG, "%s: Received %sPhaseFinished",
-				   __func__, final ? "Final" : "Intermediate");
-
-			res = gnutls_ia_permute_inner_secret(
-				conn->session, conn->session_keys_len,
-				(char *) conn->session_keys);
-			if (conn->session_keys) {
-				os_memset(conn->session_keys, 0,
-					  conn->session_keys_len);
-				os_free(conn->session_keys);
-			}
-			conn->session_keys = NULL;
-			conn->session_keys_len = 0;
-			if (res) {
-				wpa_printf(MSG_DEBUG, "%s: Failed to permute "
-					   "inner secret: %s",
-					   __func__, gnutls_strerror(res));
-				wpabuf_free(out);
-				return NULL;
-			}
-
-			res = gnutls_ia_verify_endphase(conn->session,
-							wpabuf_head(out));
-			if (res == 0) {
-				wpa_printf(MSG_DEBUG, "%s: Correct endphase "
-					   "checksum", __func__);
-			} else {
-				wpa_printf(MSG_INFO, "%s: Endphase "
-					   "verification failed: %s",
-					   __func__, gnutls_strerror(res));
-				wpabuf_free(out);
-				return NULL;
-			}
-
-			if (final)
-				conn->final_phase_finished = 1;
-
-			return out;
-		}
-
-		if (res < 0) {
-			wpa_printf(MSG_DEBUG, "%s - gnutls_ia_recv failed: %d "
-				   "(%s)", __func__, (int) res,
-				   gnutls_strerror(res));
-			wpabuf_free(out);
-			return NULL;
-		}
-		wpabuf_put(out, res);
-		return out;
-	}
-#endif /* GNUTLS_IA */
-
 	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
 				 wpabuf_size(out));
 	if (res < 0) {
@@ -1319,133 +1186,7 @@
 
 unsigned int tls_capabilities(void *tls_ctx)
 {
-	unsigned int capa = 0;
-
-#ifdef GNUTLS_IA
-	capa |= TLS_CAPABILITY_IA;
-#endif /* GNUTLS_IA */
-
-	return capa;
-}
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-#ifdef GNUTLS_IA
-	int ret;
-
-	if (conn == NULL)
-		return -1;
-
-	conn->tls_ia = tls_ia;
-	if (!tls_ia)
-		return 0;
-
-	ret = gnutls_ia_allocate_server_credentials(&conn->iacred_srv);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to allocate IA credentials: %s",
-			   gnutls_strerror(ret));
-		return -1;
-	}
-
-	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_IA,
-				     conn->iacred_srv);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "Failed to configure IA credentials: %s",
-			   gnutls_strerror(ret));
-		gnutls_ia_free_server_credentials(conn->iacred_srv);
-		conn->iacred_srv = NULL;
-		return -1;
-	}
-
 	return 0;
-#else /* GNUTLS_IA */
-	return -1;
-#endif /* GNUTLS_IA */
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-#ifdef GNUTLS_IA
-	int ret;
-	struct wpabuf *buf;
-
-	if (conn == NULL || conn->session == NULL || !conn->tls_ia)
-		return NULL;
-
-	ret = gnutls_ia_permute_inner_secret(conn->session,
-					     conn->session_keys_len,
-					     (char *) conn->session_keys);
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-	conn->session_keys = NULL;
-	conn->session_keys_len = 0;
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to permute inner secret: %s",
-			   __func__, gnutls_strerror(ret));
-		return NULL;
-	}
-
-	ret = gnutls_ia_endphase_send(conn->session, final);
-	if (ret) {
-		wpa_printf(MSG_DEBUG, "%s: Failed to send endphase: %s",
-			   __func__, gnutls_strerror(ret));
-		return NULL;
-	}
-
-	buf = conn->push_buf;
-	conn->push_buf = NULL;
-	return buf;
-#else /* GNUTLS_IA */
-	return NULL;
-#endif /* GNUTLS_IA */
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	if (conn == NULL)
-		return -1;
-
-	return conn->final_phase_finished;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-#ifdef GNUTLS_IA
-	if (conn == NULL || !conn->tls_ia)
-		return -1;
-
-	if (conn->session_keys) {
-		os_memset(conn->session_keys, 0, conn->session_keys_len);
-		os_free(conn->session_keys);
-	}
-	conn->session_keys_len = 0;
-
-	if (key) {
-		conn->session_keys = os_malloc(key_len);
-		if (conn->session_keys == NULL)
-			return -1;
-		os_memcpy(conn->session_keys, key, key_len);
-		conn->session_keys_len = key_len;
-	} else {
-		conn->session_keys = NULL;
-		conn->session_keys_len = 0;
-	}
-
-	return 0;
-#else /* GNUTLS_IA */
-	return -1;
-#endif /* GNUTLS_IA */
 }
 
 
diff --git a/src/crypto/tls_internal.c b/src/crypto/tls_internal.c
index cc165f6..f5e31d9 100644
--- a/src/crypto/tls_internal.c
+++ b/src/crypto/tls_internal.c
@@ -290,13 +290,6 @@
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
 			    struct tls_keys *keys)
 {
@@ -339,6 +332,17 @@
 					 const struct wpabuf *in_data,
 					 struct wpabuf **appl_data)
 {
+	return tls_connection_handshake2(tls_ctx, conn, in_data, appl_data,
+					 NULL);
+}
+
+
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+					  struct tls_connection *conn,
+					  const struct wpabuf *in_data,
+					  struct wpabuf **appl_data,
+					  int *need_more_data)
+{
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 	u8 *res, *ad;
 	size_t res_len, ad_len;
@@ -351,7 +355,7 @@
 	res = tlsv1_client_handshake(conn->client,
 				     in_data ? wpabuf_head(in_data) : NULL,
 				     in_data ? wpabuf_len(in_data) : 0,
-				     &res_len, &ad, &ad_len);
+				     &res_len, &ad, &ad_len, need_more_data);
 	if (res == NULL)
 		return NULL;
 	out = wpabuf_alloc_ext_data(res, res_len);
@@ -462,23 +466,23 @@
 				       struct tls_connection *conn,
 				       const struct wpabuf *in_data)
 {
+	return tls_connection_decrypt2(tls_ctx, conn, in_data, NULL);
+}
+
+
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+					struct tls_connection *conn,
+					const struct wpabuf *in_data,
+					int *need_more_data)
+{
+	if (need_more_data)
+		*need_more_data = 0;
+
 #ifdef CONFIG_TLS_INTERNAL_CLIENT
 	if (conn->client) {
-		struct wpabuf *buf;
-		int res;
-		buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
-		if (buf == NULL)
-			return NULL;
-		res = tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
-					   wpabuf_len(in_data),
-					   wpabuf_mhead(buf),
-					   wpabuf_size(buf));
-		if (res < 0) {
-			wpabuf_free(buf);
-			return NULL;
-		}
-		wpabuf_put(buf, res);
-		return buf;
+		return tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
+					    wpabuf_len(in_data),
+					    need_more_data);
 	}
 #endif /* CONFIG_TLS_INTERNAL_CLIENT */
 #ifdef CONFIG_TLS_INTERNAL_SERVER
@@ -611,28 +615,6 @@
 }
 
 
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
-
-
 int tls_connection_set_session_ticket_cb(void *tls_ctx,
 					 struct tls_connection *conn,
 					 tls_session_ticket_cb cb,
diff --git a/src/crypto/tls_none.c b/src/crypto/tls_none.c
index 0c836bb..927edf5 100644
--- a/src/crypto/tls_none.c
+++ b/src/crypto/tls_none.c
@@ -84,13 +84,6 @@
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
 			    struct tls_keys *keys)
 {
@@ -205,25 +198,3 @@
 {
 	return 0;
 }
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
diff --git a/src/crypto/tls_nss.c b/src/crypto/tls_nss.c
index ad834b6..09a1e73 100644
--- a/src/crypto/tls_nss.c
+++ b/src/crypto/tls_nss.c
@@ -419,13 +419,6 @@
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
 int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
 			    struct tls_keys *keys)
 {
@@ -649,28 +642,6 @@
 }
 
 
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
-
-
 int tls_connection_set_session_ticket_cb(void *tls_ctx,
 					 struct tls_connection *conn,
 					 tls_session_ticket_cb cb,
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index 14ff87e..8374096 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -59,6 +59,7 @@
 	void (*event_cb)(void *ctx, enum tls_event ev,
 			 union tls_event_data *data);
 	void *cb_ctx;
+	int cert_in_cb;
 };
 
 static struct tls_global *tls_global = NULL;
@@ -694,6 +695,7 @@
 		if (conf) {
 			tls_global->event_cb = conf->event_cb;
 			tls_global->cb_ctx = conf->cb_ctx;
+			tls_global->cert_in_cb = conf->cert_in_cb;
 		}
 
 #ifdef CONFIG_FIPS
@@ -1144,7 +1146,7 @@
 		return;
 
 	os_memset(&ev, 0, sizeof(ev));
-	if (conn->cert_probe) {
+	if (conn->cert_probe || tls_global->cert_in_cb) {
 		cert = get_x509_cert(err_cert);
 		ev.peer_cert.cert = cert;
 	}
@@ -1661,6 +1663,7 @@
 
 	if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
 					 SSL_FILETYPE_ASN1) != 1 &&
+	    SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
 	    SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
 					 SSL_FILETYPE_PEM) != 1) {
 		tls_show_errors(MSG_INFO, __func__,
@@ -2809,35 +2812,6 @@
 }
 
 
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final)
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
-
-
 #if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
 /* Pre-shared secred requires a patch to openssl, so this function is
  * commented out unless explicitly needed for EAP-FAST in order to be able to
diff --git a/src/crypto/tls_schannel.c b/src/crypto/tls_schannel.c
index 4a94e99..a33d24e 100644
--- a/src/crypto/tls_schannel.c
+++ b/src/crypto/tls_schannel.c
@@ -736,32 +736,3 @@
 {
 	return 0;
 }
-
-
-int tls_connection_set_ia(void *tls_ctx, struct tls_connection *conn,
-			  int tls_ia)
-{
-	return -1;
-}
-
-
-struct wpabuf * tls_connection_ia_send_phase_finished(
-	void *tls_ctx, struct tls_connection *conn, int final);
-{
-	return NULL;
-}
-
-
-int tls_connection_ia_final_phase_finished(void *tls_ctx,
-					   struct tls_connection *conn)
-{
-	return -1;
-}
-
-
-int tls_connection_ia_permute_inner_secret(void *tls_ctx,
-					   struct tls_connection *conn,
-					   const u8 *key, size_t key_len)
-{
-	return -1;
-}
diff --git a/src/drivers/Apple80211.h b/src/drivers/Apple80211.h
deleted file mode 100644
index 2a612e7..0000000
--- a/src/drivers/Apple80211.h
+++ /dev/null
@@ -1,156 +0,0 @@
-#ifndef APPLE80211_H
-#define APPLE80211_H
-
-/*
- * Apple80211 framework definitions
- * This is an undocumented interface and the definitions here are based on
- * information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
- * whatever related information can be found with google and experiments ;-).
- */
-
-typedef struct __WirelessRef *WirelessRef;
-typedef SInt32 WirelessError;
-#define errWirelessNoError 0
-
-typedef struct WirelessInfo {
-	UInt16 link_qual;
-	UInt16 comms_qual;
-	UInt16 signal;
-	UInt16 noise;
-	UInt16 port_stat;
-	UInt16 client_mode;
-	UInt16 res1;
-	UInt16 power;
-	UInt16 res2;
-	UInt8 bssID[6];
-	UInt8 ssid[34];
-} WirelessInfo;
-
-typedef struct WirelessInfo2 {
-	/* TODO - these are probably not in correct order or complete */
-	WirelessInfo info1;
-	UInt8 macAddress[6];
-} WirelessInfo2;
-
-typedef struct WirelessNetworkInfo {
-	UInt16 channel;
-	UInt16 noise;
-	UInt16 signal;
-	UInt8 bssid[6];
-	UInt16 beacon_int;
-	UInt16 capability;
-	UInt16 ssid_len;
-	UInt8 ssid[32];
-} WirelessNetworkInfo;
-
-typedef int wirelessKeyType; /* TODO */
-
-int WirelessIsAvailable(void);
-WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
-WirelessError WirelessDetach(WirelessRef ref);
-WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
-			      void *out_ptr, int out_bytes);
-WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
-WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
-WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
-WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
-WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
-WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
-WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
-			   UInt32 strip_dups);
-WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
-				CFArrayRef *ibss_results, UInt32 strip_dups);
-WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
-				   UInt32 strip_dups, CFStringRef ssid);
-WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
-				    UInt32 strip_dups, CFArrayRef *results);
-WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
-WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
-			      CFStringRef passwd);
-WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
-/*
- * Set WEP key
- * ref: wireless reference from WirelessAttach()
- * type: ?
- * key_idx: 0..3
- * key_len: 13 for WEP-104 or 0 for clearing the key
- * key: Pointer to the key or %NULL if key_len = 0
- */
-WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
-			     int key_idx, int key_len,
-			     const unsigned char *key);
-/*
- * Set WPA key (e.g., PMK for 4-way handshake)
- * ref: wireless reference from WirelessAttach()
- * type: 0..4; 1 = PMK
- * key_len: 16, 32, or 0
- * key: Pointer to the key or %NULL if key_len = 0
- */
-WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
-				int key_len, const unsigned char *key);
-WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
-				CFStringRef key);
-WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
-				 CFStringRef key);
-WirelessError WirelessDisassociate(WirelessRef ref);
-
-/*
- * Get a copy of scan results for the given SSID
- * The returned dictionary includes following entries:
- * beaconInterval: CFNumber(kCFNumberSInt32Type)
- * SSID: CFData buffer of the SSID
- * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
- * name: Name of the network (SSID string)
- * BSSID: CFData buffer of the BSSID
- * channel: CFNumber(kCFNumberSInt32Type)
- * signal: CFNumber(kCFNumberSInt32Type)
- * appleIE: CFData
- * WPSNOPINRequired: CFBoolean
- * noise: CFNumber(kCFNumberSInt32Type)
- * capability: CFNumber(kCFNumberSInt32Type)
- * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
- * appleIE_Version: CFNumber(kCFNumberSInt32Type)
- * appleIE_Robust: CFBoolean
- * WPSConfigured: CFBoolean
- * scanWasDirected: CFBoolean
- * appleIE_Product: CFNumber(kCFNumberSInt32Type)
- * authModes: CFArray of CFNumber(kCFNumberSInt32Type)
- * multiCipher: CFNumber(kCFNumberSInt32Type)
- */
-CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
-
-/*
- * Get information about the current association
- * The returned dictionary includes following entries:
- * keyData: CFData buffer of the key (e.g., 32-octet PSK)
- * multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
- * channel: CFNumber(kCFNumberSInt32Type)
- * isIBSS: CFBoolean
- * authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
- *	129 = WPA2-Enterprise
- * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
- * SSID: CFData buffer of the SSID
- * cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
- */
-CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
-
-WirelessError WirelessConfigure(WirelessRef ref);
-
-/*
- * Get ASP information
- * The returned dictionary includes following entries:
- * Version: version number (e.g., 3.0)
- * Channel: channel (e.g., 1)
- * Vendor: vendor (e.g., 2)
- */
-CFDictionaryRef WirelessGetInfoASP(void);
-
-/*
- * Get a copy of the interface dictionary
- * The returned dictionary has a key,value pairs for wireless interfaces.
- * The key is the interface name and the value is the driver identifier, e.g.,
- * en1: com.apple.driver.AirPort.Atheros
- */
-CFDictionaryRef WirelessCopyInterfaceDict(void);
-
-#endif /* APPLE80211_H */
diff --git a/src/drivers/MobileApple80211.c b/src/drivers/MobileApple80211.c
deleted file mode 100644
index ce004fe..0000000
--- a/src/drivers/MobileApple80211.c
+++ /dev/null
@@ -1,189 +0,0 @@
-#include "includes.h"
-#include <dlfcn.h>
-
-#include "common.h"
-
-#include <CoreFoundation/CoreFoundation.h>
-#include "MobileApple80211.h"
-
-/*
- * Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
- * having to link with full Preferences.framework.
- */
-
-static void *aeropuerto = NULL;
-
-
-int _Apple80211Initialized(void)
-{
-	return aeropuerto ? 1 : 0;
-}
-
-
-static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
-
-int Apple80211Open(Apple80211Ref *ctx)
-{
-	return __Apple80211Open(ctx);
-}
-
-
-static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
-
-int Apple80211Close(Apple80211Ref ctx)
-{
-	return __Apple80211Close(ctx);
-}
-
-
-static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
-	= NULL;
-
-int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
-{
-	return __Apple80211GetIfListCopy(handle, list);
-}
-
-
-static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
-					  CFStringRef interface) = NULL;
-
-int Apple80211BindToInterface(Apple80211Ref handle,
-			      CFStringRef interface)
-{
-	return __Apple80211BindToInterface(handle, interface);
-}
-
-
-static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
-					       CFStringRef *name) = NULL;
-
-int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
-				   CFStringRef *name)
-{
-	return __Apple80211GetInterfaceNameCopy(handle, name);
-}
-
-
-static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
-				      CFDictionaryRef *info) = NULL;
-
-int Apple80211GetInfoCopy(Apple80211Ref handle,
-			  CFDictionaryRef *info)
-{
-	return __Apple80211GetInfoCopy(handle, info);
-}
-
-
-static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
-
-int Apple80211GetPower(Apple80211Ref handle, char *pwr)
-{
-	return __Apple80211GetPower(handle, pwr);
-}
-
-
-static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
-
-int Apple80211SetPower(Apple80211Ref handle, char pwr)
-{
-	return __Apple80211SetPower(handle, pwr);
-}
-
-
-static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
-			       CFDictionaryRef parameters) = NULL;
-
-int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
-		   CFDictionaryRef parameters)
-{
-	return __Apple80211Scan(handle, list, parameters);
-}
-
-
-static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
-				    CFStringRef password) = NULL;
-
-int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
-			CFStringRef password)
-{
-	return __Apple80211Associate(handle, bss, password);
-}
-
-
-static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
-					       CFDictionaryRef bss,
-					       CFStringRef password,
-					       CFDictionaryRef *info) =
-	NULL;
-
-int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
-				   CFStringRef password, CFDictionaryRef *info)
-{
-	return __Apple80211AssociateAndCopyInfo(handle, bss, password, info);
-}
-
-
-static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
-				    CFDictionaryRef arg2, void *value) = NULL;
-
-int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
-			void *value)
-{
-	return __Apple80211CopyValue(handle, field, arg2, value);
-}
-
-
-#define DLSYM(s) \
-do { \
-	__ ## s = dlsym(aeropuerto, #s); \
-	if (__ ## s == NULL) { \
-		wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
-			   "symbol '" #s "' (%s)", dlerror()); \
-		err = 1; \
-	} \
-} while (0)
-
-
-__attribute__ ((constructor))
-void _Apple80211_constructor(void)
-{
-	const char *fname = "/System/Library/SystemConfiguration/"
-		"Aeropuerto.bundle/Aeropuerto";
-	int err = 0;
-
-	aeropuerto = dlopen(fname, RTLD_LAZY);
-	if (!aeropuerto) {
-		wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
-			   "for symbols", fname);
-		return;
-	}
-
-	DLSYM(Apple80211Open);
-	DLSYM(Apple80211Close);
-	DLSYM(Apple80211GetIfListCopy);
-	DLSYM(Apple80211BindToInterface);
-	DLSYM(Apple80211GetInterfaceNameCopy);
-	DLSYM(Apple80211GetInfoCopy);
-	DLSYM(Apple80211GetPower);
-	DLSYM(Apple80211SetPower);
-	DLSYM(Apple80211Scan);
-	DLSYM(Apple80211Associate);
-	DLSYM(Apple80211AssociateAndCopyInfo);
-	DLSYM(Apple80211CopyValue);
-
-	if (err) {
-		dlclose(aeropuerto);
-		aeropuerto = NULL;
-	}
-}
-
-
-__attribute__ ((destructor))
-void _Apple80211_destructor(void)
-{
-	if (aeropuerto) {
-		dlclose(aeropuerto);
-		aeropuerto = NULL;
-	}
-}
diff --git a/src/drivers/MobileApple80211.h b/src/drivers/MobileApple80211.h
deleted file mode 100644
index 64d439d..0000000
--- a/src/drivers/MobileApple80211.h
+++ /dev/null
@@ -1,43 +0,0 @@
-#ifndef MOBILEAPPLE80211_H
-#define MOBILEAPPLE80211_H
-
-/*
- * MobileApple80211 interface for iPhone/iPod touch
- * These functions are available from Aeropuerto.
- */
-
-struct Apple80211;
-typedef struct Apple80211 *Apple80211Ref;
-
-int Apple80211Open(Apple80211Ref *ctx);
-int Apple80211Close(Apple80211Ref ctx);
-int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
-int Apple80211BindToInterface(Apple80211Ref handle,
-			      CFStringRef interface);
-int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
-				   CFStringRef *name);
-int Apple80211GetInfoCopy(Apple80211Ref handle,
-			  CFDictionaryRef *info);
-int Apple80211GetPower(Apple80211Ref handle, char *pwr);
-int Apple80211SetPower(Apple80211Ref handle, char pwr);
-
-/* parameters can be NULL; returns scan results in CFArrayRef *list;
- * caller will need to free with CFRelease() */
-int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
-		   CFDictionaryRef parameters);
-
-int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
-			CFStringRef password);
-int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
-				   CFStringRef password,
-				   CFDictionaryRef *info);
-
-enum {
-	APPLE80211_VALUE_SSID = 1,
-	APPLE80211_VALUE_BSSID = 9
-};
-
-int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
-			void *value);
-
-#endif /* MOBILEAPPLE80211_H */
diff --git a/src/drivers/android_drv.h b/src/drivers/android_drv.h
new file mode 100644
index 0000000..6df7160
--- /dev/null
+++ b/src/drivers/android_drv.h
@@ -0,0 +1,62 @@
+/*
+ * Android driver interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ */
+
+#ifndef ANDROID_DRV_H
+#define ANDROID_DRV_H
+
+#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE "
+
+#define WEXT_CSCAN_AMOUNT		9
+
+#define MAX_SSID_LEN 32
+
+#define MAX_DRV_CMD_SIZE		248
+#define DRV_NUMBER_SEQUENTIAL_ERRORS	4
+
+#define WEXT_PNOSETUP_HEADER		"PNOSETUP "
+#define WEXT_PNOSETUP_HEADER_SIZE	9
+#define WEXT_PNO_TLV_PREFIX		'S'
+#define WEXT_PNO_TLV_VERSION		'1'
+#define WEXT_PNO_TLV_SUBVERSION		'2'
+#define WEXT_PNO_TLV_RESERVED		'0'
+#define WEXT_PNO_VERSION_SIZE		4
+#define WEXT_PNO_AMOUNT			16
+#define WEXT_PNO_SSID_SECTION		'S'
+/* SSID header size is SSID section type above + SSID length */
+#define WEXT_PNO_SSID_HEADER_SIZE	2
+#define WEXT_PNO_SCAN_INTERVAL_SECTION	'T'
+#define WEXT_PNO_SCAN_INTERVAL_LENGTH	2
+#define WEXT_PNO_SCAN_INTERVAL		30
+/* Scan interval size is scan interval section type + scan interval length
+ * above */
+#define WEXT_PNO_SCAN_INTERVAL_SIZE	(1 + WEXT_PNO_SCAN_INTERVAL_LENGTH)
+#define WEXT_PNO_REPEAT_SECTION		'R'
+#define WEXT_PNO_REPEAT_LENGTH		1
+#define WEXT_PNO_REPEAT			4
+/* Repeat section size is Repeat section type + Repeat value length above */
+#define WEXT_PNO_REPEAT_SIZE		(1 + WEXT_PNO_REPEAT_LENGTH)
+#define WEXT_PNO_MAX_REPEAT_SECTION	'M'
+#define WEXT_PNO_MAX_REPEAT_LENGTH	1
+#define WEXT_PNO_MAX_REPEAT		3
+/* Max Repeat section size is Max Repeat section type + Max Repeat value length
+ * above */
+#define WEXT_PNO_MAX_REPEAT_SIZE	(1 + WEXT_PNO_MAX_REPEAT_LENGTH)
+/* This corresponds to the size of all sections expect SSIDs */
+#define WEXT_PNO_NONSSID_SECTIONS_SIZE \
+(WEXT_PNO_SCAN_INTERVAL_SIZE + WEXT_PNO_REPEAT_SIZE + WEXT_PNO_MAX_REPEAT_SIZE)
+/* PNO Max command size is total of header, version, ssid and other sections +
+ * Null termination */
+#define WEXT_PNO_MAX_COMMAND_SIZE \
+	(WEXT_PNOSETUP_HEADER_SIZE + WEXT_PNO_VERSION_SIZE \
+	 + WEXT_PNO_AMOUNT * (WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN) \
+	 + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1)
+
+#endif /* ANDROID_DRV_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 19f732d..ceed531 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -35,14 +35,6 @@
 #define HOSTAPD_CHAN_HT40MINUS 0x00000020
 #define HOSTAPD_CHAN_HT40 0x00000040
 
-#ifdef ANDROID_BRCM_P2P_PATCH
-/**
- * Monitor interface name is derived from p2p interface name
- * We need to reset p2p interface name early to take care of extra character in
- */
-#define WPA_MONITOR_IFNAME_PREFIX	"m."
-#endif
-
 /**
  * struct hostapd_channel_data - Channel information
  */
@@ -68,6 +60,8 @@
 	u8 max_tx_power;
 };
 
+#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
+
 /**
  * struct hostapd_hw_modes - Supported hardware mode information
  */
@@ -111,6 +105,8 @@
 	 * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters
 	 */
 	u8 a_mpdu_params;
+
+	unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
 };
 
 
@@ -203,7 +199,7 @@
 	const char *drv_name;
 };
 
-#define WPAS_MAX_SCAN_SSIDS 10
+#define WPAS_MAX_SCAN_SSIDS 16
 
 /**
  * struct wpa_driver_scan_params - Scan parameters
@@ -272,6 +268,15 @@
 	 * num_filter_ssids - Number of entries in filter_ssids array
 	 */
 	size_t num_filter_ssids;
+
+	/**
+	 * p2p_probe - Used to disable CCK (802.11b) rates for P2P probes
+	 *
+	 * When set, the driver is expected to remove rates 1, 2, 5.5, and 11
+	 * Mbps from the support rates element(s) in the Probe Request frames
+	 * and not to transmit the frames at any of those rates.
+	 */
+	u8 p2p_probe;
 };
 
 /**
@@ -290,6 +295,12 @@
 	size_t wep_key_len[4];
 	int wep_tx_keyidx;
 	int local_state_change;
+
+	/**
+	 * p2p - Whether this connection is a P2P group
+	 */
+	int p2p;
+
 };
 
 enum wps_mode {
@@ -353,6 +364,11 @@
 	size_t wpa_ie_len;
 
 	/**
+	 * wpa_proto - Bitfield of WPA_PROTO_* values to indicate WPA/WPA2
+	 */
+	unsigned int wpa_proto;
+
+	/**
 	 * pairwise_suite - Selected pairwise cipher suite
 	 *
 	 * This is usually ignored if @wpa_ie is used.
@@ -502,6 +518,183 @@
 	int uapsd;
 };
 
+enum hide_ssid {
+	NO_SSID_HIDING,
+	HIDDEN_SSID_ZERO_LEN,
+	HIDDEN_SSID_ZERO_CONTENTS
+};
+
+struct wpa_driver_ap_params {
+	/**
+	 * head - Beacon head from IEEE 802.11 header to IEs before TIM IE
+	 */
+	const u8 *head;
+
+	/**
+	 * head_len - Length of the head buffer in octets
+	 */
+	size_t head_len;
+
+	/**
+	 * tail - Beacon tail following TIM IE
+	 */
+	const u8 *tail;
+
+	/**
+	 * tail_len - Length of the tail buffer in octets
+	 */
+	size_t tail_len;
+
+	/**
+	 * dtim_period - DTIM period
+	 */
+	int dtim_period;
+
+	/**
+	 * beacon_int - Beacon interval
+	 */
+	int beacon_int;
+
+	/**
+	 * basic_rates: -1 terminated array of basic rates in 100 kbps
+	 *
+	 * This parameter can be used to set a specific basic rate set for the
+	 * BSS. If %NULL, default basic rate set is used.
+	 */
+	int *basic_rates;
+
+	/**
+	 * proberesp - Probe Response template
+	 *
+	 * This is used by drivers that reply to Probe Requests internally in
+	 * AP mode and require the full Probe Response template.
+	 */
+	const u8 *proberesp;
+
+	/**
+	 * proberesp_len - Length of the proberesp buffer in octets
+	 */
+	size_t proberesp_len;
+
+	/**
+	 * ssid - The SSID to use in Beacon/Probe Response frames
+	 */
+	const u8 *ssid;
+
+	/**
+	 * ssid_len - Length of the SSID (1..32)
+	 */
+	size_t ssid_len;
+
+	/**
+	 * hide_ssid - Whether to hide the SSID
+	 */
+	enum hide_ssid hide_ssid;
+
+	/**
+	 * pairwise_ciphers - WPA_CIPHER_* bitfield
+	 */
+	unsigned int pairwise_ciphers;
+
+	/**
+	 * group_cipher - WPA_CIPHER_*
+	 */
+	unsigned int group_cipher;
+
+	/**
+	 * key_mgmt_suites - WPA_KEY_MGMT_* bitfield
+	 */
+	unsigned int key_mgmt_suites;
+
+	/**
+	 * auth_algs - WPA_AUTH_ALG_* bitfield
+	 */
+	unsigned int auth_algs;
+
+	/**
+	 * wpa_version - WPA_PROTO_* bitfield
+	 */
+	unsigned int wpa_version;
+
+	/**
+	 * privacy - Whether privacy is used in the BSS
+	 */
+	int privacy;
+
+	/**
+	 * beacon_ies - WPS/P2P IE(s) for Beacon frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that do
+	 * not use the full Beacon template.
+	 */
+	const struct wpabuf *beacon_ies;
+
+	/**
+	 * proberesp_ies - P2P/WPS IE(s) for Probe Response frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that
+	 * reply to Probe Request frames internally.
+	 */
+	const struct wpabuf *proberesp_ies;
+
+	/**
+	 * assocresp_ies - WPS IE(s) for (Re)Association Response frames
+	 *
+	 * This is used to add IEs like WPS IE by drivers that reply to
+	 * (Re)Association Request frames internally.
+	 */
+	const struct wpabuf *assocresp_ies;
+
+	/**
+	 * isolate - Whether to isolate frames between associated stations
+	 *
+	 * If this is non-zero, the AP is requested to disable forwarding of
+	 * frames between associated stations.
+	 */
+	int isolate;
+
+	/**
+	 * cts_protect - Whether CTS protection is enabled
+	 */
+	int cts_protect;
+
+	/**
+	 * preamble - Whether short preamble is enabled
+	 */
+	int preamble;
+
+	/**
+	 * short_slot_time - Whether short slot time is enabled
+	 *
+	 * 0 = short slot time disable, 1 = short slot time enabled, -1 = do
+	 * not set (e.g., when 802.11g mode is not in use)
+	 */
+	int short_slot_time;
+
+	/**
+	 * ht_opmode - HT operation mode or -1 if HT not in use
+	 */
+	int ht_opmode;
+
+	/**
+	 * interworking - Whether Interworking is enabled
+	 */
+	int interworking;
+
+	/**
+	 * hessid - Homogeneous ESS identifier or %NULL if not set
+	 */
+	const u8 *hessid;
+
+	/**
+	 * access_network_type - Access Network Type (0..15)
+	 *
+	 * This is used for filtering Probe Request frames when Interworking is
+	 * enabled.
+	 */
+	u8 access_network_type;
+};
+
 /**
  * struct wpa_driver_capa - Driver capability information
  */
@@ -530,7 +723,7 @@
 #define WPA_DRIVER_FLAGS_DRIVER_IE	0x00000001
 /* Driver needs static WEP key setup after association command */
 #define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
-#define WPA_DRIVER_FLAGS_USER_SPACE_MLME 0x00000004
+/* unused: 0x00000004 */
 /* 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
@@ -571,9 +764,24 @@
 #define WPA_DRIVER_FLAGS_OFFCHANNEL_TX			0x00008000
 /* 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 */
+#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS		0x00020000
+/* Driver supports roaming (BSS selection) in firmware */
+#define WPA_DRIVER_FLAGS_BSS_SELECTION			0x00040000
+/* Driver supports operating as a TDLS peer */
+#define WPA_DRIVER_FLAGS_TDLS_SUPPORT			0x00080000
+/* 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 */
+#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD		0x00200000
+/* Driver supports U-APSD in AP mode */
+#define WPA_DRIVER_FLAGS_AP_UAPSD			0x00400000
 	unsigned int flags;
 
 	int max_scan_ssids;
+	int max_sched_scan_ssids;
+	int sched_scan_supported;
+	int max_match_sets;
 
 	/**
 	 * max_remain_on_chan - Maximum remain-on-channel duration in msec
@@ -585,6 +793,20 @@
 	 * supports in AP mode
 	 */
 	unsigned int max_stations;
+
+	/**
+	 * probe_resp_offloads - Bitmap of supported protocols by the driver
+	 * for Probe Response offloading.
+	 */
+/* 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 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2		0x00000002
+/* 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) */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING	0x00000008
+	unsigned int probe_resp_offloads;
 };
 
 
@@ -610,6 +832,9 @@
 	size_t supp_rates_len;
 	u16 listen_interval;
 	const struct ieee80211_ht_capabilities *ht_capabilities;
+	u32 flags; /* bitmask of WPA_STA_* flags */
+	int set; /* Set STA parameters instead of add */
+	u8 qosinfo;
 };
 
 struct hostapd_freq_params {
@@ -661,6 +886,7 @@
 };
 
 struct wpa_init_params {
+	void *global_priv;
 	const u8 *bssid;
 	const char *ifname;
 	const u8 *ssid;
@@ -693,6 +919,7 @@
 #define WPA_STA_WMM BIT(1)
 #define WPA_STA_SHORT_PREAMBLE BIT(2)
 #define WPA_STA_MFP BIT(3)
+#define WPA_STA_TDLS_PEER BIT(4)
 
 /**
  * struct p2p_params - P2P parameters for driver-based P2P management
@@ -1079,91 +1306,21 @@
 	 * flags: Variable for returning hardware feature flags
 	 * Returns: Pointer to allocated hardware data on success or %NULL on
 	 * failure. Caller is responsible for freeing this.
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to %wpa_supplicant or hostapd.
 	 */
 	struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
 							 u16 *num_modes,
 							 u16 *flags);
 
 	/**
-	 * set_channel - Set channel
-	 * @priv: Private driver interface data
-	 * @phymode: HOSTAPD_MODE_IEEE80211B, ..
-	 * @chan: IEEE 802.11 channel number
-	 * @freq: Frequency of the channel in MHz
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*set_channel)(void *priv, enum hostapd_hw_mode phymode, int chan,
-			   int freq);
-
-	/**
-	 * set_ssid - Set SSID
-	 * @priv: Private driver interface data
-	 * @ssid: SSID
-	 * @ssid_len: SSID length
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*set_ssid)(void *priv, const u8 *ssid, size_t ssid_len);
-
-	/**
-	 * set_bssid - Set BSSID
-	 * @priv: Private driver interface data
-	 * @bssid: BSSID
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*set_bssid)(void *priv, const u8 *bssid);
-
-	/**
 	 * send_mlme - Send management frame from MLME
 	 * @priv: Private driver interface data
 	 * @data: IEEE 802.11 management frame with IEEE 802.11 header
 	 * @data_len: Size of the management frame
+	 * @noack: Do not wait for this frame to be acked (disable retries)
 	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
 	 */
-	int (*send_mlme)(void *priv, const u8 *data, size_t data_len);
-
-	/**
-	 * mlme_add_sta - Add a STA entry into the driver/netstack
-	 * @priv: Private driver interface data
-	 * @addr: MAC address of the STA (e.g., BSSID of the AP)
-	 * @supp_rates: Supported rate set (from (Re)AssocResp); in IEEE 802.11
-	 * format (one octet per rate, 1 = 0.5 Mbps)
-	 * @supp_rates_len: Number of entries in supp_rates
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant. When the MLME code
-	 * completes association with an AP, this function is called to
-	 * configure the driver/netstack with a STA entry for data frame
-	 * processing (TX rate control, encryption/decryption).
-	 */
-	int (*mlme_add_sta)(void *priv, const u8 *addr, const u8 *supp_rates,
-			    size_t supp_rates_len);
-
-	/**
-	 * mlme_remove_sta - Remove a STA entry from the driver/netstack
-	 * @priv: Private driver interface data
-	 * @addr: MAC address of the STA (e.g., BSSID of the AP)
-	 * Returns: 0 on success, -1 on failure
-	 *
-	 * This function is only needed for drivers that export MLME
-	 * (management frame processing) to wpa_supplicant.
-	 */
-	int (*mlme_remove_sta)(void *priv, const u8 *addr);
+	int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
+			 int noack);
 
 	/**
 	 * update_ft_ies - Update FT (IEEE 802.11r) IEs
@@ -1292,24 +1449,25 @@
 			    struct wpa_driver_auth_params *params);
 
 	/**
-	 * set_beacon - Set Beacon frame template
+	 * set_ap - Set Beacon and Probe Response information for AP mode
 	 * @priv: Private driver interface data
-	 * @head: Beacon head from IEEE 802.11 header to IEs before TIM IE
-	 * @head_len: Length of the head buffer in octets
-	 * @tail: Beacon tail following TIM IE
-	 * @tail_len: Length of the tail buffer in octets
-	 * @dtim_period: DTIM period
-	 * @beacon_int: Beacon interval
-	 * Returns: 0 on success, -1 on failure
+	 * @params: Parameters to use in AP mode
 	 *
-	 * This function is used to configure Beacon template for the driver in
+	 * This function is used to configure Beacon template and/or extra IEs
+	 * to add for Beacon and Probe Response frames for the driver in
 	 * AP mode. The driver is responsible for building the full Beacon
 	 * frame by concatenating the head part with TIM IE generated by the
-	 * driver/firmware and finishing with the tail part.
+	 * driver/firmware and finishing with the tail part. Depending on the
+	 * driver architectue, this can be done either by using the full
+	 * template or the set of additional IEs (e.g., WPS and P2P IE).
+	 * Similarly, Probe Response processing depends on the driver design.
+	 * If the driver (or firmware) takes care of replying to Probe Request
+	 * frames, the extra IEs provided here needs to be added to the Probe
+	 * Response frames.
+	 *
+	 * Returns: 0 on success, -1 on failure
 	 */
-	int (*set_beacon)(void *priv, const u8 *head, size_t head_len,
-			  const u8 *tail, size_t tail_len, int dtim_period,
-			  int beacon_int);
+	int (*set_ap)(void *priv, struct wpa_driver_ap_params *params);
 
 	/**
 	 * hapd_init - Initialize driver interface (hostapd only)
@@ -1318,7 +1476,7 @@
 	 * Returns: Pointer to private data, %NULL on failure
 	 *
 	 * This function is used instead of init() or init2() when the driver
-	 * wrapper is used withh hostapd.
+	 * wrapper is used with hostapd.
 	 */
 	void * (*hapd_init)(struct hostapd_data *hapd,
 			    struct wpa_init_params *params);
@@ -1338,8 +1496,10 @@
 	 * This is an optional function to configure the kernel driver to
 	 * enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This
 	 * can be left undefined (set to %NULL) if IEEE 802.1X support is
-	 * always enabled and the driver uses set_beacon() to set WPA/RSN IE
+	 * always enabled and the driver uses set_ap() to set WPA/RSN IE
 	 * for Beacon frames.
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params);
 
@@ -1351,7 +1511,9 @@
 	 *
 	 * This is an optional function to configure privacy field in the
 	 * kernel driver for Beacon frames. This can be left undefined (set to
-	 * %NULL) if the driver uses the Beacon template from set_beacon().
+	 * %NULL) if the driver uses the Beacon template from set_ap().
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_privacy)(void *priv, int enabled);
 
@@ -1393,7 +1555,9 @@
 	 * This is an optional function to add information elements in the
 	 * kernel driver for Beacon and Probe Response frames. This can be left
 	 * undefined (set to %NULL) if the driver uses the Beacon template from
-	 * set_beacon().
+	 * set_ap().
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
 
@@ -1467,8 +1631,7 @@
 	 * Returns: Length of the SSID on success, -1 on failure
 	 *
 	 * This function need not be implemented if the driver uses Beacon
-	 * template from set_beacon() and does not reply to Probe Request
-	 * frames.
+	 * template from set_ap() and does not reply to Probe Request frames.
 	 */
 	int (*hapd_get_ssid)(void *priv, u8 *buf, int len);
 
@@ -1478,6 +1641,8 @@
 	 * @buf: SSID
 	 * @len: Length of the SSID in octets
 	 * Returns: 0 on success, -1 on failure
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*hapd_set_ssid)(void *priv, const u8 *buf, int len);
 
@@ -1501,6 +1666,9 @@
 	 * This function is used to add a station entry to the driver once the
 	 * station has completed association. This is only used if the driver
 	 * does not take care of association processing.
+	 *
+	 * With TDLS, this function is also used to add or set (params->set 1)
+	 * TDLS peer entries.
 	 */
 	int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
 
@@ -1557,41 +1725,6 @@
 			     int total_flags, int flags_or, int flags_and);
 
 	/**
-	 * set_rate_sets - Set supported and basic rate sets (AP only)
-	 * @priv: Private driver interface data
-	 * @supp_rates: -1 terminated array of supported rates in 100 kbps
-	 * @basic_rates: -1 terminated array of basic rates in 100 kbps
-	 * @mode: hardware mode (HOSTAPD_MODE_*)
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
-			     int mode);
-
-	/**
-	 * set_cts_protect - Set CTS protection mode (AP only)
-	 * @priv: Private driver interface data
-	 * @value: Whether CTS protection is enabled
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_cts_protect)(void *priv, int value);
-
-	/**
-	 * set_preamble - Set preamble mode (AP only)
-	 * @priv: Private driver interface data
-	 * @value: Whether short preamble is enabled
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_preamble)(void *priv, int value);
-
-	/**
-	 * set_short_slot_time - Set short slot time (AP only)
-	 * @priv: Private driver interface data
-	 * @value: Whether short slot time is enabled
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_short_slot_time)(void *priv, int value);
-
-	/**
 	 * set_tx_queue_params - Set TX queue parameters
 	 * @priv: Private driver interface data
 	 * @queue: Queue number (0 = VO, 1 = VI, 2 = BE, 3 = BK)
@@ -1604,17 +1737,6 @@
 				   int cw_max, int burst_time);
 
 	/**
-	 * valid_bss_mask - Validate BSSID mask
-	 * @priv: Private driver interface data
-	 * @addr: Address
-	 * @mask: Mask
-	 * Returns: 0 if mask is valid, -1 if mask is not valid, 1 if mask can
-	 * be used, but the main interface address must be the first address in
-	 * the block if mask is applied
-	 */
-	int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask);
-
-	/**
 	 * if_add - Add a virtual interface
 	 * @priv: Private driver interface data
 	 * @type: Interface type
@@ -1709,19 +1831,6 @@
 	int (*set_radius_acl_expire)(void *priv, const u8 *mac);
 
 	/**
-	 * set_ht_params - Set HT parameters (AP only)
-	 * @priv: Private driver interface data
-	 * @ht_capab: HT Capabilities IE
-	 * @ht_capab_len: Length of ht_capab in octets
-	 * @ht_oper: HT Operation IE
-	 * @ht_oper_len: Length of ht_oper in octets
-	 * Returns: 0 on success, -1 on failure
-	 */
-	int (*set_ht_params)(void *priv,
-			     const u8 *ht_capab, size_t ht_capab_len,
-			     const u8 *ht_oper, size_t ht_oper_len);
-
-	/**
 	 * set_ap_wps_ie - Add WPS IE(s) into Beacon/Probe Response frames (AP)
 	 * @priv: Private driver interface data
 	 * @beacon: WPS IE(s) for Beacon frames or %NULL to remove extra IE(s)
@@ -1733,7 +1842,7 @@
 	 *
 	 * This is an optional function to add WPS IE in the kernel driver for
 	 * Beacon and Probe Response frames. This can be left undefined (set
-	 * to %NULL) if the driver uses the Beacon template from set_beacon()
+	 * to %NULL) if the driver uses the Beacon template from set_ap()
 	 * and does not process Probe Request frames. If the driver takes care
 	 * of (Re)Association frame processing, the assocresp buffer includes
 	 * WPS IE(s) that need to be added to (Re)Association Response frames
@@ -1746,6 +1855,8 @@
 	 * also used to provide Probe Response IEs for P2P Listen state
 	 * operations for drivers that generate the Probe Response frames
 	 * internally.
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon,
 			     const struct wpabuf *proberesp,
@@ -1782,6 +1893,7 @@
 	 * @bssid: BSSID (Address 3)
 	 * @data: Frame body
 	 * @data_len: data length in octets
+	 @ @no_cck: Whether CCK rates must not be used to transmit this frame
 	 * Returns: 0 on success, -1 on failure
 	 *
 	 * This command can be used to request the driver to transmit an action
@@ -1799,7 +1911,7 @@
 	 */
 	int (*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);
+			   const u8 *data, size_t data_len, int no_cck);
 
 	/**
 	 * send_action_cancel_wait - Cancel action frame TX wait
@@ -1866,19 +1978,6 @@
 	int (*probe_req_report)(void *priv, int report);
 
 	/**
-	 * disable_11b_rates - Set whether IEEE 802.11b rates are used for TX
-	 * @priv: Private driver interface data
-	 * @disabled: Whether IEEE 802.11b rates are disabled
-	 * Returns: 0 on success, -1 on failure (or if not supported)
-	 *
-	 * This command is used to disable IEEE 802.11b rates (1, 2, 5.5, and
-	 * 11 Mbps) as TX rates for data and management frames. This can be
-	 * used to optimize channel use when there is no need to support IEEE
-	 * 802.11b-only devices.
-	 */
-	int (*disable_11b_rates)(void *priv, int disabled);
-
-	/**
 	 * deinit_ap - Deinitialize AP mode
 	 * @priv: Private driver interface data
 	 * Returns: 0 on success, -1 on failure (or if not supported)
@@ -1990,11 +2089,6 @@
 	int (*ampdu)(void *priv, int ampdu);
 
 	/**
-	 * set_intra_bss - Enables/Disables intra BSS bridging
-	 */
-	int (*set_intra_bss)(void *priv, int enabled);
-
-	/**
 	 * get_radio_name - Get physical radio name for the device
 	 * @priv: Private driver interface data
 	 * Returns: Radio name or %NULL if not known
@@ -2132,7 +2226,7 @@
 	 * struct wpa_driver_capa.
 	 */
 	int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr,
-				 u16 config_methods);
+				 u16 config_methods, int join);
 
 	/**
 	 * p2p_sd_request - Schedule a service discovery query
@@ -2232,7 +2326,7 @@
 	 * @status_code: Status Code or Reason Code to use (if needed)
 	 * @buf: TDLS IEs to add to the message
 	 * @len: Length of buf in octets
-	 * Returns: 0 on success, -1 on failure
+	 * Returns: 0 on success, negative (<0) on failure
 	 *
 	 * This optional function can be used to send packet to driver which is
 	 * responsible for receiving and sending all TDLS packets.
@@ -2241,6 +2335,16 @@
 			      u8 dialog_token, u16 status_code,
 			      const u8 *buf, size_t len);
 
+	/**
+	 * tdls_oper - Ask the driver to perform high-level TDLS operations
+	 * @priv: Private driver interface data
+	 * @oper: TDLS high-level operation. See %enum tdls_oper
+	 * @peer: Destination (peer) MAC address
+	 * Returns: 0 on success, negative (<0) on failure
+	 *
+	 * This optional function can be used to send high-level TDLS commands
+	 * to the driver.
+	 */
 	int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
 
 	/**
@@ -2259,9 +2363,11 @@
 	 * This function can be used to set authentication algorithms for AP
 	 * mode when static WEP is used. If the driver uses user space MLME/SME
 	 * implementation, there is no need to implement this function.
+	 *
+	 * DEPRECATED - use set_ap() instead
 	 */
 	int (*set_authmode)(void *priv, int authmode);
-
+#ifdef ANDROID
 	/**
 	 * driver_cmd - execute driver-specific command
 	 * @priv: private driver interface data
@@ -2272,6 +2378,135 @@
 	 * Returns: 0 on success, -1 on failure
 	 */
 	 int (*driver_cmd)(void *priv, char *cmd, char *buf, size_t buf_len);
+#endif
+	/**
+	 * set_rekey_info - Set rekey information
+	 * @priv: Private driver interface data
+	 * @kek: Current KEK
+	 * @kck: Current KCK
+	 * @replay_ctr: Current EAPOL-Key Replay Counter
+	 *
+	 * This optional function can be used to provide information for the
+	 * driver/firmware to process EAPOL-Key frames in Group Key Handshake
+	 * while the host (including wpa_supplicant) is sleeping.
+	 */
+	void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
+			       const u8 *replay_ctr);
+
+	/**
+	 * sta_assoc - Station association indication
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for association frame
+	 * @addr: MAC address of the station to associate
+	 * @reassoc: flag to indicate re-association
+	 * @status: association response status code
+	 * @ie: assoc response ie buffer
+	 * @len: ie buffer length
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function indicates the driver to send (Re)Association
+	 * Response frame to the station.
+	 */
+	 int (*sta_assoc)(void *priv, const u8 *own_addr, const u8 *addr,
+			  int reassoc, u16 status, const u8 *ie, size_t len);
+
+	/**
+	 * sta_auth - Station authentication indication
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for authentication frame
+	 * @addr: MAC address of the station to associate
+	 * @seq: authentication sequence number
+	 * @status: authentication response status code
+	 * @ie: authentication frame ie buffer
+	 * @len: ie buffer length
+	 *
+	 * This function indicates the driver to send Authentication frame
+	 * to the station.
+	 */
+	 int (*sta_auth)(void *priv, const u8 *own_addr, const u8 *addr,
+			 u16 seq, u16 status, const u8 *ie, size_t len);
+
+	/**
+	 * add_tspec - Add traffic stream
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station to associate
+	 * @tspec_ie: tspec ie buffer
+	 * @tspec_ielen: tspec ie length
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function adds the traffic steam for the station
+	 * and fills the medium_time in tspec_ie.
+	 */
+	 int (*add_tspec)(void *priv, const u8 *addr, u8 *tspec_ie,
+			  size_t tspec_ielen);
+
+	/**
+	 * add_sta_node - Add a station node in the driver
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station to add
+	 * @auth_alg: authentication algorithm used by the station
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function adds the station node in the driver, when
+	 * the station gets added by FT-over-DS.
+	 */
+	int (*add_sta_node)(void *priv, const u8 *addr, u16 auth_alg);
+
+	/**
+	 * sched_scan - Request the driver to initiate scheduled scan
+	 * @priv: Private driver interface data
+	 * @params: Scan parameters
+	 * @interval: Interval between scan cycles in milliseconds
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This operation should be used for scheduled scan offload to
+	 * the hardware. Every time scan results are available, the
+	 * driver should report scan results event for wpa_supplicant
+	 * which will eventually request the results with
+	 * wpa_driver_get_scan_results2(). This operation is optional
+	 * and if not provided or if it returns -1, we fall back to
+	 * normal host-scheduled scans.
+	 */
+	int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params,
+			  u32 interval);
+
+	/**
+	 * stop_sched_scan - Request the driver to stop a scheduled scan
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This should cause the scheduled scan to be stopped and
+	 * results should stop being sent. Must be supported if
+	 * sched_scan is supported.
+	 */
+	int (*stop_sched_scan)(void *priv);
+
+	/**
+	 * poll_client - Probe (null data or such) the given station
+	 * @priv: Private driver interface data
+	 * @own_addr: MAC address of sending interface
+	 * @addr: MAC address of the station to probe
+	 * @qos: Indicates whether station is QoS station
+	 *
+	 * This function is used to verify whether an associated station is
+	 * still present. This function does not need to be implemented if the
+	 * driver provides such inactivity polling mechanism.
+	 */
+	void (*poll_client)(void *priv, const u8 *own_addr,
+			    const u8 *addr, int qos);
+#ifdef ANDROID_P2P
+	/**
+	 * go_switch_channel - Announce channel switch and migrate the GO to a
+	 * given frequency.
+	 * @priv: Private driver interface data
+	 * @freq: frequency in MHz
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to move the GO to the legacy STA channel to avoid
+	 * frequency conflict in single channel concurrency.
+	 */
+	int (*go_switch_channel)(void *priv, unsigned int freq);
+#endif
 };
 
 
@@ -2674,7 +2909,35 @@
 	/**
 	 * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore
 	 */
-	EVENT_IBSS_PEER_LOST
+	EVENT_IBSS_PEER_LOST,
+
+	/**
+	 * EVENT_DRIVER_GTK_REKEY - Device/driver did GTK rekey
+	 *
+	 * This event carries the new replay counter to notify wpa_supplicant
+	 * of the current EAPOL-Key Replay Counter in case the driver/firmware
+	 * completed Group Key Handshake while the host (including
+	 * wpa_supplicant was sleeping).
+	 */
+	EVENT_DRIVER_GTK_REKEY,
+
+	/**
+	 * EVENT_SCHED_SCAN_STOPPED - Scheduled scan was stopped
+	 */
+	EVENT_SCHED_SCAN_STOPPED,
+
+	/**
+	 * EVENT_DRIVER_CLIENT_POLL_OK - Station responded to poll
+	 *
+	 * This event indicates that the station responded to the poll
+	 * initiated with @poll_client.
+	 */
+	EVENT_DRIVER_CLIENT_POLL_OK,
+
+	/**
+	 * EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
+	 */
+	EVENT_EAPOL_TX_STATUS
 };
 
 
@@ -2898,7 +3161,9 @@
 	 */
 	struct auth_info {
 		u8 peer[ETH_ALEN];
+		u8 bssid[ETH_ALEN];
 		u16 auth_type;
+		u16 auth_transaction;
 		u16 status_code;
 		const u8 *ies;
 		size_t ies_len;
@@ -2966,8 +3231,9 @@
 	 * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events
 	 */
 	struct rx_from_unknown {
-		const u8 *frame;
-		size_t len;
+		const u8 *bssid;
+		const u8 *addr;
+		int wds;
 	} rx_from_unknown;
 
 	/**
@@ -3075,6 +3341,18 @@
 		const u8 *sa;
 
 		/**
+		 * da - Destination address of the received Probe Request frame
+		 *	or %NULL if not available
+		 */
+		const u8 *da;
+
+		/**
+		 * bssid - BSSID of the received Probe Request frame or %NULL
+		 *	if not available
+		 */
+		const u8 *bssid;
+
+		/**
 		 * ie - IEs from the Probe Request body
 		 */
 		const u8 *ie;
@@ -3206,6 +3484,39 @@
 	struct ibss_peer_lost {
 		u8 peer[ETH_ALEN];
 	} ibss_peer_lost;
+
+	/**
+	 * struct driver_gtk_rekey - Data for EVENT_DRIVER_GTK_REKEY
+	 */
+	struct driver_gtk_rekey {
+		const u8 *bssid;
+		const u8 *replay_ctr;
+	} driver_gtk_rekey;
+
+	/**
+	 * struct client_poll - Data for EVENT_DRIVER_CLIENT_POLL_OK events
+	 * @addr: station address
+	 */
+	struct client_poll {
+		u8 addr[ETH_ALEN];
+	} client_poll;
+
+	/**
+	 * struct eapol_tx_status
+	 * @dst: Original destination
+	 * @data: Data starting with IEEE 802.1X header (!)
+	 * @data_len: Length of data
+	 * @ack: Indicates ack or lost frame
+	 *
+	 * This corresponds to hapd_send_eapol if the frame sent
+	 * there isn't just reported as EVENT_TX_STATUS.
+	 */
+	struct eapol_tx_status {
+		const u8 *dst;
+		const u8 *data;
+		int data_len;
+		int ack;
+	} eapol_tx_status;
 };
 
 /**
@@ -3258,4 +3569,10 @@
 	wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
 }
 
+/* driver_common.c */
+void wpa_scan_results_free(struct wpa_scan_results *res);
+
+/* Convert wpa_event_type to a string for logging */
+const char * event_to_string(enum wpa_event_type event);
+
 #endif /* DRIVER_H */
diff --git a/src/drivers/driver_atheros.c b/src/drivers/driver_atheros.c
index 1e78f6e..b17d1a6 100644
--- a/src/drivers/driver_atheros.c
+++ b/src/drivers/driver_atheros.c
@@ -34,7 +34,7 @@
  */
 #define ATH_WPS_IE
 
-#include "os/linux/include/ieee80211_external.h"
+#include "ieee80211_external.h"
 
 
 #ifdef CONFIG_WPS
@@ -45,7 +45,7 @@
 #endif
 #endif /* CONFIG_WPS */
 
-#include "wireless_copy.h"
+#include "linux_wext.h"
 
 #include "driver.h"
 #include "eloop.h"
@@ -641,6 +641,7 @@
 
 	wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
 		   (unsigned long) ie_len);
+	wpa_hexdump(MSG_DEBUG, "atheros: set_generic_elem", ie, ie_len);
 
 	wpabuf_free(drv->wpa_ie);
 	drv->wpa_ie = wpabuf_alloc_copy(ie, ie_len);
@@ -658,6 +659,8 @@
 			  wpabuf_len(drv->wps_beacon_ie));
 		app_ie->app_buflen = ie_len + wpabuf_len(drv->wps_beacon_ie);
 	}
+	wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(Beacon)",
+		    app_ie->app_buf, app_ie->app_buflen);
 	set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
 		     sizeof(struct ieee80211req_getset_appiebuf) +
 		     app_ie->app_buflen);
@@ -672,6 +675,8 @@
 			wpabuf_len(drv->wps_probe_resp_ie);
 	} else
 		app_ie->app_buflen = ie_len;
+	wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF(ProbeResp)",
+		    app_ie->app_buf, app_ie->app_buflen);
 	set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, app_ie,
 		     sizeof(struct ieee80211req_getset_appiebuf) +
 		     app_ie->app_buflen);
@@ -748,6 +753,8 @@
 
 	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));
@@ -785,8 +792,9 @@
 	u8 buf[512];
 	struct ieee80211req_getset_appiebuf *beac_ie;
 
-	wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
-		   (unsigned long) len);
+	wpa_printf(MSG_DEBUG, "%s buflen = %lu frametype=%u", __func__,
+		   (unsigned long) len, frametype);
+	wpa_hexdump(MSG_DEBUG, "atheros: IE", ie, len);
 
 	beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
 	beac_ie->app_frmtype = frametype;
@@ -797,11 +805,15 @@
 	if (((frametype == IEEE80211_APPIE_FRAME_BEACON) ||
 	     (frametype == IEEE80211_APPIE_FRAME_PROBE_RESP)) &&
 	    (drv->wpa_ie != NULL)) {
+		wpa_hexdump_buf(MSG_DEBUG, "atheros: Append WPA/RSN IE",
+				drv->wpa_ie);
 		os_memcpy(&(beac_ie->app_buf[len]), wpabuf_head(drv->wpa_ie),
 			  wpabuf_len(drv->wpa_ie));
 		beac_ie->app_buflen += wpabuf_len(drv->wpa_ie);
 	}
 
+	wpa_hexdump(MSG_DEBUG, "atheros: SET_APPIEBUF",
+		    beac_ie->app_buf, beac_ie->app_buflen);
 	return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
 			    sizeof(struct ieee80211req_getset_appiebuf) +
 			    beac_ie->app_buflen);
@@ -814,6 +826,11 @@
 {
 	struct atheros_driver_data *drv = priv;
 
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - beacon", beacon);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - proberesp",
+			proberesp);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: set_ap_wps_ie - assocresp",
+			assocresp);
 	wpabuf_free(drv->wps_beacon_ie);
 	drv->wps_beacon_ie = beacon ? wpabuf_dup(beacon) : NULL;
 	wpabuf_free(drv->wps_probe_resp_ie);
@@ -1332,6 +1349,8 @@
 	os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
 	iwr.u.essid.pointer = (caddr_t) buf;
 	iwr.u.essid.length = len;
+	iwr.u.essid.length = (len > IW_ESSID_MAX_SIZE) ?
+		IW_ESSID_MAX_SIZE : len;
 
 	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
 		perror("ioctl[SIOCGIWESSID]");
@@ -1374,6 +1393,34 @@
 	return set80211param(priv, IEEE80211_PARAM_AUTHMODE, authmode);
 }
 
+static int atheros_set_ap(void *priv, struct wpa_driver_ap_params *params)
+{
+	/*
+	 * TODO: Use this to replace set_authmode, set_privacy, set_ieee8021x,
+	 * set_generic_elem, and hapd_set_ssid.
+	 */
+
+	wpa_printf(MSG_DEBUG, "atheros: set_ap - pairwise_ciphers=0x%x "
+		   "group_cipher=0x%x key_mgmt_suites=0x%x auth_algs=0x%x "
+		   "wpa_version=0x%x privacy=%d interworking=%d",
+		   params->pairwise_ciphers, params->group_cipher,
+		   params->key_mgmt_suites, params->auth_algs,
+		   params->wpa_version, params->privacy, params->interworking);
+	wpa_hexdump_ascii(MSG_DEBUG, "atheros: SSID",
+			  params->ssid, params->ssid_len);
+	if (params->hessid)
+		wpa_printf(MSG_DEBUG, "atheros: HESSID " MACSTR,
+			   MAC2STR(params->hessid));
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: beacon_ies",
+			params->beacon_ies);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: proberesp_ies",
+			params->proberesp_ies);
+	wpa_hexdump_buf(MSG_DEBUG, "atheros: assocresp_ies",
+			params->assocresp_ies);
+
+	return 0;
+}
+
 const struct wpa_driver_ops wpa_driver_atheros_ops = {
 	.name			= "atheros",
 	.hapd_init		= atheros_init,
@@ -1396,4 +1443,5 @@
 	.commit			= atheros_commit,
 	.set_ap_wps_ie		= atheros_set_ap_wps_ie,
 	.set_authmode		= atheros_set_authmode,
+	.set_ap			= atheros_set_ap,
 };
diff --git a/src/drivers/driver_broadcom.c b/src/drivers/driver_broadcom.c
deleted file mode 100644
index cb88543..0000000
--- a/src/drivers/driver_broadcom.c
+++ /dev/null
@@ -1,599 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with old Broadcom wl.o driver
- * Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
- * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- * Please note that the newer Broadcom driver ("hybrid Linux driver") supports
- * Linux wireless extensions and does not need (or even work) with this old
- * driver wrapper. Use driver_wext.c with that driver.
- */
-
-#include "includes.h"
-
-#include <sys/ioctl.h>
-
-#include "common.h"
-
-#if 0
-#include <netpacket/packet.h>
-#include <net/ethernet.h>     /* the L2 protocols */
-#else
-#include <linux/if_packet.h>
-#include <linux/if_ether.h>   /* The L2 protocols */
-#endif
-#include <net/if.h>
-#include <typedefs.h>
-
-/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
- * WRT54G GPL tarball. */
-#include <wlioctl.h>
-
-#include "driver.h"
-#include "eloop.h"
-
-struct wpa_driver_broadcom_data {
-	void *ctx;
-	int ioctl_sock;
-	int event_sock;
-	char ifname[IFNAMSIZ + 1];
-};
-
-
-#ifndef WLC_DEAUTHENTICATE
-#define WLC_DEAUTHENTICATE 143
-#endif
-#ifndef WLC_DEAUTHENTICATE_WITH_REASON
-#define WLC_DEAUTHENTICATE_WITH_REASON 201
-#endif
-#ifndef WLC_SET_TKIP_COUNTERMEASURES
-#define WLC_SET_TKIP_COUNTERMEASURES 202
-#endif
-
-#if !defined(PSK_ENABLED) /* NEW driver interface */
-#define WL_VERSION 360130
-/* wireless authentication bit vector */
-#define WPA_ENABLED 1
-#define PSK_ENABLED 2
-                                                                                
-#define WAUTH_WPA_ENABLED(wauth)  ((wauth) & WPA_ENABLED)
-#define WAUTH_PSK_ENABLED(wauth)  ((wauth) & PSK_ENABLED)
-#define WAUTH_ENABLED(wauth)    ((wauth) & (WPA_ENABLED | PSK_ENABLED))
-
-#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
-
-typedef wl_wsec_key_t wsec_key_t;
-#endif
-
-typedef struct {
-	uint32 val;
-	struct ether_addr ea;
-	uint16 res;
-} wlc_deauth_t;
-
-
-static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
-					     void *timeout_ctx);
-
-static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
-			  void *buf, int len)
-{
-	struct ifreq ifr;
-	wl_ioctl_t ioc;
-	int ret = 0;
-
-	wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
-		   drv->ifname, cmd, len, buf);
-	/* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
-
-	ioc.cmd = cmd;
-	ioc.buf = buf;
-	ioc.len = len;
-	os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
-	ifr.ifr_data = (caddr_t) &ioc;
-	if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
-		if (cmd != WLC_GET_MAGIC)
-			perror(ifr.ifr_name);
-		wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
-			   cmd, ret);
-	}
-
-	return ret;
-}
-
-static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
-		return 0;
-	
-	os_memset(bssid, 0, ETH_ALEN);
-	return -1;
-}
-
-static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_ssid_t s;
-	
-	if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
-		return -1;
-
-	os_memcpy(ssid, s.SSID, s.SSID_len);
-	return s.SSID_len;
-}
-
-static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	unsigned int wauth, wsec;
-	struct ether_addr ea;
-
-	os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
-	if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
-	    -1 ||
-	    broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
-		return -1;
-
-	if (enable) {
-		wauth = PSK_ENABLED;
-		wsec = TKIP_ENABLED;
-	} else {
-		wauth = 255;
-		wsec &= ~(TKIP_ENABLED | AES_ENABLED);
-	}
-
-	if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
-	    -1 ||
-	    broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
-		return -1;
-
-	/* FIX: magic number / error handling? */
-	broadcom_ioctl(drv, 122, &ea, sizeof(ea));
-
-	return 0;
-}
-
-static int wpa_driver_broadcom_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 wpa_driver_broadcom_data *drv = priv;
-	int ret;
-	wsec_key_t wkt;
-
-	os_memset(&wkt, 0, sizeof wkt);
-	wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
-		   set_tx ? "PRIMARY " : "", key_idx, alg);
-	if (key && key_len > 0)
-		wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
-
-	switch (alg) {
-	case WPA_ALG_NONE:
-		wkt.algo = CRYPTO_ALGO_OFF;
-		break;
-	case WPA_ALG_WEP:
-		wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
-		break;
-	case WPA_ALG_TKIP:
-		wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
-		break;
-	case WPA_ALG_CCMP:
-		wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
-			       * AES_OCB_MSDU, AES_OCB_MPDU? */
-		break;
-	default:
-		wkt.algo = CRYPTO_ALGO_NALG;
-		break;
-	}
-
-	if (seq && seq_len > 0)
-		wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
-
-	if (addr)
-		wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
-
-	wkt.index = key_idx;
-	wkt.len = key_len;
-	if (key && key_len > 0) {
-		os_memcpy(wkt.data, key, key_len);
-		if (key_len == 32) {
-			/* hack hack hack XXX */
-			os_memcpy(&wkt.data[16], &key[24], 8);
-			os_memcpy(&wkt.data[24], &key[16], 8);
-		}
-	}
-	/* wkt.algo = CRYPTO_ALGO_...; */
-	wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
-	if (addr && set_tx)
-		os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
-	ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
-	if (addr && set_tx) {
-		/* FIX: magic number / error handling? */
-		broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
-	}
-	return ret;
-}
-
-
-static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
-					      void *sock_ctx)
-{
-	char buf[8192];
-	int left;
-	wl_wpa_header_t *wwh;
-	union wpa_event_data data;
-	u8 *resp_ies = NULL;
-
-	if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
-		return;
-
-	wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
-
-	if ((size_t) left < sizeof(wl_wpa_header_t))
-		return;
-
-	wwh = (wl_wpa_header_t *) buf;
-
-	if (wwh->snap.type != WL_WPA_ETHER_TYPE)
-		return;
-	if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
-		return;
-
-	os_memset(&data, 0, sizeof(data));
-
-	switch (wwh->type) {
-	case WLC_ASSOC_MSG:
-		left -= WL_WPA_HEADER_LEN;
-		wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
-			   left);
-		if (left > 0) {
-			resp_ies = os_malloc(left);
-			if (resp_ies == NULL)
-				return;
-			os_memcpy(resp_ies, buf + WL_WPA_HEADER_LEN, left);
-			data.assoc_info.resp_ies = resp_ies;
-			data.assoc_info.resp_ies_len = left;
-		}
-
-		wpa_supplicant_event(ctx, EVENT_ASSOC, &data);
-		os_free(resp_ies);
-		break;
-	case WLC_DISASSOC_MSG:
-		wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
-		wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
-		break;
-	case WLC_PTK_MIC_MSG:
-		wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
-		data.michael_mic_failure.unicast = 1;
-		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-		break;
-	case WLC_GTK_MIC_MSG:
-		wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
-		data.michael_mic_failure.unicast = 0;
-		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
-			   wwh->type);
-		break;
-	}
-}	
-
-static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
-{
-	int s;
-	struct sockaddr_ll ll;
-	struct wpa_driver_broadcom_data *drv;
-	struct ifreq ifr;
-
-	/* open socket to kernel */
-	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-		perror("socket");
-		return NULL;
-	}
-	/* do it */
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
-		perror(ifr.ifr_name);
-		return NULL;
-	}
-
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->ioctl_sock = s;
-
-	s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
-	if (s < 0) {
-		perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	os_memset(&ll, 0, sizeof(ll));
-	ll.sll_family = AF_PACKET;
-	ll.sll_protocol = ntohs(ETH_P_802_2);
-	ll.sll_ifindex = ifr.ifr_ifindex;
-	ll.sll_hatype = 0;
-	ll.sll_pkttype = PACKET_HOST;
-	ll.sll_halen = 0;
-
-	if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
-		perror("bind(netlink)");
-		close(s);
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
-				 NULL);
-	drv->event_sock = s;
-	wpa_driver_broadcom_set_wpa(drv, 1);
-
-	return drv;
-}
-
-static void wpa_driver_broadcom_deinit(void *priv)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wpa_driver_broadcom_set_wpa(drv, 0);
-	eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
-	eloop_unregister_read_sock(drv->event_sock);
-	close(drv->event_sock);
-	close(drv->ioctl_sock);
-	os_free(drv);
-}
-
-static int wpa_driver_broadcom_set_countermeasures(void *priv,
-						   int enabled)
-{
-#if 0
-	struct wpa_driver_broadcom_data *drv = priv;
-	/* FIX: ? */
-	return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
-			      sizeof(enabled));
-#else
-	return 0;
-#endif
-}
-
-static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	/* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
-	int _restrict = (enabled ? 1 : 0);
-	
-	if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT, 
-			   &_restrict, sizeof(_restrict)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
-			   &_restrict, sizeof(_restrict)) < 0)
-		return -1;
-
-	return 0;
-}
-
-static void wpa_driver_broadcom_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);
-}
-
-static int wpa_driver_broadcom_scan(void *priv,
-				    struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_ssid_t wst = { 0, "" };
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
-		wst.SSID_len = ssid_len;
-		os_memcpy(wst.SSID, ssid, ssid_len);
-	}
-	
-	if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
-		return -1;
-
-	eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
-			       drv->ctx);
-	return 0;
-}
-
-
-static const int frequency_list[] = { 
-	2412, 2417, 2422, 2427, 2432, 2437, 2442,
-	2447, 2452, 2457, 2462, 2467, 2472, 2484 
-};
-
-struct bss_ie_hdr {
-	u8 elem_id;
-	u8 len;
-	u8 oui[3];
-	/* u8 oui_type; */
-	/* u16 version; */
-} __attribute__ ((packed));
-
-static struct wpa_scan_results *
-wpa_driver_broadcom_get_scan_results(void *priv)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	char *buf;
-	wl_scan_results_t *wsr;
-	wl_bss_info_t *wbi;
-	size_t ap_num;
-	struct wpa_scan_results *res;
-
-	buf = os_malloc(WLC_IOCTL_MAXLEN);
-	if (buf == NULL)
-		return NULL;
-
-	wsr = (wl_scan_results_t *) buf;
-
-	wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
-	wsr->version = 107;
-	wsr->count = 0;
-
-	if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
-		os_free(buf);
-		return NULL;
-	}
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL) {
-		os_free(buf);
-		return NULL;
-	}
-
-	res->res = os_zalloc(wsr->count * sizeof(struct wpa_scan_res *));
-	if (res->res == NULL) {
-		os_free(res);
-		os_free(buf);
-		return NULL;
-	}
-
-	for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
-		struct wpa_scan_res *r;
-		r = os_malloc(sizeof(*r) + wbi->ie_length);
-		if (r == NULL)
-			break;
-		res->res[res->num++] = r;
-
-		os_memcpy(r->bssid, &wbi->BSSID, ETH_ALEN);
-		r->freq = frequency_list[wbi->channel - 1];
-		/* get ie's */
-		os_memcpy(r + 1, wbi + 1, wbi->ie_length);
-		r->ie_len = wbi->ie_length;
-
-		wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
-	}
-
-	wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
-		   "BSSes)",
-		   wsr->buflen, (unsigned long) ap_num);
-	
-	os_free(buf);
-	return res;
-	}
-
-static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
-					      int reason_code)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_deauth_t wdt;
-	wdt.val = reason_code;
-	os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
-	wdt.res = 0x7fff;
-	return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
-			      sizeof(wdt));
-}
-
-static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
-					    int reason_code)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	return broadcom_ioctl(drv, WLC_DISASSOC, NULL, 0);
-}
-
-static int
-wpa_driver_broadcom_associate(void *priv,
-			      struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_broadcom_data *drv = priv;
-	wlc_ssid_t s;
-	int infra = 1;
-	int auth = 0;
-	int wsec = 4;
-	int dummy;
-	int wpa_auth;
-	int ret;
-
-	ret = wpa_driver_broadcom_set_drop_unencrypted(
-		drv, params->drop_unencrypted);
-
-	s.SSID_len = params->ssid_len;
-	os_memcpy(s.SSID, params->ssid, params->ssid_len);
-
-	switch (params->pairwise_suite) {
-	case CIPHER_WEP40:
-	case CIPHER_WEP104:
-		wsec = 1;
-		break;
-
-	case CIPHER_TKIP:
-		wsec = 2;
-		break;
-
-	case CIPHER_CCMP:
-		wsec = 4;
-		break;
-
-	default:
-		wsec = 0;
-		break;
-	}
-
-	switch (params->key_mgmt_suite) {
-	case KEY_MGMT_802_1X:
-		wpa_auth = 1;
-		break;
-
-	case KEY_MGMT_PSK:
-		wpa_auth = 2;
-		break;
-
-	default:
-		wpa_auth = 255;
-		break;
-	}
-
-	/* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
-	 * group_suite, key_mgmt_suite);
-	 * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
-	 * wl join uses wlc_sec_wep here, not wlc_set_wsec */
-
-	if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
-			   sizeof(wpa_auth)) < 0 ||
-	    broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
-	    broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
-		return -1;
-
-	return ret;
-}
-
-const struct wpa_driver_ops wpa_driver_broadcom_ops = {
-	.name = "broadcom",
-	.desc = "Broadcom wl.o driver",
-	.get_bssid = wpa_driver_broadcom_get_bssid,
-	.get_ssid = wpa_driver_broadcom_get_ssid,
-	.set_key = wpa_driver_broadcom_set_key,
-	.init = wpa_driver_broadcom_init,
-	.deinit = wpa_driver_broadcom_deinit,
-	.set_countermeasures = wpa_driver_broadcom_set_countermeasures,
-	.scan2 = wpa_driver_broadcom_scan,
-	.get_scan_results2 = wpa_driver_broadcom_get_scan_results,
-	.deauthenticate = wpa_driver_broadcom_deauthenticate,
-	.disassociate = wpa_driver_broadcom_disassociate,
-	.associate = wpa_driver_broadcom_associate,
-};
diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c
new file mode 100644
index 0000000..26ca8d6
--- /dev/null
+++ b/src/drivers/driver_common.c
@@ -0,0 +1,90 @@
+/*
+ * Common driver-related functions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include "utils/common.h"
+#include "driver.h"
+
+void wpa_scan_results_free(struct wpa_scan_results *res)
+{
+	size_t i;
+
+	if (res == NULL)
+		return;
+
+	for (i = 0; i < res->num; i++)
+		os_free(res->res[i]);
+	os_free(res->res);
+	os_free(res);
+}
+
+
+const char * event_to_string(enum wpa_event_type event)
+{
+#define E2S(n) case EVENT_ ## n: return #n
+	switch (event) {
+	E2S(ASSOC);
+	E2S(DISASSOC);
+	E2S(MICHAEL_MIC_FAILURE);
+	E2S(SCAN_RESULTS);
+	E2S(ASSOCINFO);
+	E2S(INTERFACE_STATUS);
+	E2S(PMKID_CANDIDATE);
+	E2S(STKSTART);
+	E2S(TDLS);
+	E2S(FT_RESPONSE);
+	E2S(IBSS_RSN_START);
+	E2S(AUTH);
+	E2S(DEAUTH);
+	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(RX_ACTION);
+	E2S(REMAIN_ON_CHANNEL);
+	E2S(CANCEL_REMAIN_ON_CHANNEL);
+	E2S(MLME_RX);
+	E2S(RX_PROBE_REQ);
+	E2S(NEW_STA);
+	E2S(EAPOL_RX);
+	E2S(SIGNAL_CHANGE);
+	E2S(INTERFACE_ENABLED);
+	E2S(INTERFACE_DISABLED);
+	E2S(CHANNEL_LIST_CHANGED);
+	E2S(INTERFACE_UNAVAILABLE);
+	E2S(BEST_CHANNEL);
+	E2S(UNPROT_DEAUTH);
+	E2S(UNPROT_DISASSOC);
+	E2S(STATION_LOW_ACK);
+	E2S(P2P_DEV_FOUND);
+	E2S(P2P_GO_NEG_REQ_RX);
+	E2S(P2P_GO_NEG_COMPLETED);
+	E2S(P2P_PROV_DISC_REQUEST);
+	E2S(P2P_PROV_DISC_RESPONSE);
+	E2S(P2P_SD_REQUEST);
+	E2S(P2P_SD_RESPONSE);
+	E2S(IBSS_PEER_LOST);
+	E2S(DRIVER_GTK_REKEY);
+	E2S(SCHED_SCAN_STOPPED);
+	E2S(DRIVER_CLIENT_POLL_OK);
+	E2S(EAPOL_TX_STATUS);
+	}
+
+	return "UNKNOWN";
+#undef E2S
+}
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
index e855c1b..8fc0efd 100644
--- a/src/drivers/driver_hostap.c
+++ b/src/drivers/driver_hostap.c
@@ -15,7 +15,7 @@
 #include "includes.h"
 #include <sys/ioctl.h>
 
-#include "wireless_copy.h"
+#include "linux_wext.h"
 #include "common.h"
 #include "driver.h"
 #include "driver_wext.h"
@@ -23,8 +23,6 @@
 #include "driver_hostap.h"
 
 
-#ifdef HOSTAPD
-
 #include <net/if_arp.h>
 #include <netpacket/packet.h>
 
@@ -32,6 +30,7 @@
 #include "netlink.h"
 #include "linux_ioctl.h"
 #include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
 
 
 /* MTU to be set for the wlan#ap device; this is mainly needed for IEEE 802.1X
@@ -84,8 +83,8 @@
 
 	sa = hdr->addr2;
 	os_memset(&event, 0, sizeof(event));
-	event.rx_from_unknown.frame = buf;
-	event.rx_from_unknown.len = len;
+	event.rx_from_unknown.bssid = get_hdr_bssid(hdr, len);
+	event.rx_from_unknown.addr = sa;
 	wpa_supplicant_event(drv->hapd, EVENT_RX_FROM_UNKNOWN, &event);
 
 	pos = (u8 *) (hdr + 1);
@@ -148,7 +147,6 @@
 {
 	struct ieee80211_hdr *hdr;
 	u16 fc, extra_len, type, stype;
-	unsigned char *extra = NULL;
 	size_t data_len = len;
 	int ver;
 	union wpa_event_data event;
@@ -185,7 +183,6 @@
 			return;
 		}
 		len -= extra_len + 2;
-		extra = buf + len;
 	} else if (ver == 1 || ver == 2) {
 		handle_tx_callback(drv, buf, data_len, ver == 2 ? 1 : 0);
 		return;
@@ -273,7 +270,7 @@
 }
 
 
-static int hostap_send_mlme(void *priv, const u8 *msg, size_t len)
+static int hostap_send_mlme(void *priv, const u8 *msg, size_t len, int noack)
 {
 	struct hostap_driver_data *drv = priv;
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
@@ -322,7 +319,7 @@
 	pos += 2;
 	memcpy(pos, data, data_len);
 
-	res = hostap_send_mlme(drv, (u8 *) hdr, len);
+	res = hostap_send_mlme(drv, (u8 *) hdr, len, 0);
 	if (res < 0) {
 		wpa_printf(MSG_ERROR, "hostap_send_eapol - packet len: %lu - "
 			   "failed: %d (%s)",
@@ -1054,7 +1051,26 @@
 	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
 	mgmt.u.deauth.reason_code = host_to_le16(reason);
 	return hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-				sizeof(mgmt.u.deauth));
+				sizeof(mgmt.u.deauth), 0);
+}
+
+
+static int hostap_set_freq(void *priv, struct hostapd_freq_params *freq)
+{
+	struct hostap_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;
 }
 
 
@@ -1072,7 +1088,7 @@
 	memcpy(mgmt.bssid, own_addr, ETH_ALEN);
 	mgmt.u.disassoc.reason_code = host_to_le16(reason);
 	return  hostap_send_mlme(drv, (u8 *) &mgmt, IEEE80211_HDRLEN +
-				 sizeof(mgmt.u.disassoc));
+				 sizeof(mgmt.u.disassoc), 0);
 }
 
 
@@ -1126,492 +1142,38 @@
 	return mode;
 }
 
-#else /* HOSTAPD */
 
-struct wpa_driver_hostap_data {
-	void *wext; /* private data for driver_wext */
-	void *ctx;
-	char ifname[IFNAMSIZ + 1];
-	int sock;
-	int current_mode; /* infra/adhoc */
-};
-
-
-static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg);
-
-
-static int hostapd_ioctl(struct wpa_driver_hostap_data *drv,
-			 struct prism2_hostapd_param *param,
-			 int len, int show_err)
+static void wpa_driver_hostap_poll_client(void *priv, const u8 *own_addr,
+					  const u8 *addr, int qos)
 {
-	struct iwreq iwr;
+	struct ieee80211_hdr hdr;
 
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) param;
-	iwr.u.data.length = len;
+	os_memset(&hdr, 0, sizeof(hdr));
 
-	if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
-		int ret = errno;
-		if (show_err)
-			perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
-		return ret;
-	}
+	/*
+	 * WLAN_FC_STYPE_NULLFUNC would be more appropriate,
+	 * but it is apparently not retried so TX Exc events
+	 * are not received for it.
+	 * This is the reason the driver overrides the default
+	 * handling.
+	 */
+	hdr.frame_control = IEEE80211_FC(WLAN_FC_TYPE_DATA,
+					 WLAN_FC_STYPE_DATA);
 
-	return 0;
+	hdr.frame_control |=
+		host_to_le16(WLAN_FC_FROMDS);
+	os_memcpy(hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+	os_memcpy(hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+	os_memcpy(hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+	hostap_send_mlme(priv, (u8 *)&hdr, sizeof(hdr), 0);
 }
 
 
-static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv,
-					const u8 *wpa_ie, size_t wpa_ie_len)
-{
-	struct prism2_hostapd_param *param;
-	int res;
-	size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
-	if (blen < sizeof(*param))
-		blen = sizeof(*param);
-
-	param = os_zalloc(blen);
-	if (param == NULL)
-		return -1;
-
-	param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
-	param->u.generic_elem.len = wpa_ie_len;
-	os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
-	res = hostapd_ioctl(drv, param, blen, 1);
-
-	os_free(param);
-
-	return res;
-}
-
-
-static int prism2param(struct wpa_driver_hostap_data *drv, int param,
-		       int value)
-{
-	struct iwreq iwr;
-	int *i, ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	i = (int *) iwr.u.name;
-	*i++ = param;
-	*i++ = value;
-
-	if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
-		perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
-		ret = -1;
-	}
-	return ret;
-}
-
-
-static int wpa_driver_hostap_set_wpa(void *priv, int enabled)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	int ret = 0;
-
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-
-	if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0)
-		ret = -1;
-	if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0)
-		ret = -1;
-	if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0)
-		ret = -1;
-
-	return ret;
-}
-
-
-static void show_set_key_error(struct prism2_hostapd_param *param)
-{
-	switch (param->u.crypt.err) {
-	case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
-		wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
-			   param->u.crypt.alg);
-		wpa_printf(MSG_INFO, "You may need to load kernel module to "
-			   "register that algorithm.");
-		wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
-			   "WEP.");
-		break;
-	case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
-		wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
-			   MAC2STR(param->sta_addr));
-		break;
-	case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
-		wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
-		break;
-	case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
-		wpa_printf(MSG_INFO, "Key setting failed.");
-		break;
-	case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
-		wpa_printf(MSG_INFO, "TX key index setting failed.");
-		break;
-	case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
-		wpa_printf(MSG_INFO, "Card configuration failed.");
-		break;
-	}
-}
-
-
-static int wpa_driver_hostap_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 wpa_driver_hostap_data *drv = priv;
-	struct prism2_hostapd_param *param;
-	u8 *buf;
-	size_t blen;
-	int ret = 0;
-	char *alg_name;
-
-	switch (alg) {
-	case WPA_ALG_NONE:
-		alg_name = "none";
-		break;
-	case WPA_ALG_WEP:
-		alg_name = "WEP";
-		break;
-	case WPA_ALG_TKIP:
-		alg_name = "TKIP";
-		break;
-	case WPA_ALG_CCMP:
-		alg_name = "CCMP";
-		break;
-	default:
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	if (seq_len > 8)
-		return -2;
-
-	blen = sizeof(*param) + key_len;
-	buf = os_zalloc(blen);
-	if (buf == NULL)
-		return -1;
-
-	param = (struct prism2_hostapd_param *) buf;
-	param->cmd = PRISM2_SET_ENCRYPTION;
-	/* TODO: In theory, STA in client mode can use five keys; four default
-	 * keys for receiving (with keyidx 0..3) and one individual key for
-	 * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
-	 * keyidx 0 is reserved for this unicast use and default keys can only
-	 * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
-	 * This should be fine for more or less all cases, but for completeness
-	 * sake, the driver could be enhanced to support the missing key. */
-#if 0
-	if (addr == NULL)
-		os_memset(param->sta_addr, 0xff, ETH_ALEN);
-	else
-		os_memcpy(param->sta_addr, addr, ETH_ALEN);
-#else
-	os_memset(param->sta_addr, 0xff, ETH_ALEN);
-#endif
-	os_strlcpy((char *) param->u.crypt.alg, alg_name,
-		   HOSTAP_CRYPT_ALG_NAME_LEN);
-	param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
-	param->u.crypt.idx = key_idx;
-	if (seq)
-		os_memcpy(param->u.crypt.seq, seq, seq_len);
-	param->u.crypt.key_len = key_len;
-	os_memcpy((u8 *) (param + 1), key, key_len);
-
-	if (hostapd_ioctl(drv, param, blen, 1)) {
-		wpa_printf(MSG_WARNING, "Failed to set encryption.");
-		show_set_key_error(param);
-		ret = -1;
-	}
-	os_free(buf);
-
-	return ret;
-}
-
-
-static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled);
-}
-
-
-static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv,
-				   int type)
-{
-	struct iwreq iwr;
-	int *i, ret = 0;
-
-	wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	i = (int *) iwr.u.name;
-	*i++ = type;
-
-	if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) {
-	        perror("ioctl[PRISM2_IOCTL_RESET]");
-	        ret = -1;
-	}
-	return ret;
-}
-
-
-static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv,
-				  const u8 *addr, int cmd, int reason_code)
-{
-	struct prism2_hostapd_param param;
-	int ret;
-
-	/* There does not seem to be a better way of deauthenticating or
-	 * disassociating with Prism2/2.5/3 than sending the management frame
-	 * and then resetting the Port0 to make sure both the AP and the STA
-	 * end up in disconnected state. */
-	os_memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_MLME;
-	os_memcpy(param.sta_addr, addr, ETH_ALEN);
-	param.u.mlme.cmd = cmd;
-	param.u.mlme.reason_code = reason_code;
-	ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
-	if (ret == 0) {
-		os_sleep(0, 100000);
-		ret = wpa_driver_hostap_reset(drv, 2);
-	}
-	return ret;
-}
-
-
-static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr,
-					    int reason_code)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH,
-				      reason_code);
-}
-
-
-static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC,
-				      reason_code);
-}
-
-
-static int
-wpa_driver_hostap_associate(void *priv,
-			    struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	int ret = 0;
-	int allow_unencrypted_eapol;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED,
-			params->drop_unencrypted) < 0)
-		ret = -1;
-	if (wpa_driver_hostap_set_auth_alg(drv, params->auth_alg) < 0)
-		ret = -1;
-	if (params->mode != drv->current_mode) {
-		/* At the moment, Host AP driver requires host_roaming=2 for
-		 * infrastructure mode and host_roaming=0 for adhoc. */
-		if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING,
-				params->mode == IEEE80211_MODE_IBSS ? 0 : 2) <
-		    0) {
-			wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming",
-				   __func__);
-		}
-		drv->current_mode = params->mode;
-	}
-
-	if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
-			params->key_mgmt_suite != KEY_MGMT_NONE) < 0)
-		ret = -1;
-	if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie,
-					 params->wpa_ie_len) < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0)
-		ret = -1;
-	if (params->freq &&
-	    wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
-	    < 0)
-		ret = -1;
-	if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
-		ret = -1;
-
-	/* Allow unencrypted EAPOL messages even if pairwise keys are set when
-	 * not using WPA. IEEE 802.1X specifies that these frames are not
-	 * encrypted, but WPA encrypts them when pairwise keys are in use. */
-	if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
-	    params->key_mgmt_suite == KEY_MGMT_PSK)
-		allow_unencrypted_eapol = 0;
-	else
-		allow_unencrypted_eapol = 1;
-	
-	if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X,
-			allow_unencrypted_eapol) < 0) {
-		wpa_printf(MSG_DEBUG, "hostap: Failed to configure "
-			   "ieee_802_1x param");
-		/* Ignore this error.. driver_hostap.c can also be used with
-		 * other drivers that do not support this prism2_param. */
-	}
-
-	return ret;
-}
-
-
-static int wpa_driver_hostap_scan(void *priv,
-				  struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	struct prism2_hostapd_param param;
-	int ret;
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (ssid == NULL) {
-		/* Use standard Linux Wireless Extensions ioctl if possible
-		 * because some drivers using hostap code in wpa_supplicant
-		 * might not support Host AP specific scan request (with SSID
-		 * info). */
-		return wpa_driver_wext_scan(drv->wext, params);
-	}
-
-	if (ssid_len > 32)
-		ssid_len = 32;
-
-	os_memset(&param, 0, sizeof(param));
-	param.cmd = PRISM2_HOSTAPD_SCAN_REQ;
-	param.u.scan_req.ssid_len = ssid_len;
-	os_memcpy(param.u.scan_req.ssid, ssid, ssid_len);
-	ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
-
-	/* Not all drivers generate "scan completed" wireless event, so try to
-	 * read results after a timeout. */
-	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
-			     drv->ctx);
-	eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext,
-			       drv->ctx);
-
-	return ret;
-}
-
-
-static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	int algs = 0;
-
-	if (auth_alg & WPA_AUTH_ALG_OPEN)
-		algs |= 1;
-	if (auth_alg & WPA_AUTH_ALG_SHARED)
-		algs |= 2;
-	if (auth_alg & WPA_AUTH_ALG_LEAP)
-		algs |= 4;
-	if (algs == 0)
-		algs = 1; /* at least one algorithm should be set */
-
-	return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs);
-}
-
-
-static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static struct wpa_scan_results * wpa_driver_hostap_get_scan_results(void *priv)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_hostap_set_operstate(void *priv, int state)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_hostap_data *drv;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->wext = wpa_driver_wext_init(ctx, ifname);
-	if (drv->wext == NULL) {
-		os_free(drv);
-		return NULL;
-	}
-
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0) {
-		perror("socket");
-		wpa_driver_wext_deinit(drv->wext);
-		os_free(drv);
-		return NULL;
-	}
-
-	if (os_strncmp(ifname, "wlan", 4) == 0) {
-		/*
-		 * Host AP driver may use both wlan# and wifi# interface in
-		 * wireless events.
-		 */
-		char ifname2[IFNAMSIZ + 1];
-		os_strlcpy(ifname2, ifname, sizeof(ifname2));
-		os_memcpy(ifname2, "wifi", 4);
-		wpa_driver_wext_alternative_ifindex(drv->wext, ifname2);
-	}
-
-	wpa_driver_hostap_set_wpa(drv, 1);
-
-	return drv;
-}
-
-
-static void wpa_driver_hostap_deinit(void *priv)
-{
-	struct wpa_driver_hostap_data *drv = priv;
-	wpa_driver_hostap_set_wpa(drv, 0);
-	wpa_driver_wext_deinit(drv->wext);
-	close(drv->sock);
-	os_free(drv);
-}
-
-#endif /* HOSTAPD */
-
-
 const struct wpa_driver_ops wpa_driver_hostap_ops = {
 	.name = "hostap",
 	.desc = "Host AP driver (Intersil Prism2/2.5/3)",
 	.set_key = wpa_driver_hostap_set_key,
-#ifdef HOSTAPD
 	.hapd_init = hostap_init,
 	.hapd_deinit = hostap_driver_deinit,
 	.set_ieee8021x = hostap_set_ieee8021x,
@@ -1632,17 +1194,6 @@
 	.sta_clear_stats = hostap_sta_clear_stats,
 	.get_hw_feature_data = hostap_get_hw_feature_data,
 	.set_ap_wps_ie = hostap_set_ap_wps_ie,
-#else /* HOSTAPD */
-	.get_bssid = wpa_driver_hostap_get_bssid,
-	.get_ssid = wpa_driver_hostap_get_ssid,
-	.set_countermeasures = wpa_driver_hostap_set_countermeasures,
-	.scan2 = wpa_driver_hostap_scan,
-	.get_scan_results2 = wpa_driver_hostap_get_scan_results,
-	.deauthenticate = wpa_driver_hostap_deauthenticate,
-	.disassociate = wpa_driver_hostap_disassociate,
-	.associate = wpa_driver_hostap_associate,
-	.init = wpa_driver_hostap_init,
-	.deinit = wpa_driver_hostap_deinit,
-	.set_operstate = wpa_driver_hostap_set_operstate,
-#endif /* HOSTAPD */
+	.set_freq = hostap_set_freq,
+	.poll_client = wpa_driver_hostap_poll_client,
 };
diff --git a/src/drivers/driver_iphone.m b/src/drivers/driver_iphone.m
deleted file mode 100644
index 8213fda..0000000
--- a/src/drivers/driver_iphone.m
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#define Boolean __DummyBoolean
-#include <CoreFoundation/CoreFoundation.h>
-#undef Boolean
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-
-#include "MobileApple80211.h"
-
-struct wpa_driver_iphone_data {
-	void *ctx;
-	Apple80211Ref wireless_ctx;
-	CFArrayRef scan_results;
-	int ctrl_power;
-};
-
-
-static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
-{
-	const void *res;
-	CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
-						    kCFStringEncodingMacRoman);
-	if (str == NULL)
-		return NULL;
-
-	res = CFDictionaryGetValue(dict, str);
-	CFRelease(str);
-	return res;
-}
-
-
-static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	CFDataRef data;
-	int err, len;
-
-	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
-				  &data);
-	if (err != 0) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
-			   "failed: %d", err);
-		return -1;
-	}
-
-	len = CFDataGetLength(data);
-	if (len > 32) {
-		CFRelease(data);
-		return -1;
-	}
-	os_memcpy(ssid, CFDataGetBytePtr(data), len);
-	CFRelease(data);
-
-	return len;
-}
-
-
-static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	CFStringRef data;
-	int err;
-	int a1, a2, a3, a4, a5, a6;
-
-	err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
-				  &data);
-	if (err != 0) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
-			   "failed: %d", err);
-		return -1;
-	}
-
-	sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
-	       "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
-	bssid[0] = a1;
-	bssid[1] = a2;
-	bssid[2] = a3;
-	bssid[3] = a4;
-	bssid[4] = a5;
-	bssid[5] = a6;
-
-	CFRelease(data);
-
-	return 0;
-}
-
-
-static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	int err;
-
-	if (drv->scan_results) {
-		CFRelease(drv->scan_results);
-		drv->scan_results = NULL;
-	}
-
-	err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
-			   err);
-		return -1;
-	}
-
-	eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
-			       drv->ctx);
-	return 0;
-}
-
-
-static int wpa_driver_iphone_get_scan_results(void *priv,
-					      struct wpa_scan_result *results,
-					      size_t max_size)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	size_t i, num;
-
-	if (drv->scan_results == NULL)
-		return 0;
-
-	num = CFArrayGetCount(drv->scan_results);
-	if (num > max_size)
-		num = max_size;
-	os_memset(results, 0, num * sizeof(struct wpa_scan_result));
-
-	for (i = 0; i < num; i++) {
-		struct wpa_scan_result *res = &results[i];
-		CFDictionaryRef dict =
-			CFArrayGetValueAtIndex(drv->scan_results, i);
-		CFDataRef data;
-		CFStringRef str;
-		CFNumberRef num;
-		int val;
-
-		data = cfdict_get_key_str(dict, "SSID");
-		if (data) {
-			res->ssid_len = CFDataGetLength(data);
-			if (res->ssid_len > 32)
-				res->ssid_len = 32;
-			os_memcpy(res->ssid, CFDataGetBytePtr(data),
-				  res->ssid_len);
-		}
-
-		str = cfdict_get_key_str(dict, "BSSID");
-		if (str) {
-			int a1, a2, a3, a4, a5, a6;
-			sscanf(CFStringGetCStringPtr(
-				       str, kCFStringEncodingMacRoman),
-			       "%x:%x:%x:%x:%x:%x",
-			       &a1, &a2, &a3, &a4, &a5, &a6);
-			res->bssid[0] = a1;
-			res->bssid[1] = a2;
-			res->bssid[2] = a3;
-			res->bssid[3] = a4;
-			res->bssid[4] = a5;
-			res->bssid[5] = a6;
-		}
-
-		num = cfdict_get_key_str(dict, "CAPABILITIES");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->caps = val;
-		}
-
-		num = cfdict_get_key_str(dict, "CHANNEL");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->freq = 2407 + val * 5;
-		}
-
-		num = cfdict_get_key_str(dict, "RSSI");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->level = val;
-		}
-
-		num = cfdict_get_key_str(dict, "NOISE");
-		if (num) {
-			if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
-				res->noise = val;
-		}
-
-		data = cfdict_get_key_str(dict, "IE");
-		if (data) {
-			u8 *ptr = (u8 *) CFDataGetBytePtr(data);
-			int len = CFDataGetLength(data);
-			u8 *pos = ptr, *end = ptr + len;
-
-			while (pos + 2 < end) {
-				if (pos + 2 + pos[1] > end)
-					break;
-				if (pos[0] == WLAN_EID_RSN &&
-				    pos[1] <= SSID_MAX_WPA_IE_LEN) {
-					os_memcpy(res->rsn_ie, pos,
-						  2 + pos[1]);
-					res->rsn_ie_len = 2 + pos[1];
-				}
-				if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
-				    pos[1] > 4 && pos[2] == 0x00 &&
-				    pos[3] == 0x50 && pos[4] == 0xf2 &&
-				    pos[5] == 0x01) {
-					os_memcpy(res->wpa_ie, pos,
-						  2 + pos[1]);
-					res->wpa_ie_len = 2 + pos[1];
-				}
-
-				pos = pos + 2 + pos[1];
-			}
-		}
-	}
-
-	return num;
-}
-
-
-static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_iphone_data *drv = eloop_ctx;
-	u8 bssid[ETH_ALEN];
-
-	if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
-		eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
-				       drv, drv->ctx);
-		return;
-	}
-
-	wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
-}
-
-
-static int wpa_driver_iphone_associate(
-	void *priv, struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	int i, num, err;
-	size_t ssid_len;
-	CFDictionaryRef bss = NULL;
-
-	/*
-	 * TODO: Consider generating parameters instead of just using an entry
-	 * from scan results in order to support ap_scan=2.
-	 */
-
-	if (drv->scan_results == NULL) {
-		wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
-			   "associate");
-		return -1;
-	}
-
-	num = CFArrayGetCount(drv->scan_results);
-
-	for (i = 0; i < num; i++) {
-		CFDictionaryRef dict =
-			CFArrayGetValueAtIndex(drv->scan_results, i);
-		CFDataRef data;
-
-		data = cfdict_get_key_str(dict, "SSID");
-		if (data == NULL)
-			continue;
-
-		ssid_len = CFDataGetLength(data);
-		if (ssid_len != params->ssid_len ||
-		    os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
-		    != 0)
-			continue;
-
-		bss = dict;
-		break;
-	}
-
-	if (bss == NULL) {
-		wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
-			   "results - cannot associate");
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
-		   "from scan results");
-
-	err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
-			   "%d", err);
-		return -1;
-	}
-
-	/*
-	 * Driver is actually already associated; report association from an
-	 * eloop callback.
-	 */
-	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
-	eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
-			       drv->ctx);
-
-	return 0;
-}
-
-
-static int wpa_driver_iphone_set_key(void *priv, 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)
-{
-	/*
-	 * TODO: Need to either support configuring PMK for 4-way handshake or
-	 * PTK for TKIP/CCMP.
-	 */
-	return -1;
-}
-
-
-static int wpa_driver_iphone_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;
-	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_4WAY_HANDSHAKE;
-
-	return 0;
-}
-
-
-static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_iphone_data *drv;
-	int err;
-	char power;
-	CFStringRef name;
-	CFDictionaryRef dict;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	err = Apple80211Open(&drv->wireless_ctx);
-	if (err) {
-		wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
-			   err);
-		os_free(drv);
-		return NULL;
-	}
-
-	name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
-					 kCFStringEncodingISOLatin1);
-	if (name == NULL) {
-		wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
-		Apple80211Close(drv->wireless_ctx);
-		os_free(drv);
-		return NULL;
-	}
-
-	err = Apple80211BindToInterface(drv->wireless_ctx, name);
-	CFRelease(name);
-
-	if (err) {
-		wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
-			   "failed: %d", err);
-		Apple80211Close(drv->wireless_ctx);
-		os_free(drv);
-		return NULL;
-	}
-
-	err = Apple80211GetPower(drv->wireless_ctx, &power);
-	if (err)
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
-			   err);
-
-	wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
-
-	if (!power) {
-		drv->ctrl_power = 1;
-		err = Apple80211SetPower(drv->wireless_ctx, 1);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
-				   "failed: %d", err);
-			Apple80211Close(drv->wireless_ctx);
-			os_free(drv);
-			return NULL;
-		}
-	}
-
-	err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
-	if (err == 0) {
-		CFShow(dict);
-		CFRelease(dict);
-	} else {
-		printf("Apple80211GetInfoCopy: %d\n", err);
-	}
-
-	return drv;
-}
-
-
-static void wpa_driver_iphone_deinit(void *priv)
-{
-	struct wpa_driver_iphone_data *drv = priv;
-	int err;
-
-	eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
-	eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
-
-	if (drv->ctrl_power) {
-		wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
-		err = Apple80211SetPower(drv->wireless_ctx, 0);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
-				   "failed: %d", err);
-		}
-	}
-
-	err = Apple80211Close(drv->wireless_ctx);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
-			   err);
-	}
-
-	if (drv->scan_results)
-		CFRelease(drv->scan_results);
-
-	os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_iphone_ops = {
-	.name = "iphone",
-	.desc = "iPhone/iPod touch Apple80211 driver",
-	.get_ssid = wpa_driver_iphone_get_ssid,
-	.get_bssid = wpa_driver_iphone_get_bssid,
-	.init = wpa_driver_iphone_init,
-	.deinit = wpa_driver_iphone_deinit,
-	.scan = wpa_driver_iphone_scan,
-	.get_scan_results = wpa_driver_iphone_get_scan_results,
-	.associate = wpa_driver_iphone_associate,
-	.set_key = wpa_driver_iphone_set_key,
-	.get_capa = wpa_driver_iphone_get_capa,
-};
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
index 630fbf4..edb086f 100644
--- a/src/drivers/driver_madwifi.c
+++ b/src/drivers/driver_madwifi.c
@@ -27,7 +27,7 @@
 #include "driver_wext.h"
 #include "eloop.h"
 #include "common/ieee802_11_defs.h"
-#include "wireless_copy.h"
+#include "linux_wext.h"
 
 /*
  * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
@@ -71,8 +71,6 @@
 
 #define WPA_KEY_RSC_LEN 8
 
-#ifdef HOSTAPD
-
 #include "priv_netlink.h"
 #include "netlink.h"
 #include "linux_ioctl.h"
@@ -734,6 +732,8 @@
 
 	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));
@@ -804,6 +804,24 @@
 #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])
 {
@@ -1274,554 +1292,11 @@
 	return linux_set_iface_flags(drv->ioctl_sock, drv->iface, 1);
 }
 
-#else /* HOSTAPD */
-
-struct wpa_driver_madwifi_data {
-	void *wext; /* private data for driver_wext */
-	void *ctx;
-	char ifname[IFNAMSIZ + 1];
-	int sock;
-};
-
-static int wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg);
-static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
-					       size_t ies_len);
-
-
-static int
-set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
-	     int show_err)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	if (len < IFNAMSIZ &&
-	    op != IEEE80211_IOCTL_SET_APPIEBUF) {
-		/*
-		 * Argument data fits inline; put it there.
-		 */
-		os_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->sock, op, &iwr) < 0) {
-		if (show_err) {
-#ifdef MADWIFI_NG
-			int first = IEEE80211_IOCTL_SETPARAM;
-			int last = IEEE80211_IOCTL_KICKMAC;
-			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]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
-				"ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
-				NULL,
-				"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;
-			int last = IEEE80211_IOCTL_CHANLIST;
-			static const char *opnames[] = {
-				"ioctl[IEEE80211_IOCTL_SETPARAM]",
-				"ioctl[IEEE80211_IOCTL_GETPARAM]",
-				"ioctl[IEEE80211_IOCTL_SETKEY]",
-				"ioctl[IEEE80211_IOCTL_GETKEY]",
-				"ioctl[IEEE80211_IOCTL_DELKEY]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_SETMLME]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_SETOPTIE]",
-				"ioctl[IEEE80211_IOCTL_GETOPTIE]",
-				"ioctl[IEEE80211_IOCTL_ADDMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_DELMAC]",
-				NULL,
-				"ioctl[IEEE80211_IOCTL_CHANLIST]",
-			};
-#endif /* MADWIFI_NG */
-			int idx = op - first;
-			if (first <= op && op <= last &&
-			    idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
-			    && opnames[idx])
-				perror(opnames[idx]);
-			else
-				perror("ioctl[unknown???]");
-		}
-		return -1;
-	}
-	return 0;
-}
-
-static int
-set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
-	      int show_err)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.mode = op;
-	os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
-
-	if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
-		if (show_err) 
-			perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
-		return -1;
-	}
-	return 0;
-}
-
-static int
-wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
-			      const u8 *wpa_ie, size_t wpa_ie_len)
-{
-	struct iwreq iwr;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	/* NB: SETOPTIE is not fixed-size so must not be inlined */
-	iwr.u.data.pointer = (void *) wpa_ie;
-	iwr.u.data.length = wpa_ie_len;
-
-	if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
-		perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
-		return -1;
-	}
-	return 0;
-}
-
-static int
-wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
-			   const u8 *addr)
-{
-	struct ieee80211req_del_key wk;
-
-	wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
-	os_memset(&wk, 0, sizeof(wk));
-	wk.idk_keyix = key_idx;
-	if (addr != NULL)
-		os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
-
-	return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
-}
-
-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 wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_key wk;
-	char *alg_name;
-	u_int8_t cipher;
-
-	if (alg == WPA_ALG_NONE)
-		return wpa_driver_madwifi_del_key(drv, key_idx, addr);
-
-	switch (alg) {
-	case WPA_ALG_WEP:
-		if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
-					      ETH_ALEN) == 0) {
-			/*
-			 * madwifi did not seem to like static WEP key
-			 * configuration with IEEE80211_IOCTL_SETKEY, so use
-			 * Linux wireless extensions ioctl for this.
-			 */
-			return wpa_driver_wext_set_key(ifname, drv->wext, alg,
-						       addr, key_idx, set_tx,
-						       seq, seq_len,
-						       key, key_len);
-		}
-		alg_name = "WEP";
-		cipher = IEEE80211_CIPHER_WEP;
-		break;
-	case WPA_ALG_TKIP:
-		alg_name = "TKIP";
-		cipher = IEEE80211_CIPHER_TKIP;
-		break;
-	case WPA_ALG_CCMP:
-		alg_name = "CCMP";
-		cipher = IEEE80211_CIPHER_AES_CCM;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
-			__FUNCTION__, alg);
-		return -1;
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	if (seq_len > sizeof(u_int64_t)) {
-		wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
-			   __FUNCTION__, (unsigned long) seq_len);
-		return -2;
-	}
-	if (key_len > sizeof(wk.ik_keydata)) {
-		wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
-			   __FUNCTION__, (unsigned long) key_len);
-		return -3;
-	}
-
-	os_memset(&wk, 0, sizeof(wk));
-	wk.ik_type = cipher;
-	wk.ik_flags = IEEE80211_KEY_RECV;
-	if (addr == NULL ||
-	    os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
-		wk.ik_flags |= IEEE80211_KEY_GROUP;
-	if (set_tx) {
-		wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
-		os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
-	} else
-		os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
-	wk.ik_keyix = key_idx;
-	wk.ik_keylen = key_len;
-#ifdef WORDS_BIGENDIAN
-	if (seq) {
-		size_t i;
-		u8 tmp[WPA_KEY_RSC_LEN];
-		os_memset(tmp, 0, sizeof(tmp));
-		for (i = 0; i < seq_len; i++)
-			tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
-		os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
-	}
-#else /* WORDS_BIGENDIAN */
-	if (seq)
-		os_memcpy(&wk.ik_keyrsc, seq, seq_len);
-#endif /* WORDS_BIGENDIAN */
-	os_memcpy(wk.ik_keydata, key, key_len);
-
-	return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
-}
-
-static int
-wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
-}
-
-static int
-wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	mlme.im_op = IEEE80211_MLME_DEAUTH;
-	mlme.im_reason = reason_code;
-	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-	return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
-}
-
-static int
-wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	mlme.im_op = IEEE80211_MLME_DISASSOC;
-	mlme.im_reason = reason_code;
-	os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
-	return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
-}
-
-static int
-wpa_driver_madwifi_associate(void *priv,
-			     struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct ieee80211req_mlme mlme;
-	int ret = 0, privacy = 1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED,
-			  params->drop_unencrypted, 1) < 0)
-		ret = -1;
-	if (wpa_driver_madwifi_set_auth_alg(drv, params->auth_alg) < 0)
-		ret = -1;
-
-	/*
-	 * NB: Don't need to set the freq or cipher-related state as
-	 *     this is implied by the bssid which is used to locate
-	 *     the scanned node state which holds it.  The ssid is
-	 *     needed to disambiguate an AP that broadcasts multiple
-	 *     ssid's but uses the same bssid.
-	 */
-	/* XXX error handling is wrong but unclear what to do... */
-	if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
-					  params->wpa_ie_len) < 0)
-		ret = -1;
-
-	if (params->pairwise_suite == CIPHER_NONE &&
-	    params->group_suite == CIPHER_NONE &&
-	    params->key_mgmt_suite == KEY_MGMT_NONE &&
-	    params->wpa_ie_len == 0)
-		privacy = 0;
-
-	if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
-		ret = -1;
-
-	if (params->wpa_ie_len &&
-	    set80211param(drv, IEEE80211_PARAM_WPA,
-			  params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
-		ret = -1;
-
-	if (params->bssid == NULL) {
-		/* ap_scan=2 mode - driver takes care of AP selection and
-		 * roaming */
-		/* FIX: this does not seem to work; would probably need to
-		 * change something in the driver */
-		if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
-			ret = -1;
-
-		if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
-					     params->ssid_len) < 0)
-			ret = -1;
-	} else {
-		if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
-			ret = -1;
-		if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
-					     params->ssid_len) < 0)
-			ret = -1;
-		os_memset(&mlme, 0, sizeof(mlme));
-		mlme.im_op = IEEE80211_MLME_ASSOC;
-		os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
-		if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
-				 sizeof(mlme), 1) < 0) {
-			wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
-				   __func__);
-			ret = -1;
-		}
-	}
-
-	return ret;
-}
-
-static int
-wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	int authmode;
-
-	if ((auth_alg & WPA_AUTH_ALG_OPEN) &&
-	    (auth_alg & WPA_AUTH_ALG_SHARED))
-		authmode = IEEE80211_AUTH_AUTO;
-	else if (auth_alg & WPA_AUTH_ALG_SHARED)
-		authmode = IEEE80211_AUTH_SHARED;
-	else
-		authmode = IEEE80211_AUTH_OPEN;
-
-	return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
-}
-
-static int
-wpa_driver_madwifi_scan(void *priv, struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	wpa_driver_madwifi_set_probe_req_ie(drv, params->extra_ies,
-					    params->extra_ies_len);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	/* set desired ssid before scan */
-	/* FIX: scan should not break the current association, so using
-	 * set_ssid may not be the best way of doing this.. */
-	if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
-		ret = -1;
-
-	if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
-		perror("ioctl[SIOCSIWSCAN]");
-		ret = -1;
-	}
-
-	/*
-	 * madwifi delivers a scan complete event so no need to poll, but
-	 * register a backup timeout anyway to make sure that we recover even
-	 * if the driver does not send this event for any reason. This timeout
-	 * will only be used if the event is not delivered (event handler will
-	 * cancel the timeout).
-	 */
-	eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
-			     drv->ctx);
-	eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
-			       drv->ctx);
-
-	return ret;
-}
-
-static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_get_bssid(drv->wext, bssid);
-}
-
-
-static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_get_ssid(drv->wext, ssid);
-}
-
-
-static struct wpa_scan_results *
-wpa_driver_madwifi_get_scan_results(void *priv)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_get_scan_results(drv->wext);
-}
-
-
-static int wpa_driver_madwifi_set_operstate(void *priv, int state)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-	return wpa_driver_wext_set_operstate(drv->wext, state);
-}
-
-
-static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
-					       size_t ies_len)
-{
-	struct ieee80211req_getset_appiebuf *probe_req_ie;
-	int ret;
-
-	probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
-	if (probe_req_ie == NULL)
-		return -1;
-
-	probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
-	probe_req_ie->app_buflen = ies_len;
-	os_memcpy(probe_req_ie->app_buf, ies, ies_len);
-
-	ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
-			   sizeof(struct ieee80211req_getset_appiebuf) +
-			   ies_len, 1);
-
-	os_free(probe_req_ie);
-
-	return ret;
-}
-
-
-static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_madwifi_data *drv;
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->wext = wpa_driver_wext_init(ctx, ifname);
-	if (drv->wext == NULL)
-		goto fail;
-
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->sock < 0)
-		goto fail2;
-
-	if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
-			   "roaming", __FUNCTION__);
-		goto fail3;
-	}
-
-	if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
-			   __FUNCTION__);
-		goto fail3;
-	}
-
-	return drv;
-
-fail3:
-	close(drv->sock);
-fail2:
-	wpa_driver_wext_deinit(drv->wext);
-fail:
-	os_free(drv);
-	return NULL;
-}
-
-
-static void wpa_driver_madwifi_deinit(void *priv)
-{
-	struct wpa_driver_madwifi_data *drv = priv;
-
-	if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
-			   __FUNCTION__);
-	}
-	if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
-			   "roaming", __FUNCTION__);
-	}
-	if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
-			   "flag", __FUNCTION__);
-	}
-	if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
-			   __FUNCTION__);
-	}
-
-	wpa_driver_wext_deinit(drv->wext);
-
-	close(drv->sock);
-	os_free(drv);
-}
-
-#endif /* HOSTAPD */
-
 
 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,
-#ifdef HOSTAPD
 	.hapd_init		= madwifi_init,
 	.hapd_deinit		= madwifi_deinit,
 	.set_ieee8021x		= madwifi_set_ieee8021x,
@@ -1840,17 +1315,5 @@
 	.sta_clear_stats        = madwifi_sta_clear_stats,
 	.commit			= madwifi_commit,
 	.set_ap_wps_ie		= madwifi_set_ap_wps_ie,
-#else /* HOSTAPD */
-	.get_bssid		= wpa_driver_madwifi_get_bssid,
-	.get_ssid		= wpa_driver_madwifi_get_ssid,
-	.init			= wpa_driver_madwifi_init,
-	.deinit			= wpa_driver_madwifi_deinit,
-	.set_countermeasures	= wpa_driver_madwifi_set_countermeasures,
-	.scan2			= wpa_driver_madwifi_scan,
-	.get_scan_results2	= wpa_driver_madwifi_get_scan_results,
-	.deauthenticate		= wpa_driver_madwifi_deauthenticate,
-	.disassociate		= wpa_driver_madwifi_disassociate,
-	.associate		= wpa_driver_madwifi_associate,
-	.set_operstate		= wpa_driver_madwifi_set_operstate,
-#endif /* HOSTAPD */
+	.set_freq		= madwifi_set_freq,
 };
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index aeb7304..dbe9a28 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -3213,119 +3213,33 @@
 }
 
 
-const struct wpa_driver_ops wpa_driver_ndis_ops = {
-	"ndis",
-	"Windows NDIS driver",
-	wpa_driver_ndis_get_bssid,
-	wpa_driver_ndis_get_ssid,
-	wpa_driver_ndis_set_key,
-	wpa_driver_ndis_init,
-	wpa_driver_ndis_deinit,
-	NULL /* set_param */,
-	NULL /* set_countermeasures */,
-	wpa_driver_ndis_deauthenticate,
-	wpa_driver_ndis_disassociate,
-	wpa_driver_ndis_associate,
-	wpa_driver_ndis_add_pmkid,
-	wpa_driver_ndis_remove_pmkid,
-	wpa_driver_ndis_flush_pmkid,
-	wpa_driver_ndis_get_capa,
-	wpa_driver_ndis_poll,
-	wpa_driver_ndis_get_ifname,
-	wpa_driver_ndis_get_mac_addr,
-	NULL /* send_eapol */,
-	NULL /* set_operstate */,
-	NULL /* mlme_setprotection */,
-	NULL /* get_hw_feature_data */,
-	NULL /* set_channel */,
-	NULL /* set_ssid */,
-	NULL /* set_bssid */,
-	NULL /* send_mlme */,
-	NULL /* mlme_add_sta */,
-	NULL /* mlme_remove_sta */,
-	NULL /* update_ft_ies */,
-	NULL /* send_ft_action */,
-	wpa_driver_ndis_get_scan_results,
-	NULL /* set_country */,
-	NULL /* global_init */,
-	NULL /* global_deinit */,
-	NULL /* init2 */,
-	wpa_driver_ndis_get_interfaces,
-	wpa_driver_ndis_scan,
-	NULL /* authenticate */,
-	NULL /* set_beacon */,
-	NULL /* hapd_init */,
-	NULL /* hapd_deinit */,
-	NULL /* set_ieee8021x */,
-	NULL /* set_privacy */,
-	NULL /* get_seqnum */,
-	NULL /* flush */,
-	NULL /* set_generic_elem */,
-	NULL /* read_sta_data */,
-	NULL /* hapd_send_eapol */,
-	NULL /* sta_deauth */,
-	NULL /* sta_disassoc */,
-	NULL /* sta_remove */,
-	NULL /* hapd_get_ssid */,
-	NULL /* hapd_set_ssid */,
-	NULL /* hapd_set_countermeasures */,
-	NULL /* sta_add */,
-	NULL /* get_inact_sec */,
-	NULL /* sta_clear_stats */,
-	NULL /* set_freq */,
-	NULL /* set_rts */,
-	NULL /* set_frag */,
-	NULL /* sta_set_flags */,
-	NULL /* set_rate_sets */,
-	NULL /* set_cts_protect */,
-	NULL /* set_preamble */,
-	NULL /* set_short_slot_time */,
-	NULL /* set_tx_queue_params */,
-	NULL /* valid_bss_mask */,
-	NULL /* if_add */,
-	NULL /* if_remove */,
-	NULL /* set_sta_vlan */,
-	NULL /* commit */,
-	NULL /* send_ether */,
-	NULL /* set_radius_acl_auth */,
-	NULL /* set_radius_acl_expire */,
-	NULL /* set_ht_params */,
-	NULL /* set_ap_wps_ie */,
-	NULL /* set_supp_port */,
-	NULL /* set_wds_sta */,
-	NULL /* send_action */,
-	NULL /* send_action_cancel_wait */,
-	NULL /* remain_on_channel */,
-	NULL /* cancel_remain_on_channel */,
-	NULL /* probe_req_report */,
-	NULL /* disable_11b_rates */,
-	NULL /* deinit_ap */,
-	NULL /* suspend */,
-	NULL /* resume */,
-	NULL /* signal_monitor */,
-	NULL /* send_frame */,
-	NULL /* shared_freq */,
-	NULL /* get_noa */,
-	NULL /* set_noa */,
-	NULL /* set_p2p_powersave */,
-	NULL /* ampdu */,
-	NULL /* set_intra_bss */,
-	NULL /* get_radio_name */,
-	NULL /* p2p_find */,
-	NULL /* p2p_stop_find */,
-	NULL /* p2p_listen */,
-	NULL /* p2p_connect */,
-	NULL /* wps_success_cb */,
-	NULL /* p2p_group_formation_failed */,
-	NULL /* p2p_set_params */,
-	NULL /* p2p_prov_disc_req */,
-	NULL /* p2p_sd_request */,
-	NULL /* p2p_sd_cancel_request */,
-	NULL /* p2p_sd_response */,
-	NULL /* p2p_service_update */,
-	NULL /* p2p_reject */,
-	NULL /* p2p_invite */,
-	NULL /* send_tdls_mgmt */,
-	NULL /* tdls_oper */,
-	NULL /* signal_poll */
-};
+static const char *ndis_drv_name = "ndis";
+static const char *ndis_drv_desc = "Windows NDIS driver";
+
+struct wpa_driver_ops wpa_driver_ndis_ops;
+
+void driver_ndis_init_ops(void)
+{
+	os_memset(&wpa_driver_ndis_ops, 0, sizeof(wpa_driver_ndis_ops));
+	wpa_driver_ndis_ops.name = ndis_drv_name;
+	wpa_driver_ndis_ops.desc = ndis_drv_desc;
+	wpa_driver_ndis_ops.get_bssid = wpa_driver_ndis_get_bssid;
+	wpa_driver_ndis_ops.get_ssid = wpa_driver_ndis_get_ssid;
+	wpa_driver_ndis_ops.set_key = wpa_driver_ndis_set_key;
+	wpa_driver_ndis_ops.init = wpa_driver_ndis_init;
+	wpa_driver_ndis_ops.deinit = wpa_driver_ndis_deinit;
+	wpa_driver_ndis_ops.deauthenticate = wpa_driver_ndis_deauthenticate;
+	wpa_driver_ndis_ops.disassociate = wpa_driver_ndis_disassociate;
+	wpa_driver_ndis_ops.associate = wpa_driver_ndis_associate;
+	wpa_driver_ndis_ops.add_pmkid = wpa_driver_ndis_add_pmkid;
+	wpa_driver_ndis_ops.remove_pmkid = wpa_driver_ndis_remove_pmkid;
+	wpa_driver_ndis_ops.flush_pmkid = wpa_driver_ndis_flush_pmkid;
+	wpa_driver_ndis_ops.get_capa = wpa_driver_ndis_get_capa;
+	wpa_driver_ndis_ops.poll = wpa_driver_ndis_poll;
+	wpa_driver_ndis_ops.get_ifname = wpa_driver_ndis_get_ifname;
+	wpa_driver_ndis_ops.get_mac_addr = wpa_driver_ndis_get_mac_addr;
+	wpa_driver_ndis_ops.get_scan_results2 =
+		wpa_driver_ndis_get_scan_results;
+	wpa_driver_ndis_ops.get_interfaces = wpa_driver_ndis_get_interfaces;
+	wpa_driver_ndis_ops.scan2 = wpa_driver_ndis_scan;
+}
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index df309c5..a00f703 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -28,21 +28,47 @@
 #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/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "l2_packet/l2_packet.h"
 #include "netlink.h"
 #include "linux_ioctl.h"
 #include "radiotap.h"
 #include "radiotap_iter.h"
 #include "rfkill.h"
 #include "driver.h"
-#if defined(ANDROID_BRCM_P2P_PATCH) && !defined(HOSTAPD)
+#if defined(ANDROID_P2P) && !defined(HOSTAPD)
 #include "wpa_supplicant_i.h"
 #endif
+#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
@@ -91,6 +117,37 @@
 #endif /* CONFIG_LIBNL20 */
 
 
+static struct nl_handle * nl_create_handle(struct nl_cb *cb, const char *dbg)
+{
+	struct nl_handle *handle;
+
+	handle = nl80211_handle_alloc(cb);
+	if (handle == NULL) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+			   "callbacks (%s)", dbg);
+		return NULL;
+	}
+
+	if (genl_connect(handle)) {
+		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+			   "netlink (%s)", dbg);
+		nl80211_handle_destroy(handle);
+		return NULL;
+	}
+
+	return handle;
+}
+
+
+static void nl_destroy_handles(struct nl_handle **handle)
+{
+	if (*handle == NULL)
+		return;
+	nl80211_handle_destroy(*handle);
+	*handle = NULL;
+}
+
+
 #ifndef IFF_LOWER_UP
 #define IFF_LOWER_UP   0x10000         /* driver signals L1 up         */
 #endif
@@ -107,8 +164,30 @@
 
 struct nl80211_global {
 	struct dl_list interfaces;
+	int if_add_ifindex;
+	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);
+static void wpa_driver_nl80211_deinit(void *priv);
+
 struct i802_bss {
 	struct wpa_driver_nl80211_data *drv;
 	struct i802_bss *next;
@@ -118,19 +197,28 @@
 	unsigned int beacon_set:1;
 	unsigned int added_if_into_bridge:1;
 	unsigned int added_bridge:1;
+
+	u8 addr[ETH_ALEN];
+
+	int freq;
+
+	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;
-	u8 addr[ETH_ALEN];
+	struct dl_list wiphy_list;
 	char phyname[32];
 	void *ctx;
-	struct netlink_data *netlink;
-	int ioctl_sock; /* socket for ioctl() use */
 	int ifindex;
 	int if_removed;
 	int if_disabled;
+	int ignore_if_down_event;
 	struct rfkill_data *rfkill;
 	struct wpa_driver_capa capa;
 	int has_capability;
@@ -139,42 +227,43 @@
 
 	int scan_complete_events;
 
-	struct nl_handle *nl_handle;
-	struct nl_handle *nl_handle_event;
-	struct nl_handle *nl_handle_preq;
-	struct nl_cache *nl_cache;
-	struct nl_cache *nl_cache_event;
-	struct nl_cache *nl_cache_preq;
 	struct nl_cb *nl_cb;
-	struct genl_family *nl80211;
 
 	u8 auth_bssid[ETH_ALEN];
 	u8 bssid[ETH_ALEN];
 	int associated;
 	u8 ssid[32];
 	size_t ssid_len;
-	int nlmode;
-	int ap_scan_as_station;
+	enum nl80211_iftype nlmode;
+	enum nl80211_iftype ap_scan_as_station;
 	unsigned int assoc_freq;
 
 	int monitor_sock;
 	int monitor_ifidx;
-	int no_monitor_iface_capab;
-	int disable_11b_rates;
+	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;
 
 	u64 remain_on_chan_cookie;
 	u64 send_action_cookie;
 
 	unsigned int last_mgmt_freq;
-	unsigned int ap_oper_freq;
 
 	struct wpa_driver_scan_filter *filter_ssids;
 	size_t num_filter_ssids;
 
 	struct i802_bss first_bss;
 
+	int eapol_tx_sock;
+
 #ifdef HOSTAPD
 	int eapol_sock; /* socket for EAPOL frames */
 
@@ -185,12 +274,27 @@
 	int last_freq;
 	int last_freq_ht;
 #endif /* HOSTAPD */
+
+	/* 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_scan_timeout(void *eloop_ctx,
 					    void *timeout_ctx);
-static int wpa_driver_nl80211_set_mode(void *priv, int mode);
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+				       enum nl80211_iftype nlmode);
 static int
 wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
 static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
@@ -198,22 +302,28 @@
 				   int local_state_change);
 static void nl80211_remove_monitor_interface(
 	struct wpa_driver_nl80211_data *drv);
-static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
+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);
+				  const u8 *buf, size_t buf_len, u64 *cookie,
+				  int no_cck, int no_ack, int offchanok);
 static int wpa_driver_nl80211_probe_req_report(void *priv, int report);
-#ifdef ANDROID_BRCM_P2P_PATCH
+#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);
+#endif /* ANDROID */
+#ifdef ANDROID_P2P
 static void mlme_event_deauth_disassoc(struct wpa_driver_nl80211_data *drv,
 				  enum wpa_event_type type,
 				  const u8 *frame, size_t len);
-int wpa_driver_get_p2p_noa(void *priv, u8 *buf, size_t len);
 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
 
+#endif
 #ifdef HOSTAPD
 static void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
 static void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx);
@@ -222,12 +332,19 @@
 					enum wpa_driver_if_type type,
 					const char *ifname);
 #else /* HOSTAPD */
-static int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+static inline void add_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline void del_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
+{
+}
+
+static inline int have_ifidx(struct wpa_driver_nl80211_data *drv, int ifidx)
 {
 	return 0;
 }
 #endif /* HOSTAPD */
-
 #ifdef ANDROID
 extern int wpa_driver_nl80211_driver_cmd(void *priv, char *cmd, char *buf,
 					 size_t buf_len);
@@ -238,12 +355,36 @@
 				     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 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)
+{
+	return (nlmode == NL80211_IFTYPE_STATION ||
+		nlmode == NL80211_IFTYPE_P2P_CLIENT);
+}
+
+
+static int is_p2p_interface(enum nl80211_iftype nlmode)
+{
+	return (nlmode == NL80211_IFTYPE_P2P_CLIENT ||
+		nlmode == NL80211_IFTYPE_P2P_GO);
+}
 
 
 struct nl80211_bss_info_arg {
 	struct wpa_driver_nl80211_data *drv;
 	struct wpa_scan_results *res;
 	unsigned int assoc_freq;
+	u8 assoc_bssid[ETH_ALEN];
 };
 
 static int bss_info_handler(struct nl_msg *msg, void *arg);
@@ -279,7 +420,7 @@
 }
 
 
-static int send_and_recv(struct wpa_driver_nl80211_data *drv,
+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 *),
 			 void *valid_data)
@@ -287,7 +428,7 @@
 	struct nl_cb *cb;
 	int err = -ENOMEM;
 
-	cb = nl_cb_clone(drv->nl_cb);
+	cb = nl_cb_clone(global->nl_cb);
 	if (!cb)
 		goto out;
 
@@ -314,13 +455,22 @@
 }
 
 
+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);
+}
+
 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, drv->nl_handle, msg, valid_handler,
-			     valid_data);
+	return send_and_recv(drv->global, drv->global->nl, msg,
+			     valid_handler, valid_data);
 }
 
 
@@ -361,7 +511,7 @@
 }
 
 
-static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
+static int nl_get_multicast_id(struct nl80211_global *global,
 			       const char *family, const char *group)
 {
 	struct nl_msg *msg;
@@ -371,11 +521,11 @@
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
-	genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
+	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);
 
-	ret = send_and_recv_msgs(drv, msg, family_handler, &res);
+	ret = send_and_recv_msgs_global(global, msg, family_handler, &res);
 	msg = NULL;
 	if (ret == 0)
 		ret = res.id;
@@ -386,6 +536,235 @@
 }
 
 
+static 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);
+}
+
+
+struct wiphy_idx_data {
+	int wiphy_idx;
+};
+
+
+static int netdev_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_idx_data *info = arg;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_WIPHY])
+		info->wiphy_idx = nla_get_u32(tb[NL80211_ATTR_WIPHY]);
+
+	return NL_SKIP;
+}
+
+
+static int nl80211_get_wiphy_index(struct i802_bss *bss)
+{
+	struct nl_msg *msg;
+	struct wiphy_idx_data data = {
+		.wiphy_idx = -1,
+	};
+
+	msg = nlmsg_alloc();
+	if (!msg)
+		return -1;
+
+	nl80211_cmd(bss->drv, msg, 0, NL80211_CMD_GET_INTERFACE);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
+
+	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;
+}
+
+
+static int nl80211_register_beacons(struct wpa_driver_nl80211_data *drv,
+				    struct nl80211_wiphy_data *w)
+{
+	struct nl_msg *msg;
+	int ret = -1;
+
+	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);
+
+	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;
+}
+
+
+static void nl80211_recv_beacons(int sock, void *eloop_ctx, void *handle)
+{
+	struct nl80211_wiphy_data *w = eloop_ctx;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Beacon event message available");
+
+	nl_recvmsgs(handle, w->nl_cb);
+}
+
+
+static int process_beacon_event(struct nl_msg *msg, void *arg)
+{
+	struct nl80211_wiphy_data *w = arg;
+	struct wpa_driver_nl80211_data *drv;
+	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	union wpa_event_data event;
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (gnlh->cmd != NL80211_CMD_FRAME) {
+		wpa_printf(MSG_DEBUG, "nl80211: Unexpected beacon event? (%d)",
+			   gnlh->cmd);
+		return NL_SKIP;
+	}
+
+	if (!tb[NL80211_ATTR_FRAME])
+		return NL_SKIP;
+
+	dl_list_for_each(drv, &w->drvs, struct wpa_driver_nl80211_data,
+			 wiphy_list) {
+		os_memset(&event, 0, sizeof(event));
+		event.rx_mgmt.frame = nla_data(tb[NL80211_ATTR_FRAME]);
+		event.rx_mgmt.frame_len = nla_len(tb[NL80211_ATTR_FRAME]);
+		wpa_supplicant_event(drv->ctx, EVENT_RX_MGMT, &event);
+	}
+
+	return NL_SKIP;
+}
+
+
+static struct nl80211_wiphy_data *
+nl80211_get_wiphy_data_ap(struct i802_bss *bss)
+{
+	static DEFINE_DL_LIST(nl80211_wiphys);
+	struct nl80211_wiphy_data *w;
+	int wiphy_idx, found = 0;
+	struct i802_bss *tmp_bss;
+
+	if (bss->wiphy_data != NULL)
+		return bss->wiphy_data;
+
+	wiphy_idx = nl80211_get_wiphy_index(bss);
+
+	dl_list_for_each(w, &nl80211_wiphys, struct nl80211_wiphy_data, list) {
+		if (w->wiphy_idx == wiphy_idx)
+			goto add;
+	}
+
+	/* alloc new one */
+	w = os_zalloc(sizeof(*w));
+	if (w == NULL)
+		return NULL;
+	w->wiphy_idx = wiphy_idx;
+	dl_list_init(&w->bsss);
+	dl_list_init(&w->drvs);
+
+	w->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!w->nl_cb) {
+		os_free(w);
+		return NULL;
+	}
+	nl_cb_set(w->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+	nl_cb_set(w->nl_cb, NL_CB_VALID, NL_CB_CUSTOM, process_beacon_event,
+		  w);
+
+	w->nl_beacons = nl_create_handle(bss->drv->global->nl_cb,
+					 "wiphy beacons");
+	if (w->nl_beacons == NULL) {
+		os_free(w);
+		return NULL;
+	}
+
+	if (nl80211_register_beacons(bss->drv, w)) {
+		nl_destroy_handles(&w->nl_beacons);
+		os_free(w);
+		return NULL;
+	}
+
+	eloop_register_read_sock(nl_socket_get_fd(w->nl_beacons),
+				 nl80211_recv_beacons, w, w->nl_beacons);
+
+	dl_list_add(&nl80211_wiphys, &w->list);
+
+add:
+	/* drv entry for this bss already there? */
+	dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+		if (tmp_bss->drv == bss->drv) {
+			found = 1;
+			break;
+		}
+	}
+	/* if not add it */
+	if (!found)
+		dl_list_add(&w->drvs, &bss->drv->wiphy_list);
+
+	dl_list_add(&w->bsss, &bss->wiphy_list);
+	bss->wiphy_data = w;
+	return w;
+}
+
+
+static void nl80211_put_wiphy_data_ap(struct i802_bss *bss)
+{
+	struct nl80211_wiphy_data *w = bss->wiphy_data;
+	struct i802_bss *tmp_bss;
+	int found = 0;
+
+	if (w == NULL)
+		return;
+	bss->wiphy_data = NULL;
+	dl_list_del(&bss->wiphy_list);
+
+	/* still any for this drv present? */
+	dl_list_for_each(tmp_bss, &w->bsss, struct i802_bss, wiphy_list) {
+		if (tmp_bss->drv == bss->drv) {
+			found = 1;
+			break;
+		}
+	}
+	/* if not remove it */
+	if (!found)
+		dl_list_del(&bss->drv->wiphy_list);
+
+	if (!dl_list_empty(&w->bsss))
+		return;
+
+	eloop_unregister_read_sock(nl_socket_get_fd(w->nl_beacons));
+
+	nl_cb_put(w->nl_cb);
+	nl_destroy_handles(&w->nl_beacons);
+	dl_list_del(&w->list);
+	os_free(w);
+}
+
+
 static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
 {
 	struct i802_bss *bss = priv;
@@ -479,17 +858,33 @@
 }
 
 
+static struct wpa_driver_nl80211_data *
+nl80211_find_drv(struct nl80211_global *global, int idx, u8 *buf, size_t len)
+{
+	struct wpa_driver_nl80211_data *drv;
+	dl_list_for_each(drv, &global->interfaces,
+			 struct wpa_driver_nl80211_data, list) {
+		if (wpa_driver_nl80211_own_ifindex(drv, idx, buf, len) ||
+		    have_ifidx(drv, idx))
+			return drv;
+	}
+	return NULL;
+}
+
+
 static void wpa_driver_nl80211_event_rtm_newlink(void *ctx,
 						 struct ifinfomsg *ifi,
 						 u8 *buf, size_t len)
 {
-	struct wpa_driver_nl80211_data *drv = ctx;
+	struct nl80211_global *global = ctx;
+	struct wpa_driver_nl80211_data *drv;
 	int attrlen, rta_len;
 	struct rtattr *attr;
 	u32 brid = 0;
+	char namebuf[IFNAMSIZ];
 
-	if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, buf, len) &&
-	    !have_ifidx(drv, ifi->ifi_index)) {
+	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+	if (!drv) {
 		wpa_printf(MSG_DEBUG, "nl80211: Ignore event for foreign "
 			   "ifindex %d", ifi->ifi_index);
 		return;
@@ -504,15 +899,38 @@
 		   (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
 
 	if (!drv->if_disabled && !(ifi->ifi_flags & IFF_UP)) {
+		if (if_indextoname(ifi->ifi_index, namebuf) &&
+		    linux_iface_up(drv->global->ioctl_sock,
+				   drv->first_bss.ifname) > 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+				   "event since interface %s is up", namebuf);
+			return;
+		}
 		wpa_printf(MSG_DEBUG, "nl80211: Interface down");
-		drv->if_disabled = 1;
-		wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_DISABLED, NULL);
+		if (drv->ignore_if_down_event) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface down "
+				   "event generated by mode change");
+			drv->ignore_if_down_event = 0;
+		} else {
+			drv->if_disabled = 1;
+			wpa_supplicant_event(drv->ctx,
+					     EVENT_INTERFACE_DISABLED, NULL);
+		}
 	}
 
 	if (drv->if_disabled && (ifi->ifi_flags & IFF_UP)) {
-		wpa_printf(MSG_DEBUG, "nl80211: Interface up");
-		drv->if_disabled = 0;
-		wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED, NULL);
+		if (if_indextoname(ifi->ifi_index, namebuf) &&
+		    linux_iface_up(drv->global->ioctl_sock,
+				   drv->first_bss.ifname) == 0) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignore interface up "
+				   "event since interface %s is down",
+				   namebuf);
+		} else {
+			wpa_printf(MSG_DEBUG, "nl80211: Interface up");
+			drv->if_disabled = 0;
+			wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_ENABLED,
+					     NULL);
+		}
 	}
 
 	/*
@@ -524,7 +942,7 @@
 	if (drv->operstate == 1 &&
 	    (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
 	    !(ifi->ifi_flags & IFF_RUNNING))
-		netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+		netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
 				       -1, IF_OPER_UP);
 
 	attrlen = len;
@@ -541,16 +959,13 @@
 		attr = RTA_NEXT(attr, attrlen);
 	}
 
-#ifdef HOSTAPD
 	if (ifi->ifi_family == AF_BRIDGE && brid) {
 		/* device has been added to bridge */
-		char namebuf[IFNAMSIZ];
 		if_indextoname(brid, namebuf);
 		wpa_printf(MSG_DEBUG, "nl80211: Add ifindex %u for bridge %s",
 			   brid, namebuf);
 		add_ifidx(drv, brid);
 	}
-#endif /* HOSTAPD */
 }
 
 
@@ -558,11 +973,19 @@
 						 struct ifinfomsg *ifi,
 						 u8 *buf, size_t len)
 {
-	struct wpa_driver_nl80211_data *drv = ctx;
+	struct nl80211_global *global = ctx;
+	struct wpa_driver_nl80211_data *drv;
 	int attrlen, rta_len;
 	struct rtattr *attr;
 	u32 brid = 0;
 
+	drv = nl80211_find_drv(global, ifi->ifi_index, buf, len);
+	if (!drv) {
+		wpa_printf(MSG_DEBUG, "nl80211: Ignore dellink event for "
+			   "foreign ifindex %d", ifi->ifi_index);
+		return;
+	}
+
 	attrlen = len;
 	attr = (struct rtattr *) buf;
 
@@ -578,7 +1001,6 @@
 		attr = RTA_NEXT(attr, attrlen);
 	}
 
-#ifdef HOSTAPD
 	if (ifi->ifi_family == AF_BRIDGE && brid) {
 		/* device has been removed from bridge */
 		char namebuf[IFNAMSIZ];
@@ -587,7 +1009,6 @@
 			   "%s", brid, namebuf);
 		del_ifidx(drv, brid);
 	}
-#endif /* HOSTAPD */
 }
 
 
@@ -629,8 +1050,7 @@
 	if (!msg)
 		goto nla_put_failure;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
-		    NL80211_CMD_GET_SCAN, 0);
+	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
 	arg.drv = drv;
@@ -656,12 +1076,12 @@
 	const struct ieee80211_mgmt *mgmt;
 	union wpa_event_data event;
 	u16 status;
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
 	struct wpa_supplicant *wpa_s = drv->ctx;
 #endif
 
 	mgmt = (const struct ieee80211_mgmt *) frame;
-#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (ANDROID_BRCM_P2P_PATCH)
+#if (defined (CONFIG_AP) || defined (HOSTAPD) ) && defined (ANDROID_P2P)
 	if (drv->nlmode == NL80211_IFTYPE_AP || drv->nlmode == NL80211_IFTYPE_P2P_GO) {
 		if (len < 24 + sizeof(mgmt->u.assoc_req)) {
 			wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
@@ -674,7 +1094,7 @@
 		event.assoc_info.req_ies_len = len - 24 - sizeof(mgmt->u.assoc_req);
 		event.assoc_info.addr = mgmt->sa;
 	} else {
-#endif	
+#endif
 	if (len < 24 + sizeof(mgmt->u.assoc_resp)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Too short association event "
 			   "frame");
@@ -708,7 +1128,7 @@
 	}
 
 	event.assoc_info.freq = drv->assoc_freq;
-#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (ANDROID_BRCM_P2P_PATCH)
+#if (defined (CONFIG_AP) || defined(HOSTAPD)) && defined (ANDROID_P2P)
 	}
 #endif
 	wpa_supplicant_event(drv->ctx, EVENT_ASSOC, &event);
@@ -765,6 +1185,29 @@
 }
 
 
+static void mlme_event_disconnect(struct wpa_driver_nl80211_data *drv,
+				  struct nlattr *reason, struct nlattr *addr)
+{
+	union wpa_event_data data;
+
+	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;
+	}
+
+	drv->associated = 0;
+	os_memset(&data, 0, sizeof(data));
+	if (reason)
+		data.disassoc_info.reason_code = nla_get_u16(reason);
+	wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
+}
+
+
 static void mlme_timeout_event(struct wpa_driver_nl80211_data *drv,
 			       enum nl80211_commands cmd, struct nlattr *addr)
 {
@@ -819,7 +1262,7 @@
 		event.rx_action.data = &mgmt->u.action.category + 1;
 		event.rx_action.len = frame + len - event.rx_action.data;
 		wpa_supplicant_event(drv->ctx, EVENT_RX_ACTION, &event);
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
 	} else if (stype == WLAN_FC_STYPE_ASSOC_REQ) {
 		mlme_event_assoc(drv, frame, len);
 	} else if (stype == WLAN_FC_STYPE_DISASSOC) {
@@ -835,26 +1278,29 @@
 }
 
 
-static void mlme_event_action_tx_status(struct wpa_driver_nl80211_data *drv,
-					struct nlattr *cookie, const u8 *frame,
-					size_t len, struct nlattr *ack)
+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;
-	u64 cookie_val;
 
-	if (!cookie)
-		return;
+	if (!is_ap_interface(drv->nlmode)) {
+		u64 cookie_val;
 
-	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;
+		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);
@@ -906,7 +1352,7 @@
 		reason_code = le_to_host16(mgmt->u.deauth.reason_code);
 
 	if (type == EVENT_DISASSOC) {
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
 		if (drv->nlmode == NL80211_IFTYPE_AP ||
 			drv->nlmode == NL80211_IFTYPE_P2P_GO) {
 			event.disassoc_info.addr = mgmt->sa;
@@ -920,7 +1366,7 @@
 				mgmt->u.disassoc.variable;
 		}
 	} else {
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
 		if (drv->nlmode == NL80211_IFTYPE_AP ||
 			drv->nlmode == NL80211_IFTYPE_P2P_GO) {
 		event.deauth_info.addr = mgmt->sa;
@@ -1011,8 +1457,8 @@
 		mlme_event_mgmt(drv, freq, nla_data(frame), nla_len(frame));
 		break;
 	case NL80211_CMD_FRAME_TX_STATUS:
-		mlme_event_action_tx_status(drv, cookie, nla_data(frame),
-					    nla_len(frame), ack);
+		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,
@@ -1117,7 +1563,8 @@
 	if (cookie != drv->remain_on_chan_cookie)
 		return; /* not for us */
 
-	drv->pending_remain_on_chan = !cancel_event;
+	if (cancel_event)
+		drv->pending_remain_on_chan = 0;
 
 	os_memset(&data, 0, sizeof(data));
 	data.remain_on_channel.freq = freq;
@@ -1139,6 +1586,14 @@
 	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;
@@ -1228,14 +1683,14 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_STATION, 0);
+	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);
 
 	return send_and_recv_msgs(drv, msg, get_link_signal, sig);
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -1296,13 +1751,88 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    NLM_F_DUMP, NL80211_CMD_GET_SURVEY, 0);
+	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_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;
 }
 
@@ -1385,8 +1915,7 @@
 	addr = nla_data(tb[NL80211_ATTR_MAC]);
 	wpa_printf(MSG_DEBUG, "nl80211: New station " MACSTR, MAC2STR(addr));
 
-	if (drv->nlmode == NL80211_IFTYPE_AP &&
-	    drv->no_monitor_iface_capab) {
+	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
 		u8 *ies = NULL;
 		size_t ies_len = 0;
 		if (tb[NL80211_ATTR_IE]) {
@@ -1419,8 +1948,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Delete station " MACSTR,
 		   MAC2STR(addr));
 
-	if (drv->nlmode == NL80211_IFTYPE_AP &&
-	    drv->no_monitor_iface_capab) {
+	if (is_ap_interface(drv->nlmode) && drv->device_ap_sme) {
 		drv_event_disassoc(drv->ctx, addr);
 		return;
 	}
@@ -1434,38 +1962,138 @@
 }
 
 
-static int process_event(struct nl_msg *msg, void *arg)
+static void nl80211_rekey_offload_event(struct wpa_driver_nl80211_data *drv,
+					struct nlattr **tb)
 {
-	struct wpa_driver_nl80211_data *drv = arg;
-	struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
-	struct nlattr *tb[NL80211_ATTR_MAX + 1];
+	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;
 
-	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
-		  genlmsg_attrlen(gnlh, 0), NULL);
+	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;
 
-	if (tb[NL80211_ATTR_IFINDEX]) {
-		int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
-		if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
-			wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
-				   " for foreign interface (ifindex %d)",
-				   gnlh->cmd, ifindex);
-			return NL_SKIP;
-		}
-	}
+	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);
+}
 
-	if (drv->ap_scan_as_station &&
-	    (gnlh->cmd == NL80211_CMD_NEW_SCAN_RESULTS ||
-	     gnlh->cmd == NL80211_CMD_SCAN_ABORTED)) {
+
+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;
+
+	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;
+
+	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_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 do_process_drv_event(struct wpa_driver_nl80211_data *drv,
+				 int cmd, struct nlattr **tb)
+{
+	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,
-					    IEEE80211_MODE_AP);
-		drv->ap_scan_as_station = 0;
+					    drv->ap_scan_as_station);
+		drv->ap_scan_as_station = NL80211_IFTYPE_UNSPECIFIED;
 	}
 
-	switch (gnlh->cmd) {
+	switch (cmd) {
 	case NL80211_CMD_TRIGGER_SCAN:
 		wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
 		break;
+	case NL80211_CMD_START_SCHED_SCAN:
+		wpa_printf(MSG_DEBUG, "nl80211: Sched scan started");
+		break;
+	case NL80211_CMD_SCHED_SCAN_STOPPED:
+		wpa_printf(MSG_DEBUG, "nl80211: Sched scan stopped");
+		wpa_supplicant_event(drv->ctx, EVENT_SCHED_SCAN_STOPPED, NULL);
+		break;
 	case NL80211_CMD_NEW_SCAN_RESULTS:
 		wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
 		drv->scan_complete_events = 1;
@@ -1473,6 +2101,11 @@
 				     drv->ctx);
 		send_scan_event(drv, 0, tb);
 		break;
+	case NL80211_CMD_SCHED_SCAN_RESULTS:
+		wpa_printf(MSG_DEBUG,
+			   "nl80211: New sched scan results available");
+		send_scan_event(drv, 0, tb);
+		break;
 	case NL80211_CMD_SCAN_ABORTED:
 		wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
 		/*
@@ -1487,39 +2120,25 @@
 	case NL80211_CMD_ASSOCIATE:
 	case NL80211_CMD_DEAUTHENTICATE:
 	case NL80211_CMD_DISASSOCIATE:
-	case NL80211_CMD_FRAME:
 	case NL80211_CMD_FRAME_TX_STATUS:
 	case NL80211_CMD_UNPROT_DEAUTHENTICATE:
 	case NL80211_CMD_UNPROT_DISASSOCIATE:
-		mlme_event(drv, gnlh->cmd, tb[NL80211_ATTR_FRAME],
+		mlme_event(drv, 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]);
 		break;
 	case NL80211_CMD_CONNECT:
 	case NL80211_CMD_ROAM:
-		mlme_event_connect(drv, gnlh->cmd,
+		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_DISCONNECT:
-		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");
-			break;
-		}
-		drv->associated = 0;
-		os_memset(&data, 0, sizeof(data));
-		if (tb[NL80211_ATTR_REASON_CODE])
-			data.disassoc_info.reason_code =
-				nla_get_u16(tb[NL80211_ATTR_REASON_CODE]);
-		wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, &data);
+		mlme_event_disconnect(drv, tb[NL80211_ATTR_REASON_CODE],
+				      tb[NL80211_ATTR_MAC]);
 		break;
 	case NL80211_CMD_MICHAEL_MIC_FAILURE:
 		mlme_event_michael_mic_failure(drv, tb);
@@ -1552,6 +2171,95 @@
 	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;
+	default:
+		wpa_printf(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];
+
+	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+		  genlmsg_attrlen(gnlh, 0), NULL);
+
+	if (tb[NL80211_ATTR_IFINDEX]) {
+		int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+		if (ifindex != drv->ifindex && !have_ifidx(drv, ifindex)) {
+			wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
+				   " for foreign interface (ifindex %d)",
+				   gnlh->cmd, ifindex);
+			return NL_SKIP;
+		}
+	}
+
+	do_process_drv_event(drv, gnlh->cmd, tb);
+	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;
+	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]);
+
+	dl_list_for_each(drv, &global->interfaces,
+			 struct wpa_driver_nl80211_data, list) {
+		if (ifidx == -1 || ifidx == drv->ifindex ||
+		    have_ifidx(drv, ifidx))
+			do_process_drv_event(drv, gnlh->cmd, tb);
+	}
+
+	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);
+
+	switch (gnlh->cmd) {
+	case NL80211_CMD_FRAME:
+	case NL80211_CMD_FRAME_TX_STATUS:
+		mlme_event(bss->drv, 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]);
+		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);
@@ -1565,18 +2273,11 @@
 static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
 					     void *handle)
 {
-	struct nl_cb *cb;
-	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	struct nl_cb *cb = eloop_ctx;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Event message available");
 
-	cb = nl_cb_clone(drv->nl_cb);
-	if (!cb)
-		return;
-	nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
-	nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
 	nl_recvmsgs(handle, cb);
-	nl_cb_put(cb);
 }
 
 
@@ -1604,43 +2305,82 @@
 	alpha2[1] = alpha2_arg[1];
 	alpha2[2] = '\0';
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_REQ_SET_REG, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_REQ_SET_REG);
 
 	NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
 	if (send_and_recv_msgs(drv, msg, NULL, NULL))
 		return -EINVAL;
 	return 0;
 nla_put_failure:
+	nlmsg_free(msg);
 	return -EINVAL;
 }
 
 
 struct wiphy_info_data {
-	int max_scan_ssids;
-	int ap_supported;
-	int p2p_supported;
-	int auth_supported;
-	int connect_supported;
-	int offchan_tx_supported;
-	int max_remain_on_chan;
+	struct wpa_driver_capa *capa;
+
+	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;
 };
 
 
+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 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;
 	int p2p_go_supported = 0, p2p_client_supported = 0;
+	int p2p_concurrent = 0;
+	int auth_supported = 0, connect_supported = 0;
+	struct wpa_driver_capa *capa = info->capa;
+	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 },
+	},
+	iface_limit_policy[NUM_NL80211_IFACE_LIMIT] = {
+		[NL80211_IFACE_LIMIT_TYPES] = { .type = NLA_NESTED },
+		[NL80211_IFACE_LIMIT_MAX] = { .type = NLA_U32 },
+	};
 
 	nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
 		  genlmsg_attrlen(gnlh, 0), NULL);
 
 	if (tb[NL80211_ATTR_MAX_NUM_SCAN_SSIDS])
-		info->max_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_SUPPORTED_IFTYPES]) {
 		struct nlattr *nl_mode;
 		int i;
@@ -1648,7 +2388,7 @@
 				    tb[NL80211_ATTR_SUPPORTED_IFTYPES], i) {
 			switch (nla_type(nl_mode)) {
 			case NL80211_IFTYPE_AP:
-				info->ap_supported = 1;
+				capa->flags |= WPA_DRIVER_FLAGS_AP;
 				break;
 			case NL80211_IFTYPE_P2P_GO:
 				p2p_go_supported = 1;
@@ -1656,11 +2396,69 @@
 			case NL80211_IFTYPE_P2P_CLIENT:
 				p2p_client_supported = 1;
 				break;
+			case NL80211_IFTYPE_MONITOR:
+				info->monitor_supported = 1;
+				break;
 			}
 		}
 	}
 
-	info->p2p_supported = p2p_go_supported && p2p_client_supported;
+	if (tb[NL80211_ATTR_INTERFACE_COMBINATIONS]) {
+		struct nlattr *nl_combi;
+		int rem_combi;
+
+		nla_for_each_nested(nl_combi,
+				    tb[NL80211_ATTR_INTERFACE_COMBINATIONS],
+				    rem_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;
+
+			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])
+				goto broken_combination;
+
+			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])
+					goto 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) {
+				p2p_concurrent = 1;
+				break;
+			}
+
+broken_combination:
+			;
+		}
+	}
 
 	if (tb[NL80211_ATTR_SUPPORTED_COMMANDS]) {
 		struct nlattr *nl_cmd;
@@ -1668,21 +2466,92 @@
 
 		nla_for_each_nested(nl_cmd,
 				    tb[NL80211_ATTR_SUPPORTED_COMMANDS], i) {
-			u32 cmd = nla_get_u32(nl_cmd);
-			if (cmd == NL80211_CMD_AUTHENTICATE)
-				info->auth_supported = 1;
-			else if (cmd == NL80211_CMD_CONNECT)
-				info->connect_supported = 1;
+			switch (nla_get_u32(nl_cmd)) {
+			case NL80211_CMD_AUTHENTICATE:
+				auth_supported = 1;
+				break;
+			case NL80211_CMD_CONNECT:
+				connect_supported = 1;
+				break;
+			case NL80211_CMD_START_SCHED_SCAN:
+				capa->sched_scan_supported = 1;
+				break;
+			case NL80211_CMD_PROBE_CLIENT:
+				info->poll_command_supported = 1;
+				break;
+			}
 		}
 	}
 
-	if (tb[NL80211_ATTR_OFFCHANNEL_TX_OK])
-		info->offchan_tx_supported = 1;
+	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;
+	}
+
+	/* default to 5000 since early versions of mac80211 don't set it */
+	capa->max_remain_on_chan = 5000;
+
+	if (tb[NL80211_ATTR_SUPPORT_AP_UAPSD])
+		capa->flags |= WPA_DRIVER_FLAGS_AP_UAPSD;
 
 	if (tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION])
-		info->max_remain_on_chan =
+		capa->max_remain_on_chan =
 			nla_get_u32(tb[NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION]);
 
+	if (auth_supported)
+		capa->flags |= WPA_DRIVER_FLAGS_SME;
+	else if (!connect_supported) {
+		wpa_printf(MSG_INFO, "nl80211: Driver does not support "
+			   "authentication/association or connect commands");
+		info->error = 1;
+	}
+
+	if (p2p_go_supported && p2p_client_supported)
+		capa->flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
+	if (p2p_concurrent) {
+		wpa_printf(MSG_DEBUG, "nl80211: Use separate P2P group "
+			   "interface (driver advertised support)");
+		capa->flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
+		capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
+	}
+
+	if (tb[NL80211_ATTR_TDLS_SUPPORT]) {
+		wpa_printf(MSG_DEBUG, "nl80211: TDLS supported");
+		capa->flags |= WPA_DRIVER_FLAGS_TDLS_SUPPORT;
+
+		if (tb[NL80211_ATTR_TDLS_EXTERNAL_SETUP]) {
+			wpa_printf(MSG_DEBUG, "nl80211: TDLS external setup");
+			capa->flags |=
+				WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP;
+		}
+	}
+
+	if (tb[NL80211_ATTR_DEVICE_AP_SME])
+		info->device_ap_sme = 1;
+
+	if (tb[NL80211_ATTR_FEATURE_FLAGS]) {
+		u32 flags = nla_get_u32(tb[NL80211_ATTR_FEATURE_FLAGS]);
+
+		if (flags & NL80211_FEATURE_SK_TX_STATUS)
+			info->data_tx_status = 1;
+	}
+
+	if (tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]) {
+		int protocols =
+			nla_get_u32(tb[NL80211_ATTR_PROBE_RESP_OFFLOAD]);
+		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);
+	}
+
 	return NL_SKIP;
 }
 
@@ -1693,16 +2562,13 @@
 	struct nl_msg *msg;
 
 	os_memset(info, 0, sizeof(*info));
-
-	/* default to 5000 since early versions of mac80211 don't set it */
-	info->max_remain_on_chan = 5000;
+	info->capa = &drv->capa;
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_WIPHY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->first_bss.ifindex);
 
@@ -1720,6 +2586,10 @@
 	struct wiphy_info_data info;
 	if (wpa_driver_nl80211_get_info(drv, &info))
 		return -1;
+
+	if (info.error)
+		return -1;
+
 	drv->has_capability = 1;
 	/* For now, assume TKIP, CCMP, WPA, WPA2 are supported */
 	drv->capa.key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
@@ -1734,131 +2604,132 @@
 		WPA_DRIVER_AUTH_SHARED |
 		WPA_DRIVER_AUTH_LEAP;
 
-	drv->capa.max_scan_ssids = info.max_scan_ssids;
-	if (info.ap_supported)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_AP;
-
-	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");
-		return -1;
-	}
-
-	if (info.offchan_tx_supported) {
-		wpa_printf(MSG_DEBUG, "nl80211: Using driver-based "
-			   "off-channel TX");
-		drv->capa.flags |= WPA_DRIVER_FLAGS_OFFCHANNEL_TX;
-	}
-
 	drv->capa.flags |= WPA_DRIVER_FLAGS_SANE_ERROR_CODES;
 	drv->capa.flags |= WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE;
-	if (info.p2p_supported)
-		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CAPABLE;
 	drv->capa.flags |= WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
-	drv->capa.max_remain_on_chan = info.max_remain_on_chan;
+	drv->capa.flags |= WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS;
+
+	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 poll command is supported mac80211 is new enough to
+	 * have everything we need to not need monitor interfaces.
+	 */
+	drv->use_monitor = !info.poll_command_supported;
+
+	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;
 }
 
 
-static int wpa_driver_nl80211_init_nl(struct wpa_driver_nl80211_data *drv)
+#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;
 
-	/* Initialize generic netlink and nl80211 */
-
-	drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
-	if (drv->nl_cb == NULL) {
+	global->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (global->nl_cb == NULL) {
 		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
 			   "callbacks");
-		goto err1;
+		return -1;
 	}
 
-	drv->nl_handle = nl80211_handle_alloc(drv->nl_cb);
-	if (drv->nl_handle == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
-			   "callbacks");
-		goto err2;
-	}
+	global->nl = nl_create_handle(global->nl_cb, "nl");
+	if (global->nl == NULL)
+		goto err;
 
-	drv->nl_handle_event = nl80211_handle_alloc(drv->nl_cb);
-	if (drv->nl_handle_event == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
-			   "callbacks (event)");
-		goto err2b;
-	}
-
-	if (genl_connect(drv->nl_handle)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
-			   "netlink");
-		goto err3;
-	}
-
-	if (genl_connect(drv->nl_handle_event)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
-			   "netlink (event)");
-		goto err3;
-	}
-
-#ifdef CONFIG_LIBNL20
-	if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache");
-		goto err3;
-	}
-	if (genl_ctrl_alloc_cache(drv->nl_handle_event, &drv->nl_cache_event) <
-	    0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (event)");
-		goto err3b;
-	}
-#else /* CONFIG_LIBNL20 */
-	drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
-	if (drv->nl_cache == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache");
-		goto err3;
-	}
-	drv->nl_cache_event = genl_ctrl_alloc_cache(drv->nl_handle_event);
-	if (drv->nl_cache_event == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (event)");
-		goto err3b;
-	}
-#endif /* CONFIG_LIBNL20 */
-
-	drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
-	if (drv->nl80211 == NULL) {
+	global->nl80211_id = genl_ctrl_resolve(global->nl, "nl80211");
+	if (global->nl80211_id < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
 			   "found");
-		goto err4;
+		goto err;
 	}
 
-	ret = nl_get_multicast_id(drv, "nl80211", "scan");
+	global->nl_event = nl_create_handle(global->nl_cb, "event");
+	if (global->nl_event == NULL)
+		goto err;
+
+	ret = nl_get_multicast_id(global, "nl80211", "scan");
 	if (ret >= 0)
-		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
+		ret = nl_socket_add_membership(global->nl_event, ret);
 	if (ret < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
 			   "membership for scan events: %d (%s)",
 			   ret, strerror(-ret));
-		goto err4;
+		goto err;
 	}
 
-	ret = nl_get_multicast_id(drv, "nl80211", "mlme");
+	ret = nl_get_multicast_id(global, "nl80211", "mlme");
 	if (ret >= 0)
-		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
+		ret = nl_socket_add_membership(global->nl_event, ret);
 	if (ret < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
 			   "membership for mlme events: %d (%s)",
 			   ret, strerror(-ret));
-		goto err4;
+		goto err;
 	}
 
-	ret = nl_get_multicast_id(drv, "nl80211", "regulatory");
+	ret = nl_get_multicast_id(global, "nl80211", "regulatory");
 	if (ret >= 0)
-		ret = nl_socket_add_membership(drv->nl_handle_event, ret);
+		ret = nl_socket_add_membership(global->nl_event, ret);
 	if (ret < 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Could not add multicast "
 			   "membership for regulatory events: %d (%s)",
@@ -1866,27 +2737,43 @@
 		/* Continue without regulatory events */
 	}
 
-	eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_event),
-				 wpa_driver_nl80211_event_receive, drv,
-				 drv->nl_handle_event);
+	nl_cb_set(global->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+		  no_seq_check, NULL);
+	nl_cb_set(global->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+		  process_global_event, global);
+
+	eloop_register_read_sock(nl_socket_get_fd(global->nl_event),
+				 wpa_driver_nl80211_event_receive,
+				 global->nl_cb, global->nl_event);
 
 	return 0;
 
-err4:
-	nl_cache_free(drv->nl_cache_event);
-err3b:
-	nl_cache_free(drv->nl_cache);
-err3:
-	nl80211_handle_destroy(drv->nl_handle_event);
-err2b:
-	nl80211_handle_destroy(drv->nl_handle);
-err2:
-	nl_cb_put(drv->nl_cb);
-err1:
+err:
+	nl_destroy_handles(&global->nl_event);
+	nl_destroy_handles(&global->nl);
+	nl_cb_put(global->nl_cb);
+	global->nl_cb = NULL;
 	return -1;
 }
 
 
+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");
@@ -1901,7 +2788,8 @@
 {
 	struct wpa_driver_nl80211_data *drv = ctx;
 	wpa_printf(MSG_DEBUG, "nl80211: RFKILL unblocked");
-	if (linux_set_iface_flags(drv->ioctl_sock, drv->first_bss.ifname, 1)) {
+	if (linux_set_iface_flags(drv->global->ioctl_sock,
+				  drv->first_bss.ifname, 1)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Could not set interface UP "
 			   "after rfkill unblock");
 		return;
@@ -1943,6 +2831,90 @@
 }
 
 
+static void wpa_driver_nl80211_handle_eapol_tx_status(int sock,
+						      void *eloop_ctx,
+						      void *handle)
+{
+	struct wpa_driver_nl80211_data *drv = eloop_ctx;
+	u8 data[2048];
+	struct msghdr msg;
+	struct iovec entry;
+	struct {
+		struct cmsghdr cm;
+		char control[512];
+	} control;
+	struct cmsghdr *cmsg;
+	int res, found_ee = 0, found_wifi = 0, acked = 0;
+	union wpa_event_data event;
+
+	memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = &entry;
+	msg.msg_iovlen = 1;
+	entry.iov_base = data;
+	entry.iov_len = sizeof(data);
+	msg.msg_control = &control;
+	msg.msg_controllen = sizeof(control);
+
+	res = recvmsg(sock, &msg, MSG_ERRQUEUE);
+	/* if error or not fitting 802.3 header, return */
+	if (res < 14)
+		return;
+
+	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
+	{
+		if (cmsg->cmsg_level == SOL_SOCKET &&
+		    cmsg->cmsg_type == SCM_WIFI_STATUS) {
+			int *ack;
+
+			found_wifi = 1;
+			ack = (void *)CMSG_DATA(cmsg);
+			acked = *ack;
+		}
+
+		if (cmsg->cmsg_level == SOL_PACKET &&
+		    cmsg->cmsg_type == PACKET_TX_TIMESTAMP) {
+			struct sock_extended_err *err =
+				(struct sock_extended_err *)CMSG_DATA(cmsg);
+
+			if (err->ee_origin == SO_EE_ORIGIN_TXSTATUS)
+				found_ee = 1;
+		}
+	}
+
+	if (!found_ee || !found_wifi)
+		return;
+
+	memset(&event, 0, sizeof(event));
+	event.eapol_tx_status.dst = data;
+	event.eapol_tx_status.data = data + 14;
+	event.eapol_tx_status.data_len = res - 14;
+	event.eapol_tx_status.ack = acked;
+	wpa_supplicant_event(drv->ctx, EVENT_EAPOL_TX_STATUS, &event);
+}
+
+
+static int nl80211_init_bss(struct i802_bss *bss)
+{
+	bss->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+	if (!bss->nl_cb)
+		return -1;
+
+	nl_cb_set(bss->nl_cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
+		  no_seq_check, NULL);
+	nl_cb_set(bss->nl_cb, NL_CB_VALID, NL_CB_CUSTOM,
+		  process_bss_event, bss);
+
+	return 0;
+}
+
+
+static void nl80211_destroy_bss(struct i802_bss *bss)
+{
+	nl_cb_put(bss->nl_cb);
+	bss->nl_cb = NULL;
+}
+
+
 /**
  * wpa_driver_nl80211_init - Initialize nl80211 driver interface
  * @ctx: context to be used when calling wpa_supplicant functions,
@@ -1955,10 +2927,11 @@
 				      void *global_priv)
 {
 	struct wpa_driver_nl80211_data *drv;
-	struct netlink_config *cfg;
 	struct rfkill_config *rcfg;
 	struct i802_bss *bss;
 
+	if (global_priv == NULL)
+		return NULL;
 	drv = os_zalloc(sizeof(*drv));
 	if (drv == NULL)
 		return NULL;
@@ -1969,33 +2942,19 @@
 	os_strlcpy(bss->ifname, ifname, sizeof(bss->ifname));
 	drv->monitor_ifidx = -1;
 	drv->monitor_sock = -1;
-	drv->ioctl_sock = -1;
+	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;
+
 	nl80211_get_phy_name(drv);
 
-	drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
-	if (drv->ioctl_sock < 0) {
-		perror("socket(PF_INET,SOCK_DGRAM)");
-		goto failed;
-	}
-
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL)
-		goto failed;
-	cfg->ctx = drv;
-	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
-	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		goto failed;
-	}
-
 	rcfg = os_zalloc(sizeof(*rcfg));
 	if (rcfg == NULL)
 		goto failed;
@@ -2012,32 +2971,46 @@
 	if (wpa_driver_nl80211_finish_drv_init(drv))
 		goto failed;
 
-	if (drv->global)
+	drv->eapol_tx_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+	if (drv->eapol_tx_sock < 0)
+		goto failed;
+
+	if (drv->data_tx_status) {
+		int enabled = 1;
+
+		if (setsockopt(drv->eapol_tx_sock, SOL_SOCKET, SO_WIFI_STATUS,
+			       &enabled, sizeof(enabled)) < 0) {
+			wpa_printf(MSG_DEBUG,
+				"nl80211: wifi status sockopt failed\n");
+			drv->data_tx_status = 0;
+			if (!drv->use_monitor)
+				drv->capa.flags &=
+					~WPA_DRIVER_FLAGS_EAPOL_TX_STATUS;
+		} else {
+			eloop_register_read_sock(drv->eapol_tx_sock,
+				wpa_driver_nl80211_handle_eapol_tx_status,
+				drv, NULL);
+		}
+	}
+
+	if (drv->global) {
 		dl_list_add(&drv->global->interfaces, &drv->list);
+		drv->in_interface_list = 1;
+	}
 
 	return bss;
 
 failed:
-	rfkill_deinit(drv->rfkill);
-	netlink_deinit(drv->netlink);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	genl_family_put(drv->nl80211);
-	nl_cache_free(drv->nl_cache);
-	nl80211_handle_destroy(drv->nl_handle);
-	nl_cb_put(drv->nl_cb);
-	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-
-	os_free(drv);
+	wpa_driver_nl80211_deinit(bss);
 	return NULL;
 }
 
 
-static int nl80211_register_frame(struct wpa_driver_nl80211_data *drv,
+static int nl80211_register_frame(struct i802_bss *bss,
 				  struct nl_handle *nl_handle,
 				  u16 type, const u8 *match, size_t match_len)
 {
+	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	int ret = -1;
 
@@ -2045,14 +3018,18 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_REGISTER_ACTION, 0);
+	wpa_printf(MSG_DEBUG, "nl80211: Register frame type=0x%x nl_handle=%p",
+		   type, nl_handle);
+	wpa_hexdump(MSG_DEBUG, "nl80211: Register frame match",
+		    match, match_len);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_REGISTER_ACTION);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 	NLA_PUT_U16(msg, NL80211_ATTR_FRAME_TYPE, type);
 	NLA_PUT(msg, NL80211_ATTR_FRAME_MATCH, match_len, match);
 
-	ret = send_and_recv(drv, nl_handle, msg, NULL, NULL);
+	ret = send_and_recv(drv->global, nl_handle, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Register frame command "
@@ -2069,58 +3046,213 @@
 }
 
 
-static int nl80211_register_action_frame(struct wpa_driver_nl80211_data *drv,
+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");
+	if (bss->nl_mgmt == NULL)
+		return -1;
+
+	eloop_register_read_sock(nl_socket_get_fd(bss->nl_mgmt),
+				 wpa_driver_nl80211_event_receive, bss->nl_cb,
+				 bss->nl_mgmt);
+
+	return 0;
+}
+
+
+static int nl80211_register_action_frame(struct i802_bss *bss,
 					 const u8 *match, size_t match_len)
 {
 	u16 type = (WLAN_FC_TYPE_MGMT << 2) | (WLAN_FC_STYPE_ACTION << 4);
-	return nl80211_register_frame(drv, drv->nl_handle_event,
+	return nl80211_register_frame(bss, bss->nl_mgmt,
 				      type, match, match_len);
 }
 
 
-static int nl80211_register_action_frames(struct wpa_driver_nl80211_data *drv)
+static int nl80211_mgmt_subscribe_non_ap(struct i802_bss *bss)
 {
-#ifdef CONFIG_P2P
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (nl80211_alloc_mgmt_handle(bss))
+		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with non-AP "
+		   "handle %p", bss->nl_mgmt);
+
+#if defined(CONFIG_P2P) || defined(CONFIG_INTERWORKING)
 	/* GAS Initial Request */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0a", 2) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0a", 2) < 0)
 		return -1;
 	/* GAS Initial Response */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0b", 2) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0b", 2) < 0)
 		return -1;
 	/* GAS Comeback Request */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0c", 2) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0c", 2) < 0)
 		return -1;
 	/* GAS Comeback Response */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x04\x0d", 2) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0d", 2) < 0)
 		return -1;
+#endif /* CONFIG_P2P || CONFIG_INTERWORKING */
+#ifdef CONFIG_P2P
 	/* P2P Public Action */
-	if (nl80211_register_action_frame(drv,
+	if (nl80211_register_action_frame(bss,
 					  (u8 *) "\x04\x09\x50\x6f\x9a\x09",
 					  6) < 0)
 		return -1;
 	/* P2P Action */
-	if (nl80211_register_action_frame(drv,
+	if (nl80211_register_action_frame(bss,
 					  (u8 *) "\x7f\x50\x6f\x9a\x09",
 					  5) < 0)
 		return -1;
 #endif /* CONFIG_P2P */
 #ifdef CONFIG_IEEE80211W
 	/* SA Query Response */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x08\x01", 2) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x08\x01", 2) < 0)
 		return -1;
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_TDLS
+	if ((drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)) {
+		/* TDLS Discovery Response */
+		if (nl80211_register_action_frame(bss, (u8 *) "\x04\x0e", 2) <
+		    0)
+			return -1;
+	}
+#endif /* CONFIG_TDLS */
 
 	/* FT Action frames */
-	if (nl80211_register_action_frame(drv, (u8 *) "\x06", 1) < 0)
+	if (nl80211_register_action_frame(bss, (u8 *) "\x06", 1) < 0)
 		return -1;
 	else
 		drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_FT |
 			WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
 
+	/* WNM - BSS Transition Management Request */
+	if (nl80211_register_action_frame(bss, (u8 *) "\x0a\x07", 2) < 0)
+		return -1;
+
 	return 0;
 }
 
 
+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;
+
+	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;
+	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;
+}
+
+
+static int nl80211_mgmt_subscribe_ap(struct i802_bss *bss)
+{
+	static const int stypes[] = {
+		WLAN_FC_STYPE_AUTH,
+		WLAN_FC_STYPE_ASSOC_REQ,
+		WLAN_FC_STYPE_REASSOC_REQ,
+		WLAN_FC_STYPE_DISASSOC,
+		WLAN_FC_STYPE_DEAUTH,
+		WLAN_FC_STYPE_ACTION,
+		WLAN_FC_STYPE_PROBE_REQ,
+/* Beacon doesn't work as mac80211 doesn't currently allow
+ * it, but it wouldn't really be the right thing anyway as
+ * it isn't per interface ... maybe just dump the scan
+ * results periodically for OLBC?
+ */
+//		WLAN_FC_STYPE_BEACON,
+	};
+	unsigned int i;
+
+	if (nl80211_alloc_mgmt_handle(bss))
+		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
+		   "handle %p", bss->nl_mgmt);
+
+	for (i = 0; i < sizeof(stypes) / sizeof(stypes[0]); i++) {
+		if (nl80211_register_frame(bss, bss->nl_mgmt,
+					   (WLAN_FC_TYPE_MGMT << 2) |
+					   (stypes[i] << 4),
+					   NULL, 0) < 0) {
+			goto out_err;
+		}
+	}
+
+	if (nl80211_register_spurious_class3(bss))
+		goto out_err;
+
+	if (nl80211_get_wiphy_data_ap(bss) == NULL)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+	nl_destroy_handles(&bss->nl_mgmt);
+	return -1;
+}
+
+
+static int nl80211_mgmt_subscribe_ap_dev_sme(struct i802_bss *bss)
+{
+	if (nl80211_alloc_mgmt_handle(bss))
+		return -1;
+	wpa_printf(MSG_DEBUG, "nl80211: Subscribe to mgmt frames with AP "
+		   "handle %p (device SME)", bss->nl_mgmt);
+
+	if (nl80211_register_frame(bss, bss->nl_mgmt,
+				   (WLAN_FC_TYPE_MGMT << 2) |
+				   (WLAN_FC_STYPE_ACTION << 4),
+				   NULL, 0) < 0)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+	nl_destroy_handles(&bss->nl_mgmt);
+	return -1;
+}
+
+
+static void nl80211_mgmt_unsubscribe(struct i802_bss *bss, const char *reason)
+{
+	if (bss->nl_mgmt == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "nl80211: Unsubscribe mgmt frames handle %p "
+		   "(%s)", bss->nl_mgmt, reason);
+	eloop_unregister_read_sock(nl_socket_get_fd(bss->nl_mgmt));
+	nl_destroy_handles(&bss->nl_mgmt);
+
+	nl80211_put_wiphy_data_ap(bss);
+}
+
+
 static void wpa_driver_nl80211_send_rfkill(void *eloop_ctx, void *timeout_ctx)
 {
 	wpa_supplicant_event(timeout_ctx, EVENT_INTERFACE_DISABLED, NULL);
@@ -2137,12 +3269,19 @@
 	drv->first_bss.ifindex = drv->ifindex;
 
 #ifndef HOSTAPD
-	if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA) < 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: Could not configure driver to "
+	/*
+	 * Make sure the interface starts up in station mode unless this is a
+	 * dynamically added interface (e.g., P2P) that was already configured
+	 * with proper iftype.
+	 */
+	if (drv->ifindex != drv->global->if_add_ifindex &&
+	    wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION) < 0) {
+		wpa_printf(MSG_ERROR, "nl80211: Could not configure driver to "
 			   "use managed mode");
+		return -1;
 	}
 
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
 		if (rfkill_is_blocked(drv->rfkill)) {
 			wpa_printf(MSG_DEBUG, "nl80211: Could not yet enable "
 				   "interface '%s' due to rfkill",
@@ -2156,26 +3295,17 @@
 		}
 	}
 
-	netlink_send_oper_ifla(drv->netlink, drv->ifindex,
+	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex,
 			       1, IF_OPER_DORMANT);
 #endif /* HOSTAPD */
 
 	if (wpa_driver_nl80211_capa(drv))
 		return -1;
 
-	if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, drv->addr))
+	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+			       bss->addr))
 		return -1;
 
-	if (nl80211_register_action_frames(drv) < 0) {
-		wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
-			   "frame processing - ignore for now");
-		/*
-		 * Older kernel versions did not support this, so ignore the
-		 * error for now. Some functionality may not be available
-		 * because of this.
-		 */
-	}
-
 	if (send_rfkill_event) {
 		eloop_register_timeout(0, 0, wpa_driver_nl80211_send_rfkill,
 				       drv, drv->ctx);
@@ -2193,12 +3323,12 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_BEACON, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_BEACON);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -2215,17 +3345,22 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
-	if (drv->nl_handle_preq)
+	if (drv->data_tx_status)
+		eloop_unregister_read_sock(drv->eapol_tx_sock);
+	if (drv->eapol_tx_sock >= 0)
+		close(drv->eapol_tx_sock);
+
+	if (bss->nl_preq)
 		wpa_driver_nl80211_probe_req_report(bss, 0);
 	if (bss->added_if_into_bridge) {
-		if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
-		    < 0)
+		if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+				    bss->ifname) < 0)
 			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
 				   "interface %s from bridge %s: %s",
 				   bss->ifname, bss->brname, strerror(errno));
 	}
 	if (bss->added_bridge) {
-		if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
+		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
 			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
 				   "bridge %s: %s",
 				   bss->brname, strerror(errno));
@@ -2233,7 +3368,7 @@
 
 	nl80211_remove_monitor_interface(drv);
 
-	if (drv->nlmode == NL80211_IFTYPE_AP)
+	if (is_ap_interface(drv->nlmode))
 		wpa_driver_nl80211_del_beacon(drv);
 
 #ifdef HOSTAPD
@@ -2254,32 +3389,28 @@
 		os_free(drv->if_indices);
 #endif /* HOSTAPD */
 
-	if (drv->disable_11b_rates)
+	if (drv->disabled_11b_rates)
 		nl80211_disable_11b_rates(drv, drv->ifindex, 0);
 
-	netlink_send_oper_ifla(drv->netlink, drv->ifindex, 0, IF_OPER_UP);
-	netlink_deinit(drv->netlink);
+	netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, 0,
+			       IF_OPER_UP);
 	rfkill_deinit(drv->rfkill);
 
 	eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
 
-	(void) linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0);
-	wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_INFRA);
+	(void) linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0);
+	wpa_driver_nl80211_set_mode(bss, NL80211_IFTYPE_STATION);
+	nl80211_mgmt_unsubscribe(bss, "deinit");
 
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-	genl_family_put(drv->nl80211);
-	nl_cache_free(drv->nl_cache);
-	nl_cache_free(drv->nl_cache_event);
-	nl80211_handle_destroy(drv->nl_handle);
-	nl80211_handle_destroy(drv->nl_handle_event);
 	nl_cb_put(drv->nl_cb);
 
+	nl80211_destroy_bss(&drv->first_bss);
+
 	os_free(drv->filter_ssids);
 
-	if (drv->global)
+	os_free(drv->auth_ie);
+
+	if (drv->in_interface_list)
 		dl_list_del(&drv->list);
 
 	os_free(drv);
@@ -2297,10 +3428,10 @@
 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) {
+	if (drv->ap_scan_as_station != NL80211_IFTYPE_UNSPECIFIED) {
 		wpa_driver_nl80211_set_mode(&drv->first_bss,
-					    IEEE80211_MODE_AP);
-		drv->ap_scan_as_station = 0;
+					    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);
@@ -2319,16 +3450,20 @@
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = 0, timeout;
-	struct nl_msg *msg, *ssids, *freqs;
+	struct nl_msg *msg, *ssids, *freqs, *rates;
 	size_t i;
 
+	drv->scan_for_auth = 0;
+
 	msg = nlmsg_alloc();
 	ssids = nlmsg_alloc();
 	freqs = nlmsg_alloc();
-	if (!msg || !ssids || !freqs) {
+	rates = nlmsg_alloc();
+	if (!msg || !ssids || !freqs || !rates) {
 		nlmsg_free(msg);
 		nlmsg_free(ssids);
 		nlmsg_free(freqs);
+		nlmsg_free(rates);
 		return -1;
 	}
 
@@ -2337,8 +3472,7 @@
 	params->filter_ssids = NULL;
 	drv->num_filter_ssids = params->num_filter_ssids;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_TRIGGER_SCAN, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_TRIGGER_SCAN);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
@@ -2353,8 +3487,8 @@
 		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
 
 	if (params->extra_ies) {
-		wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Scan extra IEs",
-				  params->extra_ies, params->extra_ies_len);
+		wpa_hexdump(MSG_MSGDUMP, "nl80211: Scan extra IEs",
+			    params->extra_ies, params->extra_ies_len);
 		NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
 			params->extra_ies);
 	}
@@ -2368,29 +3502,42 @@
 		nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
 	}
 
+	if (params->p2p_probe) {
+		/*
+		 * 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(rates, NL80211_BAND_2GHZ, 8,
+			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
+		nla_put_nested(msg, NL80211_ATTR_SCAN_SUPP_RATES, 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));
 #ifdef HOSTAPD
-		if (drv->nlmode == NL80211_IFTYPE_AP) {
+		if (is_ap_interface(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,
-							IEEE80211_MODE_INFRA))
+			if (wpa_driver_nl80211_set_mode(
+				    bss, NL80211_IFTYPE_STATION))
 				goto nla_put_failure;
 
 			if (wpa_driver_nl80211_scan(drv, params)) {
-				wpa_driver_nl80211_set_mode(bss,
-							    IEEE80211_MODE_AP);
+				wpa_driver_nl80211_set_mode(bss, drv->nlmode);
 				goto nla_put_failure;
 			}
 
 			/* Restore AP mode when processing scan results */
-			drv->ap_scan_as_station = 1;
+			drv->ap_scan_as_station = drv->nlmode;
 			ret = 0;
 		} else
 			goto nla_put_failure;
@@ -2420,6 +3567,165 @@
 	nlmsg_free(ssids);
 	nlmsg_free(msg);
 	nlmsg_free(freqs);
+	nlmsg_free(rates);
+	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 = 0;
+	struct nl_msg *msg, *ssids, *freqs, *match_set_ssid, *match_sets;
+	size_t i;
+
+#ifdef ANDROID
+	if (!drv->capa.sched_scan_supported)
+		return android_pno_start(bss, params);
+#endif /* ANDROID */
+
+	msg = nlmsg_alloc();
+	ssids = nlmsg_alloc();
+	freqs = nlmsg_alloc();
+	if (!msg || !ssids || !freqs) {
+		nlmsg_free(msg);
+		nlmsg_free(ssids);
+		nlmsg_free(freqs);
+		return -1;
+	}
+
+	os_free(drv->filter_ssids);
+	drv->filter_ssids = params->filter_ssids;
+	params->filter_ssids = NULL;
+	drv->num_filter_ssids = params->num_filter_ssids;
+
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_START_SCHED_SCAN);
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+	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) {
+		match_sets = nlmsg_alloc();
+
+		for (i = 0; i < drv->num_filter_ssids; i++) {
+			wpa_hexdump_ascii(MSG_MSGDUMP,
+					  "nl80211: Sched scan filter SSID",
+					  drv->filter_ssids[i].ssid,
+					  drv->filter_ssids[i].ssid_len);
+
+			match_set_ssid = nlmsg_alloc();
+			nla_put(match_set_ssid,
+				NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+				drv->filter_ssids[i].ssid_len,
+				drv->filter_ssids[i].ssid);
+
+			nla_put_nested(match_sets, i + 1, match_set_ssid);
+
+			nlmsg_free(match_set_ssid);
+		}
+
+		nla_put_nested(msg, NL80211_ATTR_SCHED_SCAN_MATCH,
+			       match_sets);
+		nlmsg_free(match_sets);
+	}
+
+	for (i = 0; i < params->num_ssids; i++) {
+		wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan SSID",
+				  params->ssids[i].ssid,
+				  params->ssids[i].ssid_len);
+		NLA_PUT(ssids, i + 1, params->ssids[i].ssid_len,
+			params->ssids[i].ssid);
+	}
+	if (params->num_ssids)
+		nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+
+	if (params->extra_ies) {
+		wpa_hexdump_ascii(MSG_MSGDUMP, "nl80211: Sched scan extra IEs",
+				  params->extra_ies, params->extra_ies_len);
+		NLA_PUT(msg, NL80211_ATTR_IE, params->extra_ies_len,
+			params->extra_ies);
+	}
+
+	if (params->freqs) {
+		for (i = 0; params->freqs[i]; i++) {
+			wpa_printf(MSG_MSGDUMP, "nl80211: Scan frequency %u "
+				   "MHz", params->freqs[i]);
+			NLA_PUT_U32(freqs, i + 1, params->freqs[i]);
+		}
+		nla_put_nested(msg, NL80211_ATTR_SCAN_FREQUENCIES, freqs);
+	}
+
+	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(ssids);
+	nlmsg_free(msg);
+	nlmsg_free(freqs);
+	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;
 }
 
@@ -2514,6 +3820,13 @@
 			wpa_printf(MSG_DEBUG, "nl80211: Associated on %u MHz",
 				   _arg->assoc_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;
@@ -2555,7 +3868,7 @@
 		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_LEVEL_INVALID;
+		r->flags |= WPA_SCAN_QUAL_INVALID;
 	} else
 		r->flags |= WPA_SCAN_LEVEL_INVALID | WPA_SCAN_QUAL_INVALID;
 	if (bss[NL80211_BSS_TSF])
@@ -2657,7 +3970,7 @@
 				   "indicates BSS status with " MACSTR
 				   " as authenticated",
 				   MAC2STR(r->bssid));
-			if (drv->nlmode == NL80211_IFTYPE_STATION &&
+			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) {
@@ -2675,13 +3988,13 @@
 				   "indicate BSS status with " MACSTR
 				   " as associated",
 				   MAC2STR(r->bssid));
-			if (drv->nlmode == NL80211_IFTYPE_STATION &&
+			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 (drv->nlmode == NL80211_IFTYPE_STATION &&
+			} else if (is_sta_interface(drv->nlmode) &&
 				   os_memcmp(drv->bssid, r->bssid, ETH_ALEN) !=
 				   0) {
 				wpa_printf(MSG_DEBUG, "nl80211: Local state "
@@ -2696,20 +4009,6 @@
 }
 
 
-static void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-	size_t i;
-
-	if (res == NULL)
-		return;
-
-	for (i = 0; i < res->num; i++)
-		os_free(res->res[i]);
-	os_free(res->res);
-	os_free(res);
-}
-
-
 static struct wpa_scan_results *
 nl80211_get_scan_results(struct wpa_driver_nl80211_data *drv)
 {
@@ -2725,8 +4024,7 @@
 	if (!msg)
 		goto nla_put_failure;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
-		    NL80211_CMD_GET_SCAN, 0);
+	nl80211_cmd(drv, msg, NLM_F_DUMP, NL80211_CMD_GET_SCAN);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
 	arg.drv = drv;
@@ -2734,8 +4032,9 @@
 	ret = send_and_recv_msgs(drv, msg, bss_info_handler, &arg);
 	msg = NULL;
 	if (ret == 0) {
-		wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
-			   (unsigned long) res->num);
+		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 "
@@ -2806,17 +4105,19 @@
 		   "set_tx=%d seq_len=%lu key_len=%lu",
 		   __func__, ifindex, alg, addr, key_idx, set_tx,
 		   (unsigned long) seq_len, (unsigned long) key_len);
+#ifdef CONFIG_TDLS
+	if (key_idx == -1)
+		key_idx = 0;
+#endif /* CONFIG_TDLS */
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
 
 	if (alg == WPA_ALG_NONE) {
-		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-			    0, NL80211_CMD_DEL_KEY, 0);
+		nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_KEY);
 	} else {
-		genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-			    0, NL80211_CMD_NEW_KEY, 0);
+		nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_KEY);
 		NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
 		switch (alg) {
 		case WPA_ALG_WEP:
@@ -2889,7 +4190,7 @@
 	 */
 	if (ret || !set_tx || alg == WPA_ALG_NONE)
 		return ret;
-	if (drv->nlmode == NL80211_IFTYPE_AP && addr &&
+	if (is_ap_interface(drv->nlmode) && addr &&
 	    !is_broadcast_ether_addr(addr))
 		return ret;
 
@@ -2897,8 +4198,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_KEY, 0);
+	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)
@@ -2940,6 +4240,7 @@
 	return ret;
 
 nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -3069,7 +4370,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0, cmd, 0);
+	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);
@@ -3080,8 +4381,9 @@
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-			   "(%s)", ret, strerror(-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;
@@ -3134,6 +4436,52 @@
 }
 
 
+static void nl80211_copy_auth_params(struct wpa_driver_nl80211_data *drv,
+				     struct wpa_driver_auth_params *params)
+{
+	int i;
+
+	drv->auth_freq = params->freq;
+	drv->auth_alg = params->auth_alg;
+	drv->auth_wep_tx_keyidx = params->wep_tx_keyidx;
+	drv->auth_local_state_change = params->local_state_change;
+	drv->auth_p2p = params->p2p;
+
+	if (params->bssid)
+		os_memcpy(drv->auth_bssid_, params->bssid, ETH_ALEN);
+	else
+		os_memset(drv->auth_bssid_, 0, ETH_ALEN);
+
+	if (params->ssid) {
+		os_memcpy(drv->auth_ssid, params->ssid, params->ssid_len);
+		drv->auth_ssid_len = params->ssid_len;
+	} else
+		drv->auth_ssid_len = 0;
+
+
+	os_free(drv->auth_ie);
+	drv->auth_ie = NULL;
+	drv->auth_ie_len = 0;
+	if (params->ie) {
+		drv->auth_ie = os_malloc(params->ie_len);
+		if (drv->auth_ie) {
+			os_memcpy(drv->auth_ie, params->ie, params->ie_len);
+			drv->auth_ie_len = params->ie_len;
+		}
+	}
+
+	for (i = 0; i < 4; i++) {
+		if (params->wep_key[i] && params->wep_key_len[i] &&
+		    params->wep_key_len[i] <= 16) {
+			os_memcpy(drv->auth_wep_key[i], params->wep_key[i],
+				  params->wep_key_len[i]);
+			drv->auth_wep_key_len[i] = params->wep_key_len[i];
+		} else
+			drv->auth_wep_key_len[i] = 0;
+	}
+}
+
+
 static int wpa_driver_nl80211_authenticate(
 	void *priv, struct wpa_driver_auth_params *params)
 {
@@ -3142,13 +4490,20 @@
 	int ret = -1, i;
 	struct nl_msg *msg;
 	enum nl80211_auth_type type;
+	enum nl80211_iftype nlmode;
 	int count = 0;
+	int is_retry;
+
+	is_retry = drv->retry_auth;
+	drv->retry_auth = 0;
 
 	drv->associated = 0;
 	os_memset(drv->auth_bssid, 0, ETH_ALEN);
 	/* FIX: IBSS mode */
-	if (drv->nlmode != NL80211_IFTYPE_STATION &&
-	    wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA) < 0)
+	nlmode = params->p2p ?
+		NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+	if (drv->nlmode != nlmode &&
+	    wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
 		return -1;
 
 retry:
@@ -3159,8 +4514,7 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Authenticate (ifindex=%d)",
 		   drv->ifindex);
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_AUTHENTICATE, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_AUTHENTICATE);
 
 	for (i = 0; i < 4; i++) {
 		if (!params->wep_key[i])
@@ -3218,8 +4572,9 @@
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
+		wpa_dbg(drv->ctx, MSG_DEBUG,
+			"nl80211: MLME command failed (auth): ret=%d (%s)",
+			ret, strerror(-ret));
 		count++;
 		if (ret == -EALREADY && count == 1 && params->bssid &&
 		    !params->local_state_change) {
@@ -3236,6 +4591,49 @@
 			nlmsg_free(msg);
 			goto retry;
 		}
+
+		if (ret == -ENOENT && params->freq && !is_retry) {
+			/*
+			 * cfg80211 has likely expired the BSS entry even
+			 * though it was previously available in our internal
+			 * BSS table. To recover quickly, start a single
+			 * channel scan on the specified channel.
+			 */
+			struct wpa_driver_scan_params scan;
+			int freqs[2];
+
+			os_memset(&scan, 0, sizeof(scan));
+			scan.num_ssids = 1;
+			if (params->ssid) {
+				scan.ssids[0].ssid = params->ssid;
+				scan.ssids[0].ssid_len = params->ssid_len;
+			}
+			freqs[0] = params->freq;
+			freqs[1] = 0;
+			scan.freqs = freqs;
+			wpa_printf(MSG_DEBUG, "nl80211: Trigger single "
+				   "channel scan to refresh cfg80211 BSS "
+				   "entry");
+			ret = wpa_driver_nl80211_scan(bss, &scan);
+			if (ret == 0) {
+				nl80211_copy_auth_params(drv, params);
+				drv->scan_for_auth = 1;
+			}
+		} else if (is_retry) {
+			/*
+			 * Need to indicate this with an event since the return
+			 * value from the retry is not delivered to core code.
+			 */
+			union wpa_event_data event;
+			wpa_printf(MSG_DEBUG, "nl80211: Authentication retry "
+				   "failed");
+			os_memset(&event, 0, sizeof(event));
+			os_memcpy(event.timeout_event.addr, drv->auth_bssid_,
+				  ETH_ALEN);
+			wpa_supplicant_event(drv->ctx, EVENT_AUTH_TIMED_OUT,
+					     &event);
+		}
+
 		goto nla_put_failure;
 	}
 	ret = 0;
@@ -3248,6 +4646,45 @@
 }
 
 
+static 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;
+	int i;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Try to authenticate again");
+
+	os_memset(&params, 0, sizeof(params));
+	params.freq = drv->auth_freq;
+	params.auth_alg = drv->auth_alg;
+	params.wep_tx_keyidx = drv->auth_wep_tx_keyidx;
+	params.local_state_change = drv->auth_local_state_change;
+	params.p2p = drv->auth_p2p;
+
+	if (!is_zero_ether_addr(drv->auth_bssid_))
+		params.bssid = drv->auth_bssid_;
+
+	if (drv->auth_ssid_len) {
+		params.ssid = drv->auth_ssid;
+		params.ssid_len = drv->auth_ssid_len;
+	}
+
+	params.ie = drv->auth_ie;
+	params.ie_len = drv->auth_ie_len;
+
+	for (i = 0; i < 4; i++) {
+		if (drv->auth_wep_key_len[i]) {
+			params.wep_key[i] = drv->auth_wep_key[i];
+			params.wep_key_len[i] = drv->auth_wep_key_len[i];
+		}
+	}
+
+	drv->retry_auth = 1;
+	return wpa_driver_nl80211_authenticate(bss, &params);
+}
+
+
 struct phy_info_arg {
 	u16 *num_modes;
 	struct hostapd_hw_modes *modes;
@@ -3300,6 +4737,7 @@
 
 		mode = &phy_info->modes[*(phy_info->num_modes)];
 		memset(mode, 0, sizeof(*mode));
+		mode->flags = HOSTAPD_MODE_FLAG_HT_INFO_KNOWN;
 		*(phy_info->num_modes) += 1;
 
 		nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
@@ -3640,8 +5078,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_REG, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_REG);
 	return send_and_recv_msgs(drv, msg, nl80211_get_reg, results);
 }
 
@@ -3664,8 +5101,7 @@
 	if (!msg)
 		return NULL;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_WIPHY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_WIPHY);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 
@@ -3673,14 +5109,16 @@
 		nl80211_set_ht40_flags(drv, &result);
 		return wpa_driver_nl80211_add_11b(result.modes, num_modes);
 	}
+	msg = NULL;
  nla_put_failure:
+	nlmsg_free(msg);
 	return NULL;
 }
 
 
-static int wpa_driver_nl80211_send_frame(struct wpa_driver_nl80211_data *drv,
-					 const void *data, size_t len,
-					 int encrypt)
+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 */
@@ -3711,6 +5149,7 @@
 		.msg_flags = 0,
 	};
 	int res;
+	u16 txflags = 0;
 
 	if (encrypt)
 		rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
@@ -3721,6 +5160,10 @@
 		return -1;
 	}
 
+	if (noack)
+		txflags |= IEEE80211_RADIOTAP_F_TX_NOACK;
+	*(le16 *) &rtap_hdr[12] = host_to_le16(txflags);
+
 	res = sendmsg(drv->monitor_sock, &msg, 0);
 	if (res < 0) {
 		wpa_printf(MSG_INFO, "nl80211: sendmsg: %s", strerror(errno));
@@ -3730,8 +5173,24 @@
 }
 
 
+static int wpa_driver_nl80211_send_frame(struct i802_bss *bss,
+					 const void *data, size_t len,
+					 int encrypt, int noack)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	u64 cookie;
+
+	if (drv->use_monitor)
+		return wpa_driver_nl80211_send_mntr(drv, data, len,
+						    encrypt, noack);
+
+	return nl80211_send_frame_cmd(bss, bss->freq, 0, data, len,
+				      &cookie, 0, noack, 0);
+}
+
+
 static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
-					size_t data_len)
+					size_t data_len, int noack)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -3741,7 +5200,8 @@
 
 	mgmt = (struct ieee80211_mgmt *) data;
 	fc = le_to_host16(mgmt->frame_control);
-	if (drv->nlmode == NL80211_IFTYPE_STATION &&
+
+	if (is_sta_interface(drv->nlmode) &&
 	    WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
 	    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
 		/*
@@ -3749,19 +5209,21 @@
 		 * but it works due to the single-threaded nature
 		 * of wpa_supplicant.
 		 */
-		return nl80211_send_frame_cmd(drv, drv->last_mgmt_freq, 0,
-					      data, data_len, NULL);
+		return nl80211_send_frame_cmd(bss, drv->last_mgmt_freq, 0,
+					      data, data_len, NULL, 1, noack,
+					      1);
 	}
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if (drv->nlmode == NL80211_IFTYPE_AP) {
-		wpa_printf(MSG_DEBUG, "%s: Sending frame on ap_oper_freq %d using nl80211_send_frame_cmd", __func__, drv->ap_oper_freq);
-		return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0,
-					  data, data_len, &drv->send_action_cookie);
+#ifdef ANDROID_P2P
+	if (is_ap_interface(drv->nlmode)) {
+		return nl80211_send_frame_cmd(bss, bss->freq, 0,
+					  data, data_len, &drv->send_action_cookie, 0, noack, 1);
 	}
 #else
-	if (drv->no_monitor_iface_capab && drv->nlmode == NL80211_IFTYPE_AP ) {
-		return nl80211_send_frame_cmd(drv, drv->ap_oper_freq, 0,
-					      data, data_len, NULL);
+
+	if (drv->device_ap_sme && is_ap_interface(drv->nlmode)) {
+		return nl80211_send_frame_cmd(bss, bss->freq, 0,
+					      data, data_len, NULL,
+					      0, noack, 0);
 	}
 #endif
 	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
@@ -3777,15 +5239,59 @@
 		if (auth_alg != WLAN_AUTH_SHARED_KEY || auth_trans != 3)
 			encrypt = 0;
 	}
-	wpa_printf(MSG_DEBUG, "%s: Sending frame using monitor interface/l2 socket", __func__);
-	return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
+
+	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt,
+					     noack);
 }
 
 
-static int wpa_driver_nl80211_set_beacon(void *priv,
-					 const u8 *head, size_t head_len,
-					 const u8 *tail, size_t tail_len,
-					 int dtim_period, int beacon_int)
+static int nl80211_set_bss(struct i802_bss *bss, int cts, int preamble,
+			   int slot, int ht_opmode, int ap_isolate,
+			   int *basic_rates)
+{
+	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 (basic_rates) {
+		u8 rates[NL80211_MAX_SUPP_RATES];
+		u8 rates_len = 0;
+		int i;
+
+		for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0;
+		     i++)
+			rates[rates_len++] = basic_rates[i] / 5;
+
+		NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+	}
+
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_ap(void *priv,
+				     struct wpa_driver_ap_params *params)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -3794,6 +5300,10 @@
 	int ret;
 	int beacon_set;
 	int ifindex = if_nametoindex(bss->ifname);
+	int num_suites;
+	u32 suites[10];
+	u32 ver;
+
 	beacon_set = bss->beacon_set;
 
 	msg = nlmsg_alloc();
@@ -3805,13 +5315,112 @@
 	if (beacon_set)
 		cmd = NL80211_CMD_SET_BEACON;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, cmd, 0);
-	NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head);
-	NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
+	nl80211_cmd(drv, msg, 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_IFINDEX, ifindex);
-	NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, beacon_int);
-	NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, dtim_period);
+	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);
+	if (params->proberesp && params->proberesp_len)
+		NLA_PUT(msg, NL80211_ATTR_PROBE_RESP, params->proberesp_len,
+			params->proberesp);
+	switch (params->hide_ssid) {
+	case NO_SSID_HIDING:
+		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+			    NL80211_HIDDEN_SSID_NOT_IN_USE);
+		break;
+	case HIDDEN_SSID_ZERO_LEN:
+		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+			    NL80211_HIDDEN_SSID_ZERO_LEN);
+		break;
+	case HIDDEN_SSID_ZERO_CONTENTS:
+		NLA_PUT_U32(msg, NL80211_ATTR_HIDDEN_SSID,
+			    NL80211_HIDDEN_SSID_ZERO_CONTENTS);
+		break;
+	}
+	if (params->privacy)
+		NLA_PUT_FLAG(msg, NL80211_ATTR_PRIVACY);
+	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);
+
+	ver = 0;
+	if (params->wpa_version & WPA_PROTO_WPA)
+		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);
+
+	num_suites = 0;
+	if (params->key_mgmt_suites & WPA_KEY_MGMT_IEEE8021X)
+		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 (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);
+
+	num_suites = 0;
+	if (params->pairwise_ciphers & WPA_CIPHER_CCMP)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_CCMP;
+	if (params->pairwise_ciphers & WPA_CIPHER_TKIP)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_TKIP;
+	if (params->pairwise_ciphers & WPA_CIPHER_WEP104)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP104;
+	if (params->pairwise_ciphers & WPA_CIPHER_WEP40)
+		suites[num_suites++] = WLAN_CIPHER_SUITE_WEP40;
+	if (num_suites) {
+		NLA_PUT(msg, NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+			num_suites * sizeof(u32), suites);
+	}
+
+	switch (params->group_cipher) {
+	case WPA_CIPHER_CCMP:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_CCMP);
+		break;
+	case WPA_CIPHER_TKIP:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_TKIP);
+		break;
+	case WPA_CIPHER_WEP104:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_WEP104);
+		break;
+	case WPA_CIPHER_WEP40:
+		NLA_PUT_U32(msg, NL80211_ATTR_CIPHER_SUITE_GROUP,
+			    WLAN_CIPHER_SUITE_WEP40);
+		break;
+	}
+
+	if (params->beacon_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE, wpabuf_len(params->beacon_ies),
+			wpabuf_head(params->beacon_ies));
+	}
+	if (params->proberesp_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE_PROBE_RESP,
+			wpabuf_len(params->proberesp_ies),
+			wpabuf_head(params->proberesp_ies));
+	}
+	if (params->assocresp_ies) {
+		NLA_PUT(msg, NL80211_ATTR_IE_ASSOC_RESP,
+			wpabuf_len(params->assocresp_ies),
+			wpabuf_head(params->assocresp_ies));
+	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	if (ret) {
@@ -3819,29 +5428,36 @@
 			   ret, strerror(-ret));
 	} else {
 		bss->beacon_set = 1;
+		nl80211_set_bss(bss, params->cts_protect, params->preamble,
+				params->short_slot_time, params->ht_opmode,
+				params->isolate, params->basic_rates);
 	}
-#if defined(ANDROID_BRCM_P2P_PATCH) && defined(HOSTAPD)
+#if defined(ANDROID_P2P) && defined(HOSTAPD)
 	wpa_driver_nl80211_probe_req_report(priv, 1);
 #endif
 	return ret;
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
 
-static int wpa_driver_nl80211_set_freq(struct wpa_driver_nl80211_data *drv,
+static int wpa_driver_nl80211_set_freq(struct i802_bss *bss,
 				       int freq, int ht_enabled,
 				       int sec_channel_offset)
 {
+	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	int ret;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Set freq %d (ht_enabled=%d "
+		   "sec_channel_offset=%d)",
+		   freq, ht_enabled, sec_channel_offset);
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_WIPHY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
@@ -3856,7 +5472,7 @@
 				    NL80211_CHAN_HT40PLUS);
 			break;
 		default:
-#ifndef ANDROID_BRCM_P2P_PATCH
+#ifndef ANDROID_P2P
 /* Should be change to HT20 as a default value because P2P firmware does not support 11n for BCM4329 */
 			NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
 				    NL80211_CHAN_HT20);
@@ -3869,50 +5485,102 @@
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
-	if (ret == 0)
+	msg = NULL;
+	if (ret == 0) {
+		bss->freq = freq;
 		return 0;
+	}
 	wpa_printf(MSG_DEBUG, "nl80211: Failed to set channel (freq=%d): "
 		   "%d (%s)", freq, ret, strerror(-ret));
 nla_put_failure:
+	nlmsg_free(msg);
 	return -1;
 }
 
 
+static u32 sta_flags_nl80211(int flags)
+{
+	u32 f = 0;
+
+	if (flags & WPA_STA_AUTHORIZED)
+		f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
+	if (flags & WPA_STA_WMM)
+		f |= BIT(NL80211_STA_FLAG_WME);
+	if (flags & WPA_STA_SHORT_PREAMBLE)
+		f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
+	if (flags & WPA_STA_MFP)
+		f |= BIT(NL80211_STA_FLAG_MFP);
+	if (flags & WPA_STA_TDLS_PEER)
+		f |= BIT(NL80211_STA_FLAG_TDLS_PEER);
+
+	return f;
+}
+
+
 static int wpa_driver_nl80211_sta_add(void *priv,
 				      struct hostapd_sta_add_params *params)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
+	struct nl_msg *msg, *wme = NULL;
+	struct nl80211_sta_flag_update upd;
 	int ret = -ENOBUFS;
 
+	if ((params->flags & WPA_STA_TDLS_PEER) &&
+	    !(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+		return -EOPNOTSUPP;
+
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_NEW_STATION, 0);
+	nl80211_cmd(drv, msg, 0, params->set ? NL80211_CMD_SET_STATION :
+		    NL80211_CMD_NEW_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 	NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
-	NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
 	NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
 		params->supp_rates);
-	NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
-		    params->listen_interval);
+	if (!params->set) {
+		NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+		NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+			    params->listen_interval);
+	}
 	if (params->ht_capabilities) {
 		NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
 			sizeof(*params->ht_capabilities),
 			params->ht_capabilities);
 	}
 
+	os_memset(&upd, 0, sizeof(upd));
+	upd.mask = sta_flags_nl80211(params->flags);
+	upd.set = upd.mask;
+	NLA_PUT(msg, NL80211_ATTR_STA_FLAGS2, sizeof(upd), &upd);
+
+	if (params->flags & WPA_STA_WMM) {
+		wme = nlmsg_alloc();
+		if (!wme)
+			goto nla_put_failure;
+
+		NLA_PUT_U8(wme, NL80211_STA_WME_UAPSD_QUEUES,
+				params->qosinfo & WMM_QOSINFO_STA_AC_MASK);
+		NLA_PUT_U8(wme, NL80211_STA_WME_MAX_SP,
+				(params->qosinfo > WMM_QOSINFO_STA_SP_SHIFT) &
+				WMM_QOSINFO_STA_SP_MASK);
+		nla_put_nested(msg, NL80211_ATTR_STA_WME, wme);
+	}
+
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
 	if (ret)
-		wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
-			   "result: %d (%s)", ret, strerror(-ret));
+		wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_%s_STATION "
+			   "result: %d (%s)", params->set ? "SET" : "NEW", ret,
+			   strerror(-ret));
 	if (ret == -EEXIST)
 		ret = 0;
  nla_put_failure:
+	nlmsg_free(wme);
+	nlmsg_free(msg);
 	return ret;
 }
 
@@ -3928,8 +5596,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
 		    if_nametoindex(bss->ifname));
@@ -3940,6 +5607,7 @@
 		return 0;
 	return ret;
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -3951,26 +5619,46 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Remove interface ifindex=%d", ifidx);
 
-#ifdef HOSTAPD
 	/* stop listening for EAPOL on this interface */
 	del_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
 
 	msg = nlmsg_alloc();
 	if (!msg)
 		goto nla_put_failure;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_INTERFACE, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_INTERFACE);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
 
 	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);
 }
 
 
+static const char * nl80211_iftype_str(enum nl80211_iftype mode)
+{
+	switch (mode) {
+	case NL80211_IFTYPE_ADHOC:
+		return "ADHOC";
+	case NL80211_IFTYPE_STATION:
+		return "STATION";
+	case NL80211_IFTYPE_AP:
+		return "AP";
+	case NL80211_IFTYPE_MONITOR:
+		return "MONITOR";
+	case NL80211_IFTYPE_P2P_CLIENT:
+		return "P2P_CLIENT";
+	case NL80211_IFTYPE_P2P_GO:
+		return "P2P_GO";
+	default:
+		return "unknown";
+	}
+}
+
+
 static int nl80211_create_iface_once(struct wpa_driver_nl80211_data *drv,
 				     const char *ifname,
 				     enum nl80211_iftype iftype,
@@ -3980,12 +5668,14 @@
 	int ifidx;
 	int ret = -ENOBUFS;
 
+	wpa_printf(MSG_DEBUG, "nl80211: Create interface iftype %d (%s)",
+		   iftype, nl80211_iftype_str(iftype));
+
 	msg = nlmsg_alloc();
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_NEW_INTERFACE, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_NEW_INTERFACE);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
@@ -4010,8 +5700,10 @@
 	}
 
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+	msg = NULL;
 	if (ret) {
  nla_put_failure:
+		nlmsg_free(msg);
 		wpa_printf(MSG_ERROR, "Failed to create interface %s: %d (%s)",
 			   ifname, ret, strerror(-ret));
 		return ret;
@@ -4024,13 +5716,11 @@
 	if (ifidx <= 0)
 		return -1;
 
-#ifdef HOSTAPD
 	/* start listening for EAPOL on this interface */
 	add_ifidx(drv, ifidx);
-#endif /* HOSTAPD */
 
 	if (addr && iftype != NL80211_IFTYPE_MONITOR &&
-	    linux_set_ifhwaddr(drv->ioctl_sock, ifname, addr)) {
+	    linux_set_ifhwaddr(drv->global->ioctl_sock, ifname, addr)) {
 		nl80211_remove_iface(drv, ifidx);
 		return -1;
 	}
@@ -4047,7 +5737,7 @@
 
 	ret = nl80211_create_iface_once(drv, ifname, iftype, addr, wds);
 
-	/* if error occured and interface exists already */
+	/* if error occurred and interface exists already */
 	if (ret == -ENFILE && if_nametoindex(ifname)) {
 		wpa_printf(MSG_INFO, "Try to remove and re-create %s", ifname);
 
@@ -4059,7 +5749,7 @@
 						wds);
 	}
 
-	if (ret >= 0 && drv->disable_11b_rates)
+	if (ret >= 0 && is_p2p_interface(iftype))
 		nl80211_disable_11b_rates(drv, ret, 1);
 
 	return ret;
@@ -4089,10 +5779,20 @@
 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.frame = buf;
-	event.rx_from_unknown.len = len;
+	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);
 }
 
@@ -4350,6 +6050,10 @@
 static void nl80211_remove_monitor_interface(
 	struct wpa_driver_nl80211_data *drv)
 {
+	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;
@@ -4369,11 +6073,25 @@
 	struct sockaddr_ll ll;
 	int optval;
 	socklen_t optlen;
-#ifdef ANDROID_BRCM_P2P_PATCH
-	snprintf(buf, IFNAMSIZ, "%s%s", WPA_MONITOR_IFNAME_PREFIX, drv->first_bss.ifname);
-#else
-	snprintf(buf, IFNAMSIZ, "mon.%s", drv->first_bss.ifname);
-#endif
+
+	if (drv->monitor_ifidx >= 0) {
+		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 =
@@ -4381,15 +6099,21 @@
 				     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->no_monitor_iface_capab = 1;
+		drv->device_ap_sme = 1;
 	}
 
 	if (drv->monitor_ifidx < 0)
 		return -1;
 
-	if (linux_set_iface_flags(drv->ioctl_sock, buf, 1))
+	if (linux_set_iface_flags(drv->global->ioctl_sock, buf, 1))
 		goto error;
 
 	memset(&ll, 0, sizeof(ll));
@@ -4433,6 +6157,98 @@
 }
 
 
+static int nl80211_setup_ap(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	wpa_printf(MSG_DEBUG, "nl80211: Setup AP - device_ap_sme=%d "
+		   "use_monitor=%d", drv->device_ap_sme, drv->use_monitor);
+
+	/*
+	 * Disable Probe Request reporting unless we need it in this way for
+	 * devices that include the AP SME, in the other case (unless using
+	 * monitor iface) we'll get it through the nl_mgmt socket instead.
+	 */
+	if (!drv->device_ap_sme)
+		wpa_driver_nl80211_probe_req_report(bss, 0);
+
+	if (!drv->device_ap_sme && !drv->use_monitor)
+		if (nl80211_mgmt_subscribe_ap(bss))
+			return -1;
+
+	if (drv->device_ap_sme && !drv->use_monitor)
+		if (nl80211_mgmt_subscribe_ap_dev_sme(bss))
+			return -1;
+
+	if (!drv->device_ap_sme && drv->use_monitor &&
+	    nl80211_create_monitor_interface(drv) &&
+	    !drv->device_ap_sme)
+		return -1;
+
+	if (drv->device_ap_sme &&
+	    wpa_driver_nl80211_probe_req_report(bss, 1) < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to enable "
+			   "Probe Request frame reporting in AP mode");
+		/* Try to survive without this */
+	}
+
+#ifdef ANDROID_P2P
+	/* For AP mode, enable probe req report even if device_ap_sme
+	 * is not enabled
+	 */
+	wpa_printf(MSG_DEBUG, "nl80211: Enabling probe req report");
+	wpa_driver_nl80211_probe_req_report(bss, 1);
+#endif
+
+	return 0;
+}
+
+
+static void nl80211_teardown_ap(struct i802_bss *bss)
+{
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+
+	if (drv->device_ap_sme) {
+		wpa_driver_nl80211_probe_req_report(bss, 0);
+		if (!drv->use_monitor)
+			nl80211_mgmt_unsubscribe(bss, "AP teardown (dev SME)");
+	} else if (drv->use_monitor)
+		nl80211_remove_monitor_interface(drv);
+	else
+		nl80211_mgmt_unsubscribe(bss, "AP teardown");
+
+	bss->beacon_set = 0;
+}
+
+
+static int nl80211_send_eapol_data(struct i802_bss *bss,
+				   const u8 *addr, const u8 *data,
+				   size_t data_len)
+{
+	struct sockaddr_ll ll;
+	int ret;
+
+	if (bss->drv->eapol_tx_sock < 0) {
+		wpa_printf(MSG_DEBUG, "nl80211: No socket to send EAPOL");
+		return -1;
+	}
+
+	os_memset(&ll, 0, sizeof(ll));
+	ll.sll_family = AF_PACKET;
+	ll.sll_ifindex = bss->ifindex;
+	ll.sll_protocol = htons(ETH_P_PAE);
+	ll.sll_halen = ETH_ALEN;
+	os_memcpy(ll.sll_addr, addr, ETH_ALEN);
+	ret = sendto(bss->drv->eapol_tx_sock, data, data_len, 0,
+		     (struct sockaddr *) &ll, sizeof(ll));
+	if (ret < 0)
+		wpa_printf(MSG_ERROR, "nl80211: EAPOL TX: %s",
+			   strerror(errno));
+
+	return ret;
+}
+
+
 static const u8 rfc1042_header[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
 
 static int wpa_driver_nl80211_hapd_send_eapol(
@@ -4447,6 +6263,9 @@
 	int res;
 	int qos = flags & WPA_STA_WMM;
 
+	if (drv->device_ap_sme || !drv->use_monitor)
+		return nl80211_send_eapol_data(bss, addr, data, data_len);
+
 	len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
 		data_len;
 	hdr = os_zalloc(len);
@@ -4484,7 +6303,7 @@
 	pos += 2;
 	memcpy(pos, data, data_len);
 
-	res = wpa_driver_nl80211_send_frame(drv, (u8 *) hdr, len, encrypt);
+	res = wpa_driver_nl80211_send_frame(bss, (u8 *) hdr, len, encrypt, 0);
 	if (res < 0) {
 		wpa_printf(MSG_ERROR, "i802_send_eapol - packet len: %lu - "
 			   "failed: %d (%s)",
@@ -4496,23 +6315,6 @@
 }
 
 
-static u32 sta_flags_nl80211(int flags)
-{
-	u32 f = 0;
-
-	if (flags & WPA_STA_AUTHORIZED)
-		f |= BIT(NL80211_STA_FLAG_AUTHORIZED);
-	if (flags & WPA_STA_WMM)
-		f |= BIT(NL80211_STA_FLAG_WME);
-	if (flags & WPA_STA_SHORT_PREAMBLE)
-		f |= BIT(NL80211_STA_FLAG_SHORT_PREAMBLE);
-	if (flags & WPA_STA_MFP)
-		f |= BIT(NL80211_STA_FLAG_MFP);
-
-	return f;
-}
-
-
 static int wpa_driver_nl80211_sta_set_flags(void *priv, const u8 *addr,
 					    int total_flags,
 					    int flags_or, int flags_and)
@@ -4532,8 +6334,7 @@
 		return -ENOMEM;
 	}
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
 		    if_nametoindex(bss->ifname));
@@ -4555,6 +6356,9 @@
 	if (total_flags & WPA_STA_MFP)
 		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
 
+	if (total_flags & WPA_STA_TDLS_PEER)
+		NLA_PUT_FLAG(flags, NL80211_STA_FLAG_TDLS_PEER);
+
 	if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
 		goto nla_put_failure;
 
@@ -4567,6 +6371,7 @@
 
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+	nlmsg_free(msg);
 	nlmsg_free(flags);
 	return -ENOBUFS;
 }
@@ -4575,20 +6380,21 @@
 static int wpa_driver_nl80211_ap(struct wpa_driver_nl80211_data *drv,
 				 struct wpa_driver_associate_params *params)
 {
-	if (params->p2p)
+	enum nl80211_iftype nlmode;
+
+	if (params->p2p) {
 		wpa_printf(MSG_DEBUG, "nl80211: Setup AP operations for P2P "
 			   "group (GO)");
-	if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode) ||
-	    wpa_driver_nl80211_set_freq(drv, params->freq, 0, 0)) {
+		nlmode = NL80211_IFTYPE_P2P_GO;
+	} else
+		nlmode = NL80211_IFTYPE_AP;
+
+	if (wpa_driver_nl80211_set_mode(&drv->first_bss, nlmode) ||
+	    wpa_driver_nl80211_set_freq(&drv->first_bss, params->freq, 0, 0)) {
 		nl80211_remove_monitor_interface(drv);
 		return -1;
 	}
 
-	/* TODO: setup monitor interface (and add code somewhere to remove this
-	 * when AP mode is stopped; associate with mode != 2 or drv_deinit) */
-	wpa_printf(MSG_DEBUG, "nl80211: Update ap_oper_freq with params->freq %d", params->freq);
-	drv->ap_oper_freq = params->freq;
-
 	return 0;
 }
 
@@ -4602,8 +6408,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_LEAVE_IBSS, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_LEAVE_IBSS);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
@@ -4631,7 +6436,8 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Join IBSS (ifindex=%d)", drv->ifindex);
 
-	if (wpa_driver_nl80211_set_mode(&drv->first_bss, params->mode)) {
+	if (wpa_driver_nl80211_set_mode(&drv->first_bss,
+					NL80211_IFTYPE_ADHOC)) {
 		wpa_printf(MSG_INFO, "nl80211: Failed to set interface into "
 			   "IBSS mode");
 		return -1;
@@ -4642,8 +6448,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_JOIN_IBSS, 0);
+	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))
@@ -4696,6 +6501,55 @@
 }
 
 
+static unsigned int nl80211_get_assoc_bssid(struct wpa_driver_nl80211_data *drv,
+					    u8 *bssid)
+{
+	struct nl_msg *msg;
+	int ret;
+	struct nl80211_bss_info_arg arg;
+
+	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) {
+		if (is_zero_ether_addr(arg.assoc_bssid))
+			return -ENOTCONN;
+		os_memcpy(bssid, arg.assoc_bssid, ETH_ALEN);
+		return 0;
+	}
+	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 int nl80211_disconnect(struct wpa_driver_nl80211_data *drv,
+			      const u8 *bssid)
+{
+	u8 addr[ETH_ALEN];
+
+	if (bssid == NULL) {
+		int res = nl80211_get_assoc_bssid(drv, addr);
+		if (res)
+			return res;
+		bssid = addr;
+	}
+
+	return wpa_driver_nl80211_disconnect(drv, bssid,
+					     WLAN_REASON_PREV_AUTH_NOT_VALID);
+}
+
+
 static int wpa_driver_nl80211_connect(
 	struct wpa_driver_nl80211_data *drv,
 	struct wpa_driver_associate_params *params)
@@ -4710,8 +6564,7 @@
 		return -1;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Connect (ifindex=%d)", drv->ifindex);
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_CONNECT, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_CONNECT);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	if (params->bssid) {
@@ -4766,15 +6619,15 @@
 	NLA_PUT_U32(msg, NL80211_ATTR_AUTH_TYPE, type);
 
 skip_auth_type:
-	if (params->wpa_ie && params->wpa_ie_len) {
-		enum nl80211_wpa_versions ver;
+	if (params->wpa_proto) {
+		enum nl80211_wpa_versions ver = 0;
 
-		if (params->wpa_ie[0] == WLAN_EID_RSN)
-			ver = NL80211_WPA_VERSION_2;
-		else
-			ver = NL80211_WPA_VERSION_1;
+		if (params->wpa_proto & WPA_PROTO_WPA)
+			ver |= NL80211_WPA_VERSION_1;
+		if (params->wpa_proto & WPA_PROTO_RSN)
+			ver |= NL80211_WPA_VERSION_2;
 
-		wpa_printf(MSG_DEBUG, "  * WPA Version %d", ver);
+		wpa_printf(MSG_DEBUG, "  * WPA Versions 0x%x", ver);
 		NLA_PUT_U32(msg, NL80211_ATTR_WPA_VERSIONS, ver);
 	}
 
@@ -4845,6 +6698,14 @@
 	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: MLME connect failed: ret=%d "
 			   "(%s)", ret, strerror(-ret));
+		/*
+		 * cfg80211 does not currently accept new connection if we are
+		 * already connected. As a workaround, force disconnection and
+		 * try again once the driver indicates it completed
+		 * disconnection.
+		 */
+		if (ret == -EALREADY)
+			nl80211_disconnect(drv, params->bssid);
 		goto nla_put_failure;
 	}
 	ret = 0;
@@ -4872,7 +6733,10 @@
 		return wpa_driver_nl80211_ibss(drv, params);
 
 	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_SME)) {
-		if (wpa_driver_nl80211_set_mode(priv, params->mode) < 0)
+		enum nl80211_iftype nlmode = params->p2p ?
+			NL80211_IFTYPE_P2P_CLIENT : NL80211_IFTYPE_STATION;
+
+		if (wpa_driver_nl80211_set_mode(priv, nlmode) < 0)
 			return -1;
 		return wpa_driver_nl80211_connect(drv, params);
 	}
@@ -4885,8 +6749,7 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Associate (ifindex=%d)",
 		   drv->ifindex);
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_ASSOCIATE, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_ASSOCIATE);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	if (params->bssid) {
@@ -4979,8 +6842,9 @@
 	ret = send_and_recv_msgs(drv, msg, NULL, NULL);
 	msg = NULL;
 	if (ret) {
-		wpa_printf(MSG_DEBUG, "nl80211: MLME command failed: ret=%d "
-			   "(%s)", ret, strerror(-ret));
+		wpa_dbg(drv->ctx, MSG_DEBUG,
+			"nl80211: MLME command failed (assoc): ret=%d (%s)",
+			ret, strerror(-ret));
 		nl80211_dump_scan(drv);
 		goto nla_put_failure;
 	}
@@ -4995,58 +6859,53 @@
 
 
 static int nl80211_set_mode(struct wpa_driver_nl80211_data *drv,
-			    int ifindex, int mode)
+			    int ifindex, enum nl80211_iftype mode)
 {
 	struct nl_msg *msg;
 	int ret = -ENOBUFS;
 
+	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;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_INTERFACE, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_INTERFACE);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, mode);
 
 	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 interface %d to mode %d:"
 		   " %d (%s)", ifindex, mode, ret, strerror(-ret));
 	return ret;
 }
 
 
-static int wpa_driver_nl80211_set_mode(void *priv, int mode)
+static int wpa_driver_nl80211_set_mode(struct i802_bss *bss,
+				       enum nl80211_iftype nlmode)
 {
-	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 	int ret = -1;
-	int nlmode;
 	int i;
+	int was_ap = is_ap_interface(drv->nlmode);
+	int res;
 
-	switch (mode) {
-	case 0:
-		nlmode = NL80211_IFTYPE_STATION;
-		break;
-	case 1:
-		nlmode = NL80211_IFTYPE_ADHOC;
-		break;
-	case 2:
-		nlmode = NL80211_IFTYPE_AP;
-		break;
-	default:
-		return -1;
-	}
-
-	if (nl80211_set_mode(drv, drv->ifindex, nlmode) == 0) {
+	res = nl80211_set_mode(drv, drv->ifindex, nlmode);
+	if (res == 0) {
 		drv->nlmode = nlmode;
 		ret = 0;
 		goto done;
 	}
 
+	if (res == -ENODEV)
+		return -1;
+
 	if (nlmode == drv->nlmode) {
 		wpa_printf(MSG_DEBUG, "nl80211: Interface already in "
 			   "requested mode - ignore error");
@@ -5061,15 +6920,21 @@
 	wpa_printf(MSG_DEBUG, "nl80211: Try mode change after setting "
 		   "interface down");
 	for (i = 0; i < 10; i++) {
-		if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0) ==
-		    0) {
+		res = linux_set_iface_flags(drv->global->ioctl_sock,
+					    bss->ifname, 0);
+		if (res == -EACCES || res == -ENODEV)
+			break;
+		if (res == 0) {
 			/* Try to set the mode again while the interface is
 			 * down */
 			ret = nl80211_set_mode(drv, drv->ifindex, nlmode);
-			if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname,
-						  1))
+			if (ret == -EACCES)
+				break;
+			res = linux_set_iface_flags(drv->global->ioctl_sock,
+						    bss->ifname, 1);
+			if (res && !ret)
 				ret = -1;
-			if (!ret)
+			else if (ret != -EBUSY)
 				break;
 		} else
 			wpa_printf(MSG_DEBUG, "nl80211: Failed to set "
@@ -5081,26 +6946,34 @@
 		wpa_printf(MSG_DEBUG, "nl80211: Mode change succeeded while "
 			   "interface is down");
 		drv->nlmode = nlmode;
+		drv->ignore_if_down_event = 1;
 	}
 
 done:
-	if (!ret && nlmode == NL80211_IFTYPE_AP) {
-		/* Setup additional AP mode functionality if needed */
-		if (!drv->no_monitor_iface_capab && drv->monitor_ifidx < 0 &&
-		    nl80211_create_monitor_interface(drv) &&
-		    !drv->no_monitor_iface_capab)
-			return -1;
-	} else if (!ret && nlmode != NL80211_IFTYPE_AP) {
-		/* Remove additional AP mode functionality */
-		nl80211_remove_monitor_interface(drv);
-		bss->beacon_set = 0;
-	}
-
-	if (ret)
+	if (ret) {
 		wpa_printf(MSG_DEBUG, "nl80211: Interface mode change to %d "
 			   "from %d failed", nlmode, drv->nlmode);
+		return ret;
+	}
 
-	return ret;
+	if (is_ap_interface(nlmode)) {
+		nl80211_mgmt_unsubscribe(bss, "start AP");
+		/* Setup additional AP mode functionality if needed */
+		if (nl80211_setup_ap(bss))
+			return -1;
+	} else if (was_ap) {
+		/* Remove additional AP mode functionality */
+		nl80211_teardown_ap(bss);
+	} else {
+		nl80211_mgmt_unsubscribe(bss, "mode change");
+	}
+
+	if (!is_ap_interface(nlmode) &&
+	    nl80211_mgmt_subscribe_non_ap(bss) < 0)
+		wpa_printf(MSG_DEBUG, "nl80211: Failed to register Action "
+			   "frame processing - ignore for now");
+
+	return 0;
 }
 
 
@@ -5124,7 +6997,7 @@
 	wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
 		   __func__, drv->operstate, state, state ? "UP" : "DORMANT");
 	drv->operstate = state;
-	return netlink_send_oper_ifla(drv->netlink, drv->ifindex, -1,
+	return netlink_send_oper_ifla(drv->global->netlink, drv->ifindex, -1,
 				      state ? IF_OPER_UP : IF_OPER_DORMANT);
 }
 
@@ -5140,8 +7013,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
 		    if_nametoindex(bss->ifname));
@@ -5155,6 +7027,7 @@
 
 	return send_and_recv_msgs(drv, msg, NULL, NULL);
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -5163,8 +7036,7 @@
 static int i802_set_freq(void *priv, struct hostapd_freq_params *freq)
 {
 	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	return wpa_driver_nl80211_set_freq(drv, freq->freq, freq->ht_enabled,
+	return wpa_driver_nl80211_set_freq(bss, freq->freq, freq->ht_enabled,
 					   freq->sec_channel_offset);
 }
 
@@ -5211,8 +7083,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_KEY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_KEY);
 
 	if (addr)
 		NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
@@ -5223,36 +7094,7 @@
 
 	return send_and_recv_msgs(drv, msg, get_key_handler, seq);
  nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
-			      int mode)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-	u8 rates[NL80211_MAX_SUPP_RATES];
-	u8 rates_len = 0;
-	int i;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_BSS, 0);
-
-	for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
-		rates[rates_len++] = basic_rates[i] / 5;
-
-	NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -5274,15 +7116,16 @@
 	else
 		val = rts;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_WIPHY, 0);
+	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);
 
 	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;
@@ -5306,15 +7149,16 @@
 	else
 		val = frag;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_WIPHY, 0);
+	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);
 
 	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;
@@ -5326,13 +7170,13 @@
 	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;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_DEL_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_DEL_STATION);
 
 	/*
 	 * XXX: FIX! this needs to flush all VLANs too
@@ -5340,8 +7184,14 @@
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
 		    if_nametoindex(bss->ifname));
 
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
+	res = send_and_recv_msgs(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;
 }
 
@@ -5409,14 +7259,14 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_GET_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_GET_STATION);
 
 	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;
 }
 
@@ -5433,8 +7283,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_WIPHY, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_WIPHY);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 
@@ -5474,59 +7323,13 @@
 
 	if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
 		return 0;
+	msg = NULL;
  nla_put_failure:
+	nlmsg_free(msg);
 	return -1;
 }
 
 
-static int i802_set_bss(void *priv, int cts, int preamble, int slot,
-			int ht_opmode)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_BSS, 0);
-
-	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);
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-	return -ENOBUFS;
-}
-
-
-static int i802_set_cts_protect(void *priv, int value)
-{
-	return i802_set_bss(priv, value, -1, -1, -1);
-}
-
-
-static int i802_set_preamble(void *priv, int value)
-{
-	return i802_set_bss(priv, -1, value, -1, -1);
-}
-
-
-static int i802_set_short_slot_time(void *priv, int value)
-{
-	return i802_set_bss(priv, -1, -1, value, -1);
-}
-
-
 static int i802_set_sta_vlan(void *priv, const u8 *addr,
 			     const char *ifname, int vlan_id)
 {
@@ -5539,8 +7342,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_STATION, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_STATION);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
 		    if_nametoindex(bss->ifname));
@@ -5549,6 +7351,7 @@
 		    if_nametoindex(ifname));
 
 	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)",
@@ -5556,23 +7359,11 @@
 			   strerror(-ret));
 	}
  nla_put_failure:
+	nlmsg_free(msg);
 	return ret;
 }
 
 
-static int i802_set_ht_params(void *priv, const u8 *ht_capab,
-			      size_t ht_capab_len, const u8 *ht_oper,
-			      size_t ht_oper_len)
-{
-	if (ht_oper_len >= 6) {
-		/* ht opmode uses 16bit in octet 5 & 6 */
-		u16 ht_opmode = le_to_host16(((u16 *) ht_oper)[2]);
-		return i802_set_bss(priv, -1, -1, -1, ht_opmode);
-	} else
-		return -1;
-}
-
-
 static int i802_get_inact_sec(void *priv, const u8 *addr)
 {
 	struct hostap_sta_driver_data data;
@@ -5610,7 +7401,7 @@
 	mgmt.u.deauth.reason_code = host_to_le16(reason);
 	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
 					    IEEE80211_HDRLEN +
-					    sizeof(mgmt.u.deauth));
+					    sizeof(mgmt.u.deauth), 0);
 }
 
 
@@ -5629,7 +7420,7 @@
 	mgmt.u.disassoc.reason_code = host_to_le16(reason);
 	return wpa_driver_nl80211_send_mlme(bss, (u8 *) &mgmt,
 					    IEEE80211_HDRLEN +
-					    sizeof(mgmt.u.disassoc));
+					    sizeof(mgmt.u.disassoc), 0);
 }
 
 #endif /* HOSTAPD || CONFIG_AP */
@@ -5716,11 +7507,11 @@
 						 NULL, 1) < 0)
 				return -1;
 			if (bridge_ifname &&
-			    linux_br_add_if(drv->ioctl_sock, bridge_ifname,
-					    name) < 0)
+			    linux_br_add_if(drv->global->ioctl_sock,
+					    bridge_ifname, name) < 0)
 				return -1;
 		}
-		linux_set_iface_flags(drv->ioctl_sock, name, 1);
+		linux_set_iface_flags(drv->global->ioctl_sock, name, 1);
 		return i802_set_sta_vlan(priv, addr, name, 0);
 	} else {
 		i802_set_sta_vlan(priv, addr, bss->ifname, 0);
@@ -5764,7 +7555,7 @@
 		 * Bridge was configured, but the bridge device does
 		 * not exist. Try to add it now.
 		 */
-		if (linux_br_add(drv->ioctl_sock, brname) < 0) {
+		if (linux_br_add(drv->global->ioctl_sock, brname) < 0) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to add the "
 				   "bridge interface %s: %s",
 				   brname, strerror(errno));
@@ -5780,7 +7571,8 @@
 
 		wpa_printf(MSG_DEBUG, "nl80211: Removing interface %s from "
 			   "bridge %s", ifname, in_br);
-		if (linux_br_del_if(drv->ioctl_sock, in_br, ifname) < 0) {
+		if (linux_br_del_if(drv->global->ioctl_sock, in_br, ifname) <
+		    0) {
 			wpa_printf(MSG_ERROR, "nl80211: Failed to "
 				   "remove interface %s from bridge "
 				   "%s: %s",
@@ -5791,7 +7583,7 @@
 
 	wpa_printf(MSG_DEBUG, "nl80211: Adding interface %s into bridge %s",
 		   ifname, brname);
-	if (linux_br_add_if(drv->ioctl_sock, brname, ifname) < 0) {
+	if (linux_br_add_if(drv->global->ioctl_sock, brname, ifname) < 0) {
 		wpa_printf(MSG_ERROR, "nl80211: Failed to add interface %s "
 			   "into bridge %s: %s",
 			   ifname, brname, strerror(errno));
@@ -5813,12 +7605,15 @@
 	int ifindex, br_ifindex;
 	int br_added = 0;
 
-	bss = wpa_driver_nl80211_init(hapd, params->ifname, NULL);
+	bss = wpa_driver_nl80211_init(hapd, params->ifname,
+				      params->global_priv);
 	if (bss == NULL)
 		return NULL;
 
 	drv = bss->drv;
 	drv->nlmode = NL80211_IFTYPE_AP;
+	drv->eapol_sock = -1;
+
 	if (linux_br_get(brname, params->ifname) == 0) {
 		wpa_printf(MSG_DEBUG, "nl80211: Interface %s is in bridge %s",
 			   params->ifname, brname);
@@ -5846,16 +7641,16 @@
 	/* start listening for EAPOL on the default AP interface */
 	add_ifidx(drv, drv->ifindex);
 
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 0))
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 0))
 		goto failed;
 
 	if (params->bssid) {
-		if (linux_set_ifhwaddr(drv->ioctl_sock, bss->ifname,
+		if (linux_set_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
 				       params->bssid))
 			goto failed;
 	}
 
-	if (wpa_driver_nl80211_set_mode(bss, IEEE80211_MODE_AP)) {
+	if (wpa_driver_nl80211_set_mode(bss, drv->nlmode)) {
 		wpa_printf(MSG_ERROR, "nl80211: Failed to set interface %s "
 			   "into AP mode", bss->ifname);
 		goto failed;
@@ -5865,7 +7660,7 @@
 	    i802_check_bridge(drv, bss, params->bridge[0], params->ifname) < 0)
 		goto failed;
 
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1))
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1))
 		goto failed;
 
 	drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
@@ -5880,25 +7675,16 @@
 		goto failed;
 	}
 
-	if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, params->own_addr))
+	if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+			       params->own_addr))
 		goto failed;
 
+	memcpy(bss->addr, params->own_addr, ETH_ALEN);
+
 	return bss;
 
 failed:
-	nl80211_remove_monitor_interface(drv);
-	rfkill_deinit(drv->rfkill);
-	netlink_deinit(drv->netlink);
-	if (drv->ioctl_sock >= 0)
-		close(drv->ioctl_sock);
-
-	genl_family_put(drv->nl80211);
-	nl_cache_free(drv->nl_cache);
-	nl80211_handle_destroy(drv->nl_handle);
-	nl_cb_put(drv->nl_cb);
-	eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle_event));
-
-	os_free(drv);
+	wpa_driver_nl80211_deinit(bss);
 	return NULL;
 }
 
@@ -5938,7 +7724,7 @@
 	struct wpa_driver_nl80211_data *drv;
 	dl_list_for_each(drv, &global->interfaces,
 			 struct wpa_driver_nl80211_data, list) {
-		if (os_memcmp(addr, drv->addr, ETH_ALEN) == 0)
+		if (os_memcmp(addr, drv->first_bss.addr, ETH_ALEN) == 0)
 			return 1;
 	}
 	return 0;
@@ -5953,9 +7739,9 @@
 	if (!drv->global)
 		return -1;
 
-	os_memcpy(new_addr, drv->addr, ETH_ALEN);
+	os_memcpy(new_addr, drv->first_bss.addr, ETH_ALEN);
 	for (idx = 0; idx < 64; idx++) {
-		new_addr[0] = drv->addr[0] | 0x02;
+		new_addr[0] = drv->first_bss.addr[0] | 0x02;
 		new_addr[0] ^= idx << 2;
 		if (!nl80211_addr_in_use(drv->global, new_addr))
 			break;
@@ -6004,7 +7790,8 @@
 	}
 
 	if (!addr &&
-	    linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, if_addr) < 0) {
+	    linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+			       if_addr) < 0) {
 		nl80211_remove_iface(drv, ifidx);
 		return -1;
 	}
@@ -6016,10 +7803,10 @@
 		/* Enforce unique P2P Interface Address */
 		u8 new_addr[ETH_ALEN], own_addr[ETH_ALEN];
 
-		if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr)
-		    < 0 ||
-		    linux_get_ifhwaddr(drv->ioctl_sock, ifname, new_addr) < 0)
-		{
+		if (linux_get_ifhwaddr(drv->global->ioctl_sock, bss->ifname,
+				       own_addr) < 0 ||
+		    linux_get_ifhwaddr(drv->global->ioctl_sock, ifname,
+				       new_addr) < 0) {
 			nl80211_remove_iface(drv, ifidx);
 			return -1;
 		}
@@ -6030,7 +7817,7 @@
 				nl80211_remove_iface(drv, ifidx);
 				return -1;
 			}
-			if (linux_set_ifhwaddr(drv->ioctl_sock, ifname,
+			if (linux_set_ifhwaddr(drv->global->ioctl_sock, ifname,
 					       new_addr) < 0) {
 				nl80211_remove_iface(drv, ifidx);
 				return -1;
@@ -6051,21 +7838,27 @@
 	}
 
 	if (type == WPA_IF_AP_BSS) {
-		if (linux_set_iface_flags(drv->ioctl_sock, ifname, 1)) {
+		if (linux_set_iface_flags(drv->global->ioctl_sock, ifname, 1))
+		{
 			nl80211_remove_iface(drv, ifidx);
 			os_free(new_bss);
 			return -1;
 		}
 		os_strlcpy(new_bss->ifname, ifname, IFNAMSIZ);
+		os_memcpy(new_bss->addr, if_addr, ETH_ALEN);
 		new_bss->ifindex = ifidx;
 		new_bss->drv = drv;
 		new_bss->next = drv->first_bss.next;
 		drv->first_bss.next = new_bss;
 		if (drv_priv)
 			*drv_priv = new_bss;
+		nl80211_init_bss(new_bss);
 	}
 #endif /* HOSTAPD */
 
+	if (drv->global)
+		drv->global->if_add_ifindex = ifidx;
+
 	return 0;
 }
 
@@ -6085,14 +7878,14 @@
 
 #ifdef HOSTAPD
 	if (bss->added_if_into_bridge) {
-		if (linux_br_del_if(drv->ioctl_sock, bss->brname, bss->ifname)
-		    < 0)
+		if (linux_br_del_if(drv->global->ioctl_sock, bss->brname,
+				    bss->ifname) < 0)
 			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
 				   "interface %s from bridge %s: %s",
 				   bss->ifname, bss->brname, strerror(errno));
 	}
 	if (bss->added_bridge) {
-		if (linux_br_del(drv->ioctl_sock, bss->brname) < 0)
+		if (linux_br_del(drv->global->ioctl_sock, bss->brname) < 0)
 			wpa_printf(MSG_INFO, "nl80211: Failed to remove "
 				   "bridge %s: %s",
 				   bss->brname, strerror(errno));
@@ -6111,6 +7904,7 @@
 		for (tbss = &drv->first_bss; tbss; tbss = tbss->next) {
 			if (tbss->next == bss) {
 				tbss->next = bss->next;
+				nl80211_destroy_bss(bss);
 				os_free(bss);
 				bss = NULL;
 				break;
@@ -6139,11 +7933,13 @@
 }
 
 
-static int nl80211_send_frame_cmd(struct wpa_driver_nl80211_data *drv,
+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_out)
+				  u64 *cookie_out, int no_cck, int no_ack,
+				  int offchanok)
 {
+	struct wpa_driver_nl80211_data *drv = bss->drv;
 	struct nl_msg *msg;
 	u64 cookie;
 	int ret = -1;
@@ -6152,16 +7948,21 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_FRAME, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME);
 
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
-#ifndef ANDROID_BRCM_P2P_PATCH
+#ifndef ANDROID_P2P
 	if (wait)
 		NLA_PUT_U32(msg, NL80211_ATTR_DURATION, wait);
 #endif
-	NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
+	if (offchanok)
+		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);
 
 	cookie = 0;
@@ -6173,11 +7974,12 @@
 			   freq, wait);
 		goto nla_put_failure;
 	}
-	wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted; "
-		   "cookie 0x%llx", (long long unsigned int) cookie);
+	wpa_printf(MSG_DEBUG, "nl80211: Frame TX command accepted%s; "
+		   "cookie 0x%llx", no_ack ? " (no ACK)" : "",
+		   (long long unsigned int) cookie);
 
 	if (cookie_out)
-		*cookie_out = cookie;
+		*cookie_out = no_ack ? (u64) -1 : cookie;
 
 nla_put_failure:
 	nlmsg_free(msg);
@@ -6189,7 +7991,8 @@
 					  unsigned int wait_time,
 					  const u8 *dst, const u8 *src,
 					  const u8 *bssid,
-					  const u8 *data, size_t data_len)
+					  const u8 *data, size_t data_len,
+					  int no_cck)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
@@ -6198,7 +8001,7 @@
 	struct ieee80211_hdr *hdr;
 
 	wpa_printf(MSG_DEBUG, "nl80211: Send Action frame (ifindex=%d, "
-		   "wait=%d ms)", drv->ifindex, wait_time);
+		   "wait=%d ms no_cck=%d)", drv->ifindex, wait_time, no_cck);
 
 	buf = os_zalloc(24 + data_len);
 	if (buf == NULL)
@@ -6211,12 +8014,14 @@
 	os_memcpy(hdr->addr2, src, ETH_ALEN);
 	os_memcpy(hdr->addr3, bssid, ETH_ALEN);
 
-	if (drv->nlmode == NL80211_IFTYPE_AP)
-		ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len);
+	if (is_ap_interface(drv->nlmode))
+		ret = wpa_driver_nl80211_send_mlme(priv, buf, 24 + data_len,
+						   0);
 	else
-		ret = nl80211_send_frame_cmd(drv, freq, wait_time, buf,
+		ret = nl80211_send_frame_cmd(bss, freq, wait_time, buf,
 					     24 + data_len,
-					     &drv->send_action_cookie);
+					     &drv->send_action_cookie,
+					     no_cck, 0, 1);
 
 	os_free(buf);
 	return ret;
@@ -6234,8 +8039,7 @@
 	if (!msg)
 		return;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_FRAME_WAIT_CANCEL, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_FRAME_WAIT_CANCEL);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U64(msg, NL80211_ATTR_COOKIE, drv->send_action_cookie);
@@ -6264,8 +8068,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_REMAIN_ON_CHANNEL, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_REMAIN_ON_CHANNEL);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
@@ -6273,17 +8076,20 @@
 
 	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",
 			   (long long unsigned int) cookie, freq, duration);
 		drv->remain_on_chan_cookie = cookie;
+		drv->pending_remain_on_chan = 1;
 		return 0;
 	}
 	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;
 }
 
@@ -6309,18 +8115,19 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
 	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;
 }
 
@@ -6331,60 +8138,43 @@
 	struct wpa_driver_nl80211_data *drv = bss->drv;
 
 	if (!report) {
-		if (drv->nl_handle_preq) {
+		if (bss->nl_preq && drv->device_ap_sme &&
+		    is_ap_interface(drv->nlmode)) {
+			/*
+			 * Do not disable Probe Request reporting that was
+			 * enabled in nl80211_setup_ap().
+			 */
+			wpa_printf(MSG_DEBUG, "nl80211: Skip disabling of "
+				   "Probe Request reporting nl_preq=%p while "
+				   "in AP mode", bss->nl_preq);
+		} else if (bss->nl_preq) {
+			wpa_printf(MSG_DEBUG, "nl80211: Disable Probe Request "
+				   "reporting nl_preq=%p", bss->nl_preq);
 			eloop_unregister_read_sock(
-				nl_socket_get_fd(drv->nl_handle_preq));
-			nl_cache_free(drv->nl_cache_preq);
-			nl80211_handle_destroy(drv->nl_handle_preq);
-			drv->nl_handle_preq = NULL;
+				nl_socket_get_fd(bss->nl_preq));
+			nl_destroy_handles(&bss->nl_preq);
 		}
 		return 0;
 	}
 
-	if (drv->nl_handle_preq) {
+	if (bss->nl_preq) {
 		wpa_printf(MSG_DEBUG, "nl80211: Probe Request reporting "
-			   "already on!");
+			   "already on! nl_preq=%p", bss->nl_preq);
 		return 0;
 	}
 
-	drv->nl_handle_preq = nl80211_handle_alloc(drv->nl_cb);
-	if (drv->nl_handle_preq == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate "
-			   "netlink callbacks (preq)");
-		goto out_err1;
-	}
-
-	if (genl_connect(drv->nl_handle_preq)) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to connect to "
-			   "generic netlink (preq)");
-		goto out_err2;
+	bss->nl_preq = nl_create_handle(drv->global->nl_cb, "preq");
+	if (bss->nl_preq == NULL)
 		return -1;
-	}
+	wpa_printf(MSG_DEBUG, "nl80211: Enable Probe Request "
+		   "reporting nl_preq=%p", bss->nl_preq);
 
-#ifdef CONFIG_LIBNL20
-	if (genl_ctrl_alloc_cache(drv->nl_handle_preq,
-				  &drv->nl_cache_preq) < 0) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (preq)");
-		goto out_err2;
-	}
-#else /* CONFIG_LIBNL20 */
-	drv->nl_cache_preq = genl_ctrl_alloc_cache(drv->nl_handle_preq);
-	if (drv->nl_cache_preq == NULL) {
-		wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
-			   "netlink cache (preq)");
-		goto out_err2;
-	}
-#endif /* CONFIG_LIBNL20 */
-
-	if (nl80211_register_frame(drv, drv->nl_handle_preq,
+	if (nl80211_register_frame(bss, bss->nl_preq,
 				   (WLAN_FC_TYPE_MGMT << 2) |
 				   (WLAN_FC_STYPE_PROBE_REQ << 4),
-				   NULL, 0) < 0) {
-		goto out_err3;
-	}
-
-#ifdef ANDROID_BRCM_P2P_PATCH
+				   NULL, 0) < 0)
+		goto out_err;
+#ifdef ANDROID_P2P
 	if (drv->nlmode != NL80211_IFTYPE_AP &&
 		drv->nlmode != NL80211_IFTYPE_P2P_GO) {
 		wpa_printf(MSG_DEBUG, "nl80211: probe_req_report control only "
@@ -6392,49 +8182,51 @@
 			   drv->nlmode);
 		goto done;
 	}
-	
-	if (nl80211_register_frame(drv, drv->nl_handle_preq,
+	if (nl80211_register_frame(bss, bss->nl_preq,
 			   (WLAN_FC_TYPE_MGMT << 2) |
 			   (WLAN_FC_STYPE_ASSOC_REQ << 4),
 			   NULL, 0) < 0) {
-		goto out_err3;
+		goto out_err;
 	}
 
-	if (nl80211_register_frame(drv, drv->nl_handle_preq,
+	if (nl80211_register_frame(bss, bss->nl_preq,
 			   (WLAN_FC_TYPE_MGMT << 2) |
 			   (WLAN_FC_STYPE_REASSOC_REQ << 4),
 			   NULL, 0) < 0) {
-		goto out_err3;
+		goto out_err;
 	}
 
-	if (nl80211_register_frame(drv, drv->nl_handle_preq,
+	if (nl80211_register_frame(bss, bss->nl_preq,
 			   (WLAN_FC_TYPE_MGMT << 2) |
 			   (WLAN_FC_STYPE_DISASSOC << 4),
 			   NULL, 0) < 0) {
-		goto out_err3;
+		goto out_err;
 	}
-	
-	if (nl80211_register_frame(drv, drv->nl_handle_preq,
+
+	if (nl80211_register_frame(bss, bss->nl_preq,
 					   (WLAN_FC_TYPE_MGMT << 2) |
 					   (WLAN_FC_STYPE_DEAUTH << 4),
 					   NULL, 0) < 0) {
-		goto out_err3;
+		goto out_err;
+	}
+
+	if (nl80211_register_frame(bss, bss->nl_preq,
+			   (WLAN_FC_TYPE_MGMT << 2) |
+			   (WLAN_FC_STYPE_ACTION << 4),
+			   NULL, 0) < 0) {
+		goto out_err;
 	}
 
 done:
-#endif
-	eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle_preq),
-				 wpa_driver_nl80211_event_receive, drv,
-				 drv->nl_handle_preq);
+#endif /* ANDROID_P2P */
+	eloop_register_read_sock(nl_socket_get_fd(bss->nl_preq),
+				 wpa_driver_nl80211_event_receive, bss->nl_cb,
+				 bss->nl_preq);
 
 	return 0;
 
- out_err3:
-	nl_cache_free(drv->nl_cache_preq);
- out_err2:
-	nl80211_handle_destroy(drv->nl_handle_preq);
-	drv->nl_handle_preq = NULL;
- out_err1:
+ out_err:
+	nl_destroy_handles(&bss->nl_preq);
 	return -1;
 }
 
@@ -6450,8 +8242,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_TX_BITRATE_MASK, 0);
+	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);
@@ -6466,8 +8257,10 @@
 	band = nla_nest_start(msg, NL80211_BAND_2GHZ);
 	if (!band)
 		goto nla_put_failure;
-	NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
-		"\x0c\x12\x18\x24\x30\x48\x60\x6c");
+	if (disabled) {
+		NLA_PUT(msg, NL80211_TXRATE_LEGACY, 8,
+			"\x0c\x12\x18\x24\x30\x48\x60\x6c");
+	}
 	nla_nest_end(msg, band);
 
 	nla_nest_end(msg, bands);
@@ -6487,23 +8280,14 @@
 }
 
 
-static int wpa_driver_nl80211_disable_11b_rates(void *priv, int disabled)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	drv->disable_11b_rates = disabled;
-	return nl80211_disable_11b_rates(drv, drv->ifindex, disabled);
-}
-
-
 static int wpa_driver_nl80211_deinit_ap(void *priv)
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (drv->nlmode != NL80211_IFTYPE_AP)
+	if (!is_ap_interface(drv->nlmode))
 		return -1;
 	wpa_driver_nl80211_del_beacon(drv);
-	return wpa_driver_nl80211_set_mode(priv, IEEE80211_MODE_INFRA);
+	return wpa_driver_nl80211_set_mode(priv, NL80211_IFTYPE_STATION);
 }
 
 
@@ -6511,7 +8295,7 @@
 {
 	struct i802_bss *bss = priv;
 	struct wpa_driver_nl80211_data *drv = bss->drv;
-	if (linux_set_iface_flags(drv->ioctl_sock, bss->ifname, 1)) {
+	if (linux_set_iface_flags(drv->global->ioctl_sock, bss->ifname, 1)) {
 		wpa_printf(MSG_DEBUG, "nl80211: Failed to set interface up on "
 			   "resume event");
 	}
@@ -6526,10 +8310,7 @@
 	int ret;
 	u8 *data, *pos;
 	size_t data_len;
-	u8 own_addr[ETH_ALEN];
-
-	if (linux_get_ifhwaddr(drv->ioctl_sock, bss->ifname, own_addr) < 0)
-		return -1;
+	const u8 *own_addr = bss->addr;
 
 	if (action != 1) {
 		wpa_printf(MSG_ERROR, "nl80211: Unsupported send_ft_action "
@@ -6561,7 +8342,7 @@
 
 	ret = wpa_driver_nl80211_send_action(bss, drv->assoc_freq, 0,
 					     drv->bssid, own_addr, drv->bssid,
-					     data, data_len);
+					     data, data_len, 0);
 	os_free(data);
 
 	return ret;
@@ -6581,8 +8362,7 @@
 	if (!msg)
 		return -1;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
-		    0, NL80211_CMD_SET_CQM, 0);
+	nl80211_cmd(drv, msg, 0, NL80211_CMD_SET_CQM);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, bss->ifindex);
 
@@ -6599,8 +8379,7 @@
 	msg = NULL;
 
 nla_put_failure:
-	if (cqm)
-		nlmsg_free(cqm);
+	nlmsg_free(cqm);
 	nlmsg_free(msg);
 	return -1;
 }
@@ -6621,34 +8400,58 @@
 }
 
 
+static int wpa_driver_nl80211_shared_freq(void *priv)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct wpa_driver_nl80211_data *driver;
+	int freq = 0;
+
+	/*
+	 * If the same PHY is in connected state with some other interface,
+	 * then retrieve the assoc freq.
+	 */
+	wpa_printf(MSG_DEBUG, "nl80211: Get shared freq for PHY %s",
+		   drv->phyname);
+
+	dl_list_for_each(driver, &drv->global->interfaces,
+			 struct wpa_driver_nl80211_data, list) {
+		if (drv == driver ||
+		    os_strcmp(drv->phyname, driver->phyname) != 0 ||
+#ifdef ANDROID_P2P
+		    (!driver->associated && !is_ap_interface(driver->nlmode)))
+#else
+		    !driver->associated)
+#endif
+			continue;
+
+		wpa_printf(MSG_DEBUG, "nl80211: Found a match for PHY %s - %s "
+			   MACSTR,
+			   driver->phyname, driver->first_bss.ifname,
+			   MAC2STR(driver->first_bss.addr));
+#ifdef ANDROID_P2P
+		if(is_ap_interface(driver->nlmode))
+			freq = driver->first_bss.freq;
+		else
+#endif
+			freq = nl80211_get_assoc_freq(driver);
+		wpa_printf(MSG_DEBUG, "nl80211: Shared freq for PHY %s: %d",
+			   drv->phyname, freq);
+	}
+
+	if (!freq)
+		wpa_printf(MSG_DEBUG, "nl80211: No shared interface for "
+			   "PHY (%s) in associated state", drv->phyname);
+
+	return freq;
+}
+
+
 static int nl80211_send_frame(void *priv, const u8 *data, size_t data_len,
 			      int encrypt)
 {
 	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	return wpa_driver_nl80211_send_frame(drv, data, data_len, encrypt);
-}
-
-
-static int nl80211_set_intra_bss(void *priv, int enabled)
-{
-	struct i802_bss *bss = priv;
-	struct wpa_driver_nl80211_data *drv = bss->drv;
-	struct nl_msg *msg;
-
-	msg = nlmsg_alloc();
-	if (!msg)
-		return -ENOMEM;
-
-	genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
-		    NL80211_CMD_SET_BSS, 0);
-
-	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
-	NLA_PUT_U8(msg, NL80211_ATTR_AP_ISOLATE, !enabled);
-
-	return send_and_recv_msgs(drv, msg, NULL, NULL);
- nla_put_failure:
-	return -ENOBUFS;
+	return wpa_driver_nl80211_send_frame(bss, data, data_len, encrypt, 0);
 }
 
 
@@ -6668,6 +8471,15 @@
 		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_CONCURRENT;
 		drv->capa.flags |= WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P;
 	}
+#ifdef ANDROID_P2P
+	if(os_strstr(param, "use_multi_chan_concurrent=1")) {
+		struct i802_bss *bss = priv;
+		struct wpa_driver_nl80211_data *drv = bss->drv;
+		wpa_printf(MSG_DEBUG, "nl80211: Use Multi channel "
+			   "concurrency");
+		drv->capa.flags |= WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT;
+	}
+#endif
 #endif /* CONFIG_P2P */
 
 	return 0;
@@ -6677,11 +8489,42 @@
 static void * nl80211_global_init(void)
 {
 	struct nl80211_global *global;
+	struct netlink_config *cfg;
+
 	global = os_zalloc(sizeof(*global));
 	if (global == NULL)
 		return NULL;
+	global->ioctl_sock = -1;
 	dl_list_init(&global->interfaces);
+	global->if_add_ifindex = -1;
+
+	cfg = os_zalloc(sizeof(*cfg));
+	if (cfg == NULL)
+		goto err;
+
+	cfg->ctx = global;
+	cfg->newlink_cb = wpa_driver_nl80211_event_rtm_newlink;
+	cfg->dellink_cb = wpa_driver_nl80211_event_rtm_dellink;
+	global->netlink = netlink_init(cfg);
+	if (global->netlink == NULL) {
+		os_free(cfg);
+		goto err;
+	}
+
+	if (wpa_driver_nl80211_init_nl_global(global) < 0)
+		goto err;
+
+	global->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (global->ioctl_sock < 0) {
+		perror("socket(PF_INET,SOCK_DGRAM)");
+		goto err;
+	}
+
 	return global;
+
+err:
+	nl80211_global_deinit(global);
+	return NULL;
 }
 
 
@@ -6695,6 +8538,23 @@
 			   "nl80211_global_deinit",
 			   dl_list_len(&global->interfaces));
 	}
+
+	if (global->netlink)
+		netlink_deinit(global->netlink);
+
+	nl_destroy_handles(&global->nl);
+
+	if (global->nl_event) {
+		eloop_unregister_read_sock(
+			nl_socket_get_fd(global->nl_event));
+		nl_destroy_handles(&global->nl_event);
+	}
+
+	nl_cb_put(global->nl_cb);
+
+	if (global->ioctl_sock >= 0)
+		close(global->ioctl_sock);
+
 	os_free(global);
 }
 
@@ -6716,8 +8576,7 @@
 	if (!msg)
 		return -ENOMEM;
 
-	genlmsg_put(msg, 0, 0, genl_family_get_id(bss->drv->nl80211), 0, 0,
-		    cmd, 0);
+	nl80211_cmd(bss->drv, msg, 0, cmd);
 
 	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(bss->ifname));
 	if (pmkid)
@@ -6727,6 +8586,7 @@
 
 	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
  nla_put_failure:
+	nlmsg_free(msg);
 	return -ENOBUFS;
 }
 
@@ -6756,6 +8616,366 @@
 }
 
 
+static void nl80211_set_rekey_info(void *priv, const u8 *kek, const u8 *kck,
+				   const u8 *replay_ctr)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nlattr *replay_nested;
+	struct nl_msg *msg;
+
+	msg = nlmsg_alloc();
+	if (!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);
+}
+
+
+static void nl80211_send_null_frame(struct i802_bss *bss, const u8 *own_addr,
+				    const u8 *addr, int qos)
+{
+	/* send data frame to poll STA and check whether
+	 * this frame is ACKed */
+	struct {
+		struct ieee80211_hdr hdr;
+		u16 qos_ctl;
+	} STRUCT_PACKED nulldata;
+	size_t size;
+
+	/* Send data frame to poll STA and check whether this frame is ACKed */
+
+	os_memset(&nulldata, 0, sizeof(nulldata));
+
+	if (qos) {
+		nulldata.hdr.frame_control =
+			IEEE80211_FC(WLAN_FC_TYPE_DATA,
+				     WLAN_FC_STYPE_QOS_NULL);
+		size = sizeof(nulldata);
+	} else {
+		nulldata.hdr.frame_control =
+			IEEE80211_FC(WLAN_FC_TYPE_DATA,
+				     WLAN_FC_STYPE_NULLFUNC);
+		size = sizeof(struct ieee80211_hdr);
+	}
+
+	nulldata.hdr.frame_control |= host_to_le16(WLAN_FC_FROMDS);
+	os_memcpy(nulldata.hdr.IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+	os_memcpy(nulldata.hdr.IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+	os_memcpy(nulldata.hdr.IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+	if (wpa_driver_nl80211_send_mlme(bss, (u8 *) &nulldata, size, 0) < 0)
+		wpa_printf(MSG_DEBUG, "nl80211_send_null_frame: Failed to "
+			   "send poll frame");
+}
+
+static void nl80211_poll_client(void *priv, const u8 *own_addr, const u8 *addr,
+				int qos)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+
+	if (!drv->poll_command_supported) {
+		nl80211_send_null_frame(bss, own_addr, addr, qos);
+		return;
+	}
+
+	msg = nlmsg_alloc();
+	if (!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);
+}
+
+
+static int nl80211_set_power_save(struct i802_bss *bss, int enabled)
+{
+	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);
+	return send_and_recv_msgs(bss->drv, msg, NULL, NULL);
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int nl80211_set_p2p_powersave(void *priv, int legacy_ps, int opp_ps,
+				     int ctwindow)
+{
+	struct i802_bss *bss = priv;
+
+	wpa_printf(MSG_DEBUG, "nl80211: set_p2p_powersave (legacy_ps=%d "
+		   "opp_ps=%d ctwindow=%d)", legacy_ps, opp_ps, ctwindow);
+
+	if (opp_ps != -1 || ctwindow != -1)
+		return -1; /* Not yet supported */
+
+	if (legacy_ps == -1)
+		return 0;
+	if (legacy_ps != 0 && legacy_ps != 1)
+		return -1; /* Not yet supported */
+
+	return nl80211_set_power_save(bss, legacy_ps);
+}
+
+
+#ifdef CONFIG_TDLS
+
+static int nl80211_send_tdls_mgmt(void *priv, const u8 *dst, u8 action_code,
+				  u8 dialog_token, u16 status_code,
+				  const u8 *buf, size_t len)
+{
+	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))
+		return -EOPNOTSUPP;
+
+	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);
+	NLA_PUT(msg, NL80211_ATTR_IE, len, buf);
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+
+static int nl80211_tdls_oper(void *priv, enum tdls_oper oper, const u8 *peer)
+{
+	struct i802_bss *bss = priv;
+	struct wpa_driver_nl80211_data *drv = bss->drv;
+	struct nl_msg *msg;
+	enum nl80211_tdls_operation nl80211_oper;
+
+	if (!(drv->capa.flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT))
+		return -EOPNOTSUPP;
+
+	switch (oper) {
+	case TDLS_DISCOVERY_REQ:
+		nl80211_oper = NL80211_TDLS_DISCOVERY_REQ;
+		break;
+	case TDLS_SETUP:
+		nl80211_oper = NL80211_TDLS_SETUP;
+		break;
+	case TDLS_TEARDOWN:
+		nl80211_oper = NL80211_TDLS_TEARDOWN;
+		break;
+	case TDLS_ENABLE_LINK:
+		nl80211_oper = NL80211_TDLS_ENABLE_LINK;
+		break;
+	case TDLS_DISABLE_LINK:
+		nl80211_oper = NL80211_TDLS_DISABLE_LINK;
+		break;
+	case TDLS_ENABLE:
+		return 0;
+	case TDLS_DISABLE:
+		return 0;
+	default:
+		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);
+
+	return send_and_recv_msgs(drv, msg, NULL, NULL);
+
+nla_put_failure:
+	nlmsg_free(msg);
+	return -ENOBUFS;
+}
+
+#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_strncpy(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 */
+
+
 const struct wpa_driver_ops wpa_driver_nl80211_ops = {
 	.name = "nl80211",
 	.desc = "Linux nl80211/cfg80211",
@@ -6763,6 +8983,8 @@
 	.get_ssid = wpa_driver_nl80211_get_ssid,
 	.set_key = wpa_driver_nl80211_set_key,
 	.scan2 = wpa_driver_nl80211_scan,
+	.sched_scan = wpa_driver_nl80211_sched_scan,
+	.stop_sched_scan = wpa_driver_nl80211_stop_sched_scan,
 	.get_scan_results2 = wpa_driver_nl80211_get_scan_results,
 	.deauthenticate = wpa_driver_nl80211_deauthenticate,
 	.disassociate = wpa_driver_nl80211_disassociate,
@@ -6776,7 +8998,7 @@
 	.set_operstate = wpa_driver_nl80211_set_operstate,
 	.set_supp_port = wpa_driver_nl80211_set_supp_port,
 	.set_country = wpa_driver_nl80211_set_country,
-	.set_beacon = wpa_driver_nl80211_set_beacon,
+	.set_ap = wpa_driver_nl80211_set_ap,
 	.if_add = wpa_driver_nl80211_if_add,
 	.if_remove = wpa_driver_nl80211_if_remove,
 	.send_mlme = wpa_driver_nl80211_send_mlme,
@@ -6798,13 +9020,8 @@
 	.sta_clear_stats = i802_sta_clear_stats,
 	.set_rts = i802_set_rts,
 	.set_frag = i802_set_frag,
-	.set_cts_protect = i802_set_cts_protect,
-	.set_preamble = i802_set_preamble,
-	.set_short_slot_time = i802_set_short_slot_time,
 	.set_tx_queue_params = i802_set_tx_queue_params,
 	.set_sta_vlan = i802_set_sta_vlan,
-	.set_ht_params = i802_set_ht_params,
-	.set_rate_sets = i802_set_rate_sets,
 	.sta_deauth = i802_sta_deauth,
 	.sta_disassoc = i802_sta_disassoc,
 #endif /* HOSTAPD || CONFIG_AP */
@@ -6815,22 +9032,30 @@
 	.cancel_remain_on_channel =
 	wpa_driver_nl80211_cancel_remain_on_channel,
 	.probe_req_report = wpa_driver_nl80211_probe_req_report,
-	.disable_11b_rates = wpa_driver_nl80211_disable_11b_rates,
 	.deinit_ap = wpa_driver_nl80211_deinit_ap,
 	.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,
-	.set_intra_bss = nl80211_set_intra_bss,
+	.shared_freq = wpa_driver_nl80211_shared_freq,
 	.set_param = nl80211_set_param,
 	.get_radio_name = nl80211_get_radio_name,
 	.add_pmkid = nl80211_add_pmkid,
 	.remove_pmkid = nl80211_remove_pmkid,
 	.flush_pmkid = nl80211_flush_pmkid,
-#ifdef ANDROID_BRCM_P2P_PATCH
-	.get_noa = wpa_driver_get_p2p_noa,
+	.set_rekey_info = nl80211_set_rekey_info,
+	.poll_client = nl80211_poll_client,
+#ifndef ANDROID_P2P
+	.set_p2p_powersave = nl80211_set_p2p_powersave,
+#endif
+#ifdef CONFIG_TDLS
+	.send_tdls_mgmt = nl80211_send_tdls_mgmt,
+	.tdls_oper = nl80211_tdls_oper,
+#endif /* CONFIG_TDLS */
+#ifdef ANDROID_P2P
 	.set_noa = wpa_driver_set_p2p_noa,
+	.get_noa = wpa_driver_get_p2p_noa,
 	.set_p2p_powersave = wpa_driver_set_p2p_ps,
 	.set_ap_wps_ie = wpa_driver_set_ap_wps_p2p_ie,
 #endif
diff --git a/src/drivers/driver_osx.m b/src/drivers/driver_osx.m
deleted file mode 100644
index 69ca4b5..0000000
--- a/src/drivers/driver_osx.m
+++ /dev/null
@@ -1,459 +0,0 @@
-/*
- * WPA Supplicant - Mac OS X Apple80211 driver interface
- * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-#define Boolean __DummyBoolean
-#include <CoreFoundation/CoreFoundation.h>
-#undef Boolean
-
-#include "common.h"
-#include "driver.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-
-#include "Apple80211.h"
-
-struct wpa_driver_osx_data {
-	void *ctx;
-	WirelessRef wireless_ctx;
-	CFArrayRef scan_results;
-};
-
-
-#ifndef CONFIG_NO_STDOUT_DEBUG
-extern int wpa_debug_level;
-
-static void dump_dict_cb(const void *key, const void *value, void *context)
-{
-        if (MSG_DEBUG < wpa_debug_level)
-                return;
-
-	wpa_printf(MSG_DEBUG, "Key:");
-	CFShow(key);
-	wpa_printf(MSG_DEBUG, "Value:");
-	CFShow(value);
-}
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-
-
-static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
-{
-#ifndef CONFIG_NO_STDOUT_DEBUG
-	wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
-		   title, (unsigned int) CFDictionaryGetCount(dict));
-	CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
-#endif /* CONFIG_NO_STDOUT_DEBUG */
-}
-
-
-static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	WirelessInfo info;
-	int len;
-
-	err = WirelessGetInfo(drv->wireless_ctx, &info);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
-			   (int) err);
-		return -1;
-	}
-	if (!info.power) {
-		wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
-		return -1;
-	}
-
-	for (len = 0; len < 32; len++)
-		if (info.ssid[len] == 0)
-			break;
-
-	os_memcpy(ssid, info.ssid, len);
-	return len;
-}
-
-
-static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	WirelessInfo info;
-
-	err = WirelessGetInfo(drv->wireless_ctx, &info);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
-			   (int) err);
-		return -1;
-	}
-	if (!info.power) {
-		wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
-		return -1;
-	}
-
-	os_memcpy(bssid, info.bssID, ETH_ALEN);
-	return 0;
-}
-
-
-static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-}
-
-
-static int wpa_driver_osx_scan(void *priv, struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (drv->scan_results) {
-		CFRelease(drv->scan_results);
-		drv->scan_results = NULL;
-	}
-
-	if (ssid) {
-		CFStringRef data;
-		data = CFStringCreateWithBytes(kCFAllocatorDefault,
-					       ssid, ssid_len,
-					       kCFStringEncodingISOLatin1,
-					       FALSE);
-		if (data == NULL) {
-			wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
-				   "failed");
-			return -1;
-		}
-
-		err = WirelessDirectedScan(drv->wireless_ctx,
-					   &drv->scan_results, 0, data);
-		CFRelease(data);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
-				   "failed: 0x%08x", (unsigned int) err);
-			return -1;
-		}
-	} else {
-		err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
-				   "0x%08x", (unsigned int) err);
-			return -1;
-		}
-	}
-
-	eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
-			       drv->ctx);
-	return 0;
-}
-
-
-static void wpa_driver_osx_add_scan_entry(struct wpa_scan_results *res,
-					  WirelessNetworkInfo *info)
-{
-	struct wpa_scan_res *result, **tmp;
-	size_t extra_len;
-	u8 *pos;
-
-	extra_len = 2 + info->ssid_len;
-
-	result = os_zalloc(sizeof(*result) + extra_len);
-	if (result == NULL)
-		return;
-	os_memcpy(result->bssid, info->bssid, ETH_ALEN);
-	result->freq = 2407 + info->channel * 5;
-	//result->beacon_int =;
-	result->caps = info->capability;
-	//result->qual = info->signal;
-	result->noise = info->noise;
-
-	pos = (u8 *)(result + 1);
-
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = info->ssid_len;
-	os_memcpy(pos, info->ssid, info->ssid_len);
-	pos += info->ssid_len;
-
-	result->ie_len = pos - (u8 *)(result + 1);
-
-	tmp = os_realloc(res->res,
-			 (res->num + 1) * sizeof(struct wpa_scan_res *));
-	if (tmp == NULL) {
-		os_free(result);
-		return;
-	}
-	tmp[res->num++] = result;
-	res->res = tmp;
-}
-
-
-static struct wpa_scan_results * wpa_driver_osx_get_scan_results(void *priv)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	struct wpa_scan_results *res;
-	size_t i, num;
-
-	if (drv->scan_results == NULL)
-		return 0;
-
-	num = CFArrayGetCount(drv->scan_results);
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL)
-		return NULL;
-
-	for (i = 0; i < num; i++)
-		wpa_driver_osx_add_scan_entry(res, (WirelessNetworkInfo *)
-			CFDataGetBytePtr(CFArrayGetValueAtIndex(
-				drv->scan_results, i)));
-
-	return res;
-}
-
-
-static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_osx_data *drv = eloop_ctx;
-	u8 bssid[ETH_ALEN];
-	CFDictionaryRef ai;
-
-	if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
-		eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
-				       drv, drv->ctx);
-		return;
-	}
-
-	ai = WirelessGetAssociationInfo(drv->wireless_ctx);
-	if (ai) {
-		wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
-		CFRelease(ai);
-	} else {
-		wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
-	}
-
-	wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
-}
-
-
-static int wpa_driver_osx_associate(void *priv,
-				    struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-	CFDataRef ssid;
-	CFStringRef key;
-	int assoc_type;
-
-	ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
-			    params->ssid_len);
-	if (ssid == NULL)
-		return -1;
-
-	/* TODO: support for WEP */
-	if (params->key_mgmt_suite == KEY_MGMT_PSK) {
-		if (params->passphrase == NULL)
-			return -1;
-		key = CFStringCreateWithCString(kCFAllocatorDefault,
-						params->passphrase,
-						kCFStringEncodingISOLatin1);
-		if (key == NULL) {
-			CFRelease(ssid);
-			return -1;
-		}
-	} else
-		key = NULL;
-
-	if (params->key_mgmt_suite == KEY_MGMT_NONE)
-		assoc_type = 0;
-	else
-		assoc_type = 4;
-
-	wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
-		   assoc_type, key);
-	err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
-	CFRelease(ssid);
-	if (key)
-		CFRelease(key);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
-			   (unsigned int) err);
-		return -1;
-	}
-
-	/*
-	 * Driver is actually already associated; report association from an
-	 * eloop callback.
-	 */
-	eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
-	eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
-			       drv->ctx);
-
-	return 0;
-}
-
-
-static int wpa_driver_osx_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 wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-
-	if (alg == WPA_ALG_WEP) {
-		err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
-				     key);
-		if (err != 0) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
-				   "0x%08x", (unsigned int) err);
-			return -1;
-		}
-
-		return 0;
-	}
-
-	if (alg == WPA_ALG_PMK) {
-		err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
-		if (err != 0) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
-				   "0x%08x", (unsigned int) err);
-			return -1;
-		}
-		return 0;
-	}
-
-	wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
-	return -1;
-}
-
-
-static int wpa_driver_osx_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;
-	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_4WAY_HANDSHAKE;
-
-	return 0;
-}
-
-
-static void * wpa_driver_osx_init(void *ctx, const char *ifname)
-{
-	struct wpa_driver_osx_data *drv;
-	WirelessError err;
-	u8 enabled, power;
-
-	if (!WirelessIsAvailable()) {
-		wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
-		return NULL;
-	}
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-	drv->ctx = ctx;
-	err = WirelessAttach(&drv->wireless_ctx, 0);
-	if (err) {
-		wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
-			   (int) err);
-		os_free(drv);
-		return NULL;
-	}
-
-	err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
-	if (err)
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
-			   (unsigned int) err);
-	err = WirelessGetPower(drv->wireless_ctx, &power);
-	if (err)
-		wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
-			   (unsigned int) err);
-
-	wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
-
-	if (!enabled) {
-		err = WirelessSetEnabled(drv->wireless_ctx, 1);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
-				   " 0x%08x", (unsigned int) err);
-			WirelessDetach(drv->wireless_ctx);
-			os_free(drv);
-			return NULL;
-		}
-	}
-
-	if (!power) {
-		err = WirelessSetPower(drv->wireless_ctx, 1);
-		if (err) {
-			wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
-				   "0x%08x", (unsigned int) err);
-			WirelessDetach(drv->wireless_ctx);
-			os_free(drv);
-			return NULL;
-		}
-	}
-
-	return drv;
-}
-
-
-static void wpa_driver_osx_deinit(void *priv)
-{
-	struct wpa_driver_osx_data *drv = priv;
-	WirelessError err;
-
-	eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
-	eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
-
-	err = WirelessSetPower(drv->wireless_ctx, 0);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
-			   "0x%08x", (unsigned int) err);
-	}
-
-	err = WirelessDetach(drv->wireless_ctx);
-	if (err) {
-		wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
-			   (unsigned int) err);
-	}
-
-	if (drv->scan_results)
-		CFRelease(drv->scan_results);
-
-	os_free(drv);
-}
-
-
-const struct wpa_driver_ops wpa_driver_osx_ops = {
-	.name = "osx",
-	.desc = "Mac OS X Apple80211 driver",
-	.get_ssid = wpa_driver_osx_get_ssid,
-	.get_bssid = wpa_driver_osx_get_bssid,
-	.init = wpa_driver_osx_init,
-	.deinit = wpa_driver_osx_deinit,
-	.scan2 = wpa_driver_osx_scan,
-	.get_scan_results2 = wpa_driver_osx_get_scan_results,
-	.associate = wpa_driver_osx_associate,
-	.set_key = wpa_driver_osx_set_key,
-	.get_capa = wpa_driver_osx_get_capa,
-};
diff --git a/src/drivers/driver_ralink.c b/src/drivers/driver_ralink.c
deleted file mode 100644
index a1e27be..0000000
--- a/src/drivers/driver_ralink.c
+++ /dev/null
@@ -1,1498 +0,0 @@
-/*
- * WPA Supplicant - driver interaction with Ralink Wireless Client
- * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- *
- */
-
-#include "includes.h"
-#include <sys/ioctl.h>
-
-#include "wireless_copy.h"
-#include "common.h"
-#include "driver.h"
-#include "l2_packet/l2_packet.h"
-#include "eloop.h"
-#include "common/ieee802_11_defs.h"
-#include "priv_netlink.h"
-#include "netlink.h"
-#include "linux_ioctl.h"
-#include "driver_ralink.h"
-
-static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx);
-
-#define MAX_SSID_LEN 32
-
-struct wpa_driver_ralink_data {
-	void *ctx;
-	int ioctl_sock;
-	struct netlink_data *netlink;
-	char ifname[IFNAMSIZ + 1];
-	u8 *assoc_req_ies;
-	size_t assoc_req_ies_len;
-	u8 *assoc_resp_ies;
-	size_t assoc_resp_ies_len;
-	int no_of_pmkid;
-	struct ndis_pmkid_entry *pmkid;
-	int we_version_compiled;
-	int ap_scan;
-	int scanning_done;
-	u8 g_driver_down;
-	BOOLEAN	bAddWepKey;
-};
-
-static int ralink_set_oid(struct wpa_driver_ralink_data *drv,
-			  unsigned short oid, char *data, int len)
-{
-	char *buf;
-	struct iwreq iwr;
-
-	buf = os_zalloc(len);
-	if (buf == NULL)
-		return -1;
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.flags = oid;
-	iwr.u.data.flags |= OID_GET_SET_TOGGLE;
-
-	if (data)
-		os_memcpy(buf, data, len);
-
-	iwr.u.data.pointer = (caddr_t) buf;
-	iwr.u.data.length = len;
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
-			   __func__, oid, len);
-		os_free(buf);
-		return -1;
-	}
-	os_free(buf);
-	return 0;
-}
-
-static int
-ralink_get_new_driver_flag(struct wpa_driver_ralink_data *drv)
-{
-	struct iwreq iwr;
-	UCHAR enabled = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (UCHAR*) &enabled;
-	iwr.u.data.flags = RT_OID_NEW_DRIVER;
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed", __func__);
-		return 0;
-	}
-
-	return (enabled == 1) ? 1 : 0;
-}
-
-static int wpa_driver_ralink_get_bssid(void *priv, u8 *bssid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
-		perror("ioctl[SIOCGIWAP]");
-		ret = -1;
-	}
-	os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
-
-	return ret;
-}
-
-static int wpa_driver_ralink_get_ssid(void *priv, u8 *ssid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-#if 0
-	struct wpa_supplicant *wpa_s = drv->ctx;
-	struct wpa_ssid *entry;
-#endif
-	int ssid_len;
-	u8 bssid[ETH_ALEN];
-	u8 ssid_str[MAX_SSID_LEN];
-	struct iwreq iwr;
-#if 0
-	int result = 0;
-#endif
-	int ret = 0;
-#if 0
-	BOOLEAN	ieee8021x_mode = FALSE;
-	BOOLEAN ieee8021x_required_key = FALSE;
-#endif
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.essid.pointer = (caddr_t) ssid;
-	iwr.u.essid.length = 32;
-
-	if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
-		perror("ioctl[SIOCGIWESSID]");
-		ret = -1;
-	} else
-		ret = iwr.u.essid.length;
-
-	if (ret <= 0)
-		return ret;
-
-	ssid_len = ret;
-	os_memset(ssid_str, 0, MAX_SSID_LEN);
-	os_memcpy(ssid_str, ssid, ssid_len);
-
-	if (drv->ap_scan == 0) {
-		/* Read BSSID form driver */
-		if (wpa_driver_ralink_get_bssid(priv, bssid) < 0) {
-			wpa_printf(MSG_WARNING, "Could not read BSSID from "
-				   "driver.");
-			return ret;
-		}
-
-#if 0
-		entry = wpa_s->conf->ssid;
-		while (entry) {
-			if (!entry->disabled && ssid_len == entry->ssid_len &&
-			    os_memcmp(ssid_str, entry->ssid, ssid_len) == 0 &&
-			    (!entry->bssid_set ||
-			     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) {
-				/* match the config of driver */
-				result = 1;
-				break;
-			}
-			entry = entry->next;
-		}
-
-		if (result) {
-			wpa_printf(MSG_DEBUG, "Ready to set 802.1x mode and "
-				   "ieee_required_keys parameters to driver");
-
-			/* set 802.1x mode and ieee_required_keys parameter */
-			if (entry->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
-				if ((entry->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST)))
-						ieee8021x_required_key = TRUE;
-				ieee8021x_mode = TRUE;
-			}
-
-			if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, (char *) &ieee8021x_mode, sizeof(BOOLEAN)) < 0)
-			{
-				wpa_printf(MSG_DEBUG, "RALINK: Failed to set OID_802_11_SET_IEEE8021X(%d)", (int) ieee8021x_mode);
-			}
-			else
-			{
-				wpa_printf(MSG_DEBUG, "ieee8021x_mode is %s", ieee8021x_mode ? "TRUE" : "FALSE");
-			}
-
-			if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
-			{
-				wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", (int) ieee8021x_required_key);
-			}
-			else
-			{
-				wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d)", ieee8021x_required_key ? "TRUE" : "FALSE",
-																								entry->eapol_flags);
-			}
-		}
-#endif
-	}
-
-	return ret;
-}
-
-static int wpa_driver_ralink_set_ssid(struct wpa_driver_ralink_data *drv,
-				      const u8 *ssid, size_t ssid_len)
-{
-	NDIS_802_11_SSID *buf;
-	int ret = 0;
-	struct iwreq iwr;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	buf = os_zalloc(sizeof(NDIS_802_11_SSID));
-	if (buf == NULL)
-		return -1;
-	os_memset(buf, 0, sizeof(buf));
-	buf->SsidLength = ssid_len;
-	os_memcpy(buf->Ssid, ssid, ssid_len);
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	iwr.u.data.flags = OID_802_11_SSID;
-	iwr.u.data.flags |= OID_GET_SET_TOGGLE;
-	iwr.u.data.pointer = (caddr_t) buf;
-	iwr.u.data.length = sizeof(NDIS_802_11_SSID);
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		perror("ioctl[RT_PRIV_IOCTL] -- OID_802_11_SSID");
-		ret = -1;
-	}
-	os_free(buf);
-	return ret;
-}
-
-static void wpa_driver_ralink_event_pmkid(struct wpa_driver_ralink_data *drv,
-					  const u8 *data, size_t data_len)
-{
-	NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
-	size_t i;
-	union wpa_event_data event;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (data_len < 8) {
-		wpa_printf(MSG_DEBUG, "RALINK: Too short PMKID Candidate List "
-			   "Event (len=%lu)", (unsigned long) data_len);
-		return;
-	}
-	pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
-	wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List Event - Version %d"
-		   " NumCandidates %d",
-		   (int) pmkid->Version, (int) pmkid->NumCandidates);
-
-	if (pmkid->Version != 1) {
-		wpa_printf(MSG_DEBUG, "RALINK: Unsupported PMKID Candidate "
-			   "List Version %d", (int) pmkid->Version);
-		return;
-	}
-
-	if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
-		wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List "
-			   "underflow");
-
-		return;
-	}
-
-
-
-	os_memset(&event, 0, sizeof(event));
-	for (i = 0; i < pmkid->NumCandidates; i++) {
-		PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
-		wpa_printf(MSG_DEBUG, "RALINK: %lu: " MACSTR " Flags 0x%x",
-			   (unsigned long) i, MAC2STR(p->BSSID),
-			   (int) p->Flags);
-		os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
-		event.pmkid_candidate.index = i;
-		event.pmkid_candidate.preauth =
-			p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
-		wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
-				     &event);
-	}
-}
-
-static int wpa_driver_ralink_set_pmkid(struct wpa_driver_ralink_data *drv)
-{
-	int len, count, i, ret;
-	struct ndis_pmkid_entry *entry;
-	NDIS_802_11_PMKID *p;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	count = 0;
-	entry = drv->pmkid;
-	while (entry) {
-		count++;
-		if (count >= drv->no_of_pmkid)
-			break;
-		entry = entry->next;
-	}
-	len = 8 + count * sizeof(BSSID_INFO);
-	p = os_zalloc(len);
-	if (p == NULL)
-		return -1;
-	p->Length = len;
-	p->BSSIDInfoCount = count;
-	entry = drv->pmkid;
-	for (i = 0; i < count; i++) {
-		os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
-		os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
-		entry = entry->next;
-	}
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID",
-		    (const u8 *) p, len);
-	ret = ralink_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
-	os_free(p);
-	return ret;
-}
-
-static int wpa_driver_ralink_add_pmkid(void *priv, const u8 *bssid,
-				       const u8 *pmkid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct ndis_pmkid_entry *entry, *prev;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	prev = NULL;
-	entry = drv->pmkid;
-	while (entry) {
-		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
-			break;
-		prev = entry;
-		entry = entry->next;
-	}
-
-	if (entry) {
-		/* Replace existing entry for this BSSID and move it into the
-		 * beginning of the list. */
-		os_memcpy(entry->pmkid, pmkid, 16);
-		if (prev) {
-			prev->next = entry->next;
-			entry->next = drv->pmkid;
-			drv->pmkid = entry;
-		}
-	} else {
-		entry = os_malloc(sizeof(*entry));
-		if (entry) {
-			os_memcpy(entry->bssid, bssid, ETH_ALEN);
-			os_memcpy(entry->pmkid, pmkid, 16);
-			entry->next = drv->pmkid;
-			drv->pmkid = entry;
-		}
-	}
-
-	return wpa_driver_ralink_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ralink_remove_pmkid(void *priv, const u8 *bssid,
-					  const u8 *pmkid)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct ndis_pmkid_entry *entry, *prev;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	entry = drv->pmkid;
-	prev = NULL;
-	drv->pmkid = NULL;
-	while (entry) {
-		if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
-		    os_memcmp(entry->pmkid, pmkid, 16) == 0) {
-			if (prev)
-				prev->next = entry->next;
-			else
-				drv->pmkid = entry->next;
-			os_free(entry);
-			break;
-		}
-		prev = entry;
-		entry = entry->next;
-	}
-	return wpa_driver_ralink_set_pmkid(drv);
-}
-
-
-static int wpa_driver_ralink_flush_pmkid(void *priv)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	NDIS_802_11_PMKID p;
-	struct ndis_pmkid_entry *pmkid, *prev;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->no_of_pmkid == 0)
-		return 0;
-
-	pmkid = drv->pmkid;
-	drv->pmkid = NULL;
-	while (pmkid) {
-		prev = pmkid;
-		pmkid = pmkid->next;
-		os_free(prev);
-	}
-
-	os_memset(&p, 0, sizeof(p));
-	p.Length = 8;
-	p.BSSIDInfoCount = 0;
-	wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
-		    (const u8 *) &p, 8);
-	return ralink_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
-}
-
-static void
-wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
-					void *ctx, char *custom)
-{
-	union wpa_event_data data;
-	u8 *req_ies = NULL, *resp_ies = NULL;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
-
-	os_memset(&data, 0, sizeof(data));
-	/* Host AP driver */
-	if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
-		/* receive a MICFAILURE report */
-		data.michael_mic_failure.unicast =
-			os_strstr(custom, " unicast") != NULL;
-		/* TODO: parse parameters(?) */
-		wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
-	} else if (os_strncmp(custom, "ASSOCINFO_ReqIEs=", 17) == 0) {
-		/* receive assoc. req. IEs */
-		char *spos;
-		int bytes;
-
-		spos = custom + 17;
-		/*get IE's length */
-		/*
-		 * bytes = strlen(spos); ==> bug, bytes may less than original
-		 * size by using this way to get size. snowpin 20070312
-		 * if (!bytes)
-		 *	return;
-		 */
-		bytes = drv->assoc_req_ies_len;
-
-		req_ies = os_malloc(bytes);
-		if (req_ies == NULL)
-			return;
-		os_memcpy(req_ies, spos, bytes);
-		data.assoc_info.req_ies = req_ies;
-		data.assoc_info.req_ies_len = bytes;
-
-		/* skip the '\0' byte */
-		spos += bytes + 1;
-
-		data.assoc_info.resp_ies = NULL;
-		data.assoc_info.resp_ies_len = 0;
-
-		if (os_strncmp(spos, " RespIEs=", 9) == 0) {
-			/* receive assoc. resp. IEs */
-			spos += 9;
-			/* get IE's length */
-			bytes = os_strlen(spos);
-			if (!bytes)
-				goto done;
-
-			resp_ies = os_malloc(bytes);
-			if (resp_ies == NULL)
-				goto done;
-			os_memcpy(resp_ies, spos, bytes);
-			data.assoc_info.resp_ies = resp_ies;
-			data.assoc_info.resp_ies_len = bytes;
-		}
-
-		wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
-
-	done:
-		/* free allocated memory */
-		os_free(resp_ies);
-		os_free(req_ies);
-	}
-}
-
-static void ralink_interface_up(struct wpa_driver_ralink_data *drv)
-{
-	union wpa_event_data event;
-	int enable_wpa_supplicant = 0;
-	drv->g_driver_down = 0;
-	os_memset(&event, 0, sizeof(event));
-	os_snprintf(event.interface_status.ifname,
-		    sizeof(event.interface_status.ifname), "%s", drv->ifname);
-
-	event.interface_status.ievent = EVENT_INTERFACE_ADDED;
-	wpa_supplicant_event(drv->ctx, EVENT_INTERFACE_STATUS, &event);
-
-	if (drv->ap_scan == 1)
-		enable_wpa_supplicant = 1;
-	else
-		enable_wpa_supplicant = 2;
-	/* trigger driver support wpa_supplicant */
-	if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-			   (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
-	{
-		wpa_printf(MSG_INFO, "RALINK: Failed to set "
-			   "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-			   (int) enable_wpa_supplicant);
-		wpa_printf(MSG_ERROR, "ralink. Driver does not support "
-			   "wpa_supplicant");
-	}
-}
-
-static void
-wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
-				 void *ctx, char *data, int len)
-{
-	struct iw_event iwe_buf, *iwe = &iwe_buf;
-	char *pos, *end, *custom, *buf, *assoc_info_buf, *info_pos;
-#if 0
-	BOOLEAN ieee8021x_required_key = FALSE;
-#endif
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	assoc_info_buf = info_pos = NULL;
-	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. */
-		os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
-		wpa_printf(MSG_DEBUG, "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_compiled > 18 && 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;
-			os_memcpy(dpos, pos + IW_EV_LCP_LEN,
-				  sizeof(struct iw_event) - dlen);
-		} else {
-			os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
-			custom += IW_EV_POINT_OFF;
-		}
-
-		switch (iwe->cmd) {
-		case IWEVCUSTOM:
-			if (custom + iwe->u.data.length > end)
-				return;
-			buf = os_malloc(iwe->u.data.length + 1);
-			if (buf == NULL)
-				return;
-			os_memcpy(buf, custom, iwe->u.data.length);
-			buf[iwe->u.data.length] = '\0';
-
-			if (drv->ap_scan == 1) {
-				if ((iwe->u.data.flags == RT_ASSOC_EVENT_FLAG)
-				    || (iwe->u.data.flags ==
-					RT_REQIE_EVENT_FLAG) ||
-				    (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG)
-				    || (iwe->u.data.flags ==
-					RT_ASSOCINFO_EVENT_FLAG)) {
-					if (drv->scanning_done == 0) {
-						os_free(buf);
-						return;
-					}
-				}
-			}
-
-			if (iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) {
-				wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive ASSOCIATED_EVENT !!!");
-			} else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive ReqIEs !!!");
-				drv->assoc_req_ies =
-					os_malloc(iwe->u.data.length);
-				if (drv->assoc_req_ies == NULL) {
-					os_free(buf);
-					return;
-				}
-
-				drv->assoc_req_ies_len = iwe->u.data.length;
-				os_memcpy(drv->assoc_req_ies, custom,
-					  iwe->u.data.length);
-			} else if (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive RespIEs !!!");
-				drv->assoc_resp_ies =
-					os_malloc(iwe->u.data.length);
-				if (drv->assoc_resp_ies == NULL) {
-					os_free(drv->assoc_req_ies);
-					drv->assoc_req_ies = NULL;
-					os_free(buf);
-					return;
-				}
-
-				drv->assoc_resp_ies_len = iwe->u.data.length;
-				os_memcpy(drv->assoc_resp_ies, custom,
-					  iwe->u.data.length);
-			} else if (iwe->u.data.flags ==
-				   RT_ASSOCINFO_EVENT_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive ASSOCINFO_EVENT !!!");
-
-				assoc_info_buf =
-					os_zalloc(drv->assoc_req_ies_len +
-						  drv->assoc_resp_ies_len + 1);
-
-				if (assoc_info_buf == NULL) {
-					os_free(drv->assoc_req_ies);
-					drv->assoc_req_ies = NULL;
-					os_free(drv->assoc_resp_ies);
-					drv->assoc_resp_ies = NULL;
-					os_free(buf);
-					return;
-				}
-
-				if (drv->assoc_req_ies) {
-					os_memcpy(assoc_info_buf,
-						  drv->assoc_req_ies,
-						  drv->assoc_req_ies_len);
-				}
-				info_pos = assoc_info_buf +
-					drv->assoc_req_ies_len;
-				if (drv->assoc_resp_ies) {
-					os_memcpy(info_pos,
-						  drv->assoc_resp_ies,
-						  drv->assoc_resp_ies_len);
-				}
-				assoc_info_buf[drv->assoc_req_ies_len +
-					       drv->assoc_resp_ies_len] = '\0';
-				wpa_driver_ralink_event_wireless_custom(
-					drv, ctx, assoc_info_buf);
-				os_free(drv->assoc_req_ies);
-				drv->assoc_req_ies = NULL;
-				os_free(drv->assoc_resp_ies);
-				drv->assoc_resp_ies = NULL;
-				os_free(assoc_info_buf);
-			} else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG)
-			{
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive DISASSOCIATED_EVENT !!!");
-				wpa_supplicant_event(ctx, EVENT_DISASSOC,
-						     NULL);
-			} else if (iwe->u.data.flags == RT_PMKIDCAND_FLAG) {
-				wpa_printf(MSG_DEBUG, "Custom wireless event: "
-					   "receive PMKIDCAND_EVENT !!!");
-				wpa_driver_ralink_event_pmkid(
-					drv, (const u8 *) custom,
-					iwe->u.data.length);
-			} else if (iwe->u.data.flags == RT_INTERFACE_DOWN) {
-				drv->g_driver_down = 1;
-				eloop_terminate();
-			} else if (iwe->u.data.flags == RT_INTERFACE_UP) {
-				ralink_interface_up(drv);
-			} else {
-				wpa_driver_ralink_event_wireless_custom(
-					drv, ctx, buf);
-			}
-			os_free(buf);
-			break;
-		}
-
-		pos += iwe->len;
-	}
-}
-
-static void
-wpa_driver_ralink_event_rtm_newlink(void *ctx, struct ifinfomsg *ifi, 
-				    u8 *buf, size_t len)
-{
-	struct wpa_driver_ralink_data *drv = ctx;
-	int attrlen, rta_len;
-	struct rtattr *attr;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg));
-
-	attrlen = len;
-	wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen);
-	attr = (struct rtattr *) buf;
-	wpa_hexdump(MSG_DEBUG, "attr1: ", (u8 *) attr, sizeof(struct rtattr));
-	rta_len = RTA_ALIGN(sizeof(struct rtattr));
-	wpa_hexdump(MSG_DEBUG, "attr2: ", (u8 *)attr,rta_len);
-	while (RTA_OK(attr, attrlen)) {
-		wpa_printf(MSG_DEBUG, "rta_type=%02x\n", attr->rta_type);
-		if (attr->rta_type == IFLA_WIRELESS) {
-			wpa_driver_ralink_event_wireless(
-				drv, ctx,
-				((char *) attr) + rta_len,
-				attr->rta_len - rta_len);
-		}
-		attr = RTA_NEXT(attr, attrlen);
-		wpa_hexdump(MSG_DEBUG, "attr3: ",
-			    (u8 *) attr, sizeof(struct rtattr));
-	}
-}
-
-static int
-ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
-{
-	struct iwreq iwr;
-	UINT we_version_compiled = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) &we_version_compiled;
-	iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED;
-
-	if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
-		wpa_printf(MSG_DEBUG, "%s: failed", __func__);
-		return -1;
-	}
-
-	drv->we_version_compiled = we_version_compiled;
-
-	return 0;
-}
-
-static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
-{
-	int s;
-	struct wpa_driver_ralink_data *drv;
-	struct ifreq ifr;
-	UCHAR enable_wpa_supplicant = 0;
-	struct netlink_config *cfg;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	/* open socket to kernel */
-	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
-		perror("socket");
-		return NULL;
-	}
-	/* do it */
-	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
-
-	if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
-		perror(ifr.ifr_name);
-		return NULL;
-	}
-
-	drv = os_zalloc(sizeof(*drv));
-	if (drv == NULL)
-		return NULL;
-
-	drv->scanning_done = 1;
-	drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */
-	drv->ctx = ctx;
-	os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
-	drv->ioctl_sock = s;
-	drv->g_driver_down = 0;
-
-	cfg = os_zalloc(sizeof(*cfg));
-	if (cfg == NULL) {
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-	cfg->ctx = drv;
-	cfg->newlink_cb = wpa_driver_ralink_event_rtm_newlink;
-	drv->netlink = netlink_init(cfg);
-	if (drv->netlink == NULL) {
-		os_free(cfg);
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	drv->no_of_pmkid = 4; /* Number of PMKID saved supported */
-
-	linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 1);
-	ralink_get_we_version_compiled(drv);
-	wpa_driver_ralink_flush_pmkid(drv);
-
-	if (drv->ap_scan == 1)
-		enable_wpa_supplicant = 1;
-	else
-		enable_wpa_supplicant = 2;
-	/* trigger driver support wpa_supplicant */
-	if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-			   (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
-	{
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-			   (int) enable_wpa_supplicant);
-		wpa_printf(MSG_ERROR, "RALINK: Driver does not support "
-			   "wpa_supplicant");
-		close(s);
-		close(drv->ioctl_sock);
-		os_free(drv);
-		return NULL;
-	}
-
-	if (drv->ap_scan == 1)
-		drv->scanning_done = 0;
-
-	return drv;
-}
-
-static void wpa_driver_ralink_deinit(void *priv)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	UCHAR enable_wpa_supplicant;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	enable_wpa_supplicant = 0;
-
-	if (drv->g_driver_down == 0) {
-		/* trigger driver disable wpa_supplicant support */
-		if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-				   (char *) &enable_wpa_supplicant,
-				   sizeof(BOOLEAN)) < 0) {
-			wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-				   "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
-				   (int) enable_wpa_supplicant);
-		}
-
-		wpa_driver_ralink_flush_pmkid(drv);
-
-		sleep(1);
-		/* linux_set_iface_flags(drv->ioctl_sock, drv->ifname, 0); */
-	}
-
-	eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
-	netlink_deinit(drv->netlink);
-	close(drv->ioctl_sock);
-	os_free(drv);
-}
-
-static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_driver_ralink_data *drv = eloop_ctx;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
-	wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
-
-	drv->scanning_done = 1;
-
-}
-
-static int wpa_driver_ralink_scan(void *priv,
-				  struct wpa_driver_scan_params *params)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-#if 0
-	if (ssid_len > IW_ESSID_MAX_SIZE) {
-		wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
-			   __FUNCTION__, (unsigned long) ssid_len);
-		return -1;
-	}
-
-	/* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */
-#endif
-
-	if (ralink_set_oid(drv, RT_OID_WPS_PROBE_REQ_IE,
-			   (char *) params->extra_ies, params->extra_ies_len) <
-	    0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "RT_OID_WPS_PROBE_REQ_IE");
-	}
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
-		perror("ioctl[SIOCSIWSCAN]");
-		ret = -1;
-	}
-
-	/* Not all drivers generate "scan completed" wireless event, so try to
-	 * read results after a timeout. */
-	eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
-	eloop_register_timeout(4, 0, wpa_driver_ralink_scan_timeout, drv,
-			       drv->ctx);
-
-	drv->scanning_done = 0;
-
-	return ret;
-}
-
-static struct wpa_scan_results *
-wpa_driver_ralink_get_scan_results(void *priv)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	UCHAR *buf = NULL;
-	size_t buf_len;
-	NDIS_802_11_BSSID_LIST_EX *wsr;
-	NDIS_WLAN_BSSID_EX *wbi;
-	struct iwreq iwr;
-	size_t ap_num;
-	u8 *pos;
-	struct wpa_scan_results *res;
-
-	if (drv->g_driver_down == 1)
-		return NULL;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (drv->we_version_compiled >= 17)
-		buf_len = 8192;
-	else
-		buf_len = 4096;
-
-	for (;;) {
-		buf = os_zalloc(buf_len);
-		iwr.u.data.length = buf_len;
-		if (buf == NULL)
-			return NULL;
-
-		wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
-
-		wsr->NumberOfItems = 0;
-		os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-		iwr.u.data.pointer = (void *) buf;
-		iwr.u.data.flags = OID_802_11_BSSID_LIST;
-
-		if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) == 0)
-			break;
-
-		if (errno == E2BIG && buf_len < 65535) {
-			os_free(buf);
-			buf = NULL;
-			buf_len *= 2;
-			if (buf_len > 65535)
-				buf_len = 65535; /* 16-bit length field */
-			wpa_printf(MSG_DEBUG, "Scan results did not fit - "
-				   "trying larger buffer (%lu bytes)",
-				   (unsigned long) buf_len);
-		} else {
-			perror("ioctl[RT_PRIV_IOCTL]");
-			os_free(buf);
-			return NULL;
-		}
-	}
-
-	res = os_zalloc(sizeof(*res));
-	if (res == NULL) {
-		os_free(buf);
-		return NULL;
-	}
-
-	res->res = os_zalloc(wsr->NumberOfItems *
-			     sizeof(struct wpa_scan_res *));
-	if (res->res == NULL) {
-		os_free(res);
-		os_free(buf);
-		return NULL;
-	}
-
-	for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems;
-	     ++ap_num) {
-		struct wpa_scan_res *r = NULL;
-		size_t extra_len = 0, var_ie_len = 0;
-		u8 *pos2;
-
-		/* SSID data element */
-		extra_len += 2 + wbi->Ssid.SsidLength;
-		var_ie_len = wbi->IELength - sizeof(NDIS_802_11_FIXED_IEs);
-		r = os_zalloc(sizeof(*r) + extra_len + var_ie_len);
-		if (r == NULL)
-			break;
-		res->res[res->num++] = r;
-
-		wpa_printf(MSG_DEBUG, "SSID - %s", wbi->Ssid.Ssid);
-		/* get ie's */
-		wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs",
-			    (u8 *) &wbi->IEs[0], wbi->IELength);
-
-		os_memcpy(r->bssid, wbi->MacAddress, ETH_ALEN);
-
-		extra_len += (2 + wbi->Ssid.SsidLength);
-		r->ie_len = extra_len + var_ie_len;
-		pos2 = (u8 *) (r + 1);
-
-		/*
-		 * Generate a fake SSID IE since the driver did not report
-		 * a full IE list.
-		 */
-		*pos2++ = WLAN_EID_SSID;
-		*pos2++ = wbi->Ssid.SsidLength;
-		os_memcpy(pos2, wbi->Ssid.Ssid, wbi->Ssid.SsidLength);
-		pos2 += wbi->Ssid.SsidLength;
-
-		r->freq = (wbi->Configuration.DSConfig / 1000);
-
-		pos = (u8 *) wbi + sizeof(*wbi) - 1;
-
-		pos += sizeof(NDIS_802_11_FIXED_IEs) - 2;
-		os_memcpy(&(r->caps), pos, 2);
-		pos += 2;
-
-		if (wbi->IELength > sizeof(NDIS_802_11_FIXED_IEs))
-			os_memcpy(pos2, pos, var_ie_len);
-
-		wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length);
-	}
-
-	os_free(buf);
-	return res;
-}
-
-static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv,
-				NDIS_802_11_AUTHENTICATION_MODE mode)
-{
-	NDIS_802_11_AUTHENTICATION_MODE auth_mode = mode;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (ralink_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
-			   (char *) &auth_mode, sizeof(auth_mode)) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_AUTHENTICATION_MODE (%d)",
-			   (int) auth_mode);
-		return -1;
-	}
-	return 0;
-}
-
-static int ralink_set_encr_type(struct wpa_driver_ralink_data *drv,
-				NDIS_802_11_WEP_STATUS encr_type)
-{
-	NDIS_802_11_WEP_STATUS wep_status = encr_type;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (ralink_set_oid(drv, OID_802_11_WEP_STATUS,
-			   (char *) &wep_status, sizeof(wep_status)) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_WEP_STATUS (%d)",
-			   (int) wep_status);
-		return -1;
-	}
-	return 0;
-}
-
-
-static int wpa_driver_ralink_remove_key(struct wpa_driver_ralink_data *drv,
-					int key_idx, const u8 *addr,
-					const u8 *bssid, int pairwise)
-{
-	NDIS_802_11_REMOVE_KEY rkey;
-	NDIS_802_11_KEY_INDEX _index;
-	int res, res2;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	os_memset(&rkey, 0, sizeof(rkey));
-
-	rkey.Length = sizeof(rkey);
-	rkey.KeyIndex = key_idx;
-
-	if (pairwise)
-		rkey.KeyIndex |= 1 << 30;
-
-	os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
-
-	res = ralink_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
-			     sizeof(rkey));
-
-	/* AlbertY@20060210 removed it */
-	if (0 /* !pairwise */) {
-		res2 = ralink_set_oid(drv, OID_802_11_REMOVE_WEP,
-				      (char *) &_index, sizeof(_index));
-	} else
-		res2 = 0;
-
-	if (res < 0 && res2 < 0)
-		return res;
-	return 0;
-}
-
-static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv,
-				     int pairwise, int key_idx, int set_tx,
-				     const u8 *key, size_t key_len)
-{
-	NDIS_802_11_WEP *wep;
-	size_t len;
-	int res;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	len = 12 + key_len;
-	wep = os_zalloc(len);
-	if (wep == NULL)
-		return -1;
-
-	wep->Length = len;
-	wep->KeyIndex = key_idx;
-
-	if (set_tx)
-		wep->KeyIndex |= 0x80000000;
-
-	wep->KeyLength = key_len;
-	os_memcpy(wep->KeyMaterial, key, key_len);
-
-	wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_WEP",
-			(const u8 *) wep, len);
-	res = ralink_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
-
-	os_free(wep);
-
-	return res;
-}
-
-static int wpa_driver_ralink_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 wpa_driver_ralink_data *drv = priv;
-	size_t len, i;
-	NDIS_802_11_KEY *nkey;
-	int res, pairwise;
-	u8 bssid[ETH_ALEN];
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	drv->bAddWepKey = FALSE;
-
-	if (addr == NULL || is_broadcast_ether_addr(addr)) {
-		/* Group Key */
-		pairwise = 0;
-		wpa_driver_ralink_get_bssid(drv, bssid);
-	} else {
-		/* Pairwise Key */
-		pairwise = 1;
-		os_memcpy(bssid, addr, ETH_ALEN);
-	}
-
-	if (alg == WPA_ALG_NONE || key_len == 0) {
-		return wpa_driver_ralink_remove_key(drv, key_idx, addr, bssid,
-						    pairwise);
-	}
-
-	if (alg == WPA_ALG_WEP) {
-		drv->bAddWepKey = TRUE;
-		return wpa_driver_ralink_add_wep(drv, pairwise, key_idx,
-						 set_tx, key, key_len);
-	}
-
-	len = 12 + 6 + 6 + 8 + key_len;
-
-	nkey = os_zalloc(len);
-	if (nkey == NULL)
-		return -1;
-
-	nkey->Length = len;
-	nkey->KeyIndex = key_idx;
-
-	if (set_tx)
-		nkey->KeyIndex |= 1 << 31;
-
-	if (pairwise)
-		nkey->KeyIndex |= 1 << 30;
-
-	if (seq && seq_len)
-		nkey->KeyIndex |= 1 << 29;
-
-	nkey->KeyLength = key_len;
-	os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
-
-	if (seq && seq_len) {
-		for (i = 0; i < seq_len; i++)
-			nkey->KeyRSC |= seq[i] << (i * 8);
-	}
-	if (alg == WPA_ALG_TKIP && key_len == 32) {
-		os_memcpy(nkey->KeyMaterial, key, 16);
-		os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
-		os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
-	} else {
-		os_memcpy(nkey->KeyMaterial, key, key_len);
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
-		   "key_len=%lu", __FUNCTION__, alg, key_idx, set_tx,
-		   (unsigned long) seq_len, (unsigned long) key_len);
-
-	wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_KEY",
-			(const u8 *) nkey, len);
-	res = ralink_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
-	os_free(nkey);
-
-	return res;
-}
-
-static int wpa_driver_ralink_disassociate(void *priv, const u8 *addr,
-					int reason_code)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	if (ralink_set_oid(drv, OID_802_11_DISASSOCIATE, "    ", 4) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_DISASSOCIATE");
-	}
-
-	return 0;
-}
-
-static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr,
-					  int reason_code)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-
-	wpa_printf(MSG_DEBUG, "g_driver_down = %d", drv->g_driver_down);
-
-	if (drv->g_driver_down == 1)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-	if (ralink_get_new_driver_flag(drv) == 0) {
-		return wpa_driver_ralink_disassociate(priv, addr, reason_code);
-	} else {
-		MLME_DEAUTH_REQ_STRUCT mlme;
-		os_memset(&mlme, 0, sizeof(MLME_DEAUTH_REQ_STRUCT));
-		mlme.Reason = reason_code;
-		os_memcpy(mlme.Addr, addr, MAC_ADDR_LEN);
-		return ralink_set_oid(drv, OID_802_11_DEAUTHENTICATION,
-				      (char *) &mlme,
-				      sizeof(MLME_DEAUTH_REQ_STRUCT));
-	}
-}
-
-static int wpa_driver_ralink_set_gen_ie(void *priv, const u8 *ie,
-					size_t ie_len)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	struct iwreq iwr;
-	int ret = 0;
-
-	os_memset(&iwr, 0, sizeof(iwr));
-	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
-	iwr.u.data.pointer = (caddr_t) ie;
-	iwr.u.data.length = ie_len;
-
-	wpa_hexdump(MSG_DEBUG, "wpa_driver_ralink_set_gen_ie: ",
-		    (u8 *) ie, ie_len);
-
-	if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
-		perror("ioctl[SIOCSIWGENIE]");
-		ret = -1;
-	}
-
-	return ret;
-}
-
-static int
-wpa_driver_ralink_associate(void *priv,
-			    struct wpa_driver_associate_params *params)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-
-	NDIS_802_11_NETWORK_INFRASTRUCTURE mode;
-	NDIS_802_11_AUTHENTICATION_MODE auth_mode;
-	NDIS_802_11_WEP_STATUS encr;
-	BOOLEAN		ieee8021xMode;
-	BOOLEAN 	ieee8021x_required_key = TRUE;
-
-	if (drv->g_driver_down == 1)
-		return -1;
-	wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
-
-	if (params->mode == IEEE80211_MODE_IBSS)
-		mode = Ndis802_11IBSS;
-	else
-		mode = Ndis802_11Infrastructure;
-
-	if (ralink_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
-			 (char *) &mode, sizeof(mode)) < 0) {
-		wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-			   "OID_802_11_INFRASTRUCTURE_MODE (%d)",
-			   (int) mode);
-		/* Try to continue anyway */
-	}
-
-	if (params->key_mgmt_suite == KEY_MGMT_WPS) {
-		UCHAR enable_wps = 0x80;
-		/* trigger driver support wpa_supplicant */
-		if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-				   (PCHAR) &enable_wps, sizeof(UCHAR)) < 0) {
-			wpa_printf(MSG_INFO, "RALINK: Failed to set "
-				   "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
-				   (int) enable_wps);
-		}
-
-		wpa_driver_ralink_set_gen_ie(priv, params->wpa_ie,
-					     params->wpa_ie_len);
-
-		ralink_set_auth_mode(drv, Ndis802_11AuthModeOpen);
-
-		ralink_set_encr_type(drv, Ndis802_11EncryptionDisabled);
-	} else {
-#ifdef CONFIG_WPS
-		UCHAR enable_wpa_supplicant;
-
-		if (drv->ap_scan == 1)
-			enable_wpa_supplicant = 0x01;
-		else
-			enable_wpa_supplicant = 0x02;
-
-		/* trigger driver support wpa_supplicant */
-		if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
-				   (PCHAR) &enable_wpa_supplicant,
-				   sizeof(UCHAR)) < 0) {
-			wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-				   "RT_OID_WPA_SUPPLICANT_SUPPORT (%d)",
-				   (int) enable_wpa_supplicant);
-		}
-
-		wpa_driver_ralink_set_gen_ie(priv, (u8 *) "", 0);
-#endif /* CONFIG_WPS */
-
-		if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
-			if (params->auth_alg & WPA_AUTH_ALG_SHARED) {
-				if (params->auth_alg & WPA_AUTH_ALG_OPEN)
-					auth_mode = Ndis802_11AuthModeAutoSwitch;
-				else
-					auth_mode = Ndis802_11AuthModeShared;
-			} else
-				auth_mode = Ndis802_11AuthModeOpen;
-		} else if (params->wpa_ie[0] == WLAN_EID_RSN) {
-			if (params->key_mgmt_suite == KEY_MGMT_PSK)
-				auth_mode = Ndis802_11AuthModeWPA2PSK;
-			else
-				auth_mode = Ndis802_11AuthModeWPA2;
-		} else {
-			if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
-				auth_mode = Ndis802_11AuthModeWPANone;
-			else if (params->key_mgmt_suite == KEY_MGMT_PSK)
-				auth_mode = Ndis802_11AuthModeWPAPSK;
-			else
-				auth_mode = Ndis802_11AuthModeWPA;
-		}
-
-		switch (params->pairwise_suite) {
-		case CIPHER_CCMP:
-			encr = Ndis802_11Encryption3Enabled;
-			break;
-		case CIPHER_TKIP:
-			encr = Ndis802_11Encryption2Enabled;
-			break;
-		case CIPHER_WEP40:
-		case CIPHER_WEP104:
-			encr = Ndis802_11Encryption1Enabled;
-			break;
-		case CIPHER_NONE:
-			if (params->group_suite == CIPHER_CCMP)
-				encr = Ndis802_11Encryption3Enabled;
-			else if (params->group_suite == CIPHER_TKIP)
-				encr = Ndis802_11Encryption2Enabled;
-			else
-				encr = Ndis802_11EncryptionDisabled;
-			break;
-		default:
-			encr = Ndis802_11EncryptionDisabled;
-			break;
-		}
-
-		ralink_set_auth_mode(drv, auth_mode);
-
-		/* notify driver that IEEE8021x mode is enabled */
-		if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA) {
-			ieee8021xMode = TRUE;
-			if (drv->bAddWepKey)
-				ieee8021x_required_key = FALSE;
-		} else
-			ieee8021xMode = FALSE;
-
-		if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY,
-				   (char *) &ieee8021x_required_key,
-				   sizeof(BOOLEAN)) < 0) {
-			wpa_printf(MSG_DEBUG, "ERROR: Failed to set "
-				   "OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)",
-				   (int) ieee8021x_required_key);
-		} else {
-			wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s",
-				   ieee8021x_required_key ? "TRUE" : "FALSE");
-		}
-
-		if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X,
-				   (char *) &ieee8021xMode, sizeof(BOOLEAN)) <
-		    0) {
-			wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-				   "OID_802_11_SET_IEEE8021X(%d)",
-				   (int) ieee8021xMode);
-		}
-
-		ralink_set_encr_type(drv, encr);
-
-		if ((ieee8021xMode == FALSE) &&
-		    (encr == Ndis802_11Encryption1Enabled)) {
-			/* static WEP */
-			int enabled = 0;
-			if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED,
-					   (char *) &enabled, sizeof(enabled))
-			    < 0) {
-				wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
-					   "OID_802_11_DROP_UNENCRYPTED(%d)",
-					   (int) encr);
-			}
-		}
-	}
-
-	return wpa_driver_ralink_set_ssid(drv, params->ssid, params->ssid_len);
-}
-
-static int
-wpa_driver_ralink_set_countermeasures(void *priv, int enabled)
-{
-	struct wpa_driver_ralink_data *drv = priv;
-	if (drv->g_driver_down == 1)
-		return -1;
-	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
-	return ralink_set_oid(drv, OID_SET_COUNTERMEASURES, (char *) &enabled,
-			      sizeof(int));
-}
-
-const struct wpa_driver_ops wpa_driver_ralink_ops = {
-	.name = "ralink",
-	.desc = "Ralink Wireless Client driver",
-	.get_bssid = wpa_driver_ralink_get_bssid,
-	.get_ssid = wpa_driver_ralink_get_ssid,
-	.set_key = wpa_driver_ralink_set_key,
-	.init = wpa_driver_ralink_init,
-	.deinit = wpa_driver_ralink_deinit,
-	.set_countermeasures	= wpa_driver_ralink_set_countermeasures,
-	.scan2 = wpa_driver_ralink_scan,
-	.get_scan_results2 = wpa_driver_ralink_get_scan_results,
-	.deauthenticate = wpa_driver_ralink_deauthenticate,
-	.disassociate = wpa_driver_ralink_disassociate,
-	.associate = wpa_driver_ralink_associate,
-	.add_pmkid = wpa_driver_ralink_add_pmkid,
-	.remove_pmkid = wpa_driver_ralink_remove_pmkid,
-	.flush_pmkid = wpa_driver_ralink_flush_pmkid,
-};
diff --git a/src/drivers/driver_ralink.h b/src/drivers/driver_ralink.h
deleted file mode 100644
index d13df28..0000000
--- a/src/drivers/driver_ralink.h
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * WPA Supplicant - driver_ralink exported functions
- * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-// Ralink defined OIDs
-#if WIRELESS_EXT <= 11
-#ifndef SIOCDEVPRIVATE
-#define SIOCDEVPRIVATE                              0x8BE0
-#endif
-#define SIOCIWFIRSTPRIV								SIOCDEVPRIVATE
-#endif
-
-#define RT_PRIV_IOCTL								(SIOCIWFIRSTPRIV + 0x0E)  
-#define RTPRIV_IOCTL_SET							(SIOCIWFIRSTPRIV + 0x02)
-
-// IEEE 802.11 OIDs  &  Ralink defined OIDs  ******
-
-// (RaConfig Set/QueryInform) ==>
-#define OID_GET_SET_TOGGLE							0x8000
-
-#define OID_802_11_ADD_WEP                          0x0112
-#define OID_802_11_REMOVE_WEP                       0x0113
-#define OID_802_11_DISASSOCIATE                     0x0114
-#define OID_802_11_PRIVACY_FILTER                   0x0118
-#define OID_802_11_ASSOCIATION_INFORMATION          0x011E
-#define OID_802_11_BSSID_LIST_SCAN                  0x0508
-#define OID_802_11_SSID                             0x0509
-#define OID_802_11_BSSID                            0x050A
-#define OID_802_11_WEP_STATUS                       0x0510
-#define OID_802_11_AUTHENTICATION_MODE              0x0511
-#define OID_802_11_INFRASTRUCTURE_MODE              0x0512
-#define OID_802_11_TX_POWER_LEVEL                   0x0517
-#define OID_802_11_REMOVE_KEY                       0x0519
-#define OID_802_11_ADD_KEY                          0x0520
-#define OID_802_11_DEAUTHENTICATION                 0x0526
-#define OID_802_11_DROP_UNENCRYPTED                 0x0527
-#define OID_802_11_BSSID_LIST                       0x0609
-#define OID_802_3_CURRENT_ADDRESS                   0x060A
-#define OID_SET_COUNTERMEASURES                     0x0616
-#define OID_802_11_SET_IEEE8021X                    0x0617	// For IEEE8021x mode 
-#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY        0x0618  // For DynamicWEP in IEEE802.1x mode
-#define OID_802_11_PMKID                            0x0620
-#define RT_OID_WPA_SUPPLICANT_SUPPORT               0x0621  // for trigger driver enable/disable wpa_supplicant support 
-#define RT_OID_WE_VERSION_COMPILED                  0x0622
-#define RT_OID_NEW_DRIVER                           0x0623
-#define RT_OID_WPS_PROBE_REQ_IE						0x0625
-
-#define PACKED  __attribute__ ((packed))
-
-//wpa_supplicant event flags
-#define	RT_ASSOC_EVENT_FLAG                         0x0101
-#define	RT_DISASSOC_EVENT_FLAG                      0x0102
-#define	RT_REQIE_EVENT_FLAG                         0x0103
-#define	RT_RESPIE_EVENT_FLAG                        0x0104
-#define	RT_ASSOCINFO_EVENT_FLAG                     0x0105
-#define RT_PMKIDCAND_FLAG                           0x0106
-#define RT_INTERFACE_DOWN                           0x0107
-#define RT_INTERFACE_UP                           	0x0108
-
-//
-// IEEE 802.11 Structures and definitions
-//
-// new types for Media Specific Indications
-
-#ifndef ULONG
-#define CHAR            char
-#define INT             int
-#define SHORT           int
-#define UINT            u32
-#undef  ULONG           
-//#define ULONG           u32
-#define ULONG           unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */
-#define USHORT          unsigned short
-#define UCHAR           unsigned char
-
-#define uint32		u32
-#define uint8		u8
-
-
-#define BOOLEAN         u8
-//#define LARGE_INTEGER s64
-#define VOID            void
-#define LONG            long
-#define LONGLONG        s64
-#define ULONGLONG       u64
-typedef VOID            *PVOID;
-typedef CHAR            *PCHAR;
-typedef UCHAR           *PUCHAR;
-typedef USHORT          *PUSHORT;
-typedef LONG            *PLONG;
-typedef ULONG           *PULONG;
-
-typedef union _LARGE_INTEGER {
-    struct {
-        ULONG LowPart;
-        LONG HighPart;
-    }vv;
-    struct {
-        ULONG LowPart;
-        LONG HighPart;
-    } u;
-    s64 QuadPart;
-} LARGE_INTEGER;
-
-#endif
-
-#define NDIS_802_11_LENGTH_SSID         32
-#define NDIS_802_11_LENGTH_RATES        8
-#define NDIS_802_11_LENGTH_RATES_EX     16
-#define MAX_LEN_OF_SSID                 32
-#define MAC_ADDR_LEN                    6
-
-typedef UCHAR   NDIS_802_11_MAC_ADDRESS[6];
-
-// mask for authentication/integrity fields
-#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS        0x0f
-
-#define NDIS_802_11_AUTH_REQUEST_REAUTH             0x01
-#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE          0x02
-#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR     0x06
-#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR        0x0E
-
-// Added new types for OFDM 5G and 2.4G
-typedef enum _NDIS_802_11_NETWORK_TYPE
-{
-    Ndis802_11FH, 
-    Ndis802_11DS, 
-    Ndis802_11OFDM5,
-    Ndis802_11OFDM24,
-    Ndis802_11Automode,
-    Ndis802_11NetworkTypeMax    // not a real type, defined as an upper bound
-} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE;
-
-//
-// Received Signal Strength Indication
-//
-typedef LONG    NDIS_802_11_RSSI;           // in dBm
-
-typedef struct _NDIS_802_11_CONFIGURATION_FH
-{
-   ULONG           Length;            // Length of structure
-   ULONG           HopPattern;        // As defined by 802.11, MSB set 
-   ULONG           HopSet;            // to one if non-802.11
-   ULONG           DwellTime;         // units are Kusec
-} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH;
-
-typedef struct _NDIS_802_11_CONFIGURATION
-{
-   ULONG                           Length;             // Length of structure
-   ULONG                           BeaconPeriod;       // units are Kusec
-   ULONG                           ATIMWindow;         // units are Kusec
-   ULONG                           DSConfig;           // Frequency, units are kHz
-   NDIS_802_11_CONFIGURATION_FH    FHConfig;
-} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION;
-
-typedef  ULONG  NDIS_802_11_KEY_INDEX;
-typedef ULONGLONG   NDIS_802_11_KEY_RSC;
-
-// Key mapping keys require a BSSID
-typedef struct _NDIS_802_11_KEY
-{
-    UINT           Length;             // Length of this structure
-    UINT           KeyIndex;           
-    UINT           KeyLength;          // length of key in bytes
-    NDIS_802_11_MAC_ADDRESS BSSID;
-    NDIS_802_11_KEY_RSC KeyRSC;
-    UCHAR           KeyMaterial[1];     // variable length depending on above field
-} NDIS_802_11_KEY, *PNDIS_802_11_KEY;
-
-typedef struct _NDIS_802_11_REMOVE_KEY
-{
-    UINT                   Length;        // Length of this structure
-    UINT                   KeyIndex;           
-    NDIS_802_11_MAC_ADDRESS BSSID;      
-} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY;
-
-typedef struct PACKED _NDIS_802_11_WEP
-{
-   UINT     Length;        // Length of this structure
-   UINT           KeyIndex;           // 0 is the per-client key, 1-N are the
-                                        // global keys
-   UINT     KeyLength;     // length of key in bytes
-   UCHAR     KeyMaterial[1];// variable length depending on above field
-} NDIS_802_11_WEP, *PNDIS_802_11_WEP;
-
-
-typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE
-{
-   Ndis802_11IBSS,
-   Ndis802_11Infrastructure,
-   Ndis802_11AutoUnknown,
-   Ndis802_11InfrastructureMax     // Not a real value, defined as upper bound
-} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE;
-
-// PMKID Structures
-typedef UCHAR   NDIS_802_11_PMKID_VALUE[16];
-
-typedef struct _BSSID_INFO
-{
-	NDIS_802_11_MAC_ADDRESS BSSID;
-	NDIS_802_11_PMKID_VALUE PMKID;
-} BSSID_INFO, *PBSSID_INFO;
-
-typedef struct _NDIS_802_11_PMKID
-{
-	ULONG Length;
-	ULONG BSSIDInfoCount;
-	BSSID_INFO BSSIDInfo[1];
-} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID;
-
-//Added new types for PMKID Candidate lists.
-typedef struct _PMKID_CANDIDATE {
-	NDIS_802_11_MAC_ADDRESS BSSID;
-	ULONG Flags;
-} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
-
-typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST
-{
-	ULONG Version;       // Version of the structure
-	ULONG NumCandidates; // No. of pmkid candidates
-	PMKID_CANDIDATE CandidateList[1];
-} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST;
-
-//Flags for PMKID Candidate list structure
-#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED	0x01
-
-// Add new authentication modes
-typedef enum _NDIS_802_11_AUTHENTICATION_MODE
-{
-   Ndis802_11AuthModeOpen,
-   Ndis802_11AuthModeShared,
-   Ndis802_11AuthModeAutoSwitch,
-   Ndis802_11AuthModeWPA,
-   Ndis802_11AuthModeWPAPSK,
-   Ndis802_11AuthModeWPANone,
-   Ndis802_11AuthModeWPA2,
-   Ndis802_11AuthModeWPA2PSK,    
-   Ndis802_11AuthModeMax           // Not a real mode, defined as upper bound
-} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE;
-
-typedef UCHAR  NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES];        // Set of 8 data rates
-typedef UCHAR  NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX];  // Set of 16 data rates
-
-typedef struct PACKED _NDIS_802_11_SSID 
-{
-    INT   SsidLength;         // length of SSID field below, in bytes;
-                                // this can be zero.
-    UCHAR   Ssid[NDIS_802_11_LENGTH_SSID];           // SSID information field
-} NDIS_802_11_SSID, *PNDIS_802_11_SSID;
-
-
-typedef struct PACKED _NDIS_WLAN_BSSID
-{
-   ULONG                               Length;     // Length of this structure
-   NDIS_802_11_MAC_ADDRESS             MacAddress; // BSSID
-   UCHAR                               Reserved[2];
-   NDIS_802_11_SSID                    Ssid;       // SSID
-   ULONG                               Privacy;    // WEP encryption requirement
-    NDIS_802_11_RSSI                    Rssi;               // receive signal
-                                                            // strength in dBm
-   NDIS_802_11_NETWORK_TYPE            NetworkTypeInUse;
-   NDIS_802_11_CONFIGURATION           Configuration;
-   NDIS_802_11_NETWORK_INFRASTRUCTURE  InfrastructureMode;
-   NDIS_802_11_RATES                   SupportedRates;
-} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;
-
-typedef struct PACKED _NDIS_802_11_BSSID_LIST
-{
-   UINT             NumberOfItems;      // in list below, at least 1
-   NDIS_WLAN_BSSID Bssid[1];
-} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
-
-// Added Capabilities, IELength and IEs for each BSSID
-typedef struct PACKED _NDIS_WLAN_BSSID_EX
-{
-    ULONG                               Length;             // Length of this structure
-    NDIS_802_11_MAC_ADDRESS             MacAddress;         // BSSID
-    UCHAR                               Reserved[2];
-    NDIS_802_11_SSID                    Ssid;               // SSID
-    UINT                                Privacy;            // WEP encryption requirement
-    NDIS_802_11_RSSI                    Rssi;               // receive signal
-                                                            // strength in dBm
-    NDIS_802_11_NETWORK_TYPE            NetworkTypeInUse;
-    NDIS_802_11_CONFIGURATION           Configuration;
-    NDIS_802_11_NETWORK_INFRASTRUCTURE  InfrastructureMode;
-    NDIS_802_11_RATES_EX                SupportedRates;
-    ULONG                               IELength;
-    UCHAR                               IEs[1];
-} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX;
-
-typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX
-{
-    UINT                   NumberOfItems;      // in list below, at least 1
-    NDIS_WLAN_BSSID_EX      Bssid[1];
-} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX;
-
-typedef struct PACKED _NDIS_802_11_FIXED_IEs 
-{
-    UCHAR Timestamp[8];
-    USHORT BeaconInterval;
-    USHORT Capabilities;
-} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs;
-
-// Added new encryption types
-// Also aliased typedef to new name
-typedef enum _NDIS_802_11_WEP_STATUS
-{
-   Ndis802_11WEPEnabled,
-   Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
-   Ndis802_11WEPDisabled,
-   Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
-   Ndis802_11WEPKeyAbsent,
-   Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
-   Ndis802_11WEPNotSupported,
-   Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
-   Ndis802_11Encryption2Enabled,
-   Ndis802_11Encryption2KeyAbsent,
-   Ndis802_11Encryption3Enabled,
-   Ndis802_11Encryption3KeyAbsent
-} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
-  NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
-
-typedef enum _NDIS_802_11_RELOAD_DEFAULTS
-{
-   Ndis802_11ReloadWEPKeys
-} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS;
-
-#define NDIS_802_11_AI_REQFI_CAPABILITIES      1
-#define NDIS_802_11_AI_REQFI_LISTENINTERVAL    2
-#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS  4
-
-#define NDIS_802_11_AI_RESFI_CAPABILITIES      1
-#define NDIS_802_11_AI_RESFI_STATUSCODE        2
-#define NDIS_802_11_AI_RESFI_ASSOCIATIONID     4
-
-typedef struct _NDIS_802_11_AI_REQFI
-{
-    USHORT Capabilities;
-    USHORT ListenInterval;
-    NDIS_802_11_MAC_ADDRESS  CurrentAPAddress;
-} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
-
-typedef struct _NDIS_802_11_AI_RESFI
-{
-    USHORT Capabilities;
-    USHORT StatusCode;
-    USHORT AssociationId;
-} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
-
-typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
-{
-    ULONG                   Length;
-    USHORT                  AvailableRequestFixedIEs;
-    NDIS_802_11_AI_REQFI    RequestFixedIEs;
-    ULONG                   RequestIELength;
-    ULONG                   OffsetRequestIEs;
-    USHORT                  AvailableResponseFixedIEs;
-    NDIS_802_11_AI_RESFI    ResponseFixedIEs;
-    ULONG                   ResponseIELength;
-    ULONG                   OffsetResponseIEs;
-} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
-
-struct ndis_pmkid_entry {
-	struct ndis_pmkid_entry *next;
-	u8 bssid[ETH_ALEN];
-	u8 pmkid[16];
-};
-
-typedef struct _MLME_DEAUTH_REQ_STRUCT {
-    UCHAR        Addr[MAC_ADDR_LEN];
-    USHORT       Reason;
-} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT;
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
index c014b96..61b75b1 100644
--- a/src/drivers/driver_roboswitch.c
+++ b/src/drivers/driver_roboswitch.c
@@ -364,7 +364,7 @@
 	/* copy ifname and take a pointer to the second to last character */
 	sep = drv->ifname +
 	      os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2;
-	/* find the '.' seperating <interface> and <vlan> */
+	/* find the '.' separating <interface> and <vlan> */
 	while (sep > drv->ifname && *sep != '.') sep--;
 	if (sep <= drv->ifname) {
 		wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in "
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
index 6bfa46d..f8e314b 100644
--- a/src/drivers/driver_test.c
+++ b/src/drivers/driver_test.c
@@ -89,7 +89,6 @@
 	int use_associnfo;
 	u8 assoc_wpa_ie[80];
 	size_t assoc_wpa_ie_len;
-	int use_mlme;
 	int associated;
 	u8 *probe_req_ie;
 	size_t probe_req_ie_len;
@@ -117,6 +116,7 @@
 	u8 pending_action_dst[ETH_ALEN];
 	u8 pending_action_bssid[ETH_ALEN];
 	unsigned int pending_action_freq;
+	unsigned int pending_action_no_cck;
 	unsigned int pending_listen_freq;
 	unsigned int pending_listen_duration;
 	int pending_p2p_scan;
@@ -309,7 +309,7 @@
 
 
 static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
-				     size_t data_len)
+				     size_t data_len, int noack)
 {
 	struct test_driver_bss *dbss = priv;
 	struct wpa_driver_test_data *drv = dbss->drv;
@@ -561,7 +561,7 @@
 		wpa_supplicant_event(drv->ctx, EVENT_RX_PROBE_REQ, &event);
 #ifdef CONFIG_P2P
 		if (drv->p2p)
-			p2p_probe_req_rx(drv->p2p, sa, ie, ielen);
+			p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
 #endif /* CONFIG_P2P */
 	}
 
@@ -1102,13 +1102,6 @@
 }
 
 
-static int test_driver_valid_bss_mask(void *priv, const u8 *addr,
-				      const u8 *mask)
-{
-	return 0;
-}
-
-
 static int test_driver_set_ssid(void *priv, const u8 *buf, int len)
 {
 	struct test_driver_bss *bss = priv;
@@ -1232,6 +1225,7 @@
 		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);
@@ -1966,6 +1960,8 @@
 		    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);
@@ -1974,6 +1970,7 @@
 #ifdef CONFIG_P2P
 			if (drv->p2p)
 				p2p_probe_req_rx(drv->p2p, mgmt->sa,
+						 mgmt->da, mgmt->bssid,
 						 event.rx_probe_req.ie,
 						 event.rx_probe_req.ie_len);
 #endif /* CONFIG_P2P */
@@ -2028,7 +2025,7 @@
 			ielen = 0;
 		drv->probe_from = from;
 		drv->probe_from_len = fromlen;
-		p2p_probe_req_rx(drv->p2p, sa, ie, ielen);
+		p2p_probe_req_rx(drv->p2p, sa, NULL, NULL, ie, ielen);
 		drv->probe_from = NULL;
 	}
 #endif /* CONFIG_P2P */
@@ -2390,13 +2387,6 @@
 		drv->use_associnfo = 1;
 	}
 
-#ifdef CONFIG_CLIENT_MLME
-	if (os_strstr(param, "use_mlme=1")) {
-		wpa_printf(MSG_DEBUG, "test_driver: Use internal MLME");
-		drv->use_mlme = 1;
-	}
-#endif /* CONFIG_CLIENT_MLME */
-
 	if (os_strstr(param, "p2p_mgmt=1")) {
 		wpa_printf(MSG_DEBUG, "test_driver: Use internal P2P "
 			   "management");
@@ -2510,8 +2500,6 @@
 	capa->auth = WPA_DRIVER_AUTH_OPEN |
 		WPA_DRIVER_AUTH_SHARED |
 		WPA_DRIVER_AUTH_LEAP;
-	if (drv->use_mlme)
-		capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
 	if (drv->p2p)
 		capa->flags |= WPA_DRIVER_FLAGS_P2P_MGMT;
 	capa->flags |= WPA_DRIVER_FLAGS_AP;
@@ -2541,50 +2529,6 @@
 }
 
 
-static int wpa_driver_test_set_channel(void *priv,
-				       enum hostapd_hw_mode phymode,
-				       int chan, int freq)
-{
-	struct test_driver_bss *dbss = priv;
-	struct wpa_driver_test_data *drv = dbss->drv;
-	wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d",
-		   __func__, phymode, chan, freq);
-	drv->current_freq = freq;
-	return 0;
-}
-
-
-static int wpa_driver_test_mlme_add_sta(void *priv, const u8 *addr,
-					const u8 *supp_rates,
-					size_t supp_rates_len)
-{
-	wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
-	return 0;
-}
-
-
-static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr)
-{
-	wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
-	return 0;
-}
-
-
-static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid,
-				    size_t ssid_len)
-{
-	wpa_printf(MSG_DEBUG, "%s", __func__);
-	return 0;
-}
-
-
-static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
-{
-	wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid));
-	return 0;
-}
-
-
 static void * wpa_driver_test_global_init(void)
 {
 	struct wpa_driver_test_global *global;
@@ -2727,7 +2671,8 @@
 				       unsigned int wait,
 				       const u8 *dst, const u8 *src,
 				       const u8 *bssid,
-				       const u8 *data, size_t data_len)
+				       const u8 *data, size_t data_len,
+				       int no_cck)
 {
 	struct test_driver_bss *dbss = priv;
 	struct wpa_driver_test_data *drv = dbss->drv;
@@ -2760,7 +2705,7 @@
 	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);
+	ret = wpa_driver_test_send_mlme(priv, buf, 24 + data_len, 0);
 	os_free(buf);
 	return ret;
 }
@@ -2770,7 +2715,6 @@
 static void test_send_action_cb(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_driver_test_data *drv = eloop_ctx;
-	int res;
 
 	if (drv->pending_action_tx == NULL)
 		return;
@@ -2783,12 +2727,13 @@
 	}
 	wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
 		   MACSTR, MAC2STR(drv->pending_action_dst));
-	res = wpa_driver_test_send_action(drv, drv->pending_action_freq, 0,
-					  drv->pending_action_dst,
-					  drv->pending_action_src,
-					  drv->pending_action_bssid,
-					  wpabuf_head(drv->pending_action_tx),
-					  wpabuf_len(drv->pending_action_tx));
+	wpa_driver_test_send_action(drv, drv->pending_action_freq, 0,
+				    drv->pending_action_dst,
+				    drv->pending_action_src,
+				    drv->pending_action_bssid,
+				    wpabuf_head(drv->pending_action_tx),
+				    wpabuf_len(drv->pending_action_tx),
+				    drv->pending_action_no_cck);
 }
 #endif /* CONFIG_P2P */
 
@@ -2980,6 +2925,7 @@
 	int ret;
 	struct wpabuf *wps_ie, *ies;
 	int social_channels[] = { 2412, 2437, 2462, 0, 0 };
+	size_t ielen;
 
 	wpa_printf(MSG_DEBUG, "%s(type=%d freq=%d)",
 		   __func__, type, freq);
@@ -3001,7 +2947,8 @@
 	if (wps_ie == NULL)
 		return -1;
 
-	ies = wpabuf_alloc(wpabuf_len(wps_ie) + 100);
+	ielen = p2p_scan_ie_buf_len(drv->p2p);
+	ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
 	if (ies == NULL) {
 		wpabuf_free(wps_ie);
 		return -1;
@@ -3069,6 +3016,7 @@
 	os_memcpy(drv->pending_action_dst, dst, ETH_ALEN);
 	os_memcpy(drv->pending_action_bssid, bssid, ETH_ALEN);
 	drv->pending_action_freq = freq;
+	drv->pending_action_no_cck = 1;
 
 	if (drv->off_channel_freq == freq) {
 		/* Already on requested channel; send immediately */
@@ -3248,7 +3196,8 @@
 static void test_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
 			       const u8 *dev_addr, const u8 *pri_dev_type,
 			       const char *dev_name, u16 supp_config_methods,
-			       u8 dev_capab, u8 group_capab)
+			       u8 dev_capab, u8 group_capab,
+			       const u8 *group_id, size_t group_id_len)
 {
 	wpa_printf(MSG_DEBUG, "%s(peer=" MACSTR " config_methods=0x%x)",
 		   __func__, MAC2STR(peer), config_methods);
@@ -3343,7 +3292,6 @@
 	.get_hw_feature_data = wpa_driver_test_get_hw_feature_data,
 	.if_add = test_driver_if_add,
 	.if_remove = test_driver_if_remove,
-	.valid_bss_mask = test_driver_valid_bss_mask,
 	.hapd_set_ssid = test_driver_set_ssid,
 	.set_privacy = test_driver_set_privacy,
 	.set_sta_vlan = test_driver_set_sta_vlan,
@@ -3362,11 +3310,6 @@
 	.get_mac_addr = wpa_driver_test_get_mac_addr,
 	.send_eapol = wpa_driver_test_send_eapol,
 	.mlme_setprotection = wpa_driver_test_mlme_setprotection,
-	.set_channel = wpa_driver_test_set_channel,
-	.set_ssid = wpa_driver_test_set_ssid,
-	.set_bssid = wpa_driver_test_set_bssid,
-	.mlme_add_sta = wpa_driver_test_mlme_add_sta,
-	.mlme_remove_sta = wpa_driver_test_mlme_remove_sta,
 	.get_scan_results2 = wpa_driver_test_get_scan_results2,
 	.global_init = wpa_driver_test_global_init,
 	.global_deinit = wpa_driver_test_global_deinit,
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
index 001716e..381cb3e 100644
--- a/src/drivers/driver_wext.c
+++ b/src/drivers/driver_wext.c
@@ -25,7 +25,7 @@
 #include <fcntl.h>
 #include <net/if_arp.h>
 
-#include "wireless_copy.h"
+#include "linux_wext.h"
 #include "common.h"
 #include "eloop.h"
 #include "common/ieee802_11_defs.h"
@@ -37,6 +37,9 @@
 #include "driver.h"
 #include "driver_wext.h"
 
+#ifdef ANDROID
+#include "android_drv.h"
+#endif /* ANDROID */
 
 static int wpa_driver_wext_flush_pmkid(void *priv);
 static int wpa_driver_wext_get_range(void *priv);
@@ -842,12 +845,13 @@
 	}
 
 	drv->mlme_sock = -1;
+
 #ifdef ANDROID
 	drv->errors = 0;
 	drv->driver_is_started = TRUE;
 	drv->skip_disconnect = 0;
 	drv->bgscan_enabled = 0;
-#endif
+#endif /* ANDROID */
 
 	if (wpa_driver_wext_finish_drv_init(drv) < 0)
 		goto err3;
@@ -1416,7 +1420,7 @@
 	tmp[res->num++] = r;
 	res->res = tmp;
 }
-				      
+
 
 /**
  * wpa_driver_wext_get_scan_results - Fetch the latest scan results
@@ -1426,7 +1430,7 @@
 struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
 {
 	struct wpa_driver_wext_data *drv = priv;
-	size_t ap_num = 0, len;
+	size_t len;
 	int first;
 	u8 *res_buf;
 	struct iw_event iwe_buf, *iwe = &iwe_buf;
@@ -1438,7 +1442,6 @@
 	if (res_buf == NULL)
 		return NULL;
 
-	ap_num = 0;
 	first = 1;
 
 	res = os_zalloc(sizeof(*res));
@@ -1868,8 +1871,10 @@
 {
 	struct iwreq iwr;
 	const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+#ifndef ANDROID
 	u8 ssid[32];
 	int i;
+#endif /* ANDROID */
 
 	/*
 	 * Only force-disconnect when the card is in infrastructure mode,
@@ -1884,40 +1889,39 @@
 	}
 
 	if (iwr.u.mode == IW_MODE_INFRA) {
+		/* Clear the BSSID selection */
+		if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0) {
+			wpa_printf(MSG_DEBUG, "WEXT: Failed to clear BSSID "
+				   "selection on disconnect");
+		}
+
+#ifndef ANDROID
 		if (drv->cfg80211) {
 			/*
 			 * cfg80211 supports SIOCSIWMLME commands, so there is
 			 * no need for the random SSID hack, but clear the
-			 * BSSID and SSID.
+			 * SSID.
 			 */
-			if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
-#ifdef ANDROID
-			    0) {
-#else
-			    wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
-#endif
+			if (wpa_driver_wext_set_ssid(drv, (u8 *) "", 0) < 0) {
 				wpa_printf(MSG_DEBUG, "WEXT: Failed to clear "
-					   "to disconnect");
+					   "SSID on disconnect");
 			}
 			return;
 		}
+
 		/*
-		 * Clear the BSSID selection and set a random SSID to make sure
-		 * the driver will not be trying to associate with something
-		 * even if it does not understand SIOCSIWMLME commands (or
-		 * tries to associate automatically after deauth/disassoc).
+		 * Set a random SSID to make sure the driver will not be trying
+		 * to associate with something even if it does not understand
+		 * SIOCSIWMLME commands (or tries to associate automatically
+		 * after deauth/disassoc).
 		 */
 		for (i = 0; i < 32; i++)
 			ssid[i] = rand() & 0xFF;
-		if (wpa_driver_wext_set_bssid(drv, null_bssid) < 0 ||
-#ifdef ANDROID
-		    0) {
-#else
-		    wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
-#endif
+		if (wpa_driver_wext_set_ssid(drv, ssid, 32) < 0) {
 			wpa_printf(MSG_DEBUG, "WEXT: Failed to set bogus "
-				   "BSSID/SSID to disconnect");
+				   "SSID to disconnect");
 		}
+#endif /* ANDROID */
 	}
 }
 
@@ -2350,6 +2354,129 @@
 }
 
 
+#ifdef ANDROID
+
+static int android_wext_cmd(struct wpa_driver_wext_data *drv, const char *cmd)
+{
+	struct iwreq iwr;
+	char buf[MAX_DRV_CMD_SIZE];
+	int ret;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+	os_memset(buf, 0, sizeof(buf));
+	os_strlcpy(buf, cmd, sizeof(buf));
+
+	iwr.u.data.pointer = buf;
+	iwr.u.data.length = sizeof(buf);
+
+	ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "%s failed (%d): %s", __func__, ret,
+			   cmd);
+		drv->errors++;
+		if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+			drv->errors = 0;
+			wpa_msg(drv->ctx, MSG_INFO, WPA_EVENT_DRIVER_STATE
+				"HANGED");
+		}
+		return ret;
+	}
+
+	drv->errors = 0;
+	return 0;
+}
+
+
+static int wext_sched_scan(void *priv, struct wpa_driver_scan_params *params,
+			   u32 interval)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	struct iwreq iwr;
+	int ret = 0, i = 0, bp;
+	char buf[WEXT_PNO_MAX_COMMAND_SIZE];
+
+	bp = WEXT_PNOSETUP_HEADER_SIZE;
+	os_memcpy(buf, WEXT_PNOSETUP_HEADER, bp);
+	buf[bp++] = WEXT_PNO_TLV_PREFIX;
+	buf[bp++] = WEXT_PNO_TLV_VERSION;
+	buf[bp++] = WEXT_PNO_TLV_SUBVERSION;
+	buf[bp++] = WEXT_PNO_TLV_RESERVED;
+
+	while (i < WEXT_PNO_AMOUNT && (size_t) i < params->num_ssids) {
+		/*
+		 * Check that there is enough space needed for 1 more SSID, the
+		 * other sections and null termination.
+		 */
+		if ((bp + WEXT_PNO_SSID_HEADER_SIZE + IW_ESSID_MAX_SIZE +
+		     WEXT_PNO_NONSSID_SECTIONS_SIZE + 1) >= (int) sizeof(buf))
+			break;
+
+		wpa_hexdump_ascii(MSG_DEBUG, "For PNO Scan",
+				  params->ssids[i].ssid,
+				  params->ssids[i].ssid_len);
+		buf[bp++] = WEXT_PNO_SSID_SECTION;
+		buf[bp++] = params->ssids[i].ssid_len;
+		os_memcpy(&buf[bp], params->ssids[i].ssid,
+			  params->ssids[i].ssid_len);
+		bp += params->ssids[i].ssid_len;
+		i++;
+	}
+
+	buf[bp++] = WEXT_PNO_SCAN_INTERVAL_SECTION;
+	/* TODO: consider using interval parameter (interval in msec) instead
+	 * of hardcoded value here */
+	os_snprintf(&buf[bp], WEXT_PNO_SCAN_INTERVAL_LENGTH + 1, "%x",
+		    WEXT_PNO_SCAN_INTERVAL);
+	bp += WEXT_PNO_SCAN_INTERVAL_LENGTH;
+
+	buf[bp++] = WEXT_PNO_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_REPEAT);
+	bp += WEXT_PNO_REPEAT_LENGTH;
+
+	buf[bp++] = WEXT_PNO_MAX_REPEAT_SECTION;
+	os_snprintf(&buf[bp], WEXT_PNO_MAX_REPEAT_LENGTH + 1, "%x",
+		    WEXT_PNO_MAX_REPEAT);
+	bp += WEXT_PNO_MAX_REPEAT_LENGTH + 1;
+
+	os_memset(&iwr, 0, sizeof(iwr));
+	os_strncpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+	iwr.u.data.pointer = buf;
+	iwr.u.data.length = bp;
+
+	ret = ioctl(drv->ioctl_sock, SIOCSIWPRIV, &iwr);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "ioctl[SIOCSIWPRIV] (pnosetup): %d",
+			   ret);
+		drv->errors++;
+		if (drv->errors > DRV_NUMBER_SEQUENTIAL_ERRORS) {
+			drv->errors = 0;
+			wpa_msg(drv->ctx, MSG_INFO,
+				WPA_EVENT_DRIVER_STATE "HANGED");
+		}
+		return ret;
+	}
+
+	drv->errors = 0;
+	drv->bgscan_enabled = 1;
+
+	return android_wext_cmd(drv, "PNOFORCE 1");
+}
+
+
+static int wext_stop_sched_scan(void *priv)
+{
+	struct wpa_driver_wext_data *drv = priv;
+	drv->bgscan_enabled = 0;
+	return android_wext_cmd(drv, "PNOFORCE 0");
+}
+
+#endif /* ANDROID */
+
+
 const struct wpa_driver_ops wpa_driver_wext_ops = {
 	.name = "wext",
 	.desc = "Linux wireless extensions (generic)",
@@ -2371,7 +2498,7 @@
 	.set_operstate = wpa_driver_wext_set_operstate,
 	.get_radio_name = wext_get_radio_name,
 #ifdef ANDROID
-	.signal_poll = wpa_driver_signal_poll,
-	.driver_cmd = wpa_driver_wext_driver_cmd,
-#endif
+	.sched_scan = wext_sched_scan,
+	.stop_sched_scan = wext_stop_sched_scan,
+#endif /* ANDROID */
 };
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
index 51e4d98..03df8e4 100644
--- a/src/drivers/driver_wext.h
+++ b/src/drivers/driver_wext.h
@@ -50,12 +50,13 @@
 	int cfg80211; /* whether driver is using cfg80211 */
 
 	u8 max_level;
+
 #ifdef ANDROID
 	int errors;
 	int driver_is_started;
 	int skip_disconnect;
 	int bgscan_enabled;
-#endif
+#endif /* ANDROID */
 };
 
 int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
@@ -90,9 +91,4 @@
 int wpa_driver_wext_cipher2wext(int cipher);
 int wpa_driver_wext_keymgmt2wext(int keymgmt);
 
-#ifdef ANDROID
-#define WPA_EVENT_DRIVER_STATE		"CTRL-EVENT-DRIVER-STATE "
-#define WEXT_CSCAN_AMOUNT		9
-#endif
-
 #endif /* DRIVER_WEXT_H */
diff --git a/src/drivers/drivers.c b/src/drivers/drivers.c
index b710778..667ea22 100644
--- a/src/drivers/drivers.c
+++ b/src/drivers/drivers.c
@@ -27,9 +27,6 @@
 #ifdef CONFIG_DRIVER_MADWIFI
 extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
 #endif /* CONFIG_DRIVER_MADWIFI */
-#ifdef CONFIG_DRIVER_BROADCOM
-extern struct wpa_driver_ops wpa_driver_broadcom_ops; /* driver_broadcom.c */
-#endif /* CONFIG_DRIVER_BROADCOM */
 #ifdef CONFIG_DRIVER_BSD
 extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
 #endif /* CONFIG_DRIVER_BSD */
@@ -42,15 +39,6 @@
 #ifdef CONFIG_DRIVER_TEST
 extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
 #endif /* CONFIG_DRIVER_TEST */
-#ifdef CONFIG_DRIVER_RALINK
-extern struct wpa_driver_ops wpa_driver_ralink_ops; /* driver_ralink.c */
-#endif /* CONFIG_DRIVER_RALINK */
-#ifdef CONFIG_DRIVER_OSX
-extern struct wpa_driver_ops wpa_driver_osx_ops; /* driver_osx.m */
-#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_IPHONE
-extern struct wpa_driver_ops wpa_driver_iphone_ops; /* driver_iphone.m */
-#endif /* CONFIG_DRIVER_IPHONE */
 #ifdef CONFIG_DRIVER_ROBOSWITCH
 /* driver_roboswitch.c */
 extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
@@ -77,9 +65,6 @@
 #ifdef CONFIG_DRIVER_MADWIFI
 	&wpa_driver_madwifi_ops,
 #endif /* CONFIG_DRIVER_MADWIFI */
-#ifdef CONFIG_DRIVER_BROADCOM
-	&wpa_driver_broadcom_ops,
-#endif /* CONFIG_DRIVER_BROADCOM */
 #ifdef CONFIG_DRIVER_BSD
 	&wpa_driver_bsd_ops,
 #endif /* CONFIG_DRIVER_BSD */
@@ -92,15 +77,6 @@
 #ifdef CONFIG_DRIVER_TEST
 	&wpa_driver_test_ops,
 #endif /* CONFIG_DRIVER_TEST */
-#ifdef CONFIG_DRIVER_RALINK
-	&wpa_driver_ralink_ops,
-#endif /* CONFIG_DRIVER_RALINK */
-#ifdef CONFIG_DRIVER_OSX
-	&wpa_driver_osx_ops,
-#endif /* CONFIG_DRIVER_OSX */
-#ifdef CONFIG_DRIVER_IPHONE
-	&wpa_driver_iphone_ops,
-#endif /* CONFIG_DRIVER_IPHONE */
 #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 ebf39c8..0cc81f9 100644
--- a/src/drivers/drivers.mak
+++ b/src/drivers/drivers.mak
@@ -12,29 +12,11 @@
 
 ##### COMMON DRIVERS
 
-ifdef CONFIG_DRIVER_HOSTAP
-DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP
-DRV_OBJS += ../src/drivers/driver_hostap.o
-CONFIG_WIRELESS_EXTENSION=y
-NEED_AP_MLME=y
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
 ifdef CONFIG_DRIVER_WIRED
 DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
 DRV_OBJS += ../src/drivers/driver_wired.o
 endif
 
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_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_NL80211
 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
 DRV_OBJS += ../src/drivers/driver_nl80211.o
@@ -44,15 +26,22 @@
 NEED_NETLINK=y
 NEED_LINUX_IOCTL=y
 NEED_RFKILL=y
-ifdef CONFIG_LIBNL_TINY
-DRV_LIBS += -lnl-tiny
-else
-DRV_LIBS += -lnl
-endif
 
-ifdef CONFIG_LIBNL20
-DRV_LIBS += -lnl-genl
-DRV_CFLAGS += -DCONFIG_LIBNL20
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
 endif
 endif
 
@@ -79,6 +68,24 @@
 
 ##### PURE AP DRIVERS
 
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += ../src/drivers/driver_hostap.o
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+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
@@ -97,18 +104,6 @@
 NEED_RFKILL=y
 endif
 
-ifdef CONFIG_DRIVER_RALINK
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK
-DRV_WPA_OBJS += ../src/drivers/driver_ralink.o
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
-ifdef CONFIG_DRIVER_BROADCOM
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM
-DRV_WPA_OBJS += ../src/drivers/driver_broadcom.o
-endif
-
 ifdef CONFIG_DRIVER_NDIS
 DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
 DRV_WPA_OBJS += ../src/drivers/driver_ndis.o
@@ -124,20 +119,6 @@
 endif
 endif
 
-ifdef CONFIG_DRIVER_OSX
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX
-DRV_WPA_OBJS += ../src/drivers/driver_osx.o
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
-endif
-
-ifdef CONFIG_DRIVER_IPHONE
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE
-DRV_WPA_OBJS += ../src/drivers/driver_iphone.o
-DRV_WPA_OBJS += ../src/drivers/MobileApple80211.o
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-endif
-
 ifdef CONFIG_DRIVER_ROBOSWITCH
 DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
 DRV_WPA_OBJS += ../src/drivers/driver_roboswitch.o
diff --git a/src/drivers/drivers.mk b/src/drivers/drivers.mk
index c690e1c..1d7129c 100644
--- a/src/drivers/drivers.mk
+++ b/src/drivers/drivers.mk
@@ -12,29 +12,11 @@
 
 ##### COMMON DRIVERS
 
-ifdef CONFIG_DRIVER_HOSTAP
-DRV_CFLAGS += -DCONFIG_DRIVER_HOSTAP
-DRV_OBJS += src/drivers/driver_hostap.c
-CONFIG_WIRELESS_EXTENSION=y
-NEED_AP_MLME=y
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
 ifdef CONFIG_DRIVER_WIRED
 DRV_CFLAGS += -DCONFIG_DRIVER_WIRED
 DRV_OBJS += src/drivers/driver_wired.c
 endif
 
-ifdef CONFIG_DRIVER_MADWIFI
-DRV_CFLAGS += -DCONFIG_DRIVER_MADWIFI
-DRV_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_NL80211
 DRV_CFLAGS += -DCONFIG_DRIVER_NL80211
 DRV_OBJS += src/drivers/driver_nl80211.c
@@ -44,15 +26,22 @@
 NEED_NETLINK=y
 NEED_LINUX_IOCTL=y
 NEED_RFKILL=y
-ifdef CONFIG_LIBNL_TINY
-DRV_LIBS += -lnl-tiny
-else
-DRV_LIBS += -lnl
-endif
 
-ifdef CONFIG_LIBNL20
-DRV_LIBS += -lnl-genl
-DRV_CFLAGS += -DCONFIG_LIBNL20
+ifdef CONFIG_LIBNL32
+  DRV_LIBS += -lnl-3
+  DRV_LIBS += -lnl-genl-3
+  DRV_CFLAGS += -DCONFIG_LIBNL20
+else
+  ifdef CONFIG_LIBNL_TINY
+    DRV_LIBS += -lnl-tiny
+  else
+    DRV_LIBS += -lnl
+  endif
+
+  ifdef CONFIG_LIBNL20
+    DRV_LIBS += -lnl-genl
+    DRV_CFLAGS += -DCONFIG_LIBNL20
+  endif
 endif
 endif
 
@@ -79,6 +68,24 @@
 
 ##### PURE AP DRIVERS
 
+ifdef CONFIG_DRIVER_HOSTAP
+DRV_AP_CFLAGS += -DCONFIG_DRIVER_HOSTAP
+DRV_AP_OBJS += src/drivers/driver_hostap.c
+CONFIG_WIRELESS_EXTENSION=y
+NEED_AP_MLME=y
+NEED_NETLINK=y
+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
@@ -97,18 +104,6 @@
 NEED_RFKILL=y
 endif
 
-ifdef CONFIG_DRIVER_RALINK
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_RALINK
-DRV_WPA_OBJS += src/drivers/driver_ralink.c
-NEED_NETLINK=y
-NEED_LINUX_IOCTL=y
-endif
-
-ifdef CONFIG_DRIVER_BROADCOM
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_BROADCOM
-DRV_WPA_OBJS += src/drivers/driver_broadcom.c
-endif
-
 ifdef CONFIG_DRIVER_NDIS
 DRV_WPA_CFLAGS += -DCONFIG_DRIVER_NDIS
 DRV_WPA_OBJS += src/drivers/driver_ndis.c
@@ -124,20 +119,6 @@
 endif
 endif
 
-ifdef CONFIG_DRIVER_OSX
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_OSX
-DRV_WPA_OBJS += src/drivers/driver_osx.c
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-DRV_WPA_LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
-endif
-
-ifdef CONFIG_DRIVER_IPHONE
-DRV_WPA_CFLAGS += -DCONFIG_DRIVER_IPHONE
-DRV_WPA_OBJS += src/drivers/driver_iphone.c
-DRV_WPA_OBJS += src/drivers/MobileApple80211.c
-DRV_WPA_LDFLAGS += -framework CoreFoundation
-endif
-
 ifdef CONFIG_DRIVER_ROBOSWITCH
 DRV_WPA_CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
 DRV_WPA_OBJS += src/drivers/driver_roboswitch.c
diff --git a/src/drivers/linux_ioctl.c b/src/drivers/linux_ioctl.c
index 0d6cf54..d7501cf 100644
--- a/src/drivers/linux_ioctl.c
+++ b/src/drivers/linux_ioctl.c
@@ -24,6 +24,7 @@
 int linux_set_iface_flags(int sock, const char *ifname, int dev_up)
 {
 	struct ifreq ifr;
+	int ret;
 
 	if (sock < 0)
 		return -1;
@@ -32,9 +33,10 @@
 	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
 
 	if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+		ret = errno ? -errno : -999;
 		wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
 			   ifname, strerror(errno));
-		return -1;
+		return ret;
 	}
 
 	if (dev_up) {
@@ -48,15 +50,38 @@
 	}
 
 	if (ioctl(sock, SIOCSIFFLAGS, &ifr) != 0) {
+		ret = errno ? -errno : -999;
 		wpa_printf(MSG_ERROR, "Could not set interface %s flags: %s",
 			   ifname, strerror(errno));
-		return -1;
+		return ret;
 	}
 
 	return 0;
 }
 
 
+int linux_iface_up(int sock, const char *ifname)
+{
+	struct ifreq ifr;
+	int ret;
+
+	if (sock < 0)
+		return -1;
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+	if (ioctl(sock, SIOCGIFFLAGS, &ifr) != 0) {
+		ret = errno ? -errno : -999;
+		wpa_printf(MSG_ERROR, "Could not read interface %s flags: %s",
+			   ifname, strerror(errno));
+		return ret;
+	}
+
+	return !!(ifr.ifr_flags & IFF_UP);
+}
+
+
 int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr)
 {
 	struct ifreq ifr;
diff --git a/src/drivers/linux_ioctl.h b/src/drivers/linux_ioctl.h
index a555738..e0bf673 100644
--- a/src/drivers/linux_ioctl.h
+++ b/src/drivers/linux_ioctl.h
@@ -16,6 +16,7 @@
 #define LINUX_IOCTL_H
 
 int linux_set_iface_flags(int sock, const char *ifname, int dev_up);
+int linux_iface_up(int sock, const char *ifname);
 int linux_get_ifhwaddr(int sock, const char *ifname, u8 *addr);
 int linux_set_ifhwaddr(int sock, const char *ifname, const u8 *addr);
 int linux_br_add(int sock, const char *brname);
diff --git a/src/drivers/linux_wext.h b/src/drivers/linux_wext.h
new file mode 100644
index 0000000..b6eea68
--- /dev/null
+++ b/src/drivers/linux_wext.h
@@ -0,0 +1,51 @@
+/*
+ * Driver interaction with generic Linux Wireless Extensions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef LINUX_WEXT_H
+#define LINUX_WEXT_H
+
+#ifndef ANDROID
+
+/*
+ * Avoid including other kernel header to avoid conflicts with C library
+ * headers.
+ */
+#define _LINUX_TYPES_H
+#define _LINUX_SOCKET_H
+#define _LINUX_IF_H
+
+#include <sys/types.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;
+#ifndef __user
+#define __user
+#endif /* __user */
+
+#endif /* ANDROID */
+
+#include <linux/wireless.h>
+
+#ifndef IW_ENCODE_ALG_PMK
+#define IW_ENCODE_ALG_PMK 4
+#endif
+
+#ifndef IW_ENC_CAPA_4WAY_HANDSHAKE
+#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010
+#endif
+
+#endif /* LINUX_WEXT_H */
diff --git a/src/drivers/netlink.c b/src/drivers/netlink.c
index ad15b1d..6778907 100644
--- a/src/drivers/netlink.c
+++ b/src/drivers/netlink.c
@@ -34,7 +34,7 @@
 	if (cb == NULL || NLMSG_PAYLOAD(h, 0) < sizeof(struct ifinfomsg))
 		return;
 	cb(netlink->cfg->ctx, NLMSG_DATA(h),
-	   NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
+	   (u8 *) NLMSG_DATA(h) + NLMSG_ALIGN(sizeof(struct ifinfomsg)),
 	   NLMSG_PAYLOAD(h, sizeof(struct ifinfomsg)));
 }
 
diff --git a/src/drivers/nl80211_copy.h b/src/drivers/nl80211_copy.h
index 7483a89..f9261c2 100644
--- a/src/drivers/nl80211_copy.h
+++ b/src/drivers/nl80211_copy.h
@@ -6,7 +6,7 @@
  * Copyright 2006-2010 Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2008 Michael Wu <flamingice@sourmilk.net>
  * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
- * Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ * Copyright 2008 Michael Buesch <m@bues.ch>
  * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
  * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
  * Copyright 2008 Colin McCabe <colin@cozybit.com>
@@ -77,6 +77,39 @@
  */
 
 /**
+ * DOC: Virtual interface / concurrency capabilities
+ *
+ * Some devices are able to operate with virtual MACs, they can have
+ * more than one virtual interface. The capability handling for this
+ * is a bit complex though, as there may be a number of restrictions
+ * on the types of concurrency that are supported.
+ *
+ * To start with, each device supports the interface types listed in
+ * the %NL80211_ATTR_SUPPORTED_IFTYPES attribute, but by listing the
+ * types there no concurrency is implied.
+ *
+ * Once concurrency is desired, more attributes must be observed:
+ * To start with, since some interface types are purely managed in
+ * software, like the AP-VLAN type in mac80211 for example, there's
+ * an additional list of these, they can be added at any time and
+ * are only restricted by some semantic restrictions (e.g. AP-VLAN
+ * cannot be added without a corresponding AP interface). This list
+ * is exported in the %NL80211_ATTR_SOFTWARE_IFTYPES attribute.
+ *
+ * Further, the list of supported combinations is exported. This is
+ * in the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute. Basically,
+ * it exports a list of "groups", and at any point in time the
+ * interfaces that are currently active must fall into any one of
+ * the advertised groups. Within each group, there are restrictions
+ * on the number of interfaces of different types that are supported
+ * and also the number of different channels, along with potentially
+ * some other restrictions. See &enum nl80211_if_combination_attrs.
+ *
+ * All together, these attributes define the concurrency of virtual
+ * interfaces that a given device supports.
+ */
+
+/**
  * enum nl80211_commands - supported nl80211 commands
  *
  * @NL80211_CMD_UNSPEC: unspecified command to catch errors
@@ -128,6 +161,13 @@
  * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
  *	using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
  *	%NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
+ *	Following attributes are provided for drivers that generate full Beacon
+ *	and Probe Response frames internally: %NL80211_ATTR_SSID,
+ *	%NL80211_ATTR_HIDDEN_SSID, %NL80211_ATTR_CIPHERS_PAIRWISE,
+ *	%NL80211_ATTR_CIPHER_GROUP, %NL80211_ATTR_WPA_VERSIONS,
+ *	%NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
+ *	%NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_IE, %NL80211_ATTR_IE_PROBE_RESP,
+ *	%NL80211_ATTR_IE_ASSOC_RESP.
  * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
  *	parameters are like for %NL80211_CMD_SET_BEACON.
  * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
@@ -148,6 +188,10 @@
  * @NL80211_CMD_SET_MPATH:  Set mesh path attributes for mesh path to
  * 	destination %NL80211_ATTR_MAC on the interface identified by
  * 	%NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_MPATH: Create a new mesh path for the destination given by
+ *	%NL80211_ATTR_MAC via %NL80211_ATTR_MPATH_NEXT_HOP.
+ * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by
+ *	%NL80211_ATTR_MAC.
  * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
  *	the interface identified by %NL80211_ATTR_IFINDEX.
  * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
@@ -172,10 +216,10 @@
  * 	to the specified ISO/IEC 3166-1 alpha2 country code. The core will
  * 	store this as a valid request and then query userspace for it.
  *
- * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
+ * @NL80211_CMD_GET_MESH_CONFIG: Get mesh networking properties for the
  *	interface identified by %NL80211_ATTR_IFINDEX
  *
- * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
+ * @NL80211_CMD_SET_MESH_CONFIG: Set mesh networking properties for the
  *      interface identified by %NL80211_ATTR_IFINDEX
  *
  * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
@@ -194,11 +238,36 @@
  *
  * @NL80211_CMD_GET_SCAN: get scan results
  * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ *	%NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ *	probe requests at CCK rate or not.
  * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
  *	NL80211_CMD_GET_SCAN and on the "scan" multicast group)
  * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
  *	partial scan results may be available
  *
+ * @NL80211_CMD_START_SCHED_SCAN: start a scheduled scan at certain
+ *	intervals, as specified by %NL80211_ATTR_SCHED_SCAN_INTERVAL.
+ *	Like with normal scans, if SSIDs (%NL80211_ATTR_SCAN_SSIDS)
+ *	are passed, they are used in the probe requests.  For
+ *	broadcast, a broadcast SSID must be passed (ie. an empty
+ *	string).  If no SSID is passed, no probe requests are sent and
+ *	a passive scan is performed.  %NL80211_ATTR_SCAN_FREQUENCIES,
+ *	if passed, define which channels should be scanned; if not
+ *	passed, all channels allowed for the current regulatory domain
+ *	are used.  Extra IEs can also be passed from the userspace by
+ *	using the %NL80211_ATTR_IE attribute.
+ * @NL80211_CMD_STOP_SCHED_SCAN: stop a scheduled scan.  Returns -ENOENT
+ *	if scheduled scan is not running.
+ * @NL80211_CMD_SCHED_SCAN_RESULTS: indicates that there are scheduled scan
+ *	results available.
+ * @NL80211_CMD_SCHED_SCAN_STOPPED: indicates that the scheduled scan has
+ *	stopped.  The driver may issue this event at any time during a
+ *	scheduled scan.  One reason for stopping the scan is if the hardware
+ *	does not support starting an association or a normal scan while running
+ *	a scheduled scan.  This event is also sent when the
+ *	%NL80211_CMD_STOP_SCHED_SCAN command is received or when the interface
+ *	is brought down while a scheduled scan was running.
+ *
  * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
  *      or noise level
  * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
@@ -365,6 +434,8 @@
  *	specified using %NL80211_ATTR_DURATION. When called, this operation
  *	returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
  *	TX status event pertaining to the TX request.
+ *	%NL80211_ATTR_TX_NO_CCK_RATE is used to decide whether to send the
+ *	management frames at CCK rate or not in 2GHz band.
  * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
  *	command may be used with the corresponding cookie to cancel the wait
  *	time if it is known that it is no longer necessary.
@@ -406,11 +477,72 @@
  *	notification. This event is used to indicate that an unprotected
  *	disassociation frame was dropped when MFP is in use.
  *
+ * @NL80211_CMD_NEW_PEER_CANDIDATE: Notification on the reception of a
+ *      beacon or probe response from a compatible mesh peer.  This is only
+ *      sent while no station information (sta_info) exists for the new peer
+ *      candidate and when @NL80211_MESH_SETUP_USERSPACE_AUTH is set.  On
+ *      reception of this notification, userspace may decide to create a new
+ *      station (@NL80211_CMD_NEW_STATION).  To stop this notification from
+ *      reoccurring, the userspace authentication daemon may want to create the
+ *      new station with the AUTHENTICATED flag unset and maybe change it later
+ *      depending on the authentication result.
+ *
+ * @NL80211_CMD_GET_WOWLAN: get Wake-on-Wireless-LAN (WoWLAN) settings.
+ * @NL80211_CMD_SET_WOWLAN: set Wake-on-Wireless-LAN (WoWLAN) settings.
+ *	Since wireless is more complex than wired ethernet, it supports
+ *	various triggers. These triggers can be configured through this
+ *	command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For
+ *	more background information, see
+ *	http://wireless.kernel.org/en/users/Documentation/WoWLAN.
+ *
+ * @NL80211_CMD_SET_REKEY_OFFLOAD: This command is used give the driver
+ *	the necessary information for supporting GTK rekey offload. This
+ *	feature is typically used during WoWLAN. The configuration data
+ *	is contained in %NL80211_ATTR_REKEY_DATA (which is nested and
+ *	contains the data in sub-attributes). After rekeying happened,
+ *	this command may also be sent by the driver as an MLME event to
+ *	inform userspace of the new replay counter.
+ *
+ * @NL80211_CMD_PMKSA_CANDIDATE: This is used as an event to inform userspace
+ *	of PMKSA caching dandidates.
+ *
+ * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
+ * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
+ *
+ * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
+ *	(or GO) interface (i.e. hostapd) to ask for unexpected frames to
+ *	implement sending deauth to stations that send unexpected class 3
+ *	frames. Also used as the event sent by the kernel when such a frame
+ *	is received.
+ *	For the event, the %NL80211_ATTR_MAC attribute carries the TA and
+ *	other attributes like the interface index are present.
+ *	If used as the command it must have an interface index and you can
+ *	only unsubscribe from the event by closing the socket. Subscription
+ *	is also for %NL80211_CMD_UNEXPECTED_4ADDR_FRAME events.
+ *
+ * @NL80211_CMD_UNEXPECTED_4ADDR_FRAME: Sent as an event indicating that the
+ *	associated station identified by %NL80211_ATTR_MAC sent a 4addr frame
+ *	and wasn't already in a 4-addr VLAN. The event will be sent similarly
+ *	to the %NL80211_CMD_UNEXPECTED_FRAME event, to the same listener.
+ *
+ * @NL80211_CMD_PROBE_CLIENT: Probe an associated station on an AP interface
+ *	by sending a null data frame to it and reporting when the frame is
+ *	acknowleged. This is used to allow timing out inactive clients. Uses
+ *	%NL80211_ATTR_IFINDEX and %NL80211_ATTR_MAC. The command returns a
+ *	direct reply with an %NL80211_ATTR_COOKIE that is later used to match
+ *	up the event with the request. The event includes the same data and
+ *	has %NL80211_ATTR_ACK set if the frame was ACKed.
+ *
+ * @NL80211_CMD_REGISTER_BEACONS: Register this socket to receive beacons from
+ *	other BSSes when any interfaces are in AP mode. This helps implement
+ *	OLBC handling in hostapd. Beacons are reported in %NL80211_CMD_FRAME
+ *	messages. Note that per PHY only one application may register.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
 enum nl80211_commands {
-/* don't change the order or add anything inbetween, this is ABI! */
+/* don't change the order or add anything between, this is ABI! */
 	NL80211_CMD_UNSPEC,
 
 	NL80211_CMD_GET_WIPHY,		/* can dump */
@@ -448,8 +580,8 @@
 	NL80211_CMD_SET_REG,
 	NL80211_CMD_REQ_SET_REG,
 
-	NL80211_CMD_GET_MESH_PARAMS,
-	NL80211_CMD_SET_MESH_PARAMS,
+	NL80211_CMD_GET_MESH_CONFIG,
+	NL80211_CMD_SET_MESH_CONFIG,
 
 	NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,
 
@@ -518,6 +650,31 @@
 	NL80211_CMD_UNPROT_DEAUTHENTICATE,
 	NL80211_CMD_UNPROT_DISASSOCIATE,
 
+	NL80211_CMD_NEW_PEER_CANDIDATE,
+
+	NL80211_CMD_GET_WOWLAN,
+	NL80211_CMD_SET_WOWLAN,
+
+	NL80211_CMD_START_SCHED_SCAN,
+	NL80211_CMD_STOP_SCHED_SCAN,
+	NL80211_CMD_SCHED_SCAN_RESULTS,
+	NL80211_CMD_SCHED_SCAN_STOPPED,
+
+	NL80211_CMD_SET_REKEY_OFFLOAD,
+
+	NL80211_CMD_PMKSA_CANDIDATE,
+
+	NL80211_CMD_TDLS_OPER,
+	NL80211_CMD_TDLS_MGMT,
+
+	NL80211_CMD_UNEXPECTED_FRAME,
+
+	NL80211_CMD_PROBE_CLIENT,
+
+	NL80211_CMD_REGISTER_BEACONS,
+
+	NL80211_CMD_UNEXPECTED_4ADDR_FRAME,
+
 	/* add new commands above here */
 
 	/* used to define NL80211_CMD_MAX below */
@@ -538,6 +695,13 @@
 #define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
 #define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
 
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
+
+/* source-level API compatibility */
+#define NL80211_CMD_GET_MESH_PARAMS NL80211_CMD_GET_MESH_CONFIG
+#define NL80211_CMD_SET_MESH_PARAMS NL80211_CMD_SET_MESH_CONFIG
+#define NL80211_MESH_SETUP_VENDOR_PATH_SEL_IE NL80211_MESH_SETUP_IE
+
 /**
  * enum nl80211_attrs - nl80211 netlink attributes
  *
@@ -608,7 +772,7 @@
  *	consisting of a nested array.
  *
  * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
- * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_STA_PLINK_ACTION: action to perform on the mesh peer link.
  * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
  * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
  * 	info given for %NL80211_CMD_GET_MPATH, nested attribute described at
@@ -653,8 +817,14 @@
  *
  * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
  *	a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS: number of SSIDs you can
+ *	scan with a single scheduled scan request, a wiphy attribute.
  * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
  *	that can be added to a scan request
+ * @NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN: maximum length of information
+ *	elements that can be added to a scheduled scan request
+ * @NL80211_ATTR_MAX_MATCH_SETS: maximum number of sets that can be
+ *	used with @NL80211_ATTR_SCHED_SCAN_MATCH, a wiphy attribute.
  *
  * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
  * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
@@ -735,18 +905,20 @@
  * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
  *	event (u16)
  * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
- *	that protected APs should be used.
+ *	that protected APs should be used. This is also used with NEW_BEACON to
+ *	indicate that the BSS is to use protection.
  *
- * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
- *	indicate which unicast key ciphers will be used with the connection
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT, ASSOCIATE, and NEW_BEACON
+ *	to indicate which unicast key ciphers will be used with the connection
  *	(an array of u32).
- * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
- *	which group key cipher will be used with the connection (a u32).
- * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
- *	which WPA version(s) the AP we want to associate with is using
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which group key cipher will be used with the connection (a
+ *	u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which WPA version(s) the AP we want to associate with is using
  *	(a u32 with flags from &enum nl80211_wpa_versions).
- * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
- *	which key management algorithm(s) to use (an array of u32).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT, ASSOCIATE, and NEW_BEACON to
+ *	indicate which key management algorithm(s) to use (an array of u32).
  *
  * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
  *	sent out by the card, for ROAM and successful CONNECT events.
@@ -852,7 +1024,13 @@
  *	This can be used to mask out antennas which are not attached or should
  *	not be used for receiving. If an antenna is not selected in this bitmap
  *	the hardware should not be configured to receive on this antenna.
- *	For a more detailed descripton see @NL80211_ATTR_WIPHY_ANTENNA_TX.
+ *	For a more detailed description see @NL80211_ATTR_WIPHY_ANTENNA_TX.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX: Bitmap of antennas which are available
+ *	for configuration as TX antennas via the above parameters.
+ *
+ * @NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX: Bitmap of antennas which are available
+ *	for configuration as RX antennas via the above parameters.
  *
  * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS
  *
@@ -868,11 +1046,135 @@
  *	attributes, specifying what a key should be set as default as.
  *	See &enum nl80211_key_default_types.
  *
+ * @NL80211_ATTR_MESH_SETUP: Optional mesh setup parameters.  These cannot be
+ *	changed once the mesh is active.
+ * @NL80211_ATTR_MESH_CONFIG: Mesh configuration parameters, a nested attribute
+ *	containing attributes from &enum nl80211_meshconf_params.
+ * @NL80211_ATTR_SUPPORT_MESH_AUTH: Currently, this means the underlying driver
+ *	allows auth frames in a mesh to be passed to userspace for processing via
+ *	the @NL80211_MESH_SETUP_USERSPACE_AUTH flag.
+ * @NL80211_ATTR_STA_PLINK_STATE: The state of a mesh peer link as
+ *	defined in &enum nl80211_plink_state. Used when userspace is
+ *	driving the peer link management state machine.
+ *	@NL80211_MESH_SETUP_USERSPACE_AMPE must be enabled.
+ *
+ * @NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED: indicates, as part of the wiphy
+ *	capabilities, the supported WoWLAN triggers
+ * @NL80211_ATTR_WOWLAN_TRIGGERS: used by %NL80211_CMD_SET_WOWLAN to
+ *	indicate which WoW triggers should be enabled. This is also
+ *	used by %NL80211_CMD_GET_WOWLAN to get the currently enabled WoWLAN
+ *	triggers.
+
+ * @NL80211_ATTR_SCHED_SCAN_INTERVAL: Interval between scheduled scan
+ *	cycles, in msecs.
+
+ * @NL80211_ATTR_SCHED_SCAN_MATCH: Nested attribute with one or more
+ *	sets of attributes to match during scheduled scans.  Only BSSs
+ *	that match any of the sets will be reported.  These are
+ *	pass-thru filter rules.
+ *	For a match to succeed, the BSS must match all attributes of a
+ *	set.  Since not every hardware supports matching all types of
+ *	attributes, there is no guarantee that the reported BSSs are
+ *	fully complying with the match sets and userspace needs to be
+ *	able to ignore them by itself.
+ *	Thus, the implementation is somewhat hardware-dependent, but
+ *	this is only an optimization and the userspace application
+ *	needs to handle all the non-filtered results anyway.
+ *	If the match attributes don't make sense when combined with
+ *	the values passed in @NL80211_ATTR_SCAN_SSIDS (eg. if an SSID
+ *	is included in the probe request, but the match attributes
+ *	will never let it go through), -EINVAL may be returned.
+ *	If ommited, no filtering is done.
+ *
+ * @NL80211_ATTR_INTERFACE_COMBINATIONS: Nested attribute listing the supported
+ *	interface combinations. In each nested item, it contains attributes
+ *	defined in &enum nl80211_if_combination_attrs.
+ * @NL80211_ATTR_SOFTWARE_IFTYPES: Nested attribute (just like
+ *	%NL80211_ATTR_SUPPORTED_IFTYPES) containing the interface types that
+ *	are managed in software: interfaces of these types aren't subject to
+ *	any restrictions in their number or combinations.
+ *
+ * @%NL80211_ATTR_REKEY_DATA: nested attribute containing the information
+ *	necessary for GTK rekeying in the device, see &enum nl80211_rekey_data.
+ *
+ * @NL80211_ATTR_SCAN_SUPP_RATES: rates per to be advertised as supported in scan,
+ *	nested array attribute containing an entry for each band, with the entry
+ *	being a list of supported rates as defined by IEEE 802.11 7.3.2.2 but
+ *	without the length restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HIDDEN_SSID: indicates whether SSID is to be hidden from Beacon
+ *	and Probe Response (when response to wildcard Probe Request); see
+ *	&enum nl80211_hidden_ssid, represented as a u32
+ *
+ * @NL80211_ATTR_IE_PROBE_RESP: Information element(s) for Probe Response frame.
+ *	This is used with %NL80211_CMD_NEW_BEACON and %NL80211_CMD_SET_BEACON to
+ *	provide extra IEs (e.g., WPS/P2P IE) into Probe Response frames when the
+ *	driver (or firmware) replies to Probe Request frames.
+ * @NL80211_ATTR_IE_ASSOC_RESP: Information element(s) for (Re)Association
+ *	Response frames. This is used with %NL80211_CMD_NEW_BEACON and
+ *	%NL80211_CMD_SET_BEACON to provide extra IEs (e.g., WPS/P2P IE) into
+ *	(Re)Association Response frames when the driver (or firmware) replies to
+ *	(Re)Association Request frames.
+ *
+ * @NL80211_ATTR_STA_WME: Nested attribute containing the wme configuration
+ *	of the station, see &enum nl80211_sta_wme_attr.
+ * @NL80211_ATTR_SUPPORT_AP_UAPSD: the device supports uapsd when working
+ *	as AP.
+ *
+ * @NL80211_ATTR_ROAM_SUPPORT: Indicates whether the firmware is capable of
+ *	roaming to another AP in the same ESS if the signal lever is low.
+ *
+ * @NL80211_ATTR_PMKSA_CANDIDATE: Nested attribute containing the PMKSA caching
+ *	candidate information, see &enum nl80211_pmksa_candidate_attr.
+ *
+ * @NL80211_ATTR_TX_NO_CCK_RATE: Indicates whether to use CCK rate or not
+ *	for management frames transmission. In order to avoid p2p probe/action
+ *	frames are being transmitted at CCK rate in 2GHz band, the user space
+ *	applications use this attribute.
+ *	This attribute is used with %NL80211_CMD_TRIGGER_SCAN and
+ *	%NL80211_CMD_FRAME commands.
+ *
+ * @NL80211_ATTR_TDLS_ACTION: Low level TDLS action code (e.g. link setup
+ *	request, link setup confirm, link teardown, etc.). Values are
+ *	described in the TDLS (802.11z) specification.
+ * @NL80211_ATTR_TDLS_DIALOG_TOKEN: Non-zero token for uniquely identifying a
+ *	TDLS conversation between two devices.
+ * @NL80211_ATTR_TDLS_OPERATION: High level TDLS operation; see
+ *	&enum nl80211_tdls_operation, represented as a u8.
+ * @NL80211_ATTR_TDLS_SUPPORT: A flag indicating the device can operate
+ *	as a TDLS peer sta.
+ * @NL80211_ATTR_TDLS_EXTERNAL_SETUP: The TDLS discovery/setup and teardown
+ *	procedures should be performed by sending TDLS packets via
+ *	%NL80211_CMD_TDLS_MGMT. Otherwise %NL80211_CMD_TDLS_OPER should be
+ *	used for asking the driver to perform a TDLS operation.
+ *
+ * @NL80211_ATTR_DEVICE_AP_SME: This u32 attribute may be listed for devices
+ *	that have AP support to indicate that they have the AP SME integrated
+ *	with support for the features listed in this attribute, see
+ *	&enum nl80211_ap_sme_features.
+ *
+ * @NL80211_ATTR_DONT_WAIT_FOR_ACK: Used with %NL80211_CMD_FRAME, this tells
+ *	the driver to not wait for an acknowledgement. Note that due to this,
+ *	it will also not give a status callback nor return a cookie. This is
+ *	mostly useful for probe responses to save airtime.
+ *
+ * @NL80211_ATTR_FEATURE_FLAGS: This u32 attribute contains flags from
+ *	&enum nl80211_feature_flags and is advertised in wiphy information.
+ * @NL80211_ATTR_PROBE_RESP_OFFLOAD: Indicates that the HW responds to probe
+ *
+ *	requests while operating in AP-mode.
+ *	This attribute holds a bitmap of the supported protocols for
+ *	offloading (see &enum nl80211_probe_resp_offload_support_attr).
+ *
+ * @NL80211_ATTR_PROBE_RESP: Probe Response template data. Contains the entire
+ *	probe-response frame. The DA field in the 802.11 header is zero-ed out,
+ *	to be filled by the FW.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
 enum nl80211_attrs {
-/* don't change the order or add anything inbetween, this is ABI! */
+/* don't change the order or add anything between, this is ABI! */
 	NL80211_ATTR_UNSPEC,
 
 	NL80211_ATTR_WIPHY,
@@ -922,7 +1224,7 @@
 	NL80211_ATTR_REG_ALPHA2,
 	NL80211_ATTR_REG_RULES,
 
-	NL80211_ATTR_MESH_PARAMS,
+	NL80211_ATTR_MESH_CONFIG,
 
 	NL80211_ATTR_BSS_BASIC_RATES,
 
@@ -1050,6 +1352,62 @@
 
 	NL80211_ATTR_MAX_REMAIN_ON_CHANNEL_DURATION,
 
+	NL80211_ATTR_MESH_SETUP,
+
+	NL80211_ATTR_WIPHY_ANTENNA_AVAIL_TX,
+	NL80211_ATTR_WIPHY_ANTENNA_AVAIL_RX,
+
+	NL80211_ATTR_SUPPORT_MESH_AUTH,
+	NL80211_ATTR_STA_PLINK_STATE,
+
+	NL80211_ATTR_WOWLAN_TRIGGERS,
+	NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED,
+
+	NL80211_ATTR_SCHED_SCAN_INTERVAL,
+
+	NL80211_ATTR_INTERFACE_COMBINATIONS,
+	NL80211_ATTR_SOFTWARE_IFTYPES,
+
+	NL80211_ATTR_REKEY_DATA,
+
+	NL80211_ATTR_MAX_NUM_SCHED_SCAN_SSIDS,
+	NL80211_ATTR_MAX_SCHED_SCAN_IE_LEN,
+
+	NL80211_ATTR_SCAN_SUPP_RATES,
+
+	NL80211_ATTR_HIDDEN_SSID,
+
+	NL80211_ATTR_IE_PROBE_RESP,
+	NL80211_ATTR_IE_ASSOC_RESP,
+
+	NL80211_ATTR_STA_WME,
+	NL80211_ATTR_SUPPORT_AP_UAPSD,
+
+	NL80211_ATTR_ROAM_SUPPORT,
+
+	NL80211_ATTR_SCHED_SCAN_MATCH,
+	NL80211_ATTR_MAX_MATCH_SETS,
+
+	NL80211_ATTR_PMKSA_CANDIDATE,
+
+	NL80211_ATTR_TX_NO_CCK_RATE,
+
+	NL80211_ATTR_TDLS_ACTION,
+	NL80211_ATTR_TDLS_DIALOG_TOKEN,
+	NL80211_ATTR_TDLS_OPERATION,
+	NL80211_ATTR_TDLS_SUPPORT,
+	NL80211_ATTR_TDLS_EXTERNAL_SETUP,
+
+	NL80211_ATTR_DEVICE_AP_SME,
+
+	NL80211_ATTR_DONT_WAIT_FOR_ACK,
+
+	NL80211_ATTR_FEATURE_FLAGS,
+
+	NL80211_ATTR_PROBE_RESP_OFFLOAD,
+
+	NL80211_ATTR_PROBE_RESP,
+
 	/* add attributes here, update the policy in nl80211.c */
 
 	__NL80211_ATTR_AFTER_LAST,
@@ -1058,6 +1416,7 @@
 
 /* source-level API compatibility */
 #define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
+#define	NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG
 
 /*
  * Allow user space programs to use #ifdef on new attributes by defining them
@@ -1083,6 +1442,7 @@
 #define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
 #define NL80211_ATTR_KEY NL80211_ATTR_KEY
 #define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+#define NL80211_ATTR_FEATURE_FLAGS NL80211_ATTR_FEATURE_FLAGS
 
 #define NL80211_MAX_SUPP_RATES			32
 #define NL80211_MAX_SUPP_REG_RULES		32
@@ -1101,7 +1461,9 @@
  * @NL80211_IFTYPE_ADHOC: independent BSS member
  * @NL80211_IFTYPE_STATION: managed BSS member
  * @NL80211_IFTYPE_AP: access point
- * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points; VLAN interfaces
+ *	are a bit special in that they must always be tied to a pre-existing
+ *	AP type interface.
  * @NL80211_IFTYPE_WDS: wireless distribution interface
  * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
  * @NL80211_IFTYPE_MESH_POINT: mesh point
@@ -1143,6 +1505,8 @@
  *	with short barker preamble
  * @NL80211_STA_FLAG_WME: station is WME/QoS capable
  * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ * @NL80211_STA_FLAG_AUTHENTICATED: station is authenticated
+ * @NL80211_STA_FLAG_TDLS_PEER: station is a TDLS peer
  * @NL80211_STA_FLAG_MAX: highest station flag number currently defined
  * @__NL80211_STA_FLAG_AFTER_LAST: internal use
  */
@@ -1152,6 +1516,8 @@
 	NL80211_STA_FLAG_SHORT_PREAMBLE,
 	NL80211_STA_FLAG_WME,
 	NL80211_STA_FLAG_MFP,
+	NL80211_STA_FLAG_AUTHENTICATED,
+	NL80211_STA_FLAG_TDLS_PEER,
 
 	/* keep last */
 	__NL80211_STA_FLAG_AFTER_LAST,
@@ -1197,6 +1563,36 @@
 };
 
 /**
+ * enum nl80211_sta_bss_param - BSS information collected by STA
+ *
+ * These attribute types are used with %NL80211_STA_INFO_BSS_PARAM
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_STA_BSS_PARAM_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_BSS_PARAM_CTS_PROT: whether CTS protection is enabled (flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_PREAMBLE:  whether short preamble is enabled
+ *	(flag)
+ * @NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME:  whether short slot time is enabled
+ *	(flag)
+ * @NL80211_STA_BSS_PARAM_DTIM_PERIOD: DTIM period for beaconing (u8)
+ * @NL80211_STA_BSS_PARAM_BEACON_INTERVAL: Beacon interval (u16)
+ * @NL80211_STA_BSS_PARAM_MAX: highest sta_bss_param number currently defined
+ * @__NL80211_STA_BSS_PARAM_AFTER_LAST: internal use
+ */
+enum nl80211_sta_bss_param {
+	__NL80211_STA_BSS_PARAM_INVALID,
+	NL80211_STA_BSS_PARAM_CTS_PROT,
+	NL80211_STA_BSS_PARAM_SHORT_PREAMBLE,
+	NL80211_STA_BSS_PARAM_SHORT_SLOT_TIME,
+	NL80211_STA_BSS_PARAM_DTIM_PERIOD,
+	NL80211_STA_BSS_PARAM_BEACON_INTERVAL,
+
+	/* keep last */
+	__NL80211_STA_BSS_PARAM_AFTER_LAST,
+	NL80211_STA_BSS_PARAM_MAX = __NL80211_STA_BSS_PARAM_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_sta_info - station information
  *
  * These attribute types are used with %NL80211_ATTR_STA_INFO
@@ -1206,17 +1602,27 @@
  * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
  * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
  * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
- * @__NL80211_STA_INFO_AFTER_LAST: internal
- * @NL80211_STA_INFO_MAX: highest possible station info attribute
  * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
  * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
- * 	containing info as possible, see &enum nl80211_sta_info_txrate.
+ * 	containing info as possible, see &enum nl80211_rate_info
  * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
  * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
  *	station)
  * @NL80211_STA_INFO_TX_RETRIES: total retries (u32, to this station)
  * @NL80211_STA_INFO_TX_FAILED: total failed packets (u32, to this station)
  * @NL80211_STA_INFO_SIGNAL_AVG: signal strength average (u8, dBm)
+ * @NL80211_STA_INFO_LLID: the station's mesh LLID
+ * @NL80211_STA_INFO_PLID: the station's mesh PLID
+ * @NL80211_STA_INFO_PLINK_STATE: peer link state for the station
+ *	(see %enum nl80211_plink_state)
+ * @NL80211_STA_INFO_RX_BITRATE: last unicast data frame rx rate, nested
+ *	attribute, like NL80211_STA_INFO_TX_BITRATE.
+ * @NL80211_STA_INFO_BSS_PARAM: current station's view of BSS, nested attribute
+ *     containing info as possible, see &enum nl80211_sta_bss_param
+ * @NL80211_STA_INFO_CONNECTED_TIME: time since the station is last connected
+ * @NL80211_STA_INFO_STA_FLAGS: Contains a struct nl80211_sta_flag_update.
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
  */
 enum nl80211_sta_info {
 	__NL80211_STA_INFO_INVALID,
@@ -1233,6 +1639,10 @@
 	NL80211_STA_INFO_TX_RETRIES,
 	NL80211_STA_INFO_TX_FAILED,
 	NL80211_STA_INFO_SIGNAL_AVG,
+	NL80211_STA_INFO_RX_BITRATE,
+	NL80211_STA_INFO_BSS_PARAM,
+	NL80211_STA_INFO_CONNECTED_TIME,
+	NL80211_STA_INFO_STA_FLAGS,
 
 	/* keep last */
 	__NL80211_STA_INFO_AFTER_LAST,
@@ -1388,7 +1798,7 @@
  * 	802.11 country information element with regulatory information it
  * 	thinks we should consider. cfg80211 only processes the country
  *	code from the IE, and relies on the regulatory domain information
- *	structure pased by userspace (CRDA) from our wireless-regdb.
+ *	structure passed by userspace (CRDA) from our wireless-regdb.
  *	If a channel is enabled but the country code indicates it should
  *	be disabled we disable the channel and re-enable it upon disassociation.
  */
@@ -1462,6 +1872,26 @@
 };
 
 /**
+ * enum nl80211_sched_scan_match_attr - scheduled scan match attributes
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_SSID: SSID to be used for matching,
+ * only report BSS with matching SSID.
+ * @NL80211_SCHED_SCAN_MATCH_ATTR_MAX: highest scheduled scan filter
+ *	attribute number currently defined
+ * @__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_sched_scan_match_attr {
+	__NL80211_SCHED_SCAN_MATCH_ATTR_INVALID,
+
+	NL80211_ATTR_SCHED_SCAN_MATCH_SSID,
+
+	/* keep last */
+	__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST,
+	NL80211_SCHED_SCAN_MATCH_ATTR_MAX =
+		__NL80211_SCHED_SCAN_MATCH_ATTR_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_reg_rule_flags - regulatory rule flags
  *
  * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
@@ -1559,14 +1989,15 @@
 /**
  * enum nl80211_meshconf_params - mesh configuration parameters
  *
- * Mesh configuration parameters
+ * Mesh configuration parameters. These can be changed while the mesh is
+ * active.
  *
  * @__NL80211_MESHCONF_INVALID: internal use
  *
  * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
  * millisecond units, used by the Peer Link Open message
  *
- * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in
+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the initial confirm timeout, in
  * millisecond units, used by the peer link management to close a peer link
  *
  * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
@@ -1582,9 +2013,6 @@
  * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
  * point.
  *
- * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
- * source mesh point for path selection elements.
- *
  * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
  * open peer links when we detect compatible mesh peers.
  *
@@ -1609,7 +2037,17 @@
  * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
  * that it takes for an HWMP information element to propagate across the mesh
  *
- * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
+ * @NL80211_MESHCONF_HWMP_ROOTMODE: whether root mode is enabled or not
+ *
+ * @NL80211_MESHCONF_ELEMENT_TTL: specifies the value of TTL field set at a
+ * source mesh point for path selection elements.
+ *
+ * @NL80211_MESHCONF_HWMP_RANN_INTERVAL:  The interval of time (in TUs) between
+ * root announcements are transmitted.
+ *
+ * @NL80211_MESHCONF_GATE_ANNOUNCEMENTS: Advertise that this mesh station has
+ * access to a broader network beyond the MBSS.  This is done via Root
+ * Announcement frames.
  *
  * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
  *
@@ -1632,6 +2070,8 @@
 	NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
 	NL80211_MESHCONF_HWMP_ROOTMODE,
 	NL80211_MESHCONF_ELEMENT_TTL,
+	NL80211_MESHCONF_HWMP_RANN_INTERVAL,
+	NL80211_MESHCONF_GATE_ANNOUNCEMENTS,
 
 	/* keep last */
 	__NL80211_MESHCONF_ATTR_AFTER_LAST,
@@ -1639,6 +2079,54 @@
 };
 
 /**
+ * enum nl80211_mesh_setup_params - mesh setup parameters
+ *
+ * Mesh setup parameters.  These are used to start/join a mesh and cannot be
+ * changed while the mesh is active.
+ *
+ * @__NL80211_MESH_SETUP_INVALID: Internal use
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL: Enable this option to use a
+ * vendor specific path selection algorithm or disable it to use the default
+ * HWMP.
+ *
+ * @NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC: Enable this option to use a
+ * vendor specific path metric or disable it to use the default Airtime
+ * metric.
+ *
+ * @NL80211_MESH_SETUP_IE: Information elements for this mesh, for instance, a
+ * robust security network ie, or a vendor specific information element that
+ * vendors will use to identify the path selection methods and metrics in use.
+ *
+ * @NL80211_MESH_SETUP_USERSPACE_AUTH: Enable this option if an authentication
+ * daemon will be authenticating mesh candidates.
+ *
+ * @NL80211_MESH_SETUP_USERSPACE_AMPE: Enable this option if an authentication
+ * daemon will be securing peer link frames.  AMPE is a secured version of Mesh
+ * Peering Management (MPM) and is implemented with the assistance of a
+ * userspace daemon.  When this flag is set, the kernel will send peer
+ * management frames to a userspace daemon that will implement AMPE
+ * functionality (security capabilities selection, key confirmation, and key
+ * management).  When the flag is unset (default), the kernel can autonomously
+ * complete (unsecured) mesh peering without the need of a userspace daemon.
+ *
+ * @NL80211_MESH_SETUP_ATTR_MAX: highest possible mesh setup attribute number
+ * @__NL80211_MESH_SETUP_ATTR_AFTER_LAST: Internal use
+ */
+enum nl80211_mesh_setup_params {
+	__NL80211_MESH_SETUP_INVALID,
+	NL80211_MESH_SETUP_ENABLE_VENDOR_PATH_SEL,
+	NL80211_MESH_SETUP_ENABLE_VENDOR_METRIC,
+	NL80211_MESH_SETUP_IE,
+	NL80211_MESH_SETUP_USERSPACE_AUTH,
+	NL80211_MESH_SETUP_USERSPACE_AMPE,
+
+	/* keep last */
+	__NL80211_MESH_SETUP_ATTR_AFTER_LAST,
+	NL80211_MESH_SETUP_ATTR_MAX = __NL80211_MESH_SETUP_ATTR_AFTER_LAST - 1
+};
+
+/**
  * enum nl80211_txq_attr - TX queue parameter attributes
  * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
  * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
@@ -1936,4 +2424,341 @@
 	NL80211_TX_POWER_FIXED,
 };
 
+/**
+ * enum nl80211_wowlan_packet_pattern_attr - WoWLAN packet pattern attribute
+ * @__NL80211_WOWLAN_PKTPAT_INVALID: invalid number for nested attribute
+ * @NL80211_WOWLAN_PKTPAT_PATTERN: the pattern, values where the mask has
+ *	a zero bit are ignored
+ * @NL80211_WOWLAN_PKTPAT_MASK: pattern mask, must be long enough to have
+ *	a bit for each byte in the pattern. The lowest-order bit corresponds
+ *	to the first byte of the pattern, but the bytes of the pattern are
+ *	in a little-endian-like format, i.e. the 9th byte of the pattern
+ *	corresponds to the lowest-order bit in the second byte of the mask.
+ *	For example: The match 00:xx:00:00:xx:00:00:00:00:xx:xx:xx (where
+ *	xx indicates "don't care") would be represented by a pattern of
+ *	twelve zero bytes, and a mask of "0xed,0x07".
+ *	Note that the pattern matching is done as though frames were not
+ *	802.11 frames but 802.3 frames, i.e. the frame is fully unpacked
+ *	first (including SNAP header unpacking) and then matched.
+ * @NUM_NL80211_WOWLAN_PKTPAT: number of attributes
+ * @MAX_NL80211_WOWLAN_PKTPAT: max attribute number
+ */
+enum nl80211_wowlan_packet_pattern_attr {
+	__NL80211_WOWLAN_PKTPAT_INVALID,
+	NL80211_WOWLAN_PKTPAT_MASK,
+	NL80211_WOWLAN_PKTPAT_PATTERN,
+
+	NUM_NL80211_WOWLAN_PKTPAT,
+	MAX_NL80211_WOWLAN_PKTPAT = NUM_NL80211_WOWLAN_PKTPAT - 1,
+};
+
+/**
+ * struct nl80211_wowlan_pattern_support - pattern support information
+ * @max_patterns: maximum number of patterns supported
+ * @min_pattern_len: minimum length of each pattern
+ * @max_pattern_len: maximum length of each pattern
+ *
+ * This struct is carried in %NL80211_WOWLAN_TRIG_PKT_PATTERN when
+ * that is part of %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED in the
+ * capability information given by the kernel to userspace.
+ */
+struct nl80211_wowlan_pattern_support {
+	__u32 max_patterns;
+	__u32 min_pattern_len;
+	__u32 max_pattern_len;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_wowlan_triggers - WoWLAN trigger definitions
+ * @__NL80211_WOWLAN_TRIG_INVALID: invalid number for nested attributes
+ * @NL80211_WOWLAN_TRIG_ANY: wake up on any activity, do not really put
+ *	the chip into a special state -- works best with chips that have
+ *	support for low-power operation already (flag)
+ * @NL80211_WOWLAN_TRIG_DISCONNECT: wake up on disconnect, the way disconnect
+ *	is detected is implementation-specific (flag)
+ * @NL80211_WOWLAN_TRIG_MAGIC_PKT: wake up on magic packet (6x 0xff, followed
+ *	by 16 repetitions of MAC addr, anywhere in payload) (flag)
+ * @NL80211_WOWLAN_TRIG_PKT_PATTERN: wake up on the specified packet patterns
+ *	which are passed in an array of nested attributes, each nested attribute
+ *	defining a with attributes from &struct nl80211_wowlan_trig_pkt_pattern.
+ *	Each pattern defines a wakeup packet. The matching is done on the MSDU,
+ *	i.e. as though the packet was an 802.3 packet, so the pattern matching
+ *	is done after the packet is converted to the MSDU.
+ *
+ *	In %NL80211_ATTR_WOWLAN_TRIGGERS_SUPPORTED, it is a binary attribute
+ *	carrying a &struct nl80211_wowlan_pattern_support.
+ * @NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED: Not a real trigger, and cannot be
+ *	used when setting, used only to indicate that GTK rekeying is supported
+ *	by the device (flag)
+ * @NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE: wake up on GTK rekey failure (if
+ *	done by the device) (flag)
+ * @NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST: wake up on EAP Identity Request
+ *	packet (flag)
+ * @NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE: wake up on 4-way handshake (flag)
+ * @NL80211_WOWLAN_TRIG_RFKILL_RELEASE: wake up when rfkill is released
+ *	(on devices that have rfkill in the device) (flag)
+ * @NUM_NL80211_WOWLAN_TRIG: number of wake on wireless triggers
+ * @MAX_NL80211_WOWLAN_TRIG: highest wowlan trigger attribute number
+ */
+enum nl80211_wowlan_triggers {
+	__NL80211_WOWLAN_TRIG_INVALID,
+	NL80211_WOWLAN_TRIG_ANY,
+	NL80211_WOWLAN_TRIG_DISCONNECT,
+	NL80211_WOWLAN_TRIG_MAGIC_PKT,
+	NL80211_WOWLAN_TRIG_PKT_PATTERN,
+	NL80211_WOWLAN_TRIG_GTK_REKEY_SUPPORTED,
+	NL80211_WOWLAN_TRIG_GTK_REKEY_FAILURE,
+	NL80211_WOWLAN_TRIG_EAP_IDENT_REQUEST,
+	NL80211_WOWLAN_TRIG_4WAY_HANDSHAKE,
+	NL80211_WOWLAN_TRIG_RFKILL_RELEASE,
+
+	/* keep last */
+	NUM_NL80211_WOWLAN_TRIG,
+	MAX_NL80211_WOWLAN_TRIG = NUM_NL80211_WOWLAN_TRIG - 1
+};
+
+/**
+ * enum nl80211_iface_limit_attrs - limit attributes
+ * @NL80211_IFACE_LIMIT_UNSPEC: (reserved)
+ * @NL80211_IFACE_LIMIT_MAX: maximum number of interfaces that
+ *	can be chosen from this set of interface types (u32)
+ * @NL80211_IFACE_LIMIT_TYPES: nested attribute containing a
+ *	flag attribute for each interface type in this set
+ * @NUM_NL80211_IFACE_LIMIT: number of attributes
+ * @MAX_NL80211_IFACE_LIMIT: highest attribute number
+ */
+enum nl80211_iface_limit_attrs {
+	NL80211_IFACE_LIMIT_UNSPEC,
+	NL80211_IFACE_LIMIT_MAX,
+	NL80211_IFACE_LIMIT_TYPES,
+
+	/* keep last */
+	NUM_NL80211_IFACE_LIMIT,
+	MAX_NL80211_IFACE_LIMIT = NUM_NL80211_IFACE_LIMIT - 1
+};
+
+/**
+ * enum nl80211_if_combination_attrs -- interface combination attributes
+ *
+ * @NL80211_IFACE_COMB_UNSPEC: (reserved)
+ * @NL80211_IFACE_COMB_LIMITS: Nested attributes containing the limits
+ *	for given interface types, see &enum nl80211_iface_limit_attrs.
+ * @NL80211_IFACE_COMB_MAXNUM: u32 attribute giving the total number of
+ *	interfaces that can be created in this group. This number doesn't
+ *	apply to interfaces purely managed in software, which are listed
+ *	in a separate attribute %NL80211_ATTR_INTERFACES_SOFTWARE.
+ * @NL80211_IFACE_COMB_STA_AP_BI_MATCH: flag attribute specifying that
+ *	beacon intervals within this group must be all the same even for
+ *	infrastructure and AP/GO combinations, i.e. the GO(s) must adopt
+ *	the infrastructure network's beacon interval.
+ * @NL80211_IFACE_COMB_NUM_CHANNELS: u32 attribute specifying how many
+ *	different channels may be used within this group.
+ * @NUM_NL80211_IFACE_COMB: number of attributes
+ * @MAX_NL80211_IFACE_COMB: highest attribute number
+ *
+ * Examples:
+ *	limits = [ #{STA} <= 1, #{AP} <= 1 ], matching BI, channels = 1, max = 2
+ *	=> allows an AP and a STA that must match BIs
+ *
+ *	numbers = [ #{AP, P2P-GO} <= 8 ], channels = 1, max = 8
+ *	=> allows 8 of AP/GO
+ *
+ *	numbers = [ #{STA} <= 2 ], channels = 2, max = 2
+ *	=> allows two STAs on different channels
+ *
+ *	numbers = [ #{STA} <= 1, #{P2P-client,P2P-GO} <= 3 ], max = 4
+ *	=> allows a STA plus three P2P interfaces
+ *
+ * The list of these four possiblities could completely be contained
+ * within the %NL80211_ATTR_INTERFACE_COMBINATIONS attribute to indicate
+ * that any of these groups must match.
+ *
+ * "Combinations" of just a single interface will not be listed here,
+ * a single interface of any valid interface type is assumed to always
+ * be possible by itself. This means that implicitly, for each valid
+ * interface type, the following group always exists:
+ *	numbers = [ #{<type>} <= 1 ], channels = 1, max = 1
+ */
+enum nl80211_if_combination_attrs {
+	NL80211_IFACE_COMB_UNSPEC,
+	NL80211_IFACE_COMB_LIMITS,
+	NL80211_IFACE_COMB_MAXNUM,
+	NL80211_IFACE_COMB_STA_AP_BI_MATCH,
+	NL80211_IFACE_COMB_NUM_CHANNELS,
+
+	/* keep last */
+	NUM_NL80211_IFACE_COMB,
+	MAX_NL80211_IFACE_COMB = NUM_NL80211_IFACE_COMB - 1
+};
+
+
+/**
+ * enum nl80211_plink_state - state of a mesh peer link finite state machine
+ *
+ * @NL80211_PLINK_LISTEN: initial state, considered the implicit
+ *	state of non existant mesh peer links
+ * @NL80211_PLINK_OPN_SNT: mesh plink open frame has been sent to
+ *	this mesh peer
+ * @NL80211_PLINK_OPN_RCVD: mesh plink open frame has been received
+ *	from this mesh peer
+ * @NL80211_PLINK_CNF_RCVD: mesh plink confirm frame has been
+ *	received from this mesh peer
+ * @NL80211_PLINK_ESTAB: mesh peer link is established
+ * @NL80211_PLINK_HOLDING: mesh peer link is being closed or cancelled
+ * @NL80211_PLINK_BLOCKED: all frames transmitted from this mesh
+ *	plink are discarded
+ * @NUM_NL80211_PLINK_STATES: number of peer link states
+ * @MAX_NL80211_PLINK_STATES: highest numerical value of plink states
+ */
+enum nl80211_plink_state {
+	NL80211_PLINK_LISTEN,
+	NL80211_PLINK_OPN_SNT,
+	NL80211_PLINK_OPN_RCVD,
+	NL80211_PLINK_CNF_RCVD,
+	NL80211_PLINK_ESTAB,
+	NL80211_PLINK_HOLDING,
+	NL80211_PLINK_BLOCKED,
+
+	/* keep last */
+	NUM_NL80211_PLINK_STATES,
+	MAX_NL80211_PLINK_STATES = NUM_NL80211_PLINK_STATES - 1
+};
+
+#define NL80211_KCK_LEN			16
+#define NL80211_KEK_LEN			16
+#define NL80211_REPLAY_CTR_LEN		8
+
+/**
+ * enum nl80211_rekey_data - attributes for GTK rekey offload
+ * @__NL80211_REKEY_DATA_INVALID: invalid number for nested attributes
+ * @NL80211_REKEY_DATA_KEK: key encryption key (binary)
+ * @NL80211_REKEY_DATA_KCK: key confirmation key (binary)
+ * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary)
+ * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal)
+ * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal)
+ */
+enum nl80211_rekey_data {
+	__NL80211_REKEY_DATA_INVALID,
+	NL80211_REKEY_DATA_KEK,
+	NL80211_REKEY_DATA_KCK,
+	NL80211_REKEY_DATA_REPLAY_CTR,
+
+	/* keep last */
+	NUM_NL80211_REKEY_DATA,
+	MAX_NL80211_REKEY_DATA = NUM_NL80211_REKEY_DATA - 1
+};
+
+/**
+ * enum nl80211_hidden_ssid - values for %NL80211_ATTR_HIDDEN_SSID
+ * @NL80211_HIDDEN_SSID_NOT_IN_USE: do not hide SSID (i.e., broadcast it in
+ *	Beacon frames)
+ * @NL80211_HIDDEN_SSID_ZERO_LEN: hide SSID by using zero-length SSID element
+ *	in Beacon frames
+ * @NL80211_HIDDEN_SSID_ZERO_CONTENTS: hide SSID by using correct length of SSID
+ *	element in Beacon frames but zero out each byte in the SSID
+ */
+enum nl80211_hidden_ssid {
+	NL80211_HIDDEN_SSID_NOT_IN_USE,
+	NL80211_HIDDEN_SSID_ZERO_LEN,
+	NL80211_HIDDEN_SSID_ZERO_CONTENTS
+};
+
+/**
+ * enum nl80211_sta_wme_attr - station WME attributes
+ * @__NL80211_STA_WME_INVALID: invalid number for nested attribute
+ * @NL80211_STA_WME_UAPSD_QUEUES: bitmap of uapsd queues. the format
+ *	is the same as the AC bitmap in the QoS info field.
+ * @NL80211_STA_WME_MAX_SP: max service period. the format is the same
+ *	as the MAX_SP field in the QoS info field (but already shifted down).
+ * @__NL80211_STA_WME_AFTER_LAST: internal
+ * @NL80211_STA_WME_MAX: highest station WME attribute
+ */
+enum nl80211_sta_wme_attr {
+	__NL80211_STA_WME_INVALID,
+	NL80211_STA_WME_UAPSD_QUEUES,
+	NL80211_STA_WME_MAX_SP,
+
+	/* keep last */
+	__NL80211_STA_WME_AFTER_LAST,
+	NL80211_STA_WME_MAX = __NL80211_STA_WME_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_pmksa_candidate_attr - attributes for PMKSA caching candidates
+ * @__NL80211_PMKSA_CANDIDATE_INVALID: invalid number for nested attributes
+ * @NL80211_PMKSA_CANDIDATE_INDEX: candidate index (u32; the smaller, the higher
+ *	priority)
+ * @NL80211_PMKSA_CANDIDATE_BSSID: candidate BSSID (6 octets)
+ * @NL80211_PMKSA_CANDIDATE_PREAUTH: RSN pre-authentication supported (flag)
+ * @NUM_NL80211_PMKSA_CANDIDATE: number of PMKSA caching candidate attributes
+ *	(internal)
+ * @MAX_NL80211_PMKSA_CANDIDATE: highest PMKSA caching candidate attribute
+ *	(internal)
+ */
+enum nl80211_pmksa_candidate_attr {
+	__NL80211_PMKSA_CANDIDATE_INVALID,
+	NL80211_PMKSA_CANDIDATE_INDEX,
+	NL80211_PMKSA_CANDIDATE_BSSID,
+	NL80211_PMKSA_CANDIDATE_PREAUTH,
+
+	/* keep last */
+	NUM_NL80211_PMKSA_CANDIDATE,
+	MAX_NL80211_PMKSA_CANDIDATE = NUM_NL80211_PMKSA_CANDIDATE - 1
+};
+
+/**
+ * enum nl80211_tdls_operation - values for %NL80211_ATTR_TDLS_OPERATION
+ * @NL80211_TDLS_DISCOVERY_REQ: Send a TDLS discovery request
+ * @NL80211_TDLS_SETUP: Setup TDLS link
+ * @NL80211_TDLS_TEARDOWN: Teardown a TDLS link which is already established
+ * @NL80211_TDLS_ENABLE_LINK: Enable TDLS link
+ * @NL80211_TDLS_DISABLE_LINK: Disable TDLS link
+ */
+enum nl80211_tdls_operation {
+	NL80211_TDLS_DISCOVERY_REQ,
+	NL80211_TDLS_SETUP,
+	NL80211_TDLS_TEARDOWN,
+	NL80211_TDLS_ENABLE_LINK,
+	NL80211_TDLS_DISABLE_LINK,
+};
+
+/*
+ * enum nl80211_ap_sme_features - device-integrated AP features
+ * Reserved for future use, no bits are defined in
+ * NL80211_ATTR_DEVICE_AP_SME yet.
+enum nl80211_ap_sme_features {
+};
+ */
+
+/**
+ * enum nl80211_feature_flags - device/driver features
+ * @NL80211_FEATURE_SK_TX_STATUS: This driver supports reflecting back
+ *	TX status to the socket error queue when requested with the
+ *	socket option.
+ */
+enum nl80211_feature_flags {
+	NL80211_FEATURE_SK_TX_STATUS	= 1 << 0,
+};
+
+/**
+ * enum nl80211_probe_resp_offload_support_attr - optional supported
+ *	protocols for probe-response offloading by the driver/FW.
+ *	To be used with the %NL80211_ATTR_PROBE_RESP_OFFLOAD attribute.
+ *	Each enum value represents a bit in the bitmap of supported
+ *	protocols. Typically a subset of probe-requests belonging to a
+ *	supported protocol will be excluded from offload and uploaded
+ *	to the host.
+ *
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS: Support for WPS ver. 1
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2: Support for WPS ver. 2
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P: Support for P2P
+ * @NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U: Support for 802.11u
+ */
+enum nl80211_probe_resp_offload_support_attr {
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS =	1<<0,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 =	1<<1,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P =	1<<2,
+	NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U =	1<<3,
+};
+
 #endif /* __LINUX_NL80211_H */
diff --git a/src/drivers/wireless_copy.h b/src/drivers/wireless_copy.h
deleted file mode 100644
index 201719b..0000000
--- a/src/drivers/wireless_copy.h
+++ /dev/null
@@ -1,1185 +0,0 @@
-/* This is based on Linux Wireless Extensions header file from WIRELESS_EXT 22.
- * I have just removed kernel related headers and added some typedefs etc. to
- * make this easier to include into user space programs.
- * Jouni Malinen, 2005-03-12.
- */
-
-
-/*
- * This file define a set of standard wireless extensions
- *
- * Version :	22	16.3.07
- *
- * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2007 Jean Tourrilhes, All Rights Reserved.
- */
-
-#ifndef _LINUX_WIRELESS_H
-#define _LINUX_WIRELESS_H
-
-/************************** DOCUMENTATION **************************/
-/*
- * Initial APIs (1996 -> onward) :
- * -----------------------------
- * Basically, the wireless extensions are for now a set of standard ioctl
- * call + /proc/net/wireless
- *
- * The entry /proc/net/wireless give statistics and information on the
- * driver.
- * This is better than having each driver having its entry because
- * its centralised and we may remove the driver module safely.
- *
- * Ioctl are used to configure the driver and issue commands.  This is
- * better than command line options of insmod because we may want to
- * change dynamically (while the driver is running) some parameters.
- *
- * The ioctl mechanimsm are copied from standard devices ioctl.
- * We have the list of command plus a structure descibing the
- * data exchanged...
- * Note that to add these ioctl, I was obliged to modify :
- *	# net/core/dev.c (two place + add include)
- *	# net/ipv4/af_inet.c (one place + add include)
- *
- * /proc/net/wireless is a copy of /proc/net/dev.
- * We have a structure for data passed from the driver to /proc/net/wireless
- * Too add this, I've modified :
- *	# net/core/dev.c (two other places)
- *	# include/linux/netdevice.h (one place)
- *	# include/linux/proc_fs.h (one place)
- *
- * New driver API (2002 -> onward) :
- * -------------------------------
- * This file is only concerned with the user space API and common definitions.
- * The new driver API is defined and documented in :
- *	# include/net/iw_handler.h
- *
- * Note as well that /proc/net/wireless implementation has now moved in :
- *	# net/core/wireless.c
- *
- * Wireless Events (2002 -> onward) :
- * --------------------------------
- * Events are defined at the end of this file, and implemented in :
- *	# net/core/wireless.c
- *
- * Other comments :
- * --------------
- * Do not add here things that are redundant with other mechanisms
- * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
- * wireless specific.
- *
- * These wireless extensions are not magic : each driver has to provide
- * support for them...
- *
- * IMPORTANT NOTE : As everything in the kernel, this is very much a
- * work in progress. Contact me if you have ideas of improvements...
- */
-
-/***************************** INCLUDES *****************************/
-
- /* jkm - replaced linux headers with C library headers, added typedefs */
-#if 0
-#include <linux/types.h>		/* for __u* and __s* typedefs */
-#include <linux/socket.h>		/* for "struct sockaddr" et al	*/
-#include <linux/if.h>			/* for IFNAMSIZ and co... */
-#else
-#include <sys/types.h>
-#include <net/if.h>
-#ifndef ANDROID
-typedef __uint32_t __u32;
-typedef __int32_t __s32;
-typedef __uint16_t __u16;
-typedef __int16_t __s16;
-typedef __uint8_t __u8;
-#endif /* ANDROID */
-#ifndef __user
-#define __user
-#endif /* __user */
-#endif
-
-/***************************** VERSION *****************************/
-/*
- * This constant is used to know the availability of the wireless
- * extensions and to know which version of wireless extensions it is
- * (there is some stuff that will be added in the future...)
- * I just plan to increment with each new version.
- */
-#define WIRELESS_EXT	22
-
-/*
- * Changes :
- *
- * V2 to V3
- * --------
- *	Alan Cox start some incompatibles changes. I've integrated a bit more.
- *	- Encryption renamed to Encode to avoid US regulation problems
- *	- Frequency changed from float to struct to avoid problems on old 386
- *
- * V3 to V4
- * --------
- *	- Add sensitivity
- *
- * V4 to V5
- * --------
- *	- Missing encoding definitions in range
- *	- Access points stuff
- *
- * V5 to V6
- * --------
- *	- 802.11 support (ESSID ioctls)
- *
- * V6 to V7
- * --------
- *	- define IW_ESSID_MAX_SIZE and IW_MAX_AP
- *
- * V7 to V8
- * --------
- *	- Changed my e-mail address
- *	- More 802.11 support (nickname, rate, rts, frag)
- *	- List index in frequencies
- *
- * V8 to V9
- * --------
- *	- Support for 'mode of operation' (ad-hoc, managed...)
- *	- Support for unicast and multicast power saving
- *	- Change encoding to support larger tokens (>64 bits)
- *	- Updated iw_params (disable, flags) and use it for NWID
- *	- Extracted iw_point from iwreq for clarity
- *
- * V9 to V10
- * ---------
- *	- Add PM capability to range structure
- *	- Add PM modifier : MAX/MIN/RELATIVE
- *	- Add encoding option : IW_ENCODE_NOKEY
- *	- Add TxPower ioctls (work like TxRate)
- *
- * V10 to V11
- * ----------
- *	- Add WE version in range (help backward/forward compatibility)
- *	- Add retry ioctls (work like PM)
- *
- * V11 to V12
- * ----------
- *	- Add SIOCSIWSTATS to get /proc/net/wireless programatically
- *	- Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
- *	- Add new statistics (frag, retry, beacon)
- *	- Add average quality (for user space calibration)
- *
- * V12 to V13
- * ----------
- *	- Document creation of new driver API.
- *	- Extract union iwreq_data from struct iwreq (for new driver API).
- *	- Rename SIOCSIWNAME as SIOCSIWCOMMIT
- *
- * V13 to V14
- * ----------
- *	- Wireless Events support : define struct iw_event
- *	- Define additional specific event numbers
- *	- Add "addr" and "param" fields in union iwreq_data
- *	- AP scanning stuff (SIOCSIWSCAN and friends)
- *
- * V14 to V15
- * ----------
- *	- Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
- *	- Make struct iw_freq signed (both m & e), add explicit padding
- *	- Add IWEVCUSTOM for driver specific event/scanning token
- *	- Add IW_MAX_GET_SPY for driver returning a lot of addresses
- *	- Add IW_TXPOW_RANGE for range of Tx Powers
- *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
- *	- Add IW_MODE_MONITOR for passive monitor
- *
- * V15 to V16
- * ----------
- *	- Increase the number of bitrates in iw_range to 32 (for 802.11g)
- *	- Increase the number of frequencies in iw_range to 32 (for 802.11b+a)
- *	- Reshuffle struct iw_range for increases, add filler
- *	- Increase IW_MAX_AP to 64 for driver returning a lot of addresses
- *	- Remove IW_MAX_GET_SPY because conflict with enhanced spy support
- *	- Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
- *	- Add IW_ENCODE_TEMP and iw_range->encoding_login_index
- *
- * V16 to V17
- * ----------
- *	- Add flags to frequency -> auto/fixed
- *	- Document (struct iw_quality *)->updated, add new flags (INVALID)
- *	- Wireless Event capability in struct iw_range
- *	- Add support for relative TxPower (yick !)
- *
- * V17 to V18 (From Jouni Malinen <j@w1.fi>)
- * ----------
- *	- Add support for WPA/WPA2
- *	- Add extended encoding configuration (SIOCSIWENCODEEXT and
- *	  SIOCGIWENCODEEXT)
- *	- Add SIOCSIWGENIE/SIOCGIWGENIE
- *	- Add SIOCSIWMLME
- *	- Add SIOCSIWPMKSA
- *	- Add struct iw_range bit field for supported encoding capabilities
- *	- Add optional scan request parameters for SIOCSIWSCAN
- *	- Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA
- *	  related parameters (extensible up to 4096 parameter values)
- *	- Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE,
- *	  IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND
- *
- * V18 to V19
- * ----------
- *	- Remove (struct iw_point *)->pointer from events and streams
- *	- Remove header includes to help user space
- *	- Increase IW_ENCODING_TOKEN_MAX from 32 to 64
- *	- Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros
- *	- Add explicit flag to tell stats are in dBm : IW_QUAL_DBM
- *	- Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros
- *
- * V19 to V20
- * ----------
- *	- RtNetlink requests support (SET/GET)
- *
- * V20 to V21
- * ----------
- *	- Remove (struct net_device *)->get_wireless_stats()
- *	- Change length in ESSID and NICK to strlen() instead of strlen()+1
- *	- Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers
- *	- Power/Retry relative values no longer * 100000
- *	- Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI
- *
- * V21 to V22
- * ----------
- *	- Prevent leaking of kernel space in stream on 64 bits.
- */
-
-/**************************** CONSTANTS ****************************/
-
-/* -------------------------- IOCTL LIST -------------------------- */
-
-/* Wireless Identification */
-#define SIOCSIWCOMMIT	0x8B00		/* Commit pending changes to driver */
-#define SIOCGIWNAME	0x8B01		/* get name == wireless protocol */
-/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
- * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
- * Don't put the name of your driver there, it's useless. */
-
-/* Basic operations */
-#define SIOCSIWNWID	0x8B02		/* set network id (pre-802.11) */
-#define SIOCGIWNWID	0x8B03		/* get network id (the cell) */
-#define SIOCSIWFREQ	0x8B04		/* set channel/frequency (Hz) */
-#define SIOCGIWFREQ	0x8B05		/* get channel/frequency (Hz) */
-#define SIOCSIWMODE	0x8B06		/* set operation mode */
-#define SIOCGIWMODE	0x8B07		/* get operation mode */
-#define SIOCSIWSENS	0x8B08		/* set sensitivity (dBm) */
-#define SIOCGIWSENS	0x8B09		/* get sensitivity (dBm) */
-
-/* Informative stuff */
-#define SIOCSIWRANGE	0x8B0A		/* Unused */
-#define SIOCGIWRANGE	0x8B0B		/* Get range of parameters */
-#define SIOCSIWPRIV	0x8B0C		/* Unused */
-#define SIOCGIWPRIV	0x8B0D		/* get private ioctl interface info */
-#define SIOCSIWSTATS	0x8B0E		/* Unused */
-#define SIOCGIWSTATS	0x8B0F		/* Get /proc/net/wireless stats */
-/* SIOCGIWSTATS is strictly used between user space and the kernel, and
- * is never passed to the driver (i.e. the driver will never see it). */
-
-/* Spy support (statistics per MAC address - used for Mobile IP support) */
-#define SIOCSIWSPY	0x8B10		/* set spy addresses */
-#define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
-#define SIOCSIWTHRSPY	0x8B12		/* set spy threshold (spy event) */
-#define SIOCGIWTHRSPY	0x8B13		/* get spy threshold */
-
-/* Access Point manipulation */
-#define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
-#define SIOCGIWAP	0x8B15		/* get access point MAC addresses */
-#define SIOCGIWAPLIST	0x8B17		/* Deprecated in favor of scanning */
-#define SIOCSIWSCAN	0x8B18		/* trigger scanning (list cells) */
-#define SIOCGIWSCAN	0x8B19		/* get scanning results */
-
-/* 802.11 specific support */
-#define SIOCSIWESSID	0x8B1A		/* set ESSID (network name) */
-#define SIOCGIWESSID	0x8B1B		/* get ESSID */
-#define SIOCSIWNICKN	0x8B1C		/* set node name/nickname */
-#define SIOCGIWNICKN	0x8B1D		/* get node name/nickname */
-/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
- * within the 'iwreq' structure, so we need to use the 'data' member to
- * point to a string in user space, like it is done for RANGE... */
-
-/* Other parameters useful in 802.11 and some other devices */
-#define SIOCSIWRATE	0x8B20		/* set default bit rate (bps) */
-#define SIOCGIWRATE	0x8B21		/* get default bit rate (bps) */
-#define SIOCSIWRTS	0x8B22		/* set RTS/CTS threshold (bytes) */
-#define SIOCGIWRTS	0x8B23		/* get RTS/CTS threshold (bytes) */
-#define SIOCSIWFRAG	0x8B24		/* set fragmentation thr (bytes) */
-#define SIOCGIWFRAG	0x8B25		/* get fragmentation thr (bytes) */
-#define SIOCSIWTXPOW	0x8B26		/* set transmit power (dBm) */
-#define SIOCGIWTXPOW	0x8B27		/* get transmit power (dBm) */
-#define SIOCSIWRETRY	0x8B28		/* set retry limits and lifetime */
-#define SIOCGIWRETRY	0x8B29		/* get retry limits and lifetime */
-
-/* Encoding stuff (scrambling, hardware security, WEP...) */
-#define SIOCSIWENCODE	0x8B2A		/* set encoding token & mode */
-#define SIOCGIWENCODE	0x8B2B		/* get encoding token & mode */
-/* Power saving stuff (power management, unicast and multicast) */
-#define SIOCSIWPOWER	0x8B2C		/* set Power Management settings */
-#define SIOCGIWPOWER	0x8B2D		/* get Power Management settings */
-
-/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM).
- * This ioctl uses struct iw_point and data buffer that includes IE id and len
- * fields. More than one IE may be included in the request. Setting the generic
- * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers
- * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers
- * are required to report the used IE as a wireless event, e.g., when
- * associating with an AP. */
-#define SIOCSIWGENIE	0x8B30		/* set generic IE */
-#define SIOCGIWGENIE	0x8B31		/* get generic IE */
-
-/* WPA : IEEE 802.11 MLME requests */
-#define SIOCSIWMLME	0x8B16		/* request MLME operation; uses
-					 * struct iw_mlme */
-/* WPA : Authentication mode parameters */
-#define SIOCSIWAUTH	0x8B32		/* set authentication mode params */
-#define SIOCGIWAUTH	0x8B33		/* get authentication mode params */
-
-/* WPA : Extended version of encoding configuration */
-#define SIOCSIWENCODEEXT 0x8B34		/* set encoding token & mode */
-#define SIOCGIWENCODEEXT 0x8B35		/* get encoding token & mode */
-
-/* WPA2 : PMKSA cache management */
-#define SIOCSIWPMKSA	0x8B36		/* PMKSA cache operation */
-
-/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
-
-/* These 32 ioctl are wireless device private, for 16 commands.
- * Each driver is free to use them for whatever purpose it chooses,
- * however the driver *must* export the description of those ioctls
- * with SIOCGIWPRIV and *must* use arguments as defined below.
- * If you don't follow those rules, DaveM is going to hate you (reason :
- * it make mixed 32/64bit operation impossible).
- */
-#define SIOCIWFIRSTPRIV	0x8BE0
-#define SIOCIWLASTPRIV	0x8BFF
-/* Previously, we were using SIOCDEVPRIVATE, but we now have our
- * separate range because of collisions with other tools such as
- * 'mii-tool'.
- * We now have 32 commands, so a bit more space ;-).
- * Also, all 'even' commands are only usable by root and don't return the
- * content of ifr/iwr to user (but you are not obliged to use the set/get
- * convention, just use every other two command). More details in iwpriv.c.
- * And I repeat : you are not forced to use them with iwpriv, but you
- * must be compliant with it.
- */
-
-/* ------------------------- IOCTL STUFF ------------------------- */
-
-/* The first and the last (range) */
-#define SIOCIWFIRST	0x8B00
-#define SIOCIWLAST	SIOCIWLASTPRIV		/* 0x8BFF */
-#define IW_IOCTL_IDX(cmd)	((cmd) - SIOCIWFIRST)
-#define IW_HANDLER(id, func)			\
-	[IW_IOCTL_IDX(id)] = func
-
-/* Odd : get (world access), even : set (root access) */
-#define IW_IS_SET(cmd)	(!((cmd) & 0x1))
-#define IW_IS_GET(cmd)	((cmd) & 0x1)
-
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/* Those are *NOT* ioctls, do not issue request on them !!! */
-/* Most events use the same identifier as ioctl requests */
-
-#define IWEVTXDROP	0x8C00		/* Packet dropped to excessive retry */
-#define IWEVQUAL	0x8C01		/* Quality part of statistics (scan) */
-#define IWEVCUSTOM	0x8C02		/* Driver specific ascii string */
-#define IWEVREGISTERED	0x8C03		/* Discovered a new node (AP mode) */
-#define IWEVEXPIRED	0x8C04		/* Expired a node (AP mode) */
-#define IWEVGENIE	0x8C05		/* Generic IE (WPA, RSN, WMM, ..)
-					 * (scan results); This includes id and
-					 * length fields. One IWEVGENIE may
-					 * contain more than one IE. Scan
-					 * results may contain one or more
-					 * IWEVGENIE events. */
-#define IWEVMICHAELMICFAILURE 0x8C06	/* Michael MIC failure
-					 * (struct iw_michaelmicfailure)
-					 */
-#define IWEVASSOCREQIE	0x8C07		/* IEs used in (Re)Association Request.
-					 * The data includes id and length
-					 * fields and may contain more than one
-					 * IE. This event is required in
-					 * Managed mode if the driver
-					 * generates its own WPA/RSN IE. This
-					 * should be sent just before
-					 * IWEVREGISTERED event for the
-					 * association. */
-#define IWEVASSOCRESPIE	0x8C08		/* IEs used in (Re)Association
-					 * Response. The data includes id and
-					 * length fields and may contain more
-					 * than one IE. This may be sent
-					 * between IWEVASSOCREQIE and
-					 * IWEVREGISTERED events for the
-					 * association. */
-#define IWEVPMKIDCAND	0x8C09		/* PMKID candidate for RSN
-					 * pre-authentication
-					 * (struct iw_pmkid_cand) */
-
-#define IWEVFIRST	0x8C00
-#define IW_EVENT_IDX(cmd)	((cmd) - IWEVFIRST)
-
-/* ------------------------- PRIVATE INFO ------------------------- */
-/*
- * The following is used with SIOCGIWPRIV. It allow a driver to define
- * the interface (name, type of data) for its private ioctl.
- * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV
- */
-
-#define IW_PRIV_TYPE_MASK	0x7000	/* Type of arguments */
-#define IW_PRIV_TYPE_NONE	0x0000
-#define IW_PRIV_TYPE_BYTE	0x1000	/* Char as number */
-#define IW_PRIV_TYPE_CHAR	0x2000	/* Char as character */
-#define IW_PRIV_TYPE_INT	0x4000	/* 32 bits int */
-#define IW_PRIV_TYPE_FLOAT	0x5000	/* struct iw_freq */
-#define IW_PRIV_TYPE_ADDR	0x6000	/* struct sockaddr */
-
-#define IW_PRIV_SIZE_FIXED	0x0800	/* Variable or fixed number of args */
-
-#define IW_PRIV_SIZE_MASK	0x07FF	/* Max number of those args */
-
-/*
- * Note : if the number of args is fixed and the size < 16 octets,
- * instead of passing a pointer we will put args in the iwreq struct...
- */
-
-/* ----------------------- OTHER CONSTANTS ----------------------- */
-
-/* Maximum frequencies in the range struct */
-#define IW_MAX_FREQUENCIES	32
-/* Note : if you have something like 80 frequencies,
- * don't increase this constant and don't fill the frequency list.
- * The user will be able to set by channel anyway... */
-
-/* Maximum bit rates in the range struct */
-#define IW_MAX_BITRATES		32
-
-/* Maximum tx powers in the range struct */
-#define IW_MAX_TXPOWER		8
-/* Note : if you more than 8 TXPowers, just set the max and min or
- * a few of them in the struct iw_range. */
-
-/* Maximum of address that you may set with SPY */
-#define IW_MAX_SPY		8
-
-/* Maximum of address that you may get in the
-   list of access points in range */
-#define IW_MAX_AP		64
-
-/* Maximum size of the ESSID and NICKN strings */
-#define IW_ESSID_MAX_SIZE	32
-
-/* Modes of operation */
-#define IW_MODE_AUTO	0	/* Let the driver decides */
-#define IW_MODE_ADHOC	1	/* Single cell network */
-#define IW_MODE_INFRA	2	/* Multi cell network, roaming, ... */
-#define IW_MODE_MASTER	3	/* Synchronisation master or Access Point */
-#define IW_MODE_REPEAT	4	/* Wireless Repeater (forwarder) */
-#define IW_MODE_SECOND	5	/* Secondary master/repeater (backup) */
-#define IW_MODE_MONITOR	6	/* Passive monitor (listen only) */
-#define IW_MODE_MESH	7	/* Mesh (IEEE 802.11s) network */
-
-/* Statistics flags (bitmask in updated) */
-#define IW_QUAL_QUAL_UPDATED	0x01	/* Value was updated since last read */
-#define IW_QUAL_LEVEL_UPDATED	0x02
-#define IW_QUAL_NOISE_UPDATED	0x04
-#define IW_QUAL_ALL_UPDATED	0x07
-#define IW_QUAL_DBM		0x08	/* Level + Noise are dBm */
-#define IW_QUAL_QUAL_INVALID	0x10	/* Driver doesn't provide value */
-#define IW_QUAL_LEVEL_INVALID	0x20
-#define IW_QUAL_NOISE_INVALID	0x40
-#define IW_QUAL_RCPI		0x80	/* Level + Noise are 802.11k RCPI */
-#define IW_QUAL_ALL_INVALID	0x70
-
-/* Frequency flags */
-#define IW_FREQ_AUTO		0x00	/* Let the driver decides */
-#define IW_FREQ_FIXED		0x01	/* Force a specific value */
-
-/* Maximum number of size of encoding token available
- * they are listed in the range structure */
-#define IW_MAX_ENCODING_SIZES	8
-
-/* Maximum size of the encoding token in bytes */
-#define IW_ENCODING_TOKEN_MAX	64	/* 512 bits (for now) */
-
-/* Flags for encoding (along with the token) */
-#define IW_ENCODE_INDEX		0x00FF	/* Token index (if needed) */
-#define IW_ENCODE_FLAGS		0xFF00	/* Flags defined below */
-#define IW_ENCODE_MODE		0xF000	/* Modes defined below */
-#define IW_ENCODE_DISABLED	0x8000	/* Encoding disabled */
-#define IW_ENCODE_ENABLED	0x0000	/* Encoding enabled */
-#define IW_ENCODE_RESTRICTED	0x4000	/* Refuse non-encoded packets */
-#define IW_ENCODE_OPEN		0x2000	/* Accept non-encoded packets */
-#define IW_ENCODE_NOKEY		0x0800  /* Key is write only, so not present */
-#define IW_ENCODE_TEMP		0x0400  /* Temporary key */
-
-/* Power management flags available (along with the value, if any) */
-#define IW_POWER_ON		0x0000	/* No details... */
-#define IW_POWER_TYPE		0xF000	/* Type of parameter */
-#define IW_POWER_PERIOD		0x1000	/* Value is a period/duration of  */
-#define IW_POWER_TIMEOUT	0x2000	/* Value is a timeout (to go asleep) */
-#define IW_POWER_MODE		0x0F00	/* Power Management mode */
-#define IW_POWER_UNICAST_R	0x0100	/* Receive only unicast messages */
-#define IW_POWER_MULTICAST_R	0x0200	/* Receive only multicast messages */
-#define IW_POWER_ALL_R		0x0300	/* Receive all messages though PM */
-#define IW_POWER_FORCE_S	0x0400	/* Force PM procedure for sending unicast */
-#define IW_POWER_REPEATER	0x0800	/* Repeat broadcast messages in PM period */
-#define IW_POWER_MODIFIER	0x000F	/* Modify a parameter */
-#define IW_POWER_MIN		0x0001	/* Value is a minimum  */
-#define IW_POWER_MAX		0x0002	/* Value is a maximum */
-#define IW_POWER_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
-
-/* Transmit Power flags available */
-#define IW_TXPOW_TYPE		0x00FF	/* Type of value */
-#define IW_TXPOW_DBM		0x0000	/* Value is in dBm */
-#define IW_TXPOW_MWATT		0x0001	/* Value is in mW */
-#define IW_TXPOW_RELATIVE	0x0002	/* Value is in arbitrary units */
-#define IW_TXPOW_RANGE		0x1000	/* Range of value between min/max */
-
-/* Retry limits and lifetime flags available */
-#define IW_RETRY_ON		0x0000	/* No details... */
-#define IW_RETRY_TYPE		0xF000	/* Type of parameter */
-#define IW_RETRY_LIMIT		0x1000	/* Maximum number of retries*/
-#define IW_RETRY_LIFETIME	0x2000	/* Maximum duration of retries in us */
-#define IW_RETRY_MODIFIER	0x00FF	/* Modify a parameter */
-#define IW_RETRY_MIN		0x0001	/* Value is a minimum  */
-#define IW_RETRY_MAX		0x0002	/* Value is a maximum */
-#define IW_RETRY_RELATIVE	0x0004	/* Value is not in seconds/ms/us */
-#define IW_RETRY_SHORT		0x0010	/* Value is for short packets  */
-#define IW_RETRY_LONG		0x0020	/* Value is for long packets */
-
-/* Scanning request flags */
-#define IW_SCAN_DEFAULT		0x0000	/* Default scan of the driver */
-#define IW_SCAN_ALL_ESSID	0x0001	/* Scan all ESSIDs */
-#define IW_SCAN_THIS_ESSID	0x0002	/* Scan only this ESSID */
-#define IW_SCAN_ALL_FREQ	0x0004	/* Scan all Frequencies */
-#define IW_SCAN_THIS_FREQ	0x0008	/* Scan only this Frequency */
-#define IW_SCAN_ALL_MODE	0x0010	/* Scan all Modes */
-#define IW_SCAN_THIS_MODE	0x0020	/* Scan only this Mode */
-#define IW_SCAN_ALL_RATE	0x0040	/* Scan all Bit-Rates */
-#define IW_SCAN_THIS_RATE	0x0080	/* Scan only this Bit-Rate */
-/* struct iw_scan_req scan_type */
-#define IW_SCAN_TYPE_ACTIVE 0
-#define IW_SCAN_TYPE_PASSIVE 1
-/* Maximum size of returned data */
-#define IW_SCAN_MAX_DATA	4096	/* In bytes */
-
-/* Scan capability flags - in (struct iw_range *)->scan_capa */
-#define IW_SCAN_CAPA_NONE		0x00
-#define IW_SCAN_CAPA_ESSID		0x01
-#define IW_SCAN_CAPA_BSSID		0x02
-#define IW_SCAN_CAPA_CHANNEL	0x04
-#define IW_SCAN_CAPA_MODE		0x08
-#define IW_SCAN_CAPA_RATE		0x10
-#define IW_SCAN_CAPA_TYPE		0x20
-#define IW_SCAN_CAPA_TIME		0x40
-
-/* Max number of char in custom event - use multiple of them if needed */
-#define IW_CUSTOM_MAX		256	/* In bytes */
-
-/* Generic information element */
-#define IW_GENERIC_IE_MAX	1024
-
-/* MLME requests (SIOCSIWMLME / struct iw_mlme) */
-#define IW_MLME_DEAUTH		0
-#define IW_MLME_DISASSOC	1
-#define IW_MLME_AUTH		2
-#define IW_MLME_ASSOC		3
-
-/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */
-#define IW_AUTH_INDEX		0x0FFF
-#define IW_AUTH_FLAGS		0xF000
-/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095)
- * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the
- * parameter that is being set/get to; value will be read/written to
- * struct iw_param value field) */
-#define IW_AUTH_WPA_VERSION		0
-#define IW_AUTH_CIPHER_PAIRWISE		1
-#define IW_AUTH_CIPHER_GROUP		2
-#define IW_AUTH_KEY_MGMT		3
-#define IW_AUTH_TKIP_COUNTERMEASURES	4
-#define IW_AUTH_DROP_UNENCRYPTED	5
-#define IW_AUTH_80211_AUTH_ALG		6
-#define IW_AUTH_WPA_ENABLED		7
-#define IW_AUTH_RX_UNENCRYPTED_EAPOL	8
-#define IW_AUTH_ROAMING_CONTROL		9
-#define IW_AUTH_PRIVACY_INVOKED		10
-#define IW_AUTH_CIPHER_GROUP_MGMT	11
-#define IW_AUTH_MFP			12
-
-/* IW_AUTH_WPA_VERSION values (bit field) */
-#define IW_AUTH_WPA_VERSION_DISABLED	0x00000001
-#define IW_AUTH_WPA_VERSION_WPA		0x00000002
-#define IW_AUTH_WPA_VERSION_WPA2	0x00000004
-
-/* IW_AUTH_PAIRWISE_CIPHER, IW_AUTH_GROUP_CIPHER, and IW_AUTH_CIPHER_GROUP_MGMT
- * values (bit field) */
-#define IW_AUTH_CIPHER_NONE	0x00000001
-#define IW_AUTH_CIPHER_WEP40	0x00000002
-#define IW_AUTH_CIPHER_TKIP	0x00000004
-#define IW_AUTH_CIPHER_CCMP	0x00000008
-#define IW_AUTH_CIPHER_WEP104	0x00000010
-#define IW_AUTH_CIPHER_AES_CMAC	0x00000020
-
-/* IW_AUTH_KEY_MGMT values (bit field) */
-#define IW_AUTH_KEY_MGMT_802_1X	1
-#define IW_AUTH_KEY_MGMT_PSK	2
-
-/* IW_AUTH_80211_AUTH_ALG values (bit field) */
-#define IW_AUTH_ALG_OPEN_SYSTEM	0x00000001
-#define IW_AUTH_ALG_SHARED_KEY	0x00000002
-#define IW_AUTH_ALG_LEAP	0x00000004
-
-/* IW_AUTH_ROAMING_CONTROL values */
-#define IW_AUTH_ROAMING_ENABLE	0	/* driver/firmware based roaming */
-#define IW_AUTH_ROAMING_DISABLE	1	/* user space program used for roaming
-					 * control */
-
-/* IW_AUTH_MFP (management frame protection) values */
-#define IW_AUTH_MFP_DISABLED	0	/* MFP disabled */
-#define IW_AUTH_MFP_OPTIONAL	1	/* MFP optional */
-#define IW_AUTH_MFP_REQUIRED	2	/* MFP required */
-
-/* SIOCSIWENCODEEXT definitions */
-#define IW_ENCODE_SEQ_MAX_SIZE	8
-/* struct iw_encode_ext ->alg */
-#define IW_ENCODE_ALG_NONE	0
-#define IW_ENCODE_ALG_WEP	1
-#define IW_ENCODE_ALG_TKIP	2
-#define IW_ENCODE_ALG_CCMP	3
-#define IW_ENCODE_ALG_PMK	4
-#define IW_ENCODE_ALG_AES_CMAC	5
-/* struct iw_encode_ext ->ext_flags */
-#define IW_ENCODE_EXT_TX_SEQ_VALID	0x00000001
-#define IW_ENCODE_EXT_RX_SEQ_VALID	0x00000002
-#define IW_ENCODE_EXT_GROUP_KEY		0x00000004
-#define IW_ENCODE_EXT_SET_TX_KEY	0x00000008
-
-/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */
-#define IW_MICFAILURE_KEY_ID	0x00000003 /* Key ID 0..3 */
-#define IW_MICFAILURE_GROUP	0x00000004
-#define IW_MICFAILURE_PAIRWISE	0x00000008
-#define IW_MICFAILURE_STAKEY	0x00000010
-#define IW_MICFAILURE_COUNT	0x00000060 /* 1 or 2 (0 = count not supported)
-					    */
-
-/* Bit field values for enc_capa in struct iw_range */
-#define IW_ENC_CAPA_WPA		0x00000001
-#define IW_ENC_CAPA_WPA2	0x00000002
-#define IW_ENC_CAPA_CIPHER_TKIP	0x00000004
-#define IW_ENC_CAPA_CIPHER_CCMP	0x00000008
-#define IW_ENC_CAPA_4WAY_HANDSHAKE	0x00000010
-
-/* Event capability macros - in (struct iw_range *)->event_capa
- * Because we have more than 32 possible events, we use an array of
- * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
-#define IW_EVENT_CAPA_BASE(cmd)		((cmd >= SIOCIWFIRSTPRIV) ? \
-					 (cmd - SIOCIWFIRSTPRIV + 0x60) : \
-					 (cmd - SIOCIWFIRST))
-#define IW_EVENT_CAPA_INDEX(cmd)	(IW_EVENT_CAPA_BASE(cmd) >> 5)
-#define IW_EVENT_CAPA_MASK(cmd)		(1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
-/* Event capability constants - event autogenerated by the kernel
- * This list is valid for most 802.11 devices, customise as needed... */
-#define IW_EVENT_CAPA_K_0	(IW_EVENT_CAPA_MASK(0x8B04) | \
-				 IW_EVENT_CAPA_MASK(0x8B06) | \
-				 IW_EVENT_CAPA_MASK(0x8B1A))
-#define IW_EVENT_CAPA_K_1	(IW_EVENT_CAPA_MASK(0x8B2A))
-/* "Easy" macro to set events in iw_range (less efficient) */
-#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
-#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
-
-
-/****************************** TYPES ******************************/
-
-/* --------------------------- SUBTYPES --------------------------- */
-/*
- *	Generic format for most parameters that fit in an int
- */
-struct	iw_param
-{
-  __s32		value;		/* The value of the parameter itself */
-  __u8		fixed;		/* Hardware should not use auto select */
-  __u8		disabled;	/* Disable the feature */
-  __u16		flags;		/* Various specifc flags (if any) */
-};
-
-/*
- *	For all data larger than 16 octets, we need to use a
- *	pointer to memory allocated in user space.
- */
-struct	iw_point
-{
-  void __user	*pointer;	/* Pointer to the data  (in user space) */
-  __u16		length;		/* number of fields or size in bytes */
-  __u16		flags;		/* Optional params */
-};
-
-#ifdef __KERNEL__
-#ifdef CONFIG_COMPAT
-
-#include <linux/compat.h>
-
-struct compat_iw_point {
-	compat_caddr_t pointer;
-	__u16 length;
-	__u16 flags;
-};
-#endif
-#endif
-
-/*
- *	A frequency
- *	For numbers lower than 10^9, we encode the number in 'm' and
- *	set 'e' to 0
- *	For number greater than 10^9, we divide it by the lowest power
- *	of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')...
- *	The power of 10 is in 'e', the result of the division is in 'm'.
- */
-struct	iw_freq
-{
-	__s32		m;		/* Mantissa */
-	__s16		e;		/* Exponent */
-	__u8		i;		/* List index (when in range struct) */
-	__u8		flags;		/* Flags (fixed/auto) */
-};
-
-/*
- *	Quality of the link
- */
-struct	iw_quality
-{
-	__u8		qual;		/* link quality (%retries, SNR,
-					   %missed beacons or better...) */
-	__u8		level;		/* signal level (dBm) */
-	__u8		noise;		/* noise level (dBm) */
-	__u8		updated;	/* Flags to know if updated */
-};
-
-/*
- *	Packet discarded in the wireless adapter due to
- *	"wireless" specific problems...
- *	Note : the list of counter and statistics in net_device_stats
- *	is already pretty exhaustive, and you should use that first.
- *	This is only additional stats...
- */
-struct	iw_discarded
-{
-	__u32		nwid;		/* Rx : Wrong nwid/essid */
-	__u32		code;		/* Rx : Unable to code/decode (WEP) */
-	__u32		fragment;	/* Rx : Can't perform MAC reassembly */
-	__u32		retries;	/* Tx : Max MAC retries num reached */
-	__u32		misc;		/* Others cases */
-};
-
-/*
- *	Packet/Time period missed in the wireless adapter due to
- *	"wireless" specific problems...
- */
-struct	iw_missed
-{
-	__u32		beacon;		/* Missed beacons/superframe */
-};
-
-/*
- *	Quality range (for spy threshold)
- */
-struct	iw_thrspy
-{
-	struct sockaddr		addr;		/* Source address (hw/mac) */
-	struct iw_quality	qual;		/* Quality of the link */
-	struct iw_quality	low;		/* Low threshold */
-	struct iw_quality	high;		/* High threshold */
-};
-
-/*
- *	Optional data for scan request
- *
- *	Note: these optional parameters are controlling parameters for the
- *	scanning behavior, these do not apply to getting scan results
- *	(SIOCGIWSCAN). Drivers are expected to keep a local BSS table and
- *	provide a merged results with all BSSes even if the previous scan
- *	request limited scanning to a subset, e.g., by specifying an SSID.
- *	Especially, scan results are required to include an entry for the
- *	current BSS if the driver is in Managed mode and associated with an AP.
- */
-struct	iw_scan_req
-{
-	__u8		scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */
-	__u8		essid_len;
-	__u8		num_channels; /* num entries in channel_list;
-				       * 0 = scan all allowed channels */
-	__u8		flags; /* reserved as padding; use zero, this may
-				* be used in the future for adding flags
-				* to request different scan behavior */
-	struct sockaddr	bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or
-				* individual address of a specific BSS */
-
-	/*
-	 * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using
-	 * the current ESSID. This allows scan requests for specific ESSID
-	 * without having to change the current ESSID and potentially breaking
-	 * the current association.
-	 */
-	__u8		essid[IW_ESSID_MAX_SIZE];
-
-	/*
-	 * Optional parameters for changing the default scanning behavior.
-	 * These are based on the MLME-SCAN.request from IEEE Std 802.11.
-	 * TU is 1.024 ms. If these are set to 0, driver is expected to use
-	 * reasonable default values. min_channel_time defines the time that
-	 * will be used to wait for the first reply on each channel. If no
-	 * replies are received, next channel will be scanned after this. If
-	 * replies are received, total time waited on the channel is defined by
-	 * max_channel_time.
-	 */
-	__u32		min_channel_time; /* in TU */
-	__u32		max_channel_time; /* in TU */
-
-	struct iw_freq	channel_list[IW_MAX_FREQUENCIES];
-};
-
-/* ------------------------- WPA SUPPORT ------------------------- */
-
-/*
- *	Extended data structure for get/set encoding (this is used with
- *	SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_*
- *	flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and
- *	only the data contents changes (key data -> this structure, including
- *	key data).
- *
- *	If the new key is the first group key, it will be set as the default
- *	TX key. Otherwise, default TX key index is only changed if
- *	IW_ENCODE_EXT_SET_TX_KEY flag is set.
- *
- *	Key will be changed with SIOCSIWENCODEEXT in all cases except for
- *	special "change TX key index" operation which is indicated by setting
- *	key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY.
- *
- *	tx_seq/rx_seq are only used when respective
- *	IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal
- *	TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start
- *	TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally
- *	used only by an Authenticator (AP or an IBSS station) to get the
- *	current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and
- *	RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for
- *	debugging/testing.
- */
-struct	iw_encode_ext
-{
-	__u32		ext_flags; /* IW_ENCODE_EXT_* */
-	__u8		tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-	__u8		rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-	struct sockaddr	addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast
-			       * (group) keys or unicast address for
-			       * individual keys */
-	__u16		alg; /* IW_ENCODE_ALG_* */
-	__u16		key_len;
-	__u8		key[0];
-};
-
-/* SIOCSIWMLME data */
-struct	iw_mlme
-{
-	__u16		cmd; /* IW_MLME_* */
-	__u16		reason_code;
-	struct sockaddr	addr;
-};
-
-/* SIOCSIWPMKSA data */
-#define IW_PMKSA_ADD		1
-#define IW_PMKSA_REMOVE		2
-#define IW_PMKSA_FLUSH		3
-
-#define IW_PMKID_LEN	16
-
-struct	iw_pmksa
-{
-	__u32		cmd; /* IW_PMKSA_* */
-	struct sockaddr	bssid;
-	__u8		pmkid[IW_PMKID_LEN];
-};
-
-/* IWEVMICHAELMICFAILURE data */
-struct	iw_michaelmicfailure
-{
-	__u32		flags;
-	struct sockaddr	src_addr;
-	__u8		tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
-};
-
-/* IWEVPMKIDCAND data */
-#define IW_PMKID_CAND_PREAUTH	0x00000001 /* RNS pre-authentication enabled */
-struct	iw_pmkid_cand
-{
-	__u32		flags; /* IW_PMKID_CAND_* */
-	__u32		index; /* the smaller the index, the higher the
-				* priority */
-	struct sockaddr	bssid;
-};
-
-/* ------------------------ WIRELESS STATS ------------------------ */
-/*
- * Wireless statistics (used for /proc/net/wireless)
- */
-struct	iw_statistics
-{
-	__u16		status;		/* Status
-					 * - device dependent for now */
-
-	struct iw_quality	qual;		/* Quality of the link
-						 * (instant/mean/max) */
-	struct iw_discarded	discard;	/* Packet discarded counts */
-	struct iw_missed	miss;		/* Packet missed counts */
-};
-
-/* ------------------------ IOCTL REQUEST ------------------------ */
-/*
- * This structure defines the payload of an ioctl, and is used 
- * below.
- *
- * Note that this structure should fit on the memory footprint
- * of iwreq (which is the same as ifreq), which mean a max size of
- * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
- * You should check this when increasing the structures defined
- * above in this file...
- */
-union	iwreq_data
-{
-	/* Config - generic */
-	char		name[IFNAMSIZ];
-	/* Name : used to verify the presence of  wireless extensions.
-	 * Name of the protocol/provider... */
-
-	struct iw_point	essid;		/* Extended network name */
-	struct iw_param	nwid;		/* network id (or domain - the cell) */
-	struct iw_freq	freq;		/* frequency or channel :
-					 * 0-1000 = channel
-					 * > 1000 = frequency in Hz */
-
-	struct iw_param	sens;		/* signal level threshold */
-	struct iw_param	bitrate;	/* default bit rate */
-	struct iw_param	txpower;	/* default transmit power */
-	struct iw_param	rts;		/* RTS threshold threshold */
-	struct iw_param	frag;		/* Fragmentation threshold */
-	__u32		mode;		/* Operation mode */
-	struct iw_param	retry;		/* Retry limits & lifetime */
-
-	struct iw_point	encoding;	/* Encoding stuff : tokens */
-	struct iw_param	power;		/* PM duration/timeout */
-	struct iw_quality qual;		/* Quality part of statistics */
-
-	struct sockaddr	ap_addr;	/* Access point address */
-	struct sockaddr	addr;		/* Destination address (hw/mac) */
-
-	struct iw_param	param;		/* Other small parameters */
-	struct iw_point	data;		/* Other large parameters */
-};
-
-/*
- * The structure to exchange data for ioctl.
- * This structure is the same as 'struct ifreq', but (re)defined for
- * convenience...
- * Do I need to remind you about structure size (32 octets) ?
- */
-struct	iwreq 
-{
-	union
-	{
-		char	ifrn_name[IFNAMSIZ];	/* if name, e.g. "eth0" */
-	} ifr_ifrn;
-
-	/* Data part (defined just above) */
-	union	iwreq_data	u;
-};
-
-/* -------------------------- IOCTL DATA -------------------------- */
-/*
- *	For those ioctl which want to exchange mode data that what could
- *	fit in the above structure...
- */
-
-/*
- *	Range of parameters
- */
-
-struct	iw_range
-{
-	/* Informative stuff (to choose between different interface) */
-	__u32		throughput;	/* To give an idea... */
-	/* In theory this value should be the maximum benchmarked
-	 * TCP/IP throughput, because with most of these devices the
-	 * bit rate is meaningless (overhead an co) to estimate how
-	 * fast the connection will go and pick the fastest one.
-	 * I suggest people to play with Netperf or any benchmark...
-	 */
-
-	/* NWID (or domain id) */
-	__u32		min_nwid;	/* Minimal NWID we are able to set */
-	__u32		max_nwid;	/* Maximal NWID we are able to set */
-
-	/* Old Frequency (backward compat - moved lower ) */
-	__u16		old_num_channels;
-	__u8		old_num_frequency;
-
-	/* Scan capabilities */
-	__u8		scan_capa; 	/* IW_SCAN_CAPA_* bit field */
-
-	/* Wireless event capability bitmasks */
-	__u32		event_capa[6];
-
-	/* signal level threshold range */
-	__s32		sensitivity;
-
-	/* Quality of link & SNR stuff */
-	/* Quality range (link, level, noise)
-	 * If the quality is absolute, it will be in the range [0 ; max_qual],
-	 * if the quality is dBm, it will be in the range [max_qual ; 0].
-	 * Don't forget that we use 8 bit arithmetics... */
-	struct iw_quality	max_qual;	/* Quality of the link */
-	/* This should contain the average/typical values of the quality
-	 * indicator. This should be the threshold between a "good" and
-	 * a "bad" link (example : monitor going from green to orange).
-	 * Currently, user space apps like quality monitors don't have any
-	 * way to calibrate the measurement. With this, they can split
-	 * the range between 0 and max_qual in different quality level
-	 * (using a geometric subdivision centered on the average).
-	 * I expect that people doing the user space apps will feedback
-	 * us on which value we need to put in each driver... */
-	struct iw_quality	avg_qual;	/* Quality of the link */
-
-	/* Rates */
-	__u8		num_bitrates;	/* Number of entries in the list */
-	__s32		bitrate[IW_MAX_BITRATES];	/* list, in bps */
-
-	/* RTS threshold */
-	__s32		min_rts;	/* Minimal RTS threshold */
-	__s32		max_rts;	/* Maximal RTS threshold */
-
-	/* Frag threshold */
-	__s32		min_frag;	/* Minimal frag threshold */
-	__s32		max_frag;	/* Maximal frag threshold */
-
-	/* Power Management duration & timeout */
-	__s32		min_pmp;	/* Minimal PM period */
-	__s32		max_pmp;	/* Maximal PM period */
-	__s32		min_pmt;	/* Minimal PM timeout */
-	__s32		max_pmt;	/* Maximal PM timeout */
-	__u16		pmp_flags;	/* How to decode max/min PM period */
-	__u16		pmt_flags;	/* How to decode max/min PM timeout */
-	__u16		pm_capa;	/* What PM options are supported */
-
-	/* Encoder stuff */
-	__u16	encoding_size[IW_MAX_ENCODING_SIZES];	/* Different token sizes */
-	__u8	num_encoding_sizes;	/* Number of entry in the list */
-	__u8	max_encoding_tokens;	/* Max number of tokens */
-	/* For drivers that need a "login/passwd" form */
-	__u8	encoding_login_index;	/* token index for login token */
-
-	/* Transmit power */
-	__u16		txpower_capa;	/* What options are supported */
-	__u8		num_txpower;	/* Number of entries in the list */
-	__s32		txpower[IW_MAX_TXPOWER];	/* list, in bps */
-
-	/* Wireless Extension version info */
-	__u8		we_version_compiled;	/* Must be WIRELESS_EXT */
-	__u8		we_version_source;	/* Last update of source */
-
-	/* Retry limits and lifetime */
-	__u16		retry_capa;	/* What retry options are supported */
-	__u16		retry_flags;	/* How to decode max/min retry limit */
-	__u16		r_time_flags;	/* How to decode max/min retry life */
-	__s32		min_retry;	/* Minimal number of retries */
-	__s32		max_retry;	/* Maximal number of retries */
-	__s32		min_r_time;	/* Minimal retry lifetime */
-	__s32		max_r_time;	/* Maximal retry lifetime */
-
-	/* Frequency */
-	__u16		num_channels;	/* Number of channels [0; num - 1] */
-	__u8		num_frequency;	/* Number of entry in the list */
-	struct iw_freq	freq[IW_MAX_FREQUENCIES];	/* list */
-	/* Note : this frequency list doesn't need to fit channel numbers,
-	 * because each entry contain its channel index */
-
-	__u32		enc_capa;	/* IW_ENC_CAPA_* bit field */
-};
-
-/*
- * Private ioctl interface information
- */
- 
-struct	iw_priv_args
-{
-	__u32		cmd;		/* Number of the ioctl to issue */
-	__u16		set_args;	/* Type and number of args */
-	__u16		get_args;	/* Type and number of args */
-	char		name[IFNAMSIZ];	/* Name of the extension */
-};
-
-/* ----------------------- WIRELESS EVENTS ----------------------- */
-/*
- * Wireless events are carried through the rtnetlink socket to user
- * space. They are encapsulated in the IFLA_WIRELESS field of
- * a RTM_NEWLINK message.
- */
-
-/*
- * A Wireless Event. Contains basically the same data as the ioctl...
- */
-struct iw_event
-{
-	__u16		len;			/* Real length of this stuff */
-	__u16		cmd;			/* Wireless IOCTL */
-	union iwreq_data	u;		/* IOCTL fixed payload */
-};
-
-/* Size of the Event prefix (including padding and alignement junk) */
-#define IW_EV_LCP_LEN	(sizeof(struct iw_event) - sizeof(union iwreq_data))
-/* Size of the various events */
-#define IW_EV_CHAR_LEN	(IW_EV_LCP_LEN + IFNAMSIZ)
-#define IW_EV_UINT_LEN	(IW_EV_LCP_LEN + sizeof(__u32))
-#define IW_EV_FREQ_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_freq))
-#define IW_EV_PARAM_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_param))
-#define IW_EV_ADDR_LEN	(IW_EV_LCP_LEN + sizeof(struct sockaddr))
-#define IW_EV_QUAL_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_quality))
-
-/* iw_point events are special. First, the payload (extra data) come at
- * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second,
- * we omit the pointer, so start at an offset. */
-#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \
-			  (char *) NULL)
-#define IW_EV_POINT_LEN	(IW_EV_LCP_LEN + sizeof(struct iw_point) - \
-			 IW_EV_POINT_OFF)
-
-#ifdef __KERNEL__
-#ifdef CONFIG_COMPAT
-struct __compat_iw_event {
-	__u16		len;			/* Real length of this stuff */
-	__u16		cmd;			/* Wireless IOCTL */
-	compat_caddr_t	pointer;
-};
-#define IW_EV_COMPAT_LCP_LEN offsetof(struct __compat_iw_event, pointer)
-#define IW_EV_COMPAT_POINT_OFF offsetof(struct compat_iw_point, length)
-
-/* Size of the various events for compat */
-#define IW_EV_COMPAT_CHAR_LEN	(IW_EV_COMPAT_LCP_LEN + IFNAMSIZ)
-#define IW_EV_COMPAT_UINT_LEN	(IW_EV_COMPAT_LCP_LEN + sizeof(__u32))
-#define IW_EV_COMPAT_FREQ_LEN	(IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_freq))
-#define IW_EV_COMPAT_PARAM_LEN	(IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_param))
-#define IW_EV_COMPAT_ADDR_LEN	(IW_EV_COMPAT_LCP_LEN + sizeof(struct sockaddr))
-#define IW_EV_COMPAT_QUAL_LEN	(IW_EV_COMPAT_LCP_LEN + sizeof(struct iw_quality))
-#define IW_EV_COMPAT_POINT_LEN	\
-	(IW_EV_COMPAT_LCP_LEN + sizeof(struct compat_iw_point) - \
-	 IW_EV_COMPAT_POINT_OFF)
-#endif
-#endif
-
-/* Size of the Event prefix when packed in stream */
-#define IW_EV_LCP_PK_LEN	(4)
-/* Size of the various events when packed in stream */
-#define IW_EV_CHAR_PK_LEN	(IW_EV_LCP_PK_LEN + IFNAMSIZ)
-#define IW_EV_UINT_PK_LEN	(IW_EV_LCP_PK_LEN + sizeof(__u32))
-#define IW_EV_FREQ_PK_LEN	(IW_EV_LCP_PK_LEN + sizeof(struct iw_freq))
-#define IW_EV_PARAM_PK_LEN	(IW_EV_LCP_PK_LEN + sizeof(struct iw_param))
-#define IW_EV_ADDR_PK_LEN	(IW_EV_LCP_PK_LEN + sizeof(struct sockaddr))
-#define IW_EV_QUAL_PK_LEN	(IW_EV_LCP_PK_LEN + sizeof(struct iw_quality))
-#define IW_EV_POINT_PK_LEN	(IW_EV_LCP_PK_LEN + 4)
-
-#endif	/* _LINUX_WIRELESS_H */
diff --git a/src/eap_common/eap_fast_common.c b/src/eap_common/eap_fast_common.c
index 4de34a8..d3406f3 100644
--- a/src/eap_common/eap_fast_common.c
+++ b/src/eap_common/eap_fast_common.c
@@ -133,9 +133,9 @@
 
 	wpa_hexdump_key(MSG_MSGDUMP, "EAP-FAST: master_secret for key "
 			"expansion", keys.master_key, keys.master_key_len);
-	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, rnd, keys.client_random_len +
-		    keys.server_random_len, out, block_size + len))
+	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+			     label, rnd, keys.client_random_len +
+			     keys.server_random_len, out, block_size + len))
 		goto fail;
 	os_free(rnd);
 	os_memmove(out, out + block_size, len);
diff --git a/src/eap_common/eap_peap_common.c b/src/eap_common/eap_peap_common.c
index 3a64b8e..8a701d2 100644
--- a/src/eap_common/eap_peap_common.c
+++ b/src/eap_common/eap_peap_common.c
@@ -1,6 +1,6 @@
 /*
  * EAP-PEAP common routines
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -18,9 +18,9 @@
 #include "crypto/sha1.h"
 #include "eap_peap_common.h"
 
-void peap_prfplus(int version, const u8 *key, size_t key_len,
-		  const char *label, const u8 *seed, size_t seed_len,
-		  u8 *buf, size_t buf_len)
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+		 const char *label, const u8 *seed, size_t seed_len,
+		 u8 *buf, size_t buf_len)
 {
 	unsigned char counter = 0;
 	size_t pos, plen;
@@ -75,7 +75,8 @@
 	while (pos < buf_len) {
 		counter++;
 		plen = buf_len - pos;
-		hmac_sha1_vector(key, key_len, 5, addr, len, hash);
+		if (hmac_sha1_vector(key, key_len, 5, addr, len, hash) < 0)
+			return -1;
 		if (plen >= SHA1_MAC_LEN) {
 			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
 			pos += SHA1_MAC_LEN;
@@ -85,4 +86,6 @@
 		}
 		len[0] = SHA1_MAC_LEN;
 	}
+
+	return 0;
 }
diff --git a/src/eap_common/eap_peap_common.h b/src/eap_common/eap_peap_common.h
index f59afb0..f182078 100644
--- a/src/eap_common/eap_peap_common.h
+++ b/src/eap_common/eap_peap_common.h
@@ -1,6 +1,6 @@
 /*
  * EAP-PEAP common routines
- * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -15,8 +15,8 @@
 #ifndef EAP_PEAP_COMMON_H
 #define EAP_PEAP_COMMON_H
 
-void peap_prfplus(int version, const u8 *key, size_t key_len,
-		  const char *label, const u8 *seed, size_t seed_len,
-		  u8 *buf, size_t buf_len);
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+		 const char *label, const u8 *seed, size_t seed_len,
+		 u8 *buf, size_t buf_len);
 
 #endif /* EAP_PEAP_COMMON_H */
diff --git a/src/eap_common/eap_pwd_common.c b/src/eap_common/eap_pwd_common.c
index c24b146..0dbdff2 100644
--- a/src/eap_common/eap_pwd_common.c
+++ b/src/eap_common/eap_pwd_common.c
@@ -75,8 +75,8 @@
 
 	/* since we're expanding to a bit length, mask off the excess */
 	if (resultbitlen % 8) {
-		mask >>= ((resultbytelen * 8) - resultbitlen);
-		result[0] &= mask;
+		mask <<= (8 - (resultbitlen % 8));
+		result[resultbytelen - 1] &= mask;
 	}
 }
 
@@ -189,6 +189,18 @@
 			    prfbuf, primebitlen);
 
 		BN_bin2bn(prfbuf, primebytelen, x_candidate);
+
+		/*
+		 * eap_pwd_kdf() returns a string of bits 0..primebitlen but
+		 * BN_bin2bn will treat that string of bits as a big endian
+		 * number. If the primebitlen is not an even multiple of 8
+		 * then excessive bits-- those _after_ primebitlen-- so now
+		 * we have to shift right the amount we masked off.
+		 */
+		if (primebitlen % 8)
+			BN_rshift(x_candidate, x_candidate,
+				  (8 - (primebitlen % 8)));
+
 		if (BN_ucmp(x_candidate, grp->prime) >= 0)
 			continue;
 
@@ -272,6 +284,7 @@
 	u8 mk[SHA256_DIGEST_LENGTH], *cruft;
 	u8 session_id[SHA256_DIGEST_LENGTH + 1];
 	u8 msk_emsk[EAP_MSK_LEN + EAP_EMSK_LEN];
+	int offset;
 
 	if ((cruft = os_malloc(BN_num_bytes(grp->prime))) == NULL)
 		return -1;
@@ -283,16 +296,21 @@
 	session_id[0] = EAP_TYPE_PWD;
 	H_Init(&ctx);
 	H_Update(&ctx, (u8 *)ciphersuite, sizeof(u32));
-	BN_bn2bin(peer_scalar, cruft);
+	offset = BN_num_bytes(grp->order) - BN_num_bytes(peer_scalar);
+	os_memset(cruft, 0, BN_num_bytes(grp->prime));
+	BN_bn2bin(peer_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(grp->order));
-	BN_bn2bin(server_scalar, cruft);
+	offset = BN_num_bytes(grp->order) - BN_num_bytes(server_scalar);
+	os_memset(cruft, 0, BN_num_bytes(grp->prime));
+	BN_bn2bin(server_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(grp->order));
 	H_Final(&ctx, &session_id[1]);
 
 	/* then compute MK = H(k | commit-peer | commit-server) */
 	H_Init(&ctx);
+	offset = BN_num_bytes(grp->prime) - BN_num_bytes(k);
 	os_memset(cruft, 0, BN_num_bytes(grp->prime));
-	BN_bn2bin(k, cruft);
+	BN_bn2bin(k, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(grp->prime));
 	H_Update(&ctx, commit_peer, SHA256_DIGEST_LENGTH);
 	H_Update(&ctx, commit_server, SHA256_DIGEST_LENGTH);
diff --git a/src/eap_common/eap_pwd_common.h b/src/eap_common/eap_pwd_common.h
index 971386d..4b841b7 100644
--- a/src/eap_common/eap_pwd_common.h
+++ b/src/eap_common/eap_pwd_common.h
@@ -35,13 +35,8 @@
 
 /*
  * EAP-pwd header, included on all payloads
+ * L(1 bit) | M(1 bit) | exch(6 bits) | total_length(if L is set)
  */
-struct eap_pwd_hdr {
-	u8 l_bit:1;
-	u8 m_bit:1;
-	u8 exch:6;
-	u8 total_length[0];         /* included when l_bit is set */
-} STRUCT_PACKED;
 
 #define EAP_PWD_OPCODE_ID_EXCH          1
 #define EAP_PWD_OPCODE_COMMIT_EXCH      2
diff --git a/src/eap_common/ikev2_common.h b/src/eap_common/ikev2_common.h
index c96a070..31a2b0d 100644
--- a/src/eap_common/ikev2_common.h
+++ b/src/eap_common/ikev2_common.h
@@ -139,7 +139,7 @@
 	IKEV2_TRANSFORM_ESN = 5
 };
 
-/* IKEv2 Tranform Type 1 (Encryption Algorithm) */
+/* IKEv2 Transform Type 1 (Encryption Algorithm) */
 enum {
 	ENCR_DES_IV64 = 1,
 	ENCR_DES = 2,
diff --git a/src/eap_peer/eap.c b/src/eap_peer/eap.c
index ecfaf30..91fa4a9 100644
--- a/src/eap_peer/eap.c
+++ b/src/eap_peer/eap.c
@@ -147,6 +147,7 @@
 	sm->methodState = METHOD_NONE;
 	sm->allowNotifications = TRUE;
 	sm->decision = DECISION_FAIL;
+	sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
 	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
 	eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
 	eapol_set_bool(sm, EAPOL_eapFail, FALSE);
@@ -1242,6 +1243,7 @@
 #endif /* CONFIG_FIPS */
 	tlsconf.event_cb = eap_peer_sm_tls_event;
 	tlsconf.cb_ctx = sm;
+	tlsconf.cert_in_cb = conf->cert_in_cb;
 	sm->ssl_ctx = tls_init(&tlsconf);
 	if (sm->ssl_ctx == NULL) {
 		wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
@@ -1466,16 +1468,11 @@
 
 
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-typedef enum {
-	TYPE_IDENTITY, TYPE_PASSWORD, TYPE_OTP, TYPE_PIN, TYPE_NEW_PASSWORD,
-	TYPE_PASSPHRASE
-} eap_ctrl_req_type;
-
-static void eap_sm_request(struct eap_sm *sm, eap_ctrl_req_type type,
+static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
 			   const char *msg, size_t msglen)
 {
 	struct eap_peer_config *config;
-	char *field, *txt, *tmp;
+	char *txt = NULL, *tmp;
 
 	if (sm == NULL)
 		return;
@@ -1483,29 +1480,20 @@
 	if (config == NULL)
 		return;
 
-	switch (type) {
-	case TYPE_IDENTITY:
-		field = "IDENTITY";
-		txt = "Identity";
+	switch (field) {
+	case WPA_CTRL_REQ_EAP_IDENTITY:
 		config->pending_req_identity++;
 		break;
-	case TYPE_PASSWORD:
-		field = "PASSWORD";
-		txt = "Password";
+	case WPA_CTRL_REQ_EAP_PASSWORD:
 		config->pending_req_password++;
 		break;
-	case TYPE_NEW_PASSWORD:
-		field = "NEW_PASSWORD";
-		txt = "New Password";
+	case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
 		config->pending_req_new_password++;
 		break;
-	case TYPE_PIN:
-		field = "PIN";
-		txt = "PIN";
+	case WPA_CTRL_REQ_EAP_PIN:
 		config->pending_req_pin++;
 		break;
-	case TYPE_OTP:
-		field = "OTP";
+	case WPA_CTRL_REQ_EAP_OTP:
 		if (msg) {
 			tmp = os_malloc(msglen + 3);
 			if (tmp == NULL)
@@ -1524,9 +1512,7 @@
 			txt = config->pending_req_otp;
 		}
 		break;
-	case TYPE_PASSPHRASE:
-		field = "PASSPHRASE";
-		txt = "Private key passphrase";
+	case WPA_CTRL_REQ_EAP_PASSPHRASE:
 		config->pending_req_passphrase++;
 		break;
 	default:
@@ -1559,7 +1545,7 @@
  */
 void eap_sm_request_identity(struct eap_sm *sm)
 {
-	eap_sm_request(sm, TYPE_IDENTITY, NULL, 0);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0);
 }
 
 
@@ -1574,7 +1560,7 @@
  */
 void eap_sm_request_password(struct eap_sm *sm)
 {
-	eap_sm_request(sm, TYPE_PASSWORD, NULL, 0);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSWORD, NULL, 0);
 }
 
 
@@ -1589,7 +1575,7 @@
  */
 void eap_sm_request_new_password(struct eap_sm *sm)
 {
-	eap_sm_request(sm, TYPE_NEW_PASSWORD, NULL, 0);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_NEW_PASSWORD, NULL, 0);
 }
 
 
@@ -1604,7 +1590,7 @@
  */
 void eap_sm_request_pin(struct eap_sm *sm)
 {
-	eap_sm_request(sm, TYPE_PIN, NULL, 0);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PIN, NULL, 0);
 }
 
 
@@ -1620,7 +1606,7 @@
  */
 void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
 {
-	eap_sm_request(sm, TYPE_OTP, msg, msg_len);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_OTP, msg, msg_len);
 }
 
 
@@ -1635,7 +1621,7 @@
  */
 void eap_sm_request_passphrase(struct eap_sm *sm)
 {
-	eap_sm_request(sm, TYPE_PASSPHRASE, NULL, 0);
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSPHRASE, NULL, 0);
 }
 
 
diff --git a/src/eap_peer/eap.h b/src/eap_peer/eap.h
index 2a80d4e..f35197f 100644
--- a/src/eap_peer/eap.h
+++ b/src/eap_peer/eap.h
@@ -216,10 +216,10 @@
 	/**
 	 * eap_param_needed - Notify that EAP parameter is needed
 	 * @ctx: eapol_ctx from eap_peer_sm_init() call
-	 * @field: Field name (e.g., "IDENTITY")
+	 * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
 	 * @txt: User readable text describing the required parameter
 	 */
-	void (*eap_param_needed)(void *ctx, const char *field,
+	void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
 				 const char *txt);
 
 	/**
@@ -262,6 +262,11 @@
 	 * This is only used by EAP-WSC and can be left %NULL if not available.
 	 */
 	struct wps_context *wps;
+
+	/**
+	 * cert_in_cb - Include server certificates in callback
+	 */
+	int cert_in_cb;
 };
 
 struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
diff --git a/src/eap_peer/eap_aka.c b/src/eap_peer/eap_aka.c
index 182f01a..766764b 100644
--- a/src/eap_peer/eap_aka.c
+++ b/src/eap_peer/eap_aka.c
@@ -235,21 +235,20 @@
 
 static void eap_aka_clear_identities(struct eap_aka_data *data, int id)
 {
-	wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old%s%s%s",
-		   id & CLEAR_PSEUDONYM ? " pseudonym" : "",
-		   id & CLEAR_REAUTH_ID ? " reauth_id" : "",
-		   id & CLEAR_EAP_ID ? " eap_id" : "");
 	if (id & CLEAR_PSEUDONYM) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old pseudonym");
 		os_free(data->pseudonym);
 		data->pseudonym = NULL;
 		data->pseudonym_len = 0;
 	}
 	if (id & CLEAR_REAUTH_ID) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old reauth_id");
 		os_free(data->reauth_id);
 		data->reauth_id = NULL;
 		data->reauth_id_len = 0;
 	}
 	if (id & CLEAR_EAP_ID) {
+		wpa_printf(MSG_DEBUG, "EAP-AKA: forgetting old eap_id");
 		os_free(data->last_eap_identity);
 		data->last_eap_identity = NULL;
 		data->last_eap_identity_len = 0;
@@ -880,11 +879,11 @@
 					    EAP_AKA_UNABLE_TO_PROCESS_PACKET);
 	}
 
-	/* Old reauthentication and pseudonym identities must not be used
-	 * anymore. In other words, if no new identities are received, full
-	 * authentication will be used on next reauthentication. */
-	eap_aka_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
-				 CLEAR_EAP_ID);
+	/* Old reauthentication identity must not be used anymore. In
+	 * other words, if no new identities are received, full
+	 * authentication will be used on next reauthentication (using
+	 * pseudonym identity or permanent identity). */
+	eap_aka_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
 
 	if (attr->encr_data) {
 		u8 *decrypted;
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 5d3e69d..3cfb41a 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -444,8 +444,9 @@
 		return 0;
 	}
 
-	if (data->phase2_priv == NULL &&
-	    eap_fast_init_phase2_method(sm, data) < 0) {
+	if ((data->phase2_priv == NULL &&
+	     eap_fast_init_phase2_method(sm, data) < 0) ||
+	    data->phase2_method == NULL) {
 		wpa_printf(MSG_INFO, "EAP-FAST: Failed to initialize "
 			   "Phase 2 EAP method %d", *pos);
 		ret->methodState = METHOD_DONE;
@@ -542,7 +543,7 @@
 
 static struct wpabuf * eap_fast_process_eap_payload_tlv(
 	struct eap_sm *sm, struct eap_fast_data *data,
-	struct eap_method_ret *ret, const struct eap_hdr *req,
+	struct eap_method_ret *ret,
 	u8 *eap_payload_tlv, size_t eap_payload_tlv_len)
 {
 	struct eap_hdr *hdr;
@@ -1037,11 +1038,15 @@
 	} else {
 		/*
 		 * This is PAC refreshing, i.e., normal authentication that is
-		 * expected to be completed with an EAP-Success.
+		 * expected to be completed with an EAP-Success. However,
+		 * RFC 5422, Section 3.5 allows EAP-Failure to be sent even
+		 * after protected success exchange in case of EAP-Fast
+		 * provisioning, so we better use DECISION_COND_SUCC here
+		 * instead of DECISION_UNCOND_SUCC.
 		 */
 		wpa_printf(MSG_DEBUG, "EAP-FAST: Send PAC-Acknowledgement TLV "
 			   "- PAC refreshing completed successfully");
-		ret->decision = DECISION_UNCOND_SUCC;
+		ret->decision = DECISION_COND_SUCC;
 	}
 	ret->methodState = METHOD_DONE;
 	return eap_fast_tlv_pac_ack();
@@ -1184,7 +1189,7 @@
 
 	if (tlv.eap_payload_tlv) {
 		tmp = eap_fast_process_eap_payload_tlv(
-			sm, data, ret, req, tlv.eap_payload_tlv,
+			sm, data, ret, tlv.eap_payload_tlv,
 			tlv.eap_payload_tlv_len);
 		resp = wpabuf_concat(resp, tmp);
 	}
diff --git a/src/eap_peer/eap_methods.c b/src/eap_peer/eap_methods.c
index 3b0af05..937fd45 100644
--- a/src/eap_peer/eap_methods.c
+++ b/src/eap_peer/eap_methods.c
@@ -77,6 +77,8 @@
 const char * eap_get_name(int vendor, EapType type)
 {
 	struct eap_method *m;
+	if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
+		return "expanded";
 	for (m = eap_methods; m; m = m->next) {
 		if (m->vendor == vendor && m->method == type)
 			return m->name;
diff --git a/src/eap_peer/eap_peap.c b/src/eap_peer/eap_peap.c
index 2b72084..7cb8213 100644
--- a/src/eap_peer/eap_peap.c
+++ b/src/eap_peer/eap_peap.c
@@ -196,7 +196,7 @@
  * @nak_type: TLV type (EAP_TLV_*)
  * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
  *
- * This funtion builds an EAP-TLV NAK message. The caller is responsible for
+ * This function builds an EAP-TLV NAK message. The caller is responsible for
  * freeing the returned buffer.
  */
 static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
@@ -285,8 +285,10 @@
 	 * in the end of the label just before ISK; is that just a typo?)
 	 */
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
-	peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
-		     isk, sizeof(isk), imck, sizeof(imck));
+	if (peap_prfplus(data->peap_version, tk, 40,
+			 "Inner Methods Compound Keys",
+			 isk, sizeof(isk), imck, sizeof(imck)) < 0)
+		return -1;
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
 			imck, sizeof(imck));
 
@@ -346,8 +348,8 @@
  * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
  * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
  *
- * This funtion builds an EAP-TLV Result message. The caller is responsible for
- * freeing the returned buffer.
+ * This function builds an EAP-TLV Result message. The caller is responsible
+ * for freeing the returned buffer.
  */
 static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
 					    struct eap_peap_data *data,
@@ -1247,9 +1249,12 @@
 		 * termination for this label while the one used for deriving
 		 * IPMK|CMK did not use null termination.
 		 */
-		peap_prfplus(data->peap_version, data->ipmk, 40,
-			     "Session Key Generating Function",
-			     (u8 *) "\00", 1, csk, sizeof(csk));
+		if (peap_prfplus(data->peap_version, data->ipmk, 40,
+				 "Session Key Generating Function",
+				 (u8 *) "\00", 1, csk, sizeof(csk)) < 0) {
+			os_free(key);
+			return NULL;
+		}
 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
 		os_memcpy(key, csk, EAP_TLS_KEY_LEN);
 		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
diff --git a/src/eap_peer/eap_pwd.c b/src/eap_peer/eap_pwd.c
index e4705b7..1957c82 100644
--- a/src/eap_peer/eap_pwd.c
+++ b/src/eap_peer/eap_pwd.c
@@ -423,8 +423,7 @@
 	BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
 
 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-			     sizeof(struct eap_pwd_hdr) +
-			     BN_num_bytes(data->grp->order) +
+			     1 + BN_num_bytes(data->grp->order) +
 			     (2 * BN_num_bytes(data->grp->prime)),
 			     EAP_CODE_RESPONSE, eap_get_id(reqData));
 	if (resp == NULL)
@@ -465,6 +464,7 @@
 	u32 cs;
 	u16 grp;
 	u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+	int offset;
 
 	/*
 	 * first build up the ciphersuite which is group | random_function |
@@ -497,7 +497,8 @@
 	 * value may start with a few zeros and the previous one did not.
 	 */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->k, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server element: x, y */
@@ -509,15 +510,19 @@
 		goto fin;
 	}
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->server_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->server_scalar);
+	BN_bn2bin(data->server_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* my element: x, y */
@@ -530,15 +535,19 @@
 	}
 
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* my scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->my_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* the ciphersuite */
@@ -564,7 +573,8 @@
 
 	/* k */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->k, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* my element */
@@ -576,15 +586,19 @@
 		goto fin;
 	}
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* my scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->my_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* server element: x, y */
@@ -596,15 +610,19 @@
 		goto fin;
 	}
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->server_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->server_scalar);
+	BN_bn2bin(data->server_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* the ciphersuite */
@@ -614,7 +632,7 @@
 	H_Final(&ctx, conf);
 
 	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-			     sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH,
+			     1 + SHA256_DIGEST_LENGTH,
 			     EAP_CODE_RESPONSE, eap_get_id(reqData));
 	if (resp == NULL)
 		goto fin;
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index 6677063..06fbc5b 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -266,21 +266,20 @@
 
 static void eap_sim_clear_identities(struct eap_sim_data *data, int id)
 {
-	wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old%s%s%s",
-		   id & CLEAR_PSEUDONYM ? " pseudonym" : "",
-		   id & CLEAR_REAUTH_ID ? " reauth_id" : "",
-		   id & CLEAR_EAP_ID ? " eap_id" : "");
-	if (id & CLEAR_PSEUDONYM) {
+	if ((id & CLEAR_PSEUDONYM) && data->pseudonym) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old pseudonym");
 		os_free(data->pseudonym);
 		data->pseudonym = NULL;
 		data->pseudonym_len = 0;
 	}
-	if (id & CLEAR_REAUTH_ID) {
+	if ((id & CLEAR_REAUTH_ID) && data->reauth_id) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old reauth_id");
 		os_free(data->reauth_id);
 		data->reauth_id = NULL;
 		data->reauth_id_len = 0;
 	}
-	if (id & CLEAR_EAP_ID) {
+	if ((id & CLEAR_EAP_ID) && data->last_eap_identity) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM: forgetting old eap_id");
 		os_free(data->last_eap_identity);
 		data->last_eap_identity = NULL;
 		data->last_eap_identity_len = 0;
@@ -649,11 +648,11 @@
 					    EAP_SIM_UNABLE_TO_PROCESS_PACKET);
 	}
 
-	/* Old reauthentication and pseudonym identities must not be used
-	 * anymore. In other words, if no new identities are received, full
-	 * authentication will be used on next reauthentication. */
-	eap_sim_clear_identities(data, CLEAR_PSEUDONYM | CLEAR_REAUTH_ID |
-				 CLEAR_EAP_ID);
+	/* Old reauthentication identity must not be used anymore. In
+	 * other words, if no new reauth identity is received, full
+	 * authentication will be used on next reauthentication (using
+	 * pseudonym identity or permanent identity). */
+	eap_sim_clear_identities(data, CLEAR_REAUTH_ID | CLEAR_EAP_ID);
 
 	if (attr->encr_data) {
 		u8 *decrypted;
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index d1567e9..2934ba4 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -112,7 +112,6 @@
 		wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
 		eap_tls_params_from_conf1(params, config);
 	}
-	params->tls_ia = data->tls_ia;
 
 	/*
 	 * Use blob data, if available. Otherwise, leave reference to external
@@ -295,9 +294,9 @@
 	os_memcpy(rnd + keys.client_random_len, keys.server_random,
 		  keys.server_random_len);
 
-	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, rnd, keys.client_random_len +
-		    keys.server_random_len, out, len))
+	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+			     label, rnd, keys.client_random_len +
+			     keys.server_random_len, out, len))
 		goto fail;
 
 	os_free(rnd);
diff --git a/src/eap_peer/eap_tls_common.h b/src/eap_peer/eap_tls_common.h
index e9e0998..e9a07b8 100644
--- a/src/eap_peer/eap_tls_common.h
+++ b/src/eap_peer/eap_tls_common.h
@@ -66,11 +66,6 @@
 	int include_tls_length;
 
 	/**
-	 * tls_ia - Whether TLS/IA is enabled for this TLS connection
-	 */
-	int tls_ia;
-
-	/**
 	 * eap - EAP state machine allocated with eap_peer_sm_init()
 	 */
 	struct eap_sm *eap;
diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c
index 6c95f72..da288eb 100644
--- a/src/eap_peer/eap_tnc.c
+++ b/src/eap_peer/eap_tnc.c
@@ -15,7 +15,6 @@
 #include "includes.h"
 
 #include "common.h"
-#include "base64.h"
 #include "eap_i.h"
 #include "tncc.h"
 
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index e8f0f38..612dfa7 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -1,6 +1,6 @@
 /*
  * EAP peer method: EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -26,17 +26,7 @@
 #include "eap_config.h"
 
 
-/* Maximum supported TTLS version
- * 0 = RFC 5281
- * 1 = draft-funk-eap-ttls-v1-00.txt
- */
-#ifndef EAP_TTLS_VERSION
-#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
-#endif /* EAP_TTLS_VERSION */
-
-
-#define MSCHAPV2_KEY_LEN 16
-#define MSCHAPV2_NT_RESPONSE_LEN 24
+#define EAP_TTLS_VERSION 0
 
 
 static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
@@ -44,9 +34,8 @@
 
 struct eap_ttls_data {
 	struct eap_ssl_data ssl;
-	int ssl_initialized;
 
-	int ttls_version, force_ttls_version;
+	int ttls_version;
 
 	const struct eap_method *phase2_method;
 	void *phase2_priv;
@@ -91,22 +80,9 @@
 	if (data == NULL)
 		return NULL;
 	data->ttls_version = EAP_TTLS_VERSION;
-	data->force_ttls_version = -1;
 	selected = "EAP";
 	data->phase2_type = EAP_TTLS_PHASE2_EAP;
 
-#if EAP_TTLS_VERSION > 0
-	if (config && config->phase1) {
-		const char *pos = os_strstr(config->phase1, "ttlsver=");
-		if (pos) {
-			data->force_ttls_version = atoi(pos + 8);
-			data->ttls_version = data->force_ttls_version;
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: Forced TTLS version "
-				   "%d", data->force_ttls_version);
-		}
-	}
-#endif /* EAP_TTLS_VERSION */
-
 	if (config && config->phase2) {
 		if (os_strstr(config->phase2, "autheap=")) {
 			selected = "EAP";
@@ -140,19 +116,11 @@
 		data->phase2_eap_type.method = EAP_TYPE_NONE;
 	}
 
-#if EAP_TTLS_VERSION > 0
-	if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
-	    data->ttls_version > 0) {
-		if (data->force_ttls_version > 0) {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
-				   "TLS library does not support TLS/IA.",
-				   data->force_ttls_version);
-			eap_ttls_deinit(sm, data);
-			return NULL;
-		}
-		data->ttls_version = 0;
+	if (eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
+		eap_ttls_deinit(sm, data);
+		return NULL;
 	}
-#endif /* EAP_TTLS_VERSION */
 
 	return data;
 }
@@ -176,8 +144,7 @@
 		return;
 	eap_ttls_phase2_eap_deinit(sm, data);
 	os_free(data->phase2_eap_types);
-	if (data->ssl_initialized)
-		eap_peer_tls_ssl_deinit(sm, &data->ssl);
+	eap_peer_tls_ssl_deinit(sm, &data->ssl);
 	os_free(data->key_data);
 	wpabuf_free(data->pending_phase2_req);
 	os_free(data);
@@ -246,39 +213,6 @@
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
-					    struct eap_ttls_data *data,
-					    const u8 *key, size_t key_len)
-{
-	u8 *buf;
-	size_t buf_len;
-	int ret;
-
-	if (key) {
-		buf_len = 2 + key_len;
-		buf = os_malloc(buf_len);
-		if (buf == NULL)
-			return -1;
-		WPA_PUT_BE16(buf, key_len);
-		os_memcpy(buf + 2, key, key_len);
-	} else {
-		buf = NULL;
-		buf_len = 0;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
-			"secret permutation", buf, buf_len);
-	ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
-						     data->ssl.conn,
-						     buf, buf_len);
-	os_free(buf);
-
-	return ret;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 static int eap_ttls_v0_derive_key(struct eap_sm *sm,
 				  struct eap_ttls_data *data)
 {
@@ -298,156 +232,10 @@
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static int eap_ttls_v1_derive_key(struct eap_sm *sm,
-				  struct eap_ttls_data *data)
-{
-	struct tls_keys keys;
-	u8 *rnd;
-
-	os_free(data->key_data);
-	data->key_data = NULL;
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive keying "
-			   "material");
-		return -1;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	data->key_data = os_malloc(EAP_TLS_KEY_LEN);
-	if (rnd == NULL || data->key_data == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
-		os_free(rnd);
-		os_free(data->key_data);
-		data->key_data = NULL;
-		return -1;
-	}
-	os_memcpy(rnd, keys.client_random, keys.client_random_len);
-	os_memcpy(rnd + keys.client_random_len, keys.server_random,
-		  keys.server_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "ttls v1 keying material", rnd, keys.client_random_len +
-		    keys.server_random_len, data->key_data, EAP_TLS_KEY_LEN)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
-		os_free(rnd);
-		os_free(data->key_data);
-		data->key_data = NULL;
-		return -1;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
-		    rnd, keys.client_random_len + keys.server_random_len);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
-			keys.inner_secret, keys.inner_secret_len);
-
-	os_free(rnd);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
-			data->key_data, EAP_TLS_KEY_LEN);
-
-	return 0;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
 					struct eap_ttls_data *data, size_t len)
 {
-#if EAP_TTLS_VERSION > 0
-	struct tls_keys keys;
-	u8 *challenge, *rnd;
-#endif /* EAP_TTLS_VERSION */
-
-	if (data->ttls_version == 0) {
-		return eap_peer_tls_derive_key(sm, &data->ssl,
-					       "ttls challenge", len);
-	}
-
-#if EAP_TTLS_VERSION > 0
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive "
-			   "implicit challenge");
-		return NULL;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	challenge = os_malloc(len);
-	if (rnd == NULL || challenge == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
-			   "challenge derivation");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-	os_memcpy(rnd, keys.server_random, keys.server_random_len);
-	os_memcpy(rnd + keys.server_random_len, keys.client_random,
-		  keys.client_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "inner application challenge", rnd,
-		    keys.client_random_len + keys.server_random_len,
-		    challenge, len)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
-			   "challenge");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-
-	os_free(rnd);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
-			challenge, len);
-
-	return challenge;
-
-#else /* EAP_TTLS_VERSION */
-
-	return NULL;
-
-#endif /* EAP_TTLS_VERSION */
-}
-
-
-static void eap_ttlsv1_phase2_eap_finish(struct eap_sm *sm,
-					 struct eap_ttls_data *data,
-					 struct eap_method_ret *ret)
-{
-#if EAP_TTLS_VERSION > 0
-	if (data->ttls_version > 0) {
-		const struct eap_method *m = data->phase2_method;
-		void *priv = data->phase2_priv;
-
-		/* TTLSv1 requires TLS/IA FinalPhaseFinished */
-		if (ret->decision == DECISION_UNCOND_SUCC)
-			ret->decision = DECISION_COND_SUCC;
-		ret->methodState = METHOD_CONT;
-
-		if (ret->decision == DECISION_COND_SUCC &&
-		    m->isKeyAvailable && m->getKey &&
-		    m->isKeyAvailable(sm, priv)) {
-			u8 *key;
-			size_t key_len;
-			key = m->getKey(sm, priv, &key_len);
-			if (key) {
-				eap_ttls_ia_permute_inner_secret(
-					sm, data, key, key_len);
-				os_free(key);
-			}
-		}
-	}
-#endif /* EAP_TTLS_VERSION */
+	return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len);
 }
 
 
@@ -494,7 +282,6 @@
 		ret->methodState = iret.methodState;
 		ret->decision = iret.decision;
 	}
-	eap_ttlsv1_phase2_eap_finish(sm, data, ret);
 
 	return 0;
 }
@@ -615,26 +402,6 @@
 }
 
 
-static void eap_ttlsv1_permute_inner(struct eap_sm *sm,
-				     struct eap_ttls_data *data)
-{
-#if EAP_TTLS_VERSION > 0
-	u8 session_key[2 * MSCHAPV2_KEY_LEN];
-
-	if (data->ttls_version == 0)
-		return;
-
-	get_asymetric_start_key(data->master_key, session_key,
-				MSCHAPV2_KEY_LEN, 0, 0);
-	get_asymetric_start_key(data->master_key,
-				session_key + MSCHAPV2_KEY_LEN,
-				MSCHAPV2_KEY_LEN, 1, 0);
-	eap_ttls_ia_permute_inner_secret(sm, data, session_key,
-					 sizeof(session_key));
-#endif /* EAP_TTLS_VERSION */
-}
-
-
 static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
 					    struct eap_ttls_data *data,
 					    struct eap_method_ret *ret,
@@ -702,8 +469,6 @@
 	}
 	data->auth_response_valid = 1;
 
-	eap_ttlsv1_permute_inner(sm, data);
-
 	pos += 24;
 	os_free(challenge);
 	AVP_PAD(buf, pos);
@@ -711,7 +476,7 @@
 	wpabuf_put(msg, pos - buf);
 	*resp = msg;
 
-	if (sm->workaround && data->ttls_version == 0) {
+	if (sm->workaround) {
 		/* At least FreeRADIUS seems to be terminating
 		 * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
 		 * packet. */
@@ -798,17 +563,10 @@
 	wpabuf_put(msg, pos - buf);
 	*resp = msg;
 
-	if (data->ttls_version > 0) {
-		/* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-		 * so do not allow connection to be terminated yet. */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		/* EAP-TTLS/MSCHAP does not provide tunneled success
-		 * notification, so assume that Phase2 succeeds. */
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_COND_SUCC;
-	}
+	/* EAP-TTLS/MSCHAP does not provide tunneled success
+	 * notification, so assume that Phase2 succeeds. */
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
 
 	return 0;
 }
@@ -859,17 +617,10 @@
 	wpabuf_put(msg, pos - buf);
 	*resp = msg;
 
-	if (data->ttls_version > 0) {
-		/* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-		 * so do not allow connection to be terminated yet. */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		/* EAP-TTLS/PAP does not provide tunneled success notification,
-		 * so assume that Phase2 succeeds. */
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_COND_SUCC;
-	}
+	/* EAP-TTLS/PAP does not provide tunneled success notification,
+	 * so assume that Phase2 succeeds. */
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
 
 	return 0;
 }
@@ -942,17 +693,10 @@
 	wpabuf_put(msg, pos - buf);
 	*resp = msg;
 
-	if (data->ttls_version > 0) {
-		/* EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report success,
-		 * so do not allow connection to be terminated yet. */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		/* EAP-TTLS/CHAP does not provide tunneled success
-		 * notification, so assume that Phase2 succeeds. */
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_COND_SUCC;
-	}
+	/* EAP-TTLS/CHAP does not provide tunneled success
+	 * notification, so assume that Phase2 succeeds. */
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
 
 	return 0;
 }
@@ -1027,36 +771,6 @@
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static struct wpabuf * eap_ttls_build_phase_finished(
-	struct eap_sm *sm, struct eap_ttls_data *data, int id, int final)
-{
-	struct wpabuf *req, *buf;
-
-	buf = tls_connection_ia_send_phase_finished(sm->ssl_ctx,
-						    data->ssl.conn,
-						    final);
-	if (buf == NULL)
-		return NULL;
-
-	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TTLS,
-			    1 + wpabuf_len(buf),
-			    EAP_CODE_RESPONSE, id);
-	if (req == NULL) {
-		wpabuf_free(buf);
-		return NULL;
-	}
-
-	wpabuf_put_u8(req, data->ttls_version);
-	wpabuf_put_buf(req, buf);
-	wpabuf_free(buf);
-	eap_update_len(req);
-
-	return req;
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 struct ttls_parse_avp {
 	u8 *mschapv2;
 	u8 *eapdata;
@@ -1366,19 +1080,9 @@
 
 	wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 "
 		   "authentication succeeded");
-	if (data->ttls_version > 0) {
-		/*
-		 * EAP-TTLSv1 uses TLS/IA FinalPhaseFinished to report
-		 * success, so do not allow connection to be terminated
-		 * yet.
-		 */
-		ret->methodState = METHOD_CONT;
-		ret->decision = DECISION_COND_SUCC;
-	} else {
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_UNCOND_SUCC;
-		data->phase2_success = 1;
-	}
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_UNCOND_SUCC;
+	data->phase2_success = 1;
 
 	/*
 	 * Reply with empty data; authentication server will reply
@@ -1493,24 +1197,6 @@
 }
 
 
-#if EAP_TTLS_VERSION > 0
-static void eap_ttls_final_phase_finished(struct eap_sm *sm,
-					  struct eap_ttls_data *data,
-					  struct eap_method_ret *ret,
-					  u8 identifier,
-					  struct wpabuf **out_data)
-{
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished received");
-	wpa_printf(MSG_INFO, "EAP-TTLS: TLS/IA authentication succeeded");
-	ret->methodState = METHOD_DONE;
-	ret->decision = DECISION_UNCOND_SUCC;
-	data->phase2_success = 1;
-	*out_data = eap_ttls_build_phase_finished(sm, data, identifier, 1);
-	eap_ttls_v1_derive_key(sm, data);
-}
-#endif /* EAP_TTLS_VERSION */
-
-
 static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
 					      struct eap_ttls_data *data,
 					      struct eap_method_ret *ret,
@@ -1534,6 +1220,21 @@
 			   "processing failed");
 		retval = -1;
 	} else {
+		struct eap_peer_config *config = eap_get_config(sm);
+		if (resp == NULL &&
+		    (config->pending_req_identity ||
+		     config->pending_req_password ||
+		     config->pending_req_otp ||
+		     config->pending_req_new_password)) {
+			/*
+			 * Use empty buffer to force implicit request
+			 * processing when EAP request is re-processed after
+			 * user input.
+			 */
+			wpabuf_free(data->pending_phase2_req);
+			data->pending_phase2_req = wpabuf_alloc(0);
+		}
+
 		retval = eap_ttls_encrypt_response(sm, data, resp, identifier,
 						   out_data);
 	}
@@ -1627,17 +1328,6 @@
 	if (retval)
 		goto done;
 
-#if EAP_TTLS_VERSION > 0
-	if (data->ttls_version > 0 &&
-	    (in_decrypted == NULL || wpabuf_len(in_decrypted) == 0) &&
-	    tls_connection_ia_final_phase_finished(sm->ssl_ctx,
-						   data->ssl.conn)) {
-		eap_ttls_final_phase_finished(sm, data, ret, identifier,
-					      out_data);
-		goto done;
-	}
-#endif /* EAP_TTLS_VERSION */
-
 continue_req:
 	data->phase2_start = 0;
 
@@ -1662,46 +1352,6 @@
 }
 
 
-static int eap_ttls_process_start(struct eap_sm *sm,
-				  struct eap_ttls_data *data, u8 flags,
-				  struct eap_method_ret *ret)
-{
-	struct eap_peer_config *config = eap_get_config(sm);
-
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own ver=%d)",
-		   flags & EAP_TLS_VERSION_MASK, data->ttls_version);
-#if EAP_TTLS_VERSION > 0
-	if ((flags & EAP_TLS_VERSION_MASK) < data->ttls_version)
-		data->ttls_version = flags & EAP_TLS_VERSION_MASK;
-	if (data->force_ttls_version >= 0 &&
-	    data->force_ttls_version != data->ttls_version) {
-		wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to select "
-			   "forced TTLS version %d",
-			   data->force_ttls_version);
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		ret->allowNotifications = FALSE;
-		return -1;
-	}
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Using TTLS version %d",
-		   data->ttls_version);
-
-	if (data->ttls_version > 0)
-		data->ssl.tls_ia = 1;
-#endif /* EAP_TTLS_VERSION */
-	if (!data->ssl_initialized &&
-	    eap_peer_tls_ssl_init(sm, &data->ssl, config)) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
-		return -1;
-	}
-	data->ssl_initialized = 1;
-
-	wpa_printf(MSG_DEBUG, "EAP-TTLS: Start");
-
-	return 0;
-}
-
-
 static int eap_ttls_process_handshake(struct eap_sm *sm,
 				      struct eap_ttls_data *data,
 				      struct eap_method_ret *ret,
@@ -1725,8 +1375,7 @@
 			ret->methodState = METHOD_MAY_CONT;
 		}
 		data->phase2_start = 1;
-		if (data->ttls_version == 0)
-			eap_ttls_v0_derive_key(sm, data);
+		eap_ttls_v0_derive_key(sm, data);
 
 		if (*out_data == NULL || wpabuf_len(*out_data) == 0) {
 			if (eap_ttls_decrypt(sm, data, ret, identifier,
@@ -1761,7 +1410,7 @@
 				       struct eap_ttls_data *data,
 				       struct eap_method_ret *ret)
 {
-	if (data->ttls_version == 0 && ret->methodState == METHOD_DONE) {
+	if (ret->methodState == METHOD_DONE) {
 		ret->allowNotifications = FALSE;
 		if (ret->decision == DECISION_UNCOND_SUCC ||
 		    ret->decision == DECISION_COND_SUCC) {
@@ -1779,8 +1428,7 @@
 			}
 #endif /* EAP_TNC */
 		}
-	} else if (data->ttls_version == 0 &&
-		   ret->methodState == METHOD_MAY_CONT &&
+	} else if (ret->methodState == METHOD_MAY_CONT &&
 		   (ret->decision == DECISION_UNCOND_SUCC ||
 		    ret->decision == DECISION_COND_SUCC)) {
 			wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
@@ -1808,8 +1456,9 @@
 	id = eap_get_id(reqData);
 
 	if (flags & EAP_TLS_FLAGS_START) {
-		if (eap_ttls_process_start(sm, data, flags, ret) < 0)
-			return NULL;
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own "
+			   "ver=%d)", flags & EAP_TLS_VERSION_MASK,
+			   data->ttls_version);
 
 		/* RFC 5281, Ch. 9.2:
 		 * "This packet MAY contain additional information in the form
@@ -1817,13 +1466,6 @@
 		 * For now, ignore any potential extra data.
 		 */
 		left = 0;
-	} else if (!data->ssl_initialized) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: First message did not "
-			   "include Start flag");
-		ret->methodState = METHOD_DONE;
-		ret->decision = DECISION_FAIL;
-		ret->allowNotifications = FALSE;
-		return NULL;
 	}
 
 	resp = NULL;
diff --git a/src/eap_peer/ikev2.c b/src/eap_peer/ikev2.c
index 1e169a0..acd7611 100644
--- a/src/eap_peer/ikev2.c
+++ b/src/eap_peer/ikev2.c
@@ -425,7 +425,7 @@
 	}
 
 	/* RFC 4306, Section 3.4:
-	 * The length of DH public value MUST be equal to the lenght of the
+	 * The length of DH public value MUST be equal to the length of the
 	 * prime modulus.
 	 */
 	if (kei_len - 4 != data->dh->prime_len) {
diff --git a/src/eap_server/eap.h b/src/eap_server/eap.h
index e1f500a..d5f8f1d 100644
--- a/src/eap_server/eap.h
+++ b/src/eap_server/eap.h
@@ -22,8 +22,6 @@
 
 struct eap_sm;
 
-#define EAP_MAX_METHODS 8
-
 #define EAP_TTLS_AUTH_PAP 1
 #define EAP_TTLS_AUTH_CHAP 2
 #define EAP_TTLS_AUTH_MSCHAP 4
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 3cba5aa..f48cf71 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -119,7 +119,7 @@
 
 	/* Full authenticator state machine local variables */
 
-	/* Long-term (maintained betwen packets) */
+	/* Long-term (maintained between packets) */
 	EapType currentMethod;
 	int currentId;
 	enum {
diff --git a/src/eap_server/eap_server.c b/src/eap_server/eap_server.c
index 0f0da29..7a5beb6 100644
--- a/src/eap_server/eap_server.c
+++ b/src/eap_server/eap_server.c
@@ -136,6 +136,14 @@
 {
 	SM_ENTRY(EAP, INITIALIZE);
 
+	if (sm->eap_if.eapRestart && !sm->eap_server && sm->identity) {
+		/*
+		 * Need to allow internal Identity method to be used instead
+		 * of passthrough at the beginning of reauthentication.
+		 */
+		eap_server_clear_identity(sm);
+	}
+
 	sm->currentId = -1;
 	sm->eap_if.eapSuccess = FALSE;
 	sm->eap_if.eapFail = FALSE;
@@ -1028,9 +1036,12 @@
 
 	not_found:
 		/* not found - remove from the list */
-		os_memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
-			   (EAP_MAX_METHODS - i - 1) *
-			   sizeof(sm->user->methods[0]));
+		if (i + 1 < EAP_MAX_METHODS) {
+			os_memmove(&sm->user->methods[i],
+				   &sm->user->methods[i + 1],
+				   (EAP_MAX_METHODS - i - 1) *
+				   sizeof(sm->user->methods[0]));
+		}
 		sm->user->methods[EAP_MAX_METHODS - 1].vendor =
 			EAP_VENDOR_IETF;
 		sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
diff --git a/src/eap_server/eap_server_aka.c b/src/eap_server/eap_server_aka.c
index 42cbdce..0f25ffd 100644
--- a/src/eap_server/eap_server_aka.c
+++ b/src/eap_server/eap_server_aka.c
@@ -133,14 +133,13 @@
 		return NULL;
 
 	data->eap_method = EAP_TYPE_AKA_PRIME;
-	data->network_name = os_malloc(os_strlen(network_name));
+	data->network_name = (u8 *) os_strdup(network_name);
 	if (data->network_name == NULL) {
 		os_free(data);
 		return NULL;
 	}
 
 	data->network_name_len = os_strlen(network_name);
-	os_memcpy(data->network_name, network_name, data->network_name_len);
 
 	data->state = IDENTITY;
 	eap_aka_determine_identity(sm, data, 1, 0);
diff --git a/src/eap_server/eap_server_methods.c b/src/eap_server/eap_server_methods.c
index 900a5dd..4d241a4 100644
--- a/src/eap_server/eap_server_methods.c
+++ b/src/eap_server/eap_server_methods.c
@@ -167,6 +167,8 @@
 const char * eap_server_get_name(int vendor, EapType type)
 {
 	struct eap_method *m;
+	if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
+		return "expanded";
 	for (m = eap_methods; m; m = m->next) {
 		if (m->vendor == vendor && m->method == type)
 			return m->name;
diff --git a/src/eap_server/eap_server_mschapv2.c b/src/eap_server/eap_server_mschapv2.c
index 64120a4..f5ee7f4 100644
--- a/src/eap_server/eap_server_mschapv2.c
+++ b/src/eap_server/eap_server_mschapv2.c
@@ -405,9 +405,12 @@
 		if (sm->user->password_hash) {
 			pw_hash = sm->user->password;
 		} else {
-			nt_password_hash(sm->user->password,
-					 sm->user->password_len,
-					 pw_hash_buf);
+			if (nt_password_hash(sm->user->password,
+					     sm->user->password_len,
+					     pw_hash_buf) < 0) {
+				data->state = FAILURE;
+				return;
+			}
 			pw_hash = pw_hash_buf;
 		}
 		generate_authenticator_response_pwhash(
diff --git a/src/eap_server/eap_server_peap.c b/src/eap_server/eap_server_peap.c
index 8a7d626..50e79c0 100644
--- a/src/eap_server/eap_server_peap.c
+++ b/src/eap_server/eap_server_peap.c
@@ -351,8 +351,12 @@
 	 * in the end of the label just before ISK; is that just a typo?)
 	 */
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
-	peap_prfplus(data->peap_version, tk, 40, "Inner Methods Compound Keys",
-		     isk, sizeof(isk), imck, sizeof(imck));
+	if (peap_prfplus(data->peap_version, tk, 40,
+			 "Inner Methods Compound Keys",
+			 isk, sizeof(isk), imck, sizeof(imck)) < 0) {
+		os_free(tk);
+		return -1;
+	}
 	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
 			imck, sizeof(imck));
 
@@ -1060,8 +1064,6 @@
 	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
 			    in_decrypted);
 
-	hdr = wpabuf_head(in_decrypted);
-
 	if (data->peap_version == 0 && data->state != PHASE2_TLV) {
 		const struct eap_hdr *resp;
 		struct eap_hdr *nhdr;
@@ -1320,9 +1322,10 @@
 		 * termination for this label while the one used for deriving
 		 * IPMK|CMK did not use null termination.
 		 */
-		peap_prfplus(data->peap_version, data->ipmk, 40,
-			     "Session Key Generating Function",
-			     (u8 *) "\00", 1, csk, sizeof(csk));
+		if (peap_prfplus(data->peap_version, data->ipmk, 40,
+				 "Session Key Generating Function",
+				 (u8 *) "\00", 1, csk, sizeof(csk)) < 0)
+			return NULL;
 		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
 		eapKeyData = os_malloc(EAP_TLS_KEY_LEN);
 		if (eapKeyData) {
diff --git a/src/eap_server/eap_server_psk.c b/src/eap_server/eap_server_psk.c
index efc7a82..fb299ae 100644
--- a/src/eap_server/eap_server_psk.c
+++ b/src/eap_server/eap_server_psk.c
@@ -125,8 +125,10 @@
 
 	os_memcpy(buf, data->id_s, data->id_s_len);
 	os_memcpy(buf + data->id_s_len, data->rand_p, EAP_PSK_RAND_LEN);
-	if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s))
+	if (omac1_aes_128(data->ak, buf, buflen, psk->mac_s)) {
+		os_free(buf);
 		goto fail;
+	}
 	os_free(buf);
 
 	if (eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk,
diff --git a/src/eap_server/eap_server_pwd.c b/src/eap_server/eap_server_pwd.c
index dd2557a..4c6f4d1 100644
--- a/src/eap_server/eap_server_pwd.c
+++ b/src/eap_server/eap_server_pwd.c
@@ -156,8 +156,8 @@
 
 	wpa_printf(MSG_DEBUG, "EAP-pwd: ID/Request");
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-			    sizeof(struct eap_pwd_hdr) +
-			    sizeof(struct eap_pwd_id) + data->id_server_len,
+			    1 + sizeof(struct eap_pwd_id) +
+			    data->id_server_len,
 			    EAP_CODE_REQUEST, id);
 	if (req == NULL) {
 		eap_pwd_state(data, FAILURE);
@@ -257,8 +257,7 @@
 	BN_bn2bin(y, element + BN_num_bytes(data->grp->prime) + offset);
 
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-			    sizeof(struct eap_pwd_hdr) +
-			    (2 * BN_num_bytes(data->grp->prime)) +
+			    1 + (2 * BN_num_bytes(data->grp->prime)) +
 			    BN_num_bytes(data->grp->order),
 			    EAP_CODE_REQUEST, id);
 	if (req == NULL)
@@ -289,6 +288,7 @@
 	HMAC_CTX ctx;
 	u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
 	u16 grp;
+	int offset;
 
 	wpa_printf(MSG_DEBUG, "EAP-pwd: Confirm/Request");
 
@@ -313,7 +313,8 @@
 	 * First is k
 	 */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->k, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server element: x, y */
@@ -326,15 +327,19 @@
 	}
 
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->my_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* peer element: x, y */
@@ -347,15 +352,19 @@
 	}
 
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* peer scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->peer_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->peer_scalar);
+	BN_bn2bin(data->peer_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* ciphersuite */
@@ -375,7 +384,7 @@
 	os_memcpy(data->my_confirm, conf, SHA256_DIGEST_LENGTH);
 
 	req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_PWD,
-			    sizeof(struct eap_pwd_hdr) + SHA256_DIGEST_LENGTH,
+			    1 + SHA256_DIGEST_LENGTH,
 			    EAP_CODE_REQUEST, id);
 	if (req == NULL)
 		goto fin;
@@ -624,6 +633,7 @@
 	u32 cs;
 	u16 grp;
 	u8 conf[SHA256_DIGEST_LENGTH], *cruft = NULL, *ptr;
+	int offset;
 
 	/* build up the ciphersuite: group | random_function | prf */
 	grp = htons(data->group_num);
@@ -649,7 +659,8 @@
 
 	/* k */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->k, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(data->k);
+	BN_bn2bin(data->k, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* peer element: x, y */
@@ -661,15 +672,19 @@
 		goto fin;
 	}
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* peer scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->peer_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->peer_scalar);
+	BN_bn2bin(data->peer_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* server element: x, y */
@@ -682,15 +697,19 @@
 	}
 
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(x, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(x);
+	BN_bn2bin(x, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(y, cruft);
+	offset = BN_num_bytes(data->grp->prime) - BN_num_bytes(y);
+	BN_bn2bin(y, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->prime));
 
 	/* server scalar */
 	os_memset(cruft, 0, BN_num_bytes(data->grp->prime));
-	BN_bn2bin(data->my_scalar, cruft);
+	offset = BN_num_bytes(data->grp->order) -
+		BN_num_bytes(data->my_scalar);
+	BN_bn2bin(data->my_scalar, cruft + offset);
 	H_Update(&ctx, cruft, BN_num_bytes(data->grp->order));
 
 	/* ciphersuite */
diff --git a/src/eap_server/eap_server_tls_common.c b/src/eap_server/eap_server_tls_common.c
index e149ee3..0bb9d14 100644
--- a/src/eap_server/eap_server_tls_common.c
+++ b/src/eap_server/eap_server_tls_common.c
@@ -94,9 +94,9 @@
 	os_memcpy(rnd + keys.client_random_len, keys.server_random,
 		  keys.server_random_len);
 
-	if (tls_prf(keys.master_key, keys.master_key_len,
-		    label, rnd, keys.client_random_len +
-		    keys.server_random_len, out, len))
+	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+			     label, rnd, keys.client_random_len +
+			     keys.server_random_len, out, len))
 		goto fail;
 
 	os_free(rnd);
diff --git a/src/eap_server/eap_server_ttls.c b/src/eap_server/eap_server_ttls.c
index 702c50c..398d0f1 100644
--- a/src/eap_server/eap_server_ttls.c
+++ b/src/eap_server/eap_server_ttls.c
@@ -1,6 +1,6 @@
 /*
  * hostapd / EAP-TTLS (RFC 5281)
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -24,16 +24,7 @@
 #include "eap_common/eap_ttls.h"
 
 
-/* Maximum supported TTLS version
- * 0 = RFC 5281
- * 1 = draft-funk-eap-ttls-v1-00.txt
- */
-#ifndef EAP_TTLS_VERSION
-#define EAP_TTLS_VERSION 0 /* TTLSv1 implementation is not yet complete */
-#endif /* EAP_TTLS_VERSION */
-
-
-#define MSCHAPV2_KEY_LEN 16
+#define EAP_TTLS_VERSION 0
 
 
 static void eap_ttls_reset(struct eap_sm *sm, void *priv);
@@ -43,17 +34,15 @@
 	struct eap_ssl_data ssl;
 	enum {
 		START, PHASE1, PHASE2_START, PHASE2_METHOD,
-		PHASE2_MSCHAPV2_RESP, PHASE_FINISHED, SUCCESS, FAILURE
+		PHASE2_MSCHAPV2_RESP, SUCCESS, FAILURE
 	} state;
 
 	int ttls_version;
-	int force_version;
 	const struct eap_method *phase2_method;
 	void *phase2_priv;
 	int mschapv2_resp_ok;
 	u8 mschapv2_auth_response[20];
 	u8 mschapv2_ident;
-	int tls_ia_configured;
 	struct wpabuf *pending_phase2_eap_resp;
 	int tnc_started;
 };
@@ -72,8 +61,6 @@
 		return "PHASE2_METHOD";
 	case PHASE2_MSCHAPV2_RESP:
 		return "PHASE2_MSCHAPV2_RESP";
-	case PHASE_FINISHED:
-		return "PHASE_FINISHED";
 	case SUCCESS:
 		return "SUCCESS";
 	case FAILURE:
@@ -111,7 +98,8 @@
 	}
 
 	avp->avp_code = host_to_be32(avp_code);
-	avp->avp_length = host_to_be32((flags << 24) | (hdrlen + len));
+	avp->avp_length = host_to_be32(((u32) flags << 24) |
+				       ((u32) (hdrlen + len)));
 
 	return avphdr + hdrlen;
 }
@@ -320,54 +308,8 @@
 static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
 					struct eap_ttls_data *data, size_t len)
 {
-	struct tls_keys keys;
-	u8 *challenge, *rnd;
-
-	if (data->ttls_version == 0) {
-		return eap_server_tls_derive_key(sm, &data->ssl,
-						 "ttls challenge", len);
-	}
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive "
-			   "implicit challenge");
-		return NULL;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	challenge = os_malloc(len);
-	if (rnd == NULL || challenge == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for implicit "
-			   "challenge derivation");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-	os_memcpy(rnd, keys.server_random, keys.server_random_len);
-	os_memcpy(rnd + keys.server_random_len, keys.client_random,
-		  keys.client_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "inner application challenge", rnd,
-		    keys.client_random_len + keys.server_random_len,
-		    challenge, len)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive implicit "
-			   "challenge");
-		os_free(rnd);
-		os_free(challenge);
-		return NULL;
-	}
-
-	os_free(rnd);
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived implicit challenge",
-			challenge, len);
-
-	return challenge;
+	return eap_server_tls_derive_key(sm, &data->ssl, "ttls challenge",
+					 len);
 }
 
 
@@ -379,27 +321,8 @@
 	if (data == NULL)
 		return NULL;
 	data->ttls_version = EAP_TTLS_VERSION;
-	data->force_version = -1;
-	if (sm->user && sm->user->force_version >= 0) {
-		data->force_version = sm->user->force_version;
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: forcing version %d",
-			   data->force_version);
-		data->ttls_version = data->force_version;
-	}
 	data->state = START;
 
-	if (!(tls_capabilities(sm->ssl_ctx) & TLS_CAPABILITY_IA) &&
-	    data->ttls_version > 0) {
-		if (data->force_version > 0) {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Forced TTLSv%d and "
-				   "TLS library does not support TLS/IA.",
-				   data->force_version);
-			eap_ttls_reset(sm, data);
-			return NULL;
-		}
-		data->ttls_version = 0;
-	}
-
 	if (eap_server_tls_ssl_init(sm, &data->ssl, 0)) {
 		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
 		eap_ttls_reset(sm, data);
@@ -516,14 +439,6 @@
 }
 
 
-static struct wpabuf * eap_ttls_build_phase_finished(
-	struct eap_sm *sm, struct eap_ttls_data *data, int final)
-{
-	return tls_connection_ia_send_phase_finished(sm->ssl_ctx,
-						     data->ssl.conn, final);
-}
-
-
 static struct wpabuf * eap_ttls_buildReq(struct eap_sm *sm, void *priv, u8 id)
 {
 	struct eap_ttls_data *data = priv;
@@ -559,11 +474,6 @@
 		data->ssl.tls_out_pos = 0;
 		data->ssl.tls_out = eap_ttls_build_phase2_mschapv2(sm, data);
 		break;
-	case PHASE_FINISHED:
-		wpabuf_free(data->ssl.tls_out);
-		data->ssl.tls_out_pos = 0;
-		data->ssl.tls_out = eap_ttls_build_phase_finished(sm, data, 1);
-		break;
 	default:
 		wpa_printf(MSG_DEBUG, "EAP-TTLS: %s - unexpected state %d",
 			   __func__, data->state);
@@ -591,37 +501,6 @@
 }
 
 
-static int eap_ttls_ia_permute_inner_secret(struct eap_sm *sm,
-					    struct eap_ttls_data *data,
-					    const u8 *key, size_t key_len)
-{
-	u8 *buf;
-	size_t buf_len;
-	int ret;
-
-	if (key) {
-		buf_len = 2 + key_len;
-		buf = os_malloc(buf_len);
-		if (buf == NULL)
-			return -1;
-		WPA_PUT_BE16(buf, key_len);
-		os_memcpy(buf + 2, key, key_len);
-	} else {
-		buf = NULL;
-		buf_len = 0;
-	}
-
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Session keys for TLS/IA inner "
-			"secret permutation", buf, buf_len);
-	ret = tls_connection_ia_permute_inner_secret(sm->ssl_ctx,
-						     data->ssl.conn,
-						     buf, buf_len);
-	os_free(buf);
-
-	return ret;
-}
-
-
 static void eap_ttls_process_phase2_pap(struct eap_sm *sm,
 					struct eap_ttls_data *data,
 					const u8 *user_password,
@@ -644,8 +523,7 @@
 	}
 
 	wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP: Correct user password");
-	eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-		       SUCCESS);
+	eap_ttls_state(data, SUCCESS);
 }
 
 
@@ -701,8 +579,7 @@
 
 	if (os_memcmp(hash, password + 1, EAP_TTLS_CHAP_PASSWORD_LEN) == 0) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Correct user password");
-		eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-			       SUCCESS);
+		eap_ttls_state(data, SUCCESS);
 	} else {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP: Invalid user password");
 		eap_ttls_state(data, FAILURE);
@@ -762,8 +639,7 @@
 
 	if (os_memcmp(nt_response, response + 2 + 24, 24) == 0) {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Correct response");
-		eap_ttls_state(data, data->ttls_version > 0 ? PHASE_FINISHED :
-			       SUCCESS);
+		eap_ttls_state(data, SUCCESS);
 	} else {
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP: Invalid NT-Response");
 		wpa_hexdump(MSG_MSGDUMP, "EAP-TTLS/MSCHAP: Received",
@@ -863,30 +739,6 @@
 		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Correct "
 			   "NT-Response");
 		data->mschapv2_resp_ok = 1;
-		if (data->ttls_version > 0) {
-			const u8 *pw_hash;
-			u8 pw_hash_buf[16], pw_hash_hash[16], master_key[16];
-			u8 session_key[2 * MSCHAPV2_KEY_LEN];
-
-			if (sm->user->password_hash)
-				pw_hash = sm->user->password;
-			else {
-				nt_password_hash(sm->user->password,
-						 sm->user->password_len,
-						 pw_hash_buf);
-				pw_hash = pw_hash_buf;
-			}
-			hash_nt_password_hash(pw_hash, pw_hash_hash);
-			get_master_key(pw_hash_hash, nt_response, master_key);
-			get_asymetric_start_key(master_key, session_key,
-						MSCHAPV2_KEY_LEN, 0, 0);
-			get_asymetric_start_key(master_key,
-						session_key + MSCHAPV2_KEY_LEN,
-						MSCHAPV2_KEY_LEN, 1, 0);
-			eap_ttls_ia_permute_inner_secret(sm, data,
-							 session_key,
-							 sizeof(session_key));
-		}
 
 		if (sm->user->password_hash) {
 			generate_authenticator_response_pwhash(
@@ -1030,17 +882,7 @@
 		}
 		break;
 	case PHASE2_METHOD:
-		if (data->ttls_version > 0) {
-			if (m->getKey) {
-				u8 *key;
-				size_t key_len;
-				key = m->getKey(sm, priv, &key_len);
-				eap_ttls_ia_permute_inner_secret(sm, data,
-								 key, key_len);
-			}
-			eap_ttls_state(data, PHASE_FINISHED);
-		} else
-			eap_ttls_state(data, SUCCESS);
+		eap_ttls_state(data, SUCCESS);
 		break;
 	case FAILURE:
 		break;
@@ -1130,23 +972,6 @@
 		return;
 	}
 
-	if (data->state == PHASE_FINISHED) {
-		if (wpabuf_len(in_decrypted) == 0 &&
-		    tls_connection_ia_final_phase_finished(sm->ssl_ctx,
-							   data->ssl.conn)) {
-			wpa_printf(MSG_DEBUG, "EAP-TTLS: FinalPhaseFinished "
-				   "received");
-			eap_ttls_state(data, SUCCESS);
-		} else {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Did not receive valid "
-				   "FinalPhaseFinished");
-			eap_ttls_state(data, FAILURE);
-		}
-
-		wpabuf_free(in_decrypted);
-		return;
-	}
-
 	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 EAP",
 			    in_decrypted);
 
@@ -1245,15 +1070,6 @@
 		data->ttls_version = peer_version;
 	}
 
-	if (data->ttls_version > 0 && !data->tls_ia_configured) {
-		if (tls_connection_set_ia(sm->ssl_ctx, data->ssl.conn, 1)) {
-			wpa_printf(MSG_INFO, "EAP-TTLS: Failed to enable "
-				   "TLS/IA");
-			return -1;
-		}
-		data->tls_ia_configured = 1;
-	}
-
 	return 0;
 }
 
@@ -1270,7 +1086,6 @@
 		break;
 	case PHASE2_START:
 	case PHASE2_METHOD:
-	case PHASE_FINISHED:
 		eap_ttls_process_phase2(sm, data, data->ssl.tls_in);
 		eap_ttls_start_tnc(sm, data);
 		break;
@@ -1279,8 +1094,7 @@
 		    0) {
 			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
 				   "acknowledged response");
-			eap_ttls_state(data, data->ttls_version > 0 ?
-				       PHASE_FINISHED : SUCCESS);
+			eap_ttls_state(data, SUCCESS);
 		} else if (!data->mschapv2_resp_ok) {
 			wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Peer "
 				   "acknowledged error");
@@ -1321,54 +1135,6 @@
 }
 
 
-static u8 * eap_ttls_v1_derive_key(struct eap_sm *sm,
-				   struct eap_ttls_data *data)
-{
-	struct tls_keys keys;
-	u8 *rnd, *key;
-
-	os_memset(&keys, 0, sizeof(keys));
-	if (tls_connection_get_keys(sm->ssl_ctx, data->ssl.conn, &keys) ||
-	    keys.client_random == NULL || keys.server_random == NULL ||
-	    keys.inner_secret == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: Could not get inner secret, "
-			   "client random, or server random to derive keying "
-			   "material");
-		return NULL;
-	}
-
-	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
-	key = os_malloc(EAP_TLS_KEY_LEN);
-	if (rnd == NULL || key == NULL) {
-		wpa_printf(MSG_INFO, "EAP-TTLS: No memory for key derivation");
-		os_free(rnd);
-		os_free(key);
-		return NULL;
-	}
-	os_memcpy(rnd, keys.client_random, keys.client_random_len);
-	os_memcpy(rnd + keys.client_random_len, keys.server_random,
-		  keys.server_random_len);
-
-	if (tls_prf(keys.inner_secret, keys.inner_secret_len,
-		    "ttls v1 keying material", rnd, keys.client_random_len +
-		    keys.server_random_len, key, EAP_TLS_KEY_LEN)) {
-		wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to derive key");
-		os_free(rnd);
-		os_free(key);
-		return NULL;
-	}
-
-	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: client/server random",
-		    rnd, keys.client_random_len + keys.server_random_len);
-	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: TLS/IA inner secret",
-			keys.inner_secret, keys.inner_secret_len);
-
-	os_free(rnd);
-
-	return key;
-}
-
-
 static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
 {
 	struct eap_ttls_data *data = priv;
@@ -1377,14 +1143,9 @@
 	if (data->state != SUCCESS)
 		return NULL;
 
-	if (data->ttls_version == 0) {
-		eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
-						       "ttls keying material",
-						       EAP_TLS_KEY_LEN);
-	} else {
-		eapKeyData = eap_ttls_v1_derive_key(sm, data);
-	}
-
+	eapKeyData = eap_server_tls_derive_key(sm, &data->ssl,
+					       "ttls keying material",
+					       EAP_TLS_KEY_LEN);
 	if (eapKeyData) {
 		*len = EAP_TLS_KEY_LEN;
 		wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
diff --git a/src/eap_server/ikev2.c b/src/eap_server/ikev2.c
index 9624d53..f5bbb14 100644
--- a/src/eap_server/ikev2.c
+++ b/src/eap_server/ikev2.c
@@ -404,7 +404,7 @@
 	}
 
 	/* RFC 4306, Section 3.4:
-	 * The length of DH public value MUST be equal to the lenght of the
+	 * The length of DH public value MUST be equal to the length of the
 	 * prime modulus.
 	 */
 	if (ker_len - 4 != data->dh->prime_len) {
diff --git a/src/eapol_auth/eapol_auth_sm.c b/src/eapol_auth/eapol_auth_sm.c
index 4aa71ad..e600954 100644
--- a/src/eapol_auth/eapol_auth_sm.c
+++ b/src/eapol_auth/eapol_auth_sm.c
@@ -1017,7 +1017,7 @@
 
 int eapol_auth_eap_pending_cb(struct eapol_state_machine *sm, void *ctx)
 {
-	if (sm == NULL || ctx != sm->eap)
+	if (sm == NULL || ctx == NULL || ctx != sm->eap)
 		return -1;
 
 	eap_sm_pending_cb(sm->eap);
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index bb6cff6..ffc6619 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -561,7 +561,7 @@
 		 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
 		 * and SUCCESS based on eapFail and eapSuccess, respectively.
 		 * However, IEEE Std 802.1X-2004 is also specifying that
-		 * eapNoResp should be set in conjuction with eapSuccess and
+		 * eapNoResp should be set in conjunction with eapSuccess and
 		 * eapFail which would mean that more than one of the
 		 * transitions here would be activated at the same time.
 		 * Skipping RESPONSE and/or RECEIVE states in these cases can
@@ -1813,7 +1813,7 @@
 
 
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-static void eapol_sm_eap_param_needed(void *ctx, const char *field,
+static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
 				      const char *txt)
 {
 	struct eapol_sm *sm = ctx;
@@ -1883,6 +1883,7 @@
 	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
 	conf.pkcs11_module_path = ctx->pkcs11_module_path;
 	conf.wps = ctx->wps;
+	conf.cert_in_cb = ctx->cert_in_cb;
 
 	sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
 	if (sm->eap == NULL) {
diff --git a/src/eapol_supp/eapol_supp_sm.h b/src/eapol_supp/eapol_supp_sm.h
index 3ea7e79..bcb00b5 100644
--- a/src/eapol_supp/eapol_supp_sm.h
+++ b/src/eapol_supp/eapol_supp_sm.h
@@ -208,10 +208,10 @@
 	/**
 	 * eap_param_needed - Notify that EAP parameter is needed
 	 * @ctx: Callback context (ctx)
-	 * @field: Field name (e.g., "IDENTITY")
+	 * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
 	 * @txt: User readable text describing the required parameter
 	 */
-	void (*eap_param_needed)(void *ctx, const char *field,
+	void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
 				 const char *txt);
 
 	/**
@@ -231,6 +231,11 @@
 	 */
 	void (*cert_cb)(void *ctx, int depth, const char *subject,
 			const char *cert_hash, const struct wpabuf *cert);
+
+	/**
+	 * cert_in_cb - Include server certificates in callback
+	 */
+	int cert_in_cb;
 };
 
 
diff --git a/src/p2p/p2p.c b/src/p2p/p2p.c
old mode 100644
new mode 100755
index bef3926..8c768f6
--- a/src/p2p/p2p.c
+++ b/src/p2p/p2p.c
@@ -17,6 +17,9 @@
 #include "common.h"
 #include "eloop.h"
 #include "common/ieee802_11_defs.h"
+#ifdef ANDROID_P2P
+#include "common/wpa_ctrl.h"
+#endif
 #include "common/ieee802_11_common.h"
 #include "wps/wps_i.h"
 #include "p2p_i.h"
@@ -106,12 +109,42 @@
 		return "INVITE";
 	case P2P_INVITE_LISTEN:
 		return "INVITE_LISTEN";
+	case P2P_SEARCH_WHEN_READY:
+		return "SEARCH_WHEN_READY";
 	default:
 		return "?";
 	}
 }
 
 
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr)
+{
+	struct p2p_device *dev = NULL;
+
+	if (!addr || !p2p)
+		return 0;
+
+	dev = p2p_get_device(p2p, addr);
+	if (dev)
+		return dev->wps_prov_info;
+	else
+		return 0;
+}
+
+
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr)
+{
+	struct p2p_device *dev = NULL;
+
+	if (!iface_addr || !p2p)
+		return;
+
+	dev = p2p_get_device_interface(p2p, iface_addr);
+	if (dev)
+		dev->wps_prov_info = 0;
+}
+
+
 void p2p_set_state(struct p2p_data *p2p, int new_state)
 {
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: State %s -> %s",
@@ -144,6 +177,8 @@
 	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->wps_method = WPS_NOT_READY;
 	p2p->go_neg_peer = NULL;
 
 	os_memset(&res, 0, sizeof(res));
@@ -219,6 +254,12 @@
 	p2p->pending_listen_usec = (timeout % 1000) * 1000;
 
 	if (p2p->p2p_scan_running) {
+		if (p2p->start_after_scan == P2P_AFTER_SCAN_NOTHING) {
+			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
+				"P2P: p2p_scan running - connect is already "
+				"pending - skip listen");
+			return 0;
+		}
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: p2p_scan running - delay start of listen state");
 		p2p->start_after_scan = P2P_AFTER_SCAN_LISTEN;
@@ -363,7 +404,7 @@
 	 * group, the information will be restored in the loop following this.
 	 */
 	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
-		if (os_memcpy(dev->member_in_go_iface, go_interface_addr,
+		if (os_memcmp(dev->member_in_go_iface, go_interface_addr,
 			      ETH_ALEN) == 0) {
 			os_memset(dev->member_in_go_iface, 0, ETH_ALEN);
 			os_memset(dev->member_in_go_dev, 0, ETH_ALEN);
@@ -372,6 +413,9 @@
 
 	for (c = 0; c < info.num_clients; c++) {
 		struct p2p_client_info *cli = &info.client[c];
+		if (os_memcmp(cli->p2p_device_addr, p2p->cfg->dev_addr,
+			      ETH_ALEN) == 0)
+			continue; /* ignore our own entry */
 		dev = p2p_get_device(p2p, cli->p2p_device_addr);
 		if (dev) {
 			/*
@@ -574,11 +618,6 @@
 			freq, msg.ds_params ? *msg.ds_params : -1);
 	}
 	dev->listen_freq = freq;
-#ifdef ANDROID_BRCM_P2P_PATCH	
-	if(msg.group_info)
-		dev->go_state = REMOTE_GO;
-#endif
-
 	if (msg.group_info)
 		dev->oper_freq = freq;
 	dev->info.level = level;
@@ -631,9 +670,10 @@
 	int i;
 
 	if (p2p->go_neg_peer == dev) {
-#ifdef ANDROID_BRCM_P2P_PATCH
+		/*
+		 * If GO Negotiation is in progress, report that it has failed.
+		 */
 		p2p_go_neg_failed(p2p, dev, -1);
-#endif
 		p2p->go_neg_peer = NULL;
 	}
 	if (p2p->invite_peer == dev)
@@ -787,19 +827,18 @@
 	enum p2p_after_scan op;
 
 	if (p2p->after_scan_tx) {
-		int ret;
 		/* TODO: schedule p2p_run_after_scan to be called from TX
 		 * status callback(?) */
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send pending "
 			"Action frame at p2p_scan completion");
-		ret = p2p->cfg->send_action(p2p->cfg->cb_ctx,
-					    p2p->after_scan_tx->freq,
-					    p2p->after_scan_tx->dst,
-					    p2p->after_scan_tx->src,
-					    p2p->after_scan_tx->bssid,
-					    (u8 *) (p2p->after_scan_tx + 1),
-					    p2p->after_scan_tx->len,
-					    p2p->after_scan_tx->wait_time);
+		p2p->cfg->send_action(p2p->cfg->cb_ctx,
+				      p2p->after_scan_tx->freq,
+				      p2p->after_scan_tx->dst,
+				      p2p->after_scan_tx->src,
+				      p2p->after_scan_tx->bssid,
+				      (u8 *) (p2p->after_scan_tx + 1),
+				      p2p->after_scan_tx->len,
+				      p2p->after_scan_tx->wait_time);
 		os_free(p2p->after_scan_tx);
 		p2p->after_scan_tx = NULL;
 		return 1;
@@ -888,6 +927,7 @@
 	p2p_device_clear_reported(p2p);
 	p2p_set_state(p2p, P2P_SEARCH);
 	eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
+	p2p->last_p2p_find_timeout = timeout;
 	if (timeout)
 		eloop_register_timeout(timeout, 0, p2p_find_timeout,
 				       p2p, NULL);
@@ -913,21 +953,47 @@
 		eloop_cancel_timeout(p2p_scan_timeout, p2p, NULL);
 		eloop_register_timeout(P2P_SCAN_TIMEOUT, 0, p2p_scan_timeout,
 				       p2p, NULL);
+	} else if (res == 1) {
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Could not start "
+			"p2p_scan at this point - will try again after "
+			"previous scan completes");
+		res = 0;
+		p2p_set_state(p2p, P2P_SEARCH_WHEN_READY);
+		eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
 	} else {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Failed to start "
 			"p2p_scan");
+		p2p_set_state(p2p, P2P_IDLE);
+		eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
 	}
 
 	return res;
 }
 
 
+int p2p_other_scan_completed(struct p2p_data *p2p)
+{
+	if (p2p->state != P2P_SEARCH_WHEN_READY)
+		return 0;
+	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Starting pending P2P find "
+		"now that previous scan was completed");
+	if (p2p_find(p2p, p2p->last_p2p_find_timeout, p2p->find_type,
+		     p2p->num_req_dev_types, p2p->req_dev_types) < 0)
+		return 0;
+	return 1;
+}
+
+
 void p2p_stop_find_for_freq(struct p2p_data *p2p, int freq)
 {
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Stopping find");
 	eloop_cancel_timeout(p2p_find_timeout, p2p, NULL);
 	p2p_clear_timeout(p2p);
 	p2p_set_state(p2p, P2P_IDLE);
+#ifdef ANDROID_P2P
+	wpa_msg(p2p->cfg->msg_ctx, MSG_INFO, P2P_EVENT_FIND_STOPPED);
+#endif
+
 	p2p_free_req_dev_types(p2p);
 	p2p->start_after_scan = P2P_AFTER_SCAN_NOTHING;
 	p2p->go_neg_peer = NULL;
@@ -938,6 +1004,16 @@
 			"since we are on correct channel for response");
 		return;
 	}
+	if (p2p->drv_in_listen) {
+		/*
+		 * The driver may not deliver callback to p2p_listen_end()
+		 * when the operation gets canceled, so clear the internal
+		 * variable that is tracking driver state.
+		 */
+		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Clear "
+			"drv_in_listen (%d)", p2p->drv_in_listen);
+		p2p->drv_in_listen = 0;
+	}
 	p2p->cfg->stop_listen(p2p->cfg->cb_ctx);
 }
 
@@ -1027,6 +1103,26 @@
 }
 
 
+static void p2p_set_dev_persistent(struct p2p_device *dev,
+				   int persistent_group)
+{
+	switch (persistent_group) {
+	case 0:
+		dev->flags &= ~(P2P_DEV_PREFER_PERSISTENT_GROUP |
+				P2P_DEV_PREFER_PERSISTENT_RECONN);
+		break;
+	case 1:
+		dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
+		dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_RECONN;
+		break;
+	case 2:
+		dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP |
+			P2P_DEV_PREFER_PERSISTENT_RECONN;
+		break;
+	}
+}
+
+
 int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
 		enum p2p_wps_method wps_method,
 		int go_intent, const u8 *own_interface_addr,
@@ -1044,6 +1140,7 @@
 	if (p2p_prepare_channel(p2p, force_freq) < 0)
 		return -1;
 
+	p2p->ssid_set = 0;
 	dev = p2p_get_device(p2p, peer_addr);
 	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
@@ -1083,10 +1180,7 @@
 	dev->connect_reqs = 0;
 	dev->go_neg_req_sent = 0;
 	dev->go_state = UNKNOWN_GO;
-	if (persistent_group)
-		dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
-	else
-		dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP;
+	p2p_set_dev_persistent(dev, persistent_group);
 	p2p->go_intent = go_intent;
 	os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
 
@@ -1156,10 +1250,7 @@
 	dev->flags &= ~P2P_DEV_USER_REJECTED;
 	dev->go_neg_req_sent = 0;
 	dev->go_state = UNKNOWN_GO;
-	if (persistent_group)
-		dev->flags |= P2P_DEV_PREFER_PERSISTENT_GROUP;
-	else
-		dev->flags &= ~P2P_DEV_PREFER_PERSISTENT_GROUP;
+	p2p_set_dev_persistent(dev, persistent_group);
 	p2p->go_intent = go_intent;
 	os_memcpy(p2p->intended_addr, own_interface_addr, ETH_ALEN);
 
@@ -1270,8 +1361,12 @@
 	os_memcpy(res.peer_device_addr, peer->info.p2p_device_addr, ETH_ALEN);
 	os_memcpy(res.peer_interface_addr, peer->intended_addr, ETH_ALEN);
 	res.wps_method = peer->wps_method;
-	if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
-		res.persistent_group = 1;
+	if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
+		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+			res.persistent_group = 2;
+		else
+			res.persistent_group = 1;
+	}
 
 	if (go) {
 		/* Setup AP mode for WPS provisioning */
@@ -1311,6 +1406,7 @@
 	res.peer_config_timeout = go ? peer->client_timeout : peer->go_timeout;
 
 	p2p_clear_timeout(p2p);
+	p2p->ssid_set = 0;
 	peer->go_neg_req_sent = 0;
 	peer->wps_method = WPS_NOT_READY;
 
@@ -1367,9 +1463,9 @@
 }
 
 
-void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da, const u8 *sa,
-			  const u8 *bssid, const u8 *data, size_t len,
-			  int freq)
+static void p2p_rx_action_public(struct p2p_data *p2p, const u8 *da,
+				 const u8 *sa, const u8 *bssid, const u8 *data,
+				 size_t len, int freq)
 {
 	if (len < 1)
 		return;
@@ -1514,6 +1610,7 @@
 	if (dev) {
 		if (dev->country[0] == 0 && msg.listen_channel)
 			os_memcpy(dev->country, msg.listen_channel, 3);
+		os_get_time(&dev->last_seen);
 		p2p_parse_free(&msg);
 		return; /* already known */
 	}
@@ -1653,13 +1750,47 @@
 }
 
 
-static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
+static int is_11b(u8 rate)
+{
+	return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
+}
+
+
+static int supp_rates_11b_only(struct ieee802_11_elems *elems)
+{
+	int num_11b = 0, num_others = 0;
+	int i;
+
+	if (elems->supp_rates == NULL && elems->ext_supp_rates == NULL)
+		return 0;
+
+	for (i = 0; elems->supp_rates && i < elems->supp_rates_len; i++) {
+		if (is_11b(elems->supp_rates[i]))
+			num_11b++;
+		else
+			num_others++;
+	}
+
+	for (i = 0; elems->ext_supp_rates && i < elems->ext_supp_rates_len;
+	     i++) {
+		if (is_11b(elems->ext_supp_rates[i]))
+			num_11b++;
+		else
+			num_others++;
+	}
+
+	return num_11b > 0 && num_others == 0;
+}
+
+
+static void p2p_reply_probe(struct p2p_data *p2p, const u8 *addr,
+			    const u8 *dst, const u8 *bssid, const u8 *ie,
 			    size_t ie_len)
 {
 	struct ieee802_11_elems elems;
 	struct wpabuf *buf;
 	struct ieee80211_mgmt *resp;
-	struct wpabuf *wps;
+	struct p2p_message msg;
 	struct wpabuf *ies;
 
 	if (!p2p->in_listen || !p2p->drv_in_listen) {
@@ -1678,6 +1809,18 @@
 		return;
 	}
 
+	if (dst && !is_broadcast_ether_addr(dst) &&
+	    os_memcmp(dst, p2p->cfg->dev_addr, ETH_ALEN) != 0) {
+		/* Not sent to the broadcast address or our P2P Device Address
+		 */
+		return;
+	}
+
+	if (bssid && !is_broadcast_ether_addr(bssid)) {
+		/* Not sent to the Wildcard BSSID */
+		return;
+	}
+
 	if (elems.ssid == NULL || elems.ssid_len != P2P_WILDCARD_SSID_LEN ||
 	    os_memcmp(elems.ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) !=
 	    0) {
@@ -1685,14 +1828,32 @@
 		return;
 	}
 
-	/* Check Requested Device Type match */
-	wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
-	if (wps && !p2p_match_dev_type(p2p, wps)) {
-		wpabuf_free(wps);
-		/* No match with Requested Device Type */
+	if (supp_rates_11b_only(&elems)) {
+		/* Indicates support for 11b rates only */
 		return;
 	}
-	wpabuf_free(wps);
+
+	os_memset(&msg, 0, sizeof(msg));
+	if (p2p_parse_ies(ie, ie_len, &msg) < 0) {
+		/* Could not parse P2P attributes */
+		return;
+	}
+
+	if (msg.device_id &&
+	    os_memcmp(msg.device_id, p2p->cfg->dev_addr, ETH_ALEN != 0)) {
+		/* Device ID did not match */
+		p2p_parse_free(&msg);
+		return;
+	}
+
+	/* Check Requested Device Type match */
+	if (msg.wps_attributes &&
+	    !p2p_match_dev_type(p2p, msg.wps_attributes)) {
+		/* No match with Requested Device Type */
+		p2p_parse_free(&msg);
+		return;
+	}
+	p2p_parse_free(&msg);
 
 	if (!p2p->cfg->send_probe_resp)
 		return; /* Response generated elsewhere */
@@ -1759,12 +1920,12 @@
 }
 
 
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
-		     size_t ie_len)
+int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+		     const u8 *bssid, const u8 *ie, size_t ie_len)
 {
 	p2p_add_dev_from_probe_req(p2p, addr, ie, ie_len);
 
-	p2p_reply_probe(p2p, addr, ie, ie_len);
+	p2p_reply_probe(p2p, addr, dst, bssid, ie, ie_len);
 
 	if ((p2p->state == P2P_CONNECT || p2p->state == P2P_CONNECT_LISTEN) &&
 	    p2p->go_neg_peer &&
@@ -2221,11 +2382,11 @@
 		} else if (dev->req_config_methods &&
 			   !(dev->flags & P2P_DEV_PD_FOR_JOIN)) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
-				"pending Provisioning Discovery Request to "
+				"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)
+			if (p2p_send_prov_disc_req(p2p, dev, 0, 0) == 0)
 				return;
 		}
 	}
@@ -2267,7 +2428,7 @@
  * p2p_retry_pd - Retry any pending provision disc requests in IDLE state
  * @p2p: P2P module context from p2p_init()
  */
-void p2p_retry_pd(struct p2p_data *p2p)
+static void p2p_retry_pd(struct p2p_data *p2p)
 {
 	struct p2p_device *dev;
 
@@ -2290,11 +2451,11 @@
 			continue;
 
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Send "
-			"pending Provisioning Discovery Request to "
+			"pending Provision Discovery Request to "
 			MACSTR " (config methods 0x%x)",
 			MAC2STR(dev->info.p2p_device_addr),
 			dev->req_config_methods);
-		p2p_send_prov_disc_req(p2p, dev, 0);
+		p2p_send_prov_disc_req(p2p, dev, 0, 0);
 		return;
 	}
 }
@@ -2395,6 +2556,12 @@
 }
 
 
+size_t p2p_scan_ie_buf_len(struct p2p_data *p2p)
+{
+	return 100;
+}
+
+
 int p2p_ie_text(struct wpabuf *p2p_ie, char *buf, char *end)
 {
 	return p2p_attr_text(p2p_ie, buf, end);
@@ -2674,15 +2841,7 @@
 	 * state once per second to give other uses a chance to use the radio.
 	 */
 	p2p_set_state(p2p, P2P_WAIT_PEER_IDLE);
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/*
-	 * We need to be back in Listen state soon enough so that we don't miss
-	 * the GO Nego req from the peer.
-	*/
-	p2p_set_timeout(p2p, 0, 0);
-#else
-	p2p_set_timeout(p2p, 1, 0);
-#endif
+	p2p_set_timeout(p2p, 0, 500000);
 }
 
 
@@ -2862,6 +3021,8 @@
 	case P2P_INVITE_LISTEN:
 		p2p_timeout_invite_listen(p2p);
 		break;
+	case P2P_SEARCH_WHEN_READY:
+		break;
 	}
 }
 
@@ -2884,13 +3045,11 @@
 }
 
 
-static const char * p2p_wps_method_text(enum p2p_wps_method method)
+const char * p2p_wps_method_text(enum p2p_wps_method method)
 {
 	switch (method) {
 	case WPS_NOT_READY:
 		return "not-ready";
-	case WPS_PIN_LABEL:
-		return "Label";
 	case WPS_PIN_DISPLAY:
 		return "Display";
 	case WPS_PIN_KEYPAD:
@@ -2918,14 +3077,10 @@
 }
 
 
-int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
-		      char *buf, size_t buflen)
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+					       const u8 *addr, int next)
 {
 	struct p2p_device *dev;
-	int res;
-	char *pos, *end;
-	struct os_time now;
-	char devtype[WPS_DEV_TYPE_BUFSIZE];
 
 	if (addr)
 		dev = p2p_get_device(p2p, addr);
@@ -2939,35 +3094,37 @@
 	}
 
 	if (dev == NULL)
+		return NULL;
+
+	return &dev->info;
+}
+
+
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+			  char *buf, size_t buflen)
+{
+	struct p2p_device *dev;
+	int res;
+	char *pos, *end;
+	struct os_time now;
+
+	if (info == NULL)
 		return -1;
 
+	dev = (struct p2p_device *) (((u8 *) info) -
+				     offsetof(struct p2p_device, info));
+
 	pos = buf;
 	end = buf + buflen;
 
-	res = os_snprintf(pos, end - pos, MACSTR "\n",
-			  MAC2STR(dev->info.p2p_device_addr));
-	if (res < 0 || res >= end - pos)
-		return pos - buf;
-	pos += res;
-
 	os_get_time(&now);
 	res = os_snprintf(pos, end - pos,
 			  "age=%d\n"
 			  "listen_freq=%d\n"
-			  "level=%d\n"
 			  "wps_method=%s\n"
 			  "interface_addr=" MACSTR "\n"
 			  "member_in_go_dev=" MACSTR "\n"
 			  "member_in_go_iface=" MACSTR "\n"
-			  "pri_dev_type=%s\n"
-			  "device_name=%s\n"
-			  "manufacturer=%s\n"
-			  "model_name=%s\n"
-			  "model_number=%s\n"
-			  "serial_number=%s\n"
-			  "config_methods=0x%x\n"
-			  "dev_capab=0x%x\n"
-			  "group_capab=0x%x\n"
 			  "go_neg_req_sent=%d\n"
 			  "go_state=%s\n"
 			  "dialog_token=%u\n"
@@ -2981,21 +3138,10 @@
 			  "invitation_reqs=%u\n",
 			  (int) (now.sec - dev->last_seen.sec),
 			  dev->listen_freq,
-			  dev->info.level,
 			  p2p_wps_method_text(dev->wps_method),
 			  MAC2STR(dev->interface_addr),
 			  MAC2STR(dev->member_in_go_dev),
 			  MAC2STR(dev->member_in_go_iface),
-			  wps_dev_type_bin2str(dev->info.pri_dev_type,
-					       devtype, sizeof(devtype)),
-			  dev->info.device_name,
-			  dev->info.manufacturer,
-			  dev->info.model_name,
-			  dev->info.model_number,
-			  dev->info.serial_number,
-			  dev->info.config_methods,
-			  dev->info.dev_capab,
-			  dev->info.group_capab,
 			  dev->go_neg_req_sent,
 			  p2p_go_state_text(dev->go_state),
 			  dev->dialog_token,
@@ -3064,6 +3210,12 @@
 }
 
 
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr)
+{
+	return p2p_get_device(p2p, addr) != NULL;
+}
+
+
 void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled)
 {
 	if (enabled) {
@@ -3624,3 +3776,20 @@
 
 	return &dev->info;
 }
+
+#ifdef ANDROID_P2P
+int p2p_search_in_progress(struct p2p_data *p2p)
+{
+	if (p2p == NULL)
+		return 0;
+
+	return p2p->state == P2P_SEARCH;
+}
+#endif
+
+int p2p_in_progress(struct p2p_data *p2p)
+{
+	if (p2p == NULL)
+		return 0;
+	return p2p->state != P2P_IDLE && p2p->state != P2P_PROVISIONING;
+}
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
old mode 100644
new mode 100755
index 72c90b1..05b4a16
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -56,7 +56,7 @@
 };
 
 enum p2p_wps_method {
-	WPS_NOT_READY, WPS_PIN_LABEL, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
+	WPS_NOT_READY, WPS_PIN_DISPLAY, WPS_PIN_KEYPAD, WPS_PBC
 };
 
 /**
@@ -120,6 +120,9 @@
 
 	/**
 	 * persistent_group - Whether the group should be made persistent
+	 * 0 = not persistent
+	 * 1 = persistent group without persistent reconnect
+	 * 2 = persistent group with persistent reconnect
 	 */
 	int persistent_group;
 
@@ -292,17 +295,6 @@
 	 */
 	u8 dev_addr[ETH_ALEN];
 
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/**
-	 * p2p_dev_addr - P2P Device Address
-	 *
-	 * Holds the p2p device address. If the driver uses primary mac address
-	 * for p2p operations, then this will hold the same value as that of 
-	 * dev_addr.
-	 */
-	u8 p2p_dev_addr[ETH_ALEN];
-#endif
-
 	/**
 	 * dev_name - Device Name
 	 */
@@ -602,6 +594,8 @@
 	 * @supp_config_methods: Supported configuration Methods
 	 * @dev_capab: Device Capabilities
 	 * @group_capab: Group Capabilities
+	 * @group_id: P2P Group ID (or %NULL if not included)
+	 * @group_id_len: Length of P2P Group ID
 	 *
 	 * This callback is used to indicate reception of a Provision Discovery
 	 * Request frame that the P2P module accepted.
@@ -609,7 +603,8 @@
 	void (*prov_disc_req)(void *ctx, const u8 *peer, u16 config_methods,
 			      const u8 *dev_addr, const u8 *pri_dev_type,
 			      const char *dev_name, u16 supp_config_methods,
-			      u8 dev_capab, u8 group_capab);
+			      u8 dev_capab, u8 group_capab,
+			      const u8 *group_id, size_t group_id_len);
 
 	/**
 	 * prov_disc_resp - Callback on Provisiong Discovery Response
@@ -857,7 +852,9 @@
  * @go_intent: Local GO intent value (1..15)
  * @own_interface_addr: Intended interface address to use with the group
  * @force_freq: The only allowed channel frequency in MHz or 0
- * @persistent_group: Whether to create a persistent group
+ * @persistent_group: Whether to create a persistent group (0 = no, 1 =
+ * persistent group without persistent reconnect, 2 = persistent group with
+ * persistent reconnect)
  * Returns: 0 on success, -1 on failure
  */
 int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
@@ -873,7 +870,9 @@
  * @go_intent: Local GO intent value (1..15)
  * @own_interface_addr: Intended interface address to use with the group
  * @force_freq: The only allowed channel frequency in MHz or 0
- * @persistent_group: Whether to create a persistent group
+ * @persistent_group: Whether to create a persistent group (0 = no, 1 =
+ * persistent group without persistent reconnect, 2 = persistent group with
+ * persistent reconnect)
  * Returns: 0 on success, -1 on failure
  *
  * This is like p2p_connect(), but the actual group negotiation is not
@@ -898,6 +897,7 @@
  * @peer_addr: MAC address of the peer P2P client
  * @config_methods: WPS Config Methods value (only one bit set)
  * @join: Whether this is used by a client joining an active group
+ * @force_freq: Forced TX frequency for the frame (mainly for the join case)
  * Returns: 0 on success, -1 on failure
  *
  * This function can be used to request a discovered P2P peer to display a PIN
@@ -909,7 +909,7 @@
  * indicated with the p2p_config::prov_disc_resp() callback.
  */
 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
-		      u16 config_methods, int join);
+		      u16 config_methods, int join, int force_freq);
 
 /**
  * p2p_sd_request - Schedule a service discovery query
@@ -1039,6 +1039,28 @@
  */
 void p2p_group_formation_failed(struct p2p_data *p2p);
 
+/**
+ * p2p_get_provisioning_info - Get any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @addr: Peer P2P Device Address
+ * Returns: WPS provisioning information (WPS config method) or 0 if no
+ * information is available
+ *
+ * This function is used to retrieve stored WPS provisioning info for the given
+ * peer.
+ */
+u16 p2p_get_provisioning_info(struct p2p_data *p2p, const u8 *addr);
+
+/**
+ * p2p_clear_provisioning_info - Clear any stored provisioning info
+ * @p2p: P2P module context from p2p_init()
+ * @iface_addr: Peer P2P Interface Address
+ *
+ * This function is used to clear stored WPS provisioning info for the given
+ * peer.
+ */
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *iface_addr);
+
 
 /* Event notifications from lower layer driver operations */
 
@@ -1046,12 +1068,14 @@
  * p2p_probe_req_rx - Report reception of a Probe Request frame
  * @p2p: P2P module context from p2p_init()
  * @addr: Source MAC address
+ * @dst: Destination MAC address if available or %NULL
+ * @bssid: BSSID if available or %NULL
  * @ie: Information elements from the Probe Request frame body
  * @ie_len: Length of ie buffer in octets
  * Returns: 0 to indicate the frame was not processed or 1 if it was
  */
-int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *ie,
-		     size_t ie_len);
+int p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+		     const u8 *bssid, const u8 *ie, size_t ie_len);
 
 /**
  * p2p_rx_action - Report received Action frame
@@ -1173,6 +1197,9 @@
 struct p2p_group_config {
 	/**
 	 * persistent_group - Whether the group is persistent
+	 * 0 = not a persistent group
+	 * 1 = persistent group without persistent reconnect
+	 * 2 = persistent group with persistent reconnect
 	 */
 	int persistent_group;
 
@@ -1244,16 +1271,6 @@
  */
 int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
 			  const u8 *ie, size_t len);
-#ifdef ANDROID_BRCM_P2P_PATCH
-/**
- * p2p_group_get_dev_addr - Retreive the device address of an assocated P2P
- * client. 
- * @group: P2P group context from p2p_group_init()
- * @addr: Interface address of the P2P client
- * Returns: P2P dev_addr on success, NULL on failure
- */
-u8 *p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
-#endif /*ANDROID_BRCM_P2P_PATCH */
 
 /**
  * p2p_group_assoc_resp_ie - Build P2P IE for (re)association response
@@ -1363,6 +1380,13 @@
 void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies);
 
 /**
+ * p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie
+ * @p2p: P2P module context from p2p_init()
+ * Returns: Number of octets that p2p_scan_ie() may add to the buffer
+ */
+size_t p2p_scan_ie_buf_len(struct p2p_data *p2p);
+
+/**
  * p2p_go_params - Generate random P2P group parameters
  * @p2p: P2P module context from p2p_init()
  * @params: Buffer for parameters
@@ -1392,16 +1416,36 @@
 const u8 * p2p_get_go_dev_addr(const struct wpabuf *p2p_ie);
 
 /**
- * p2p_get_peer_info - Get P2P peer information in text format
+ * p2p_get_peer_info - Get P2P peer information
  * @p2p: P2P module context from p2p_init()
  * @addr: P2P Device Address of the peer or %NULL to indicate the first peer
  * @next: Whether to select the peer entry following the one indicated by addr
+ * Returns: Pointer to peer info or %NULL if not found
+ */
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+					       const u8 *addr, int next);
+
+/**
+ * p2p_get_peer_info_txt - Get internal P2P peer information in text format
+ * @info: Pointer to P2P peer info from p2p_get_peer_info()
  * @buf: Buffer for returning text
  * @buflen: Maximum buffer length
  * Returns: Number of octets written to the buffer or -1 on failure
+ *
+ * Note: This information is internal to the P2P module and subject to change.
+ * As such, this should not really be used by external programs for purposes
+ * other than debugging.
  */
-int p2p_get_peer_info(struct p2p_data *p2p, const u8 *addr, int next,
-		      char *buf, size_t buflen);
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+			  char *buf, size_t buflen);
+
+/**
+ * p2p_peer_known - Check whether P2P peer is known
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P Device Address of the peer
+ * Returns: 1 if the specified device is in the P2P peer table or 0 if not
+ */
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr);
 
 /**
  * p2p_set_client_discoverability - Set client discoverability capability
@@ -1415,7 +1459,7 @@
 void p2p_set_client_discoverability(struct p2p_data *p2p, int enabled);
 
 /**
- * p2p_set_manageD_oper - Set managed P2P Device operations capability
+ * p2p_set_managed_oper - Set managed P2P Device operations capability
  * @p2p: P2P module context from p2p_init()
  * @enabled: Whether managed P2P Device operations will be enabled
  */
@@ -1490,6 +1534,15 @@
 const u8 * p2p_iterate_group_members(struct p2p_group *group, void **next);
 
 /**
+ * p2p_group_get_dev_addr - Get a P2P Device Address of a client in a group
+ * @group: P2P group context from p2p_group_init()
+ * @addr: P2P Interface Address of the client
+ * Returns: P2P Device Address of the client if found or %NULL if no match
+ * found
+ */
+const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr);
+
+/**
  * p2p_get_peer_found - Get P2P peer info structure of a found peer
  * @p2p: P2P module context from p2p_init()
  * @addr: P2P Device Address of the peer or %NULL to indicate the first peer
@@ -1528,4 +1581,29 @@
 int p2p_set_oper_channel(struct p2p_data *p2p, u8 op_reg_class, u8 op_channel,
 			 int cfg_op_channel);
 
+/**
+ * p2p_in_progress - Check whether a P2P operation is progress
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ */
+int p2p_in_progress(struct p2p_data *p2p);
+
+#ifdef ANDROID_P2P
+/**
+ * p2p_in_progress - Check whether a P2P SEARCH is in progress
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ */
+int p2p_search_in_progress(struct p2p_data *p2p);
+#endif
+
+/**
+ * p2p_other_scan_completed - Notify completion of non-P2P scan
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation was started
+ */
+int p2p_other_scan_completed(struct p2p_data *p2p);
+
+const char * p2p_wps_method_text(enum p2p_wps_method method);
+
 #endif /* P2P_H */
diff --git a/src/p2p/p2p_build.c b/src/p2p/p2p_build.c
index d59e54b..a82e16d 100644
--- a/src/p2p/p2p_build.c
+++ b/src/p2p/p2p_build.c
@@ -164,27 +164,20 @@
 	len = wpabuf_put(buf, 2); /* IE length to be filled */
 
 	/* P2P Device address */
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/* 
-	* P2P_ADDR: Supplicant uses primary mac addr for p2p and hence advertises that. To
-	* to make it compatible with solution using virtual interface for P2P, a new variable
-	* is added to hold the actual p2p device address.
-	*/
-	wpabuf_put_data(buf, p2p->cfg->p2p_dev_addr, ETH_ALEN);
-#else
 	wpabuf_put_data(buf, p2p->cfg->dev_addr, ETH_ALEN);
-#endif
 
 	/* Config Methods */
 	methods = 0;
 	if (peer && peer->wps_method != WPS_NOT_READY) {
 		if (peer->wps_method == WPS_PBC)
 			methods |= WPS_CONFIG_PUSHBUTTON;
-		else if (peer->wps_method == WPS_PIN_LABEL)
-			methods |= WPS_CONFIG_LABEL;
 		else if (peer->wps_method == WPS_PIN_DISPLAY ||
 			 peer->wps_method == WPS_PIN_KEYPAD)
 			methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
+	} else if (p2p->cfg->config_methods) {
+		methods |= p2p->cfg->config_methods &
+			(WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_DISPLAY |
+			 WPS_CONFIG_KEYPAD);
 	} else {
 		methods |= WPS_CONFIG_PUSHBUTTON;
 		methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index f5937b9..eb85f51 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -107,8 +107,6 @@
 static u16 p2p_wps_method_pw_id(enum p2p_wps_method wps_method)
 {
 	switch (wps_method) {
-	case WPS_PIN_LABEL:
-		return DEV_PW_DEFAULT;
 	case WPS_PIN_DISPLAY:
 		return DEV_PW_REGISTRAR_SPECIFIED;
 	case WPS_PIN_KEYPAD:
@@ -124,8 +122,6 @@
 static const char * p2p_wps_method_str(enum p2p_wps_method wps_method)
 {
 	switch (wps_method) {
-	case WPS_PIN_LABEL:
-		return "Label";
 	case WPS_PIN_DISPLAY:
 		return "Display";
 	case WPS_PIN_KEYPAD:
@@ -156,8 +152,11 @@
 
 	len = p2p_buf_add_ie_hdr(buf);
 	group_capab = 0;
-	if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+	if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
 		group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+			group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+	}
 	if (p2p->cross_connect)
 		group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
 	if (p2p->cfg->p2p_intra_bss)
@@ -246,8 +245,12 @@
 	p2p_buf_add_status(buf, status);
 	group_capab = 0;
 	if (peer && peer->go_state == LOCAL_GO) {
-		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
 			group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+			if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+				group_capab |=
+					P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+		}
 		if (p2p->cross_connect)
 			group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
 		if (p2p->cfg->p2p_intra_bss)
@@ -491,15 +494,7 @@
 		}
 
 		if (dev->go_neg_req_sent &&
-#ifdef ANDROID_BRCM_P2P_PATCH 
-		/* P2P_ADDR: compare against the p2p device address. The own mac 
-		address may not not be the actual p2p device address, if you 
-		are using a virtual interface.
-		*/
-		    os_memcmp(sa, p2p->cfg->p2p_dev_addr, ETH_ALEN) > 0) {
-#else
 		    os_memcmp(sa, p2p->cfg->dev_addr, ETH_ALEN) > 0) {
-#endif
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: Do not reply since peer has higher "
 				"address and GO Neg Request already sent");
@@ -524,18 +519,6 @@
 		}
 
 		switch (msg.dev_password_id) {
-		case DEV_PW_DEFAULT:
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: PIN from peer Label");
-			if (dev->wps_method != WPS_PIN_KEYPAD) {
-				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-					"P2P: We have wps_method=%s -> "
-					"incompatible",
-					p2p_wps_method_str(dev->wps_method));
-				status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
-				goto fail;
-			}
-			break;
 		case DEV_PW_REGISTRAR_SPECIFIED:
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: PIN from peer Display");
@@ -551,8 +534,7 @@
 		case DEV_PW_USER_SPECIFIED:
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: Peer entered PIN on Keypad");
-			if (dev->wps_method != WPS_PIN_LABEL &&
-			    dev->wps_method != WPS_PIN_DISPLAY) {
+			if (dev->wps_method != WPS_PIN_DISPLAY) {
 				wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 					"P2P: We have wps_method=%s -> "
 					"incompatible",
@@ -606,7 +588,10 @@
 						   p2p->op_channel))
 				p2p_reselect_channel(p2p, &intersection);
 
-			p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+			if (!p2p->ssid_set) {
+				p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+				p2p->ssid_set = 1;
+			}
 		}
 
 		dev->go_state = go ? LOCAL_GO : REMOTE_GO;
@@ -695,8 +680,12 @@
 	p2p_buf_add_status(buf, status);
 	group_capab = 0;
 	if (peer->go_state == LOCAL_GO) {
-		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP)
+		if (peer->flags & P2P_DEV_PREFER_PERSISTENT_GROUP) {
 			group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+			if (peer->flags & P2P_DEV_PREFER_PERSISTENT_RECONN)
+				group_capab |=
+					P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+		}
 		if (p2p->cross_connect)
 			group_capab |= P2P_GROUP_CAPAB_CROSS_CONN;
 		if (p2p->cfg->p2p_intra_bss)
@@ -907,18 +896,6 @@
 		dev->oper_freq = 0;
 
 	switch (msg.dev_password_id) {
-	case DEV_PW_DEFAULT:
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: PIN from peer Label");
-		if (dev->wps_method != WPS_PIN_KEYPAD) {
-			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-				"P2P: We have wps_method=%s -> "
-				"incompatible",
-				p2p_wps_method_str(dev->wps_method));
-			status = P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD;
-			goto fail;
-		}
-		break;
 	case DEV_PW_REGISTRAR_SPECIFIED:
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: PIN from peer Display");
@@ -934,8 +911,7 @@
 	case DEV_PW_USER_SPECIFIED:
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Peer entered PIN on Keypad");
-		if (dev->wps_method != WPS_PIN_LABEL &&
-		    dev->wps_method != WPS_PIN_DISPLAY) {
+		if (dev->wps_method != WPS_PIN_DISPLAY) {
 			wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 				"P2P: We have wps_method=%s -> "
 				"incompatible",
@@ -988,7 +964,10 @@
 					   p2p->op_channel))
 			p2p_reselect_channel(p2p, &intersection);
 
-		p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+		if (!p2p->ssid_set) {
+			p2p_build_ssid(p2p, p2p->ssid, &p2p->ssid_len);
+			p2p->ssid_set = 1;
+		}
 	}
 
 	p2p_set_state(p2p, P2P_GO_NEG);
diff --git a/src/p2p/p2p_group.c b/src/p2p/p2p_group.c
index 0d05319..59d1507 100644
--- a/src/p2p/p2p_group.c
+++ b/src/p2p/p2p_group.c
@@ -147,8 +147,11 @@
 	dev_capab |= P2P_DEV_CAPAB_SERVICE_DISCOVERY;
 	dev_capab |= P2P_DEV_CAPAB_INVITATION_PROCEDURE;
 	group_capab |= P2P_GROUP_CAPAB_GROUP_OWNER;
-	if (group->cfg->persistent_group)
+	if (group->cfg->persistent_group) {
 		group_capab |= P2P_GROUP_CAPAB_PERSISTENT_GROUP;
+		if (group->cfg->persistent_group == 2)
+			group_capab |= P2P_GROUP_CAPAB_PERSISTENT_RECONN;
+	}
 	if (group->p2p->cfg->p2p_intra_bss)
 		group_capab |= P2P_GROUP_CAPAB_INTRA_BSS_DIST;
 	if (group->group_formation)
@@ -183,12 +186,7 @@
 
 	len = p2p_buf_add_ie_hdr(ie);
 	p2p_group_add_common_ies(group, ie);
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/* P2P_ADDR: Use p2p_dev_addr instead of own mac addr*/
-	p2p_buf_add_device_id(ie, group->p2p->cfg->p2p_dev_addr);
-#else
 	p2p_buf_add_device_id(ie, group->p2p->cfg->dev_addr);
-#endif
 	p2p_group_add_noa(ie, group->noa);
 	p2p_buf_update_ie_hdr(ie, len);
 
@@ -315,6 +313,36 @@
 }
 
 
+static int p2p_group_remove_member(struct p2p_group *group, const u8 *addr)
+{
+	struct p2p_group_member *m, *prev;
+
+	if (group == NULL)
+		return 0;
+
+	m = group->members;
+	prev = NULL;
+	while (m) {
+		if (os_memcmp(m->addr, addr, ETH_ALEN) == 0)
+			break;
+		prev = m;
+		m = m->next;
+	}
+
+	if (m == NULL)
+		return 0;
+
+	if (prev)
+		prev->next = m->next;
+	else
+		group->members = m->next;
+	p2p_group_free_member(m);
+	group->num_members--;
+
+	return 1;
+}
+
+
 int p2p_group_notif_assoc(struct p2p_group *group, const u8 *addr,
 			  const u8 *ie, size_t len)
 {
@@ -334,6 +362,8 @@
 						       m->dev_addr);
 	}
 
+	p2p_group_remove_member(group, addr);
+
 	m->next = group->members;
 	group->members = m;
 	group->num_members++;
@@ -376,27 +406,7 @@
 
 void p2p_group_notif_disassoc(struct p2p_group *group, const u8 *addr)
 {
-	struct p2p_group_member *m, *prev;
-
-	if (group == NULL)
-		return;
-
-	m = group->members;
-	prev = NULL;
-	while (m) {
-		if (os_memcmp(m->addr, addr, ETH_ALEN) == 0)
-			break;
-		prev = m;
-		m = m->next;
-	}
-
-	if (m) {
-		if (prev)
-			prev->next = m->next;
-		else
-			group->members = m->next;
-		p2p_group_free_member(m);
-		group->num_members--;
+	if (p2p_group_remove_member(group, addr)) {
 		wpa_msg(group->p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Remove "
 			"client " MACSTR " from group; num_members=%u/%u",
 			MAC2STR(addr), group->num_members,
@@ -499,11 +509,7 @@
 	} else {
 		if (group->noa) {
 			if (wpabuf_size(group->noa) >= noa_len) {
-			#ifdef ANDROID_BRCM_P2P_PATCH
 				group->noa->used = 0;
-			#else
-				group->noa->size = 0;
-			#endif
 				wpabuf_put_data(group->noa, noa, noa_len);
 			} else {
 				wpabuf_free(group->noa);
@@ -551,19 +557,19 @@
 	return NULL;
 }
 
-#ifdef ANDROID_BRCM_P2P_PATCH
-u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr)
+
+const u8 * p2p_group_get_dev_addr(struct p2p_group *group, const u8 *addr)
 {
 	struct p2p_group_member *m;
 
-	m = p2p_group_get_client_iface(group, addr);
-
-	if (m)
-		return m->dev_addr;
-	else
+	if (group == NULL)
 		return NULL;
+	m = p2p_group_get_client_iface(group, addr);
+	if (m && !is_zero_ether_addr(m->dev_addr))
+		return m->dev_addr;
+	return NULL;
 }
-#endif /* ANDROID_BRCM_P2P_PATCH */
+
 
 static struct wpabuf * p2p_build_go_disc_req(void)
 {
@@ -662,11 +668,11 @@
 	else
 		wpa_hexdump(MSG_DEBUG, "P2P: Current NoA", curr_noa,
 			    curr_noa_len);
-#ifndef ANDROID_BRCM_P2P_PATCH
+
 	/* TODO: properly process request and store copy */
-	if (curr_noa_len > 0)
+	if (curr_noa_len > 0 || curr_noa_len == -1)
 		return P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE;
-#endif
+
 	return P2P_SC_SUCCESS;
 }
 
diff --git a/src/p2p/p2p_i.h b/src/p2p/p2p_i.h
index afb891e..0dc33e7 100644
--- a/src/p2p/p2p_i.h
+++ b/src/p2p/p2p_i.h
@@ -18,8 +18,6 @@
 #include "utils/list.h"
 #include "p2p.h"
 
-/* TODO: add removal of expired P2P device entries */
-
 enum p2p_go_state {
 	UNKNOWN_GO,
 	LOCAL_GO,
@@ -69,10 +67,18 @@
 	size_t oper_ssid_len;
 
 	/**
-	 * req_config_methods - Pending provisioning discovery methods
+	 * req_config_methods - Pending provision discovery methods
 	 */
 	u16 req_config_methods;
 
+	/**
+	 * wps_prov_info - Stored provisioning WPS config method
+	 *
+	 * This is used to store pending WPS config method between Provisioning
+	 * Discovery and connection to a running group.
+	 */
+	u16 wps_prov_info;
+
 #define P2P_DEV_PROBE_REQ_ONLY BIT(0)
 #define P2P_DEV_REPORTED BIT(1)
 #define P2P_DEV_NOT_YET_READY BIT(2)
@@ -89,6 +95,7 @@
 #define P2P_DEV_FORCE_FREQ BIT(13)
 #define P2P_DEV_PD_FOR_JOIN BIT(14)
 #define P2P_DEV_REPORTED_ONCE BIT(15)
+#define P2P_DEV_PREFER_PERSISTENT_RECONN BIT(16)
 	unsigned int flags;
 
 	int status; /* enum p2p_status_code */
@@ -200,6 +207,11 @@
 		 * P2P_INVITE_LISTEN - Listen during Invite
 		 */
 		P2P_INVITE_LISTEN,
+
+		/**
+		 * P2P_SEARCH_WHEN_READY - Waiting to start Search
+		 */
+		P2P_SEARCH_WHEN_READY,
 	} state;
 
 	/**
@@ -273,6 +285,11 @@
 	size_t ssid_len;
 
 	/**
+	 * ssid_set - Whether SSID is already set for GO Negotiation
+	 */
+	int ssid_set;
+
+	/**
 	 * Regulatory class for own operational channel
 	 */
 	u8 op_reg_class;
@@ -349,6 +366,7 @@
 	int inv_persistent;
 
 	enum p2p_discovery_type find_type;
+	unsigned int last_p2p_find_timeout;
 	u8 last_prog_scan_class;
 	u8 last_prog_scan_chan;
 	int p2p_scan_running;
@@ -532,11 +550,6 @@
 
 /* p2p_group.c */
 const u8 * p2p_group_get_interface_addr(struct p2p_group *group);
-
-#ifdef ANDROID_BRCM_P2P_PATCH
-void p2p_get_group_noa(struct p2p_group *group, u8 *noa, size_t* noa_len);
-#endif
-
 u8 p2p_group_presence_req(struct p2p_group *group,
 			  const u8 *client_interface_addr,
 			  const u8 *noa, size_t noa_len);
@@ -606,7 +619,7 @@
 void p2p_process_prov_disc_resp(struct p2p_data *p2p, const u8 *sa,
 				const u8 *data, size_t len);
 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
-			   int join);
+			   int join, int force_freq);
 void p2p_reset_pending_pd(struct p2p_data *p2p);
 
 /* p2p_invitation.c */
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 42015ad..bb2767d 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -55,11 +55,7 @@
 	else if (p2p->inv_role == P2P_INVITE_ROLE_CLIENT)
 		dev_addr = peer->info.p2p_device_addr;
 	else
-#ifdef ANDROID_BRCM_P2P_PATCH
-		dev_addr = p2p->cfg->p2p_dev_addr;
-#else
 		dev_addr = p2p->cfg->dev_addr;
-#endif
 	p2p_buf_add_group_id(buf, dev_addr, p2p->inv_ssid, p2p->inv_ssid_len);
 	p2p_buf_add_device_info(buf, p2p, peer);
 	p2p_buf_update_ie_hdr(buf, len);
diff --git a/src/p2p/p2p_pd.c b/src/p2p/p2p_pd.c
index 32d82f6..1ee59c5 100644
--- a/src/p2p/p2p_pd.c
+++ b/src/p2p/p2p_pd.c
@@ -112,7 +112,7 @@
 		MAC2STR(sa), msg.wps_config_methods, rx_freq);
 
 	dev = p2p_get_device(p2p, sa);
-	if (dev == NULL || !(dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
+	if (dev == NULL || (dev->flags & P2P_DEV_PROBE_REQ_ONLY)) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Provision Discovery Request from "
 			"unknown peer " MACSTR, MAC2STR(sa));
@@ -191,8 +191,8 @@
 					msg.device_name, msg.config_methods,
 					msg.capability ? msg.capability[0] : 0,
 					msg.capability ? msg.capability[1] :
-					0);
-
+					0,
+					msg.group_id, msg.group_id_len);
 	}
 	p2p_parse_free(&msg);
 }
@@ -209,14 +209,14 @@
 		return;
 
 	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-		"P2P: Received Provisioning Discovery Response from " MACSTR
+		"P2P: Received Provision Discovery Response from " MACSTR
 		" with config methods 0x%x",
 		MAC2STR(sa), msg.wps_config_methods);
 
 	dev = p2p_get_device(p2p, sa);
 	if (dev == NULL || !dev->req_config_methods) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore Provisioning Discovery Response from "
+			"P2P: Ignore Provision Discovery Response from "
 			MACSTR " with no pending request", MAC2STR(sa));
 		p2p_parse_free(&msg);
 		return;
@@ -229,7 +229,7 @@
 
 	if (dev->dialog_token != msg.dialog_token) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Ignore Provisioning Discovery Response with "
+			"P2P: Ignore Provision Discovery Response with "
 			"unexpected Dialog Token %u (expected %u)",
 			msg.dialog_token, dev->dialog_token);
 		p2p_parse_free(&msg);
@@ -246,7 +246,7 @@
 
 	if (msg.wps_config_methods != dev->req_config_methods) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: Peer rejected "
-			"our Provisioning Discovery Request");
+			"our Provision Discovery Request");
 		if (p2p->cfg->prov_disc_fail)
 			p2p->cfg->prov_disc_fail(p2p->cfg->cb_ctx, sa,
 						 P2P_PROV_DISC_REJECTED);
@@ -267,6 +267,10 @@
 			MAC2STR(sa));
 		dev->flags |= P2P_DEV_PD_PEER_KEYPAD;
 	}
+
+	/* Store the provisioning info */
+	dev->wps_prov_info = msg.wps_config_methods;
+
 	p2p_parse_free(&msg);
 
 out:
@@ -279,25 +283,16 @@
 
 
 int p2p_send_prov_disc_req(struct p2p_data *p2p, struct p2p_device *dev,
-			   int join)
+			   int join, int force_freq)
 {
 	struct wpabuf *req;
 	int freq;
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if(dev->go_state == REMOTE_GO) {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: GO Sending it to oper_freq %d", dev->oper_freq);
-		freq= dev->oper_freq;
-	}
-	else {
-		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: NOT GO oper_freq %d listen_freq %d", dev->oper_freq, dev->listen_freq);
-		freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
-	}
-#else
-	freq = dev->listen_freq > 0 ? dev->listen_freq : dev->oper_freq;
-#endif
 
+	if (force_freq > 0)
+		freq = force_freq;
+	else
+		freq = dev->listen_freq > 0 ? dev->listen_freq :
+			dev->oper_freq;
 	if (freq <= 0) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: No Listen/Operating frequency known for the "
@@ -345,7 +340,7 @@
 
 
 int p2p_prov_disc_req(struct p2p_data *p2p, const u8 *peer_addr,
-		      u16 config_methods, int join)
+		      u16 config_methods, int join, int force_freq)
 {
 	struct p2p_device *dev;
 
@@ -365,6 +360,9 @@
 	if (config_methods == 0)
 		return -1;
 
+	/* Reset provisioning info */
+	dev->wps_prov_info = 0;
+
 	dev->req_config_methods = config_methods;
 	if (join)
 		dev->flags |= P2P_DEV_PD_FOR_JOIN;
@@ -391,12 +389,26 @@
 	if (p2p->user_initiated_pd && p2p->state == P2P_IDLE)
 		p2p->pd_retries = MAX_PROV_DISC_REQ_RETRIES;
 
-	return p2p_send_prov_disc_req(p2p, dev, join);
+	return p2p_send_prov_disc_req(p2p, dev, join, force_freq);
 }
 
 
 void p2p_reset_pending_pd(struct p2p_data *p2p)
 {
+	struct p2p_device *dev;
+
+	dl_list_for_each(dev, &p2p->devices, struct p2p_device, list) {
+		if (os_memcmp(p2p->pending_pd_devaddr,
+			      dev->info.p2p_device_addr, ETH_ALEN))
+			continue;
+		if (!dev->req_config_methods)
+			continue;
+		if (dev->flags & P2P_DEV_PD_FOR_JOIN)
+			continue;
+		/* Reset the config methods of the device */
+		dev->req_config_methods = 0;
+	}
+
 	p2p->user_initiated_pd = 0;
 	os_memset(p2p->pending_pd_devaddr, 0, ETH_ALEN);
 	p2p->pd_retries = 0;
diff --git a/src/p2p/p2p_sd.c b/src/p2p/p2p_sd.c
index 9e26873..f53d4b5 100644
--- a/src/p2p/p2p_sd.c
+++ b/src/p2p/p2p_sd.c
@@ -16,6 +16,7 @@
 
 #include "common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/gas.h"
 #include "p2p_i.h"
 #include "p2p.h"
 
@@ -26,7 +27,7 @@
 	struct p2p_sd_query *q;
 
 	if (!(dev->info.dev_capab & P2P_DEV_CAPAB_SERVICE_DISCOVERY))
-		return 0; /* peer does not support SD */
+		return NULL; /* peer does not support SD */
 
 	for (q = p2p->sd_queries; q; q = q->next) {
 		if (q->for_all_peers && !(dev->flags & P2P_DEV_SD_INFO))
@@ -90,51 +91,21 @@
 					  struct wpabuf *tlvs)
 {
 	struct wpabuf *buf;
-	u8 *len_pos, *len_pos2;
+	u8 *len_pos;
 
-	buf = wpabuf_alloc(1000 + wpabuf_len(tlvs));
+	buf = gas_anqp_build_initial_req(0, 100 + wpabuf_len(tlvs));
 	if (buf == NULL)
 		return NULL;
 
-	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-	wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_REQ);
-	wpabuf_put_u8(buf, 0); /* Dialog Token */
-
-	/* Advertisement Protocol IE */
-	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
-	wpabuf_put_u8(buf, 2); /* Length */
-	wpabuf_put_u8(buf, 0); /* QueryRespLenLimit | PAME-BI */
-	wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
-	/* Query Request */
-	len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
-	/* NQP Query Request Frame */
-	wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
-	len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
+	/* ANQP Query Request Frame */
+	len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
 	wpabuf_put_be24(buf, OUI_WFA);
 	wpabuf_put_u8(buf, P2P_OUI_TYPE);
 	wpabuf_put_le16(buf, update_indic); /* Service Update Indicator */
 	wpabuf_put_buf(buf, tlvs);
+	gas_anqp_set_element_len(buf, len_pos);
 
-	WPA_PUT_LE16(len_pos2, (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
-	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
-
-	return buf;
-}
-
-
-static struct wpabuf * p2p_build_gas_comeback_req(u8 dialog_token)
-{
-	struct wpabuf *buf;
-
-	buf = wpabuf_alloc(3);
-	if (buf == NULL)
-		return NULL;
-
-	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-	wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_REQ);
-	wpabuf_put_u8(buf, dialog_token);
+	gas_anqp_set_len(buf);
 
 	return buf;
 }
@@ -145,7 +116,7 @@
 {
 	struct wpabuf *req;
 
-	req = p2p_build_gas_comeback_req(dialog_token);
+	req = gas_build_comeback_req(dialog_token);
 	if (req == NULL)
 		return;
 
@@ -165,42 +136,26 @@
 					     const struct wpabuf *tlvs)
 {
 	struct wpabuf *buf;
-	u8 *len_pos, *len_pos2;
+	u8 *len_pos;
 
-	buf = wpabuf_alloc(1000 + (tlvs ? wpabuf_len(tlvs) : 0));
+	buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+					  comeback_delay,
+					  100 + (tlvs ? wpabuf_len(tlvs) : 0));
 	if (buf == NULL)
 		return NULL;
 
-	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-	wpabuf_put_u8(buf, WLAN_PA_GAS_INITIAL_RESP);
-	wpabuf_put_u8(buf, dialog_token);
-	wpabuf_put_le16(buf, status_code);
-	wpabuf_put_le16(buf, comeback_delay);
-
-	/* Advertisement Protocol IE */
-	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
-	wpabuf_put_u8(buf, 2); /* Length */
-	wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
-	wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
-	/* Query Response */
-	len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
 	if (tlvs) {
-		/* NQP Query Response Frame */
-		wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
-		len_pos2 = wpabuf_put(buf, 2); /* Length (to be filled) */
+		/* ANQP Query Response Frame */
+		len_pos = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
 		wpabuf_put_be24(buf, OUI_WFA);
 		wpabuf_put_u8(buf, P2P_OUI_TYPE);
 		 /* Service Update Indicator */
 		wpabuf_put_le16(buf, update_indic);
 		wpabuf_put_buf(buf, tlvs);
-
-		WPA_PUT_LE16(len_pos2,
-			     (u8 *) wpabuf_put(buf, 0) - len_pos2 - 2);
+		gas_anqp_set_element_len(buf, len_pos);
 	}
 
-	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+	gas_anqp_set_len(buf);
 
 	return buf;
 }
@@ -214,31 +169,15 @@
 						   u16 total_len)
 {
 	struct wpabuf *buf;
-	u8 *len_pos;
 
-	buf = wpabuf_alloc(1000 + len);
+	buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+					   more, 0, 100 + len);
 	if (buf == NULL)
 		return NULL;
 
-	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
-	wpabuf_put_u8(buf, WLAN_PA_GAS_COMEBACK_RESP);
-	wpabuf_put_u8(buf, dialog_token);
-	wpabuf_put_le16(buf, status_code);
-	wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
-	wpabuf_put_le16(buf, 0); /* Comeback Delay */
-
-	/* Advertisement Protocol IE */
-	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
-	wpabuf_put_u8(buf, 2); /* Length */
-	wpabuf_put_u8(buf, 0x7f); /* QueryRespLenLimit | PAME-BI */
-	wpabuf_put_u8(buf, NATIVE_QUERY_PROTOCOL); /* Advertisement Protocol */
-
-	/* Query Response */
-	len_pos = wpabuf_put(buf, 2); /* Length (to be filled) */
-
 	if (frag_id == 0) {
-		/* NQP Query Response Frame */
-		wpabuf_put_le16(buf, NQP_VENDOR_SPECIFIC); /* Info ID */
+		/* ANQP Query Response Frame */
+		wpabuf_put_le16(buf, ANQP_VENDOR_SPECIFIC); /* Info ID */
 		wpabuf_put_le16(buf, 3 + 1 + 2 + total_len);
 		wpabuf_put_be24(buf, OUI_WFA);
 		wpabuf_put_u8(buf, P2P_OUI_TYPE);
@@ -247,8 +186,7 @@
 	}
 
 	wpabuf_put_data(buf, data, len);
-
-	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+	gas_anqp_set_len(buf);
 
 	return buf;
 }
@@ -349,7 +287,7 @@
 	}
 	pos++; /* skip QueryRespLenLimit and PAME-BI */
 
-	if (*pos != NATIVE_QUERY_PROTOCOL) {
+	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Unsupported GAS advertisement protocol id %u",
 			*pos);
@@ -366,12 +304,12 @@
 		return;
 	end = pos + slen;
 
-	/* NQP Query Request */
+	/* ANQP Query Request */
 	if (pos + 4 > end)
 		return;
-	if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+			"P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
 		return;
 	}
 	pos += 2;
@@ -380,20 +318,20 @@
 	pos += 2;
 	if (pos + slen > end || slen < 3 + 1) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid NQP Query Request length");
+			"P2P: Invalid ANQP Query Request length");
 		return;
 	}
 
 	if (WPA_GET_BE24(pos) != OUI_WFA) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+			"P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
 		return;
 	}
 	pos += 3;
 
 	if (*pos != P2P_OUI_TYPE) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP vendor type %u", *pos);
+			"P2P: Unsupported ANQP vendor type %u", *pos);
 		return;
 	}
 	pos++;
@@ -451,11 +389,7 @@
 
 	p2p->pending_action_state = P2P_NO_PENDING_ACTION;
 	if (p2p_send_action(p2p, freq, dst, p2p->cfg->dev_addr,
-		#ifdef ANDROID_BRCM_P2P_PATCH
-			   p2p->cfg->p2p_dev_addr,
-		#else
 			    p2p->cfg->dev_addr,
-		#endif
 			    wpabuf_head(resp), wpabuf_len(resp), 200) < 0)
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Failed to send Action frame");
@@ -529,7 +463,7 @@
 	}
 	pos++; /* skip QueryRespLenLimit and PAME-BI */
 
-	if (*pos != NATIVE_QUERY_PROTOCOL) {
+	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Unsupported GAS advertisement protocol id %u",
 			*pos);
@@ -567,12 +501,12 @@
 		return;
 	}
 
-	/* NQP Query Response */
+	/* ANQP Query Response */
 	if (pos + 4 > end)
 		return;
-	if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+			"P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
 		return;
 	}
 	pos += 2;
@@ -581,20 +515,20 @@
 	pos += 2;
 	if (pos + slen > end || slen < 3 + 1) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid NQP Query Response length");
+			"P2P: Invalid ANQP Query Response length");
 		return;
 	}
 
 	if (WPA_GET_BE24(pos) != OUI_WFA) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+			"P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
 		return;
 	}
 	pos += 3;
 
 	if (*pos != P2P_OUI_TYPE) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP vendor type %u", *pos);
+			"P2P: Unsupported ANQP vendor type %u", *pos);
 		return;
 	}
 	pos++;
@@ -776,7 +710,7 @@
 	}
 	pos++; /* skip QueryRespLenLimit and PAME-BI */
 
-	if (*pos != NATIVE_QUERY_PROTOCOL) {
+	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
 			"P2P: Unsupported GAS advertisement protocol id %u",
 			*pos);
@@ -808,29 +742,29 @@
 
 	if (p2p->sd_rx_resp) {
 		 /*
-		  * NQP header is only included in the first fragment; rest of
+		  * ANQP header is only included in the first fragment; rest of
 		  * the fragments start with continue TLVs.
 		  */
 		goto skip_nqp_header;
 	}
 
-	/* NQP Query Response */
+	/* ANQP Query Response */
 	if (pos + 4 > end)
 		return;
-	if (WPA_GET_LE16(pos) != NQP_VENDOR_SPECIFIC) {
+	if (WPA_GET_LE16(pos) != ANQP_VENDOR_SPECIFIC) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP Info ID %u", WPA_GET_LE16(pos));
+			"P2P: Unsupported ANQP Info ID %u", WPA_GET_LE16(pos));
 		return;
 	}
 	pos += 2;
 
 	slen = WPA_GET_LE16(pos);
 	pos += 2;
-	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: NQP Query Response "
+	wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG, "P2P: ANQP Query Response "
 		"length: %u", slen);
 	if (slen < 3 + 1) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Invalid NQP Query Response length");
+			"P2P: Invalid ANQP Query Response length");
 		return;
 	}
 	if (pos + 4 > end)
@@ -838,14 +772,14 @@
 
 	if (WPA_GET_BE24(pos) != OUI_WFA) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP OUI %06x", WPA_GET_BE24(pos));
+			"P2P: Unsupported ANQP OUI %06x", WPA_GET_BE24(pos));
 		return;
 	}
 	pos += 3;
 
 	if (*pos != P2P_OUI_TYPE) {
 		wpa_msg(p2p->cfg->msg_ctx, MSG_DEBUG,
-			"P2P: Unsupported NQP vendor type %u", *pos);
+			"P2P: Unsupported ANQP vendor type %u", *pos);
 		return;
 	}
 	pos++;
diff --git a/src/radius/radius.c b/src/radius/radius.c
index 70754ef..3ead847 100644
--- a/src/radius/radius.c
+++ b/src/radius/radius.c
@@ -218,6 +218,8 @@
 	{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },
 	{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",
 	  RADIUS_ATTR_HEXDUMP },
+	{ RADIUS_ATTR_TUNNEL_PASSWORD, "Tunnel-Password",
+	  RADIUS_ATTR_UNDIST },
 	{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },
 	{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },
 	{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",
@@ -1090,8 +1092,7 @@
 				  const u8 *secret, size_t secret_len)
 {
 	u8 buf[128];
-	int padlen, i;
-	size_t buf_len, pos;
+	size_t padlen, i, buf_len, pos;
 	const u8 *addr[2];
 	size_t len[2];
 	u8 hash[16];
@@ -1103,7 +1104,7 @@
 	buf_len = data_len;
 
 	padlen = data_len % 16;
-	if (padlen) {
+	if (padlen && data_len < sizeof(buf)) {
 		padlen = 16 - padlen;
 		os_memset(buf + data_len, 0, padlen);
 		buf_len += padlen;
@@ -1276,6 +1277,120 @@
 }
 
 
+/**
+ * radius_msg_get_tunnel_password - Parse RADIUS attribute Tunnel-Password
+ * @msg: Received RADIUS message
+ * @keylen: Length of returned password
+ * @secret: RADIUS shared secret
+ * @secret_len: Length of secret
+ * @sent_msg: Sent RADIUS message
+ * Returns: pointer to password (free with os_free) or %NULL
+ */
+char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
+				      const u8 *secret, size_t secret_len,
+				      struct radius_msg *sent_msg)
+{
+	u8 *buf = NULL;
+	size_t buflen;
+	const u8 *salt;
+	u8 *str;
+	const u8 *addr[3];
+	size_t len[3];
+	u8 hash[16];
+	u8 *pos;
+	size_t i;
+	struct radius_attr_hdr *attr;
+	const u8 *data;
+	size_t dlen;
+	const u8 *fdata = NULL; /* points to found item */
+	size_t fdlen = -1;
+	char *ret = NULL;
+
+	/* find attribute with lowest tag and check it */
+	for (i = 0; i < msg->attr_used; i++) {
+		attr = radius_get_attr_hdr(msg, i);
+		if (attr == NULL ||
+		    attr->type != RADIUS_ATTR_TUNNEL_PASSWORD) {
+			continue;
+		}
+		if (attr->length <= 5)
+			continue;
+		data = (const u8 *) (attr + 1);
+		dlen = attr->length - sizeof(*attr);
+		if (dlen <= 3 || dlen % 16 != 3)
+			continue;
+		if (fdata != NULL && fdata[0] <= data[0])
+			continue;
+
+		fdata = data;
+		fdlen = dlen;
+	}
+	if (fdata == NULL)
+		goto out;
+
+	/* alloc writable memory for decryption */
+	buf = os_malloc(fdlen);
+	if (buf == NULL)
+		goto out;
+	os_memcpy(buf, fdata, fdlen);
+	buflen = fdlen;
+
+	/* init pointers */
+	salt = buf + 1;
+	str = buf + 3;
+
+	/* decrypt blocks */
+	pos = buf + buflen - 16; /* last block */
+	while (pos >= str + 16) { /* all but the first block */
+		addr[0] = secret;
+		len[0] = secret_len;
+		addr[1] = pos - 16;
+		len[1] = 16;
+		md5_vector(2, addr, len, hash);
+
+		for (i = 0; i < 16; i++)
+			pos[i] ^= hash[i];
+
+		pos -= 16;
+	}
+
+	/* decrypt first block */
+	if (str != pos)
+		goto out;
+	addr[0] = secret;
+	len[0] = secret_len;
+	addr[1] = sent_msg->hdr->authenticator;
+	len[1] = 16;
+	addr[2] = salt;
+	len[2] = 2;
+	md5_vector(3, addr, len, hash);
+
+	for (i = 0; i < 16; i++)
+		pos[i] ^= hash[i];
+
+	/* derive plaintext length from first subfield */
+	*keylen = (unsigned char) str[0];
+	if ((u8 *) (str + *keylen) >= (u8 *) (buf + buflen)) {
+		/* decryption error - invalid key length */
+		goto out;
+	}
+	if (*keylen == 0) {
+		/* empty password */
+		goto out;
+	}
+
+	/* copy passphrase into new buffer */
+	ret = os_malloc(*keylen);
+	if (ret)
+		os_memcpy(ret, str + 1, *keylen);
+
+out:
+	/* return new buffer */
+	os_free(buf);
+	return ret;
+}
+
+
 void radius_free_class(struct radius_class_data *c)
 {
 	size_t i;
diff --git a/src/radius/radius.h b/src/radius/radius.h
index a3cdac0..e69a047 100644
--- a/src/radius/radius.h
+++ b/src/radius/radius.h
@@ -82,6 +82,7 @@
        RADIUS_ATTR_NAS_PORT_TYPE = 61,
        RADIUS_ATTR_TUNNEL_TYPE = 64,
        RADIUS_ATTR_TUNNEL_MEDIUM_TYPE = 65,
+       RADIUS_ATTR_TUNNEL_PASSWORD = 69,
        RADIUS_ATTR_CONNECT_INFO = 77,
        RADIUS_ATTR_EAP_MESSAGE = 79,
        RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80,
@@ -231,6 +232,9 @@
 				  const u8 *secret, size_t secret_len);
 int radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
 int radius_msg_get_vlanid(struct radius_msg *msg);
+char * radius_msg_get_tunnel_password(struct radius_msg *msg, int *keylen,
+				      const u8 *secret, size_t secret_len,
+				      struct radius_msg *sent_msg);
 
 static inline int radius_msg_add_attr_int32(struct radius_msg *msg, u8 type,
 					    u32 value)
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 6f1c3a5..47948bc 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -1,6 +1,6 @@
 /*
  * RADIUS authentication server
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -292,6 +292,10 @@
 	 * msg_ctx - Context data for wpa_msg() calls
 	 */
 	void *msg_ctx;
+
+#ifdef CONFIG_RADIUS_TEST
+	char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 };
 
 
@@ -574,6 +578,24 @@
 
 	if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
 		int len;
+#ifdef CONFIG_RADIUS_TEST
+		if (data->dump_msk_file) {
+			FILE *f;
+			char buf[2 * 64 + 1];
+			f = fopen(data->dump_msk_file, "a");
+			if (f) {
+				len = sess->eap_if->eapKeyDataLen;
+				if (len > 64)
+					len = 64;
+				len = wpa_snprintf_hex(
+					buf, sizeof(buf),
+					sess->eap_if->eapKeyData, len);
+				buf[len] = '\0';
+				fprintf(f, "%s\n", buf);
+				fclose(f);
+			}
+		}
+#endif /* CONFIG_RADIUS_TEST */
 		if (sess->eap_if->eapKeyDataLen > 64) {
 			len = 32;
 		} else {
@@ -1277,6 +1299,11 @@
 		}
 	}
 
+#ifdef CONFIG_RADIUS_TEST
+	if (conf->dump_msk_file)
+		data->dump_msk_file = os_strdup(conf->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
+
 	data->clients = radius_server_read_clients(conf->client_file,
 						   conf->ipv6);
 	if (data->clients == NULL) {
@@ -1328,6 +1355,9 @@
 	os_free(data->eap_fast_a_id);
 	os_free(data->eap_fast_a_id_info);
 	os_free(data->eap_req_id_text);
+#ifdef CONFIG_RADIUS_TEST
+	os_free(data->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
 	os_free(data);
 }
 
diff --git a/src/radius/radius_server.h b/src/radius/radius_server.h
index 126e314..8d6e2ab 100644
--- a/src/radius/radius_server.h
+++ b/src/radius/radius_server.h
@@ -1,6 +1,6 @@
 /*
  * RADIUS authentication server
- * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2009, 2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -201,6 +201,10 @@
 	 * msg_ctx - Context data for wpa_msg() calls
 	 */
 	void *msg_ctx;
+
+#ifdef CONFIG_RADIUS_TEST
+	const char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
 };
 
 
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index cac8c83..3877efb 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -49,6 +49,7 @@
 				   struct rsn_pmksa_cache_entry *entry,
 				   int replace)
 {
+	wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
 	pmksa->pmksa_count--;
 	pmksa->free_cb(entry, pmksa->ctx, replace);
 	_pmksa_cache_free_entry(entry);
@@ -185,6 +186,14 @@
 			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
 				   "the current AP");
 			pmksa_cache_free_entry(pmksa, pos, 1);
+
+			/*
+			 * If OKC is used, there may be other PMKSA cache
+			 * entries based on the same PMK. These needs to be
+			 * flushed so that a new entry can be created based on
+			 * the new PMK.
+			 */
+			pmksa_cache_flush(pmksa, network_ctx);
 			break;
 		}
 		prev = pos;
@@ -198,7 +207,6 @@
 		wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
 			   "entry (for " MACSTR ") to make room for new one",
 			   MAC2STR(pos->aa));
-		wpa_sm_remove_pmkid(pmksa->sm, pos->aa, pos->pmkid);
 		pmksa_cache_free_entry(pmksa, pos, 0);
 	}
 
@@ -229,6 +237,39 @@
 
 
 /**
+ * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @network_ctx: Network configuration context or %NULL to flush all entries
+ */
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+{
+	struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
+	int removed = 0;
+
+	entry = pmksa->pmksa;
+	while (entry) {
+		if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+			wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
+				   "for " MACSTR, MAC2STR(entry->aa));
+			if (prev)
+				prev->next = entry->next;
+			else
+				pmksa->pmksa = entry->next;
+			tmp = entry;
+			entry = entry->next;
+			pmksa_cache_free_entry(pmksa, tmp, 0);
+			removed++;
+		} else {
+			prev = entry;
+			entry = entry->next;
+		}
+	}
+	if (removed)
+		pmksa_cache_set_expiration(pmksa);
+}
+
+
+/**
  * pmksa_cache_deinit - Free all entries in PMKSA cache
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  */
@@ -273,22 +314,6 @@
 }
 
 
-/**
- * pmksa_cache_notify_reconfig - Reconfiguration notification for PMKSA cache
- * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
- *
- * Clear references to old data structures when wpa_supplicant is reconfigured.
- */
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
-	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
-	while (entry) {
-		entry->network_ctx = NULL;
-		entry = entry->next;
-	}
-}
-
-
 static struct rsn_pmksa_cache_entry *
 pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
 			const struct rsn_pmksa_cache_entry *old_entry,
@@ -327,6 +352,7 @@
 {
 	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
 
+	wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa));
 	if (network_ctx == NULL)
 		return NULL;
 	while (entry) {
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index a1447e5..840827d 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -57,7 +57,6 @@
 struct rsn_pmksa_cache_entry *
 pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
 		const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
-void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa);
 struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
 void pmksa_cache_clear_current(struct wpa_sm *sm);
 int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
@@ -66,6 +65,7 @@
 struct rsn_pmksa_cache_entry *
 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
 			      void *network_ctx, const u8 *aa);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
 
 #else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
 
@@ -106,10 +106,6 @@
 	return NULL;
 }
 
-static inline void pmksa_cache_notify_reconfig(struct rsn_pmksa_cache *pmksa)
-{
-}
-
 static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
 {
 }
@@ -122,6 +118,11 @@
 	return -1;
 }
 
+static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
+				     void *network_ctx)
+{
+}
+
 #endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
 
 #endif /* PMKSA_CACHE_H */
diff --git a/src/rsn_supp/preauth.c b/src/rsn_supp/preauth.c
index 6109f5e..fefca83 100644
--- a/src/rsn_supp/preauth.c
+++ b/src/rsn_supp/preauth.c
@@ -22,7 +22,6 @@
 #include "preauth.h"
 #include "pmksa_cache.h"
 #include "wpa_i.h"
-#include "common/ieee802_11_defs.h"
 
 
 #if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index e751867..27090e3 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -88,6 +88,8 @@
 
 
 #define TDLS_MAX_IE_LEN 80
+#define IEEE80211_MAX_SUPP_RATES 32
+
 struct wpa_tdls_peer {
 	struct wpa_tdls_peer *next;
 	int initiator; /* whether this end was initiator for TDLS setup */
@@ -119,6 +121,11 @@
 		int buf_len;    /* length of TPK message for retransmission */
 		u8 *buf;        /* buffer for TPK message */
 	} sm_tmr;
+
+	u16 capability;
+
+	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+	size_t supp_rates_len;
 };
 
 
@@ -214,7 +221,9 @@
 	}
 
 	if (action_code == WLAN_TDLS_SETUP_CONFIRM ||
-	    action_code == WLAN_TDLS_TEARDOWN)
+	    action_code == WLAN_TDLS_TEARDOWN ||
+	    action_code == WLAN_TDLS_DISCOVERY_REQUEST ||
+	    action_code == WLAN_TDLS_DISCOVERY_RESPONSE)
 		return 0; /* No retries */
 
 	for (peer = sm->tdls; peer; peer = peer->next) {
@@ -253,6 +262,27 @@
 }
 
 
+static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+				u16 reason_code, int free_peer)
+{
+	int ret;
+
+	if (sm->tdls_external_setup) {
+		ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
+
+		/* disable the link after teardown was sent */
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+	} else {
+		ret = wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+	}
+
+	if (sm->tdls_external_setup || free_peer)
+		wpa_tdls_peer_free(sm, peer);
+
+	return ret;
+}
+
+
 static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 
@@ -291,15 +321,11 @@
 		eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
 				       wpa_tdls_tpk_retry_timeout, sm, peer);
 	} else {
-		wpa_printf(MSG_INFO, "Sending Tear_Down Request");
-		wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
-
-		wpa_printf(MSG_INFO, "Clearing SM: Peerkey(" MACSTR ")",
-			   MAC2STR(peer->addr));
 		eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
 
-		/* clear the Peerkey statemachine */
-		wpa_tdls_peer_free(sm, peer);
+		wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request");
+		wpa_tdls_do_teardown(sm, peer,
+				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
 	}
 }
 
@@ -576,7 +602,8 @@
 	} else {
 		wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
 			   " - tear down", MAC2STR(peer->addr));
-		wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
+		wpa_tdls_do_teardown(sm, peer,
+				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
 	}
 }
 
@@ -615,8 +642,7 @@
 }
 
 
-int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
-				  u16 reason_code)
+int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
 {
 	struct wpa_tdls_peer *peer;
 	struct wpa_tdls_ftie *ftie;
@@ -625,7 +651,7 @@
 	u8 *rbuf, *pos;
 	int ielen;
 
-	if (sm->tdls_disabled)
+	if (sm->tdls_disabled || !sm->tdls_supported)
 		return -1;
 
 	/* Find the node and free from the list */
@@ -677,10 +703,11 @@
 		ftie->ie_len += 170;
 		*pos++ = 255; /* FTIE subelem */
 		*pos++ = 168; /* FTIE subelem length */
+		pos += 168;
 	}
 #endif /* CONFIG_TDLS_TESTING */
 	wpa_hexdump(MSG_DEBUG, "TDLS: FTIE for TDLS Teardown handshake",
-		    (u8 *) ftie, sizeof(*ftie));
+		    (u8 *) ftie, pos - (u8 *) ftie);
 
 	/* compute MIC before sending */
 	wpa_tdls_linkid(sm, peer, &lnkid);
@@ -705,6 +732,50 @@
 }
 
 
+int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code)
+{
+	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 == NULL) {
+		wpa_printf(MSG_DEBUG, "TDLS: Could not find peer " MACSTR
+		   " for link Teardown", MAC2STR(addr));
+		return -1;
+	}
+
+	if (!peer->tpk_success) {
+		wpa_printf(MSG_DEBUG, "TDLS: Peer " MACSTR
+		   " not connected - cannot Teardown link", MAC2STR(addr));
+		return -1;
+	}
+
+	return wpa_tdls_do_teardown(sm, peer, reason_code, 0);
+}
+
+
+void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (peer) {
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
+		wpa_tdls_peer_free(sm, peer);
+	}
+}
+
+
 static int wpa_tdls_recv_teardown(struct wpa_sm *sm, const u8 *src_addr,
 				  const u8 *buf, size_t len)
 {
@@ -802,6 +873,26 @@
 }
 
 
+static struct wpa_tdls_peer *
+wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr)
+{
+	struct wpa_tdls_peer *peer;
+
+	wpa_printf(MSG_INFO, "TDLS: Creating peer entry for " MACSTR,
+		   MAC2STR(addr));
+
+	peer = os_zalloc(sizeof(*peer));
+	if (peer == NULL)
+		return NULL;
+
+	os_memcpy(peer->addr, addr, ETH_ALEN);
+	peer->next = sm->tdls;
+	sm->tdls = peer;
+
+	return peer;
+}
+
+
 static int wpa_tdls_send_tpk_m1(struct wpa_sm *sm,
 				struct wpa_tdls_peer *peer)
 {
@@ -972,7 +1063,7 @@
 		   "Handshake Message 1 (peer " MACSTR ")",
 		   MAC2STR(peer->addr));
 
-	wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 0, 0,
+	wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_SETUP_REQUEST, 1, 0,
 			  rbuf, pos - rbuf);
 	os_free(rbuf);
 
@@ -1144,6 +1235,105 @@
 }
 
 
+static int wpa_tdls_send_discovery_response(struct wpa_sm *sm,
+					    struct wpa_tdls_peer *peer,
+					    u8 dialog_token)
+{
+	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Discovery Response "
+		   "(peer " MACSTR ")", MAC2STR(peer->addr));
+
+	return wpa_tdls_tpk_send(sm, peer->addr, WLAN_TDLS_DISCOVERY_RESPONSE,
+				 dialog_token, 0, NULL, 0);
+}
+
+
+static int
+wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
+				   const u8 *buf, size_t len)
+{
+	struct wpa_eapol_ie_parse kde;
+	const struct wpa_tdls_lnkid *lnkid;
+	struct wpa_tdls_peer *peer;
+	size_t min_req_len = sizeof(struct wpa_tdls_frame) +
+		1 /* dialog token */ + sizeof(struct wpa_tdls_lnkid);
+	u8 dialog_token;
+
+	wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from " MACSTR,
+		   MAC2STR(addr));
+
+	if (len < min_req_len) {
+		wpa_printf(MSG_DEBUG, "TDLS Discovery Request is too short: "
+			   "%d", (int) len);
+		return -1;
+	}
+
+	dialog_token = buf[sizeof(struct wpa_tdls_frame)];
+
+	if (wpa_supplicant_parse_ies(buf + sizeof(struct wpa_tdls_frame) + 1,
+				     len - (sizeof(struct wpa_tdls_frame) + 1),
+				     &kde) < 0)
+		return -1;
+
+	if (!kde.lnkid) {
+		wpa_printf(MSG_DEBUG, "TDLS: Link ID not found in Discovery "
+			   "Request");
+		return -1;
+	}
+
+	lnkid = (const struct wpa_tdls_lnkid *) kde.lnkid;
+
+	if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "TDLS: Discovery Request from different "
+			   " BSS " MACSTR, MAC2STR(lnkid->bssid));
+		return -1;
+	}
+
+	peer = wpa_tdls_add_peer(sm, addr);
+	if (peer == NULL)
+		return -1;
+
+	return wpa_tdls_send_discovery_response(sm, peer, dialog_token);
+}
+
+
+int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr)
+{
+	if (sm->tdls_disabled || !sm->tdls_supported)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "TDLS: Sending Discovery Request to peer "
+		   MACSTR, MAC2STR(addr));
+	return wpa_tdls_tpk_send(sm, addr, WLAN_TDLS_DISCOVERY_REQUEST,
+				 1, 0, NULL, 0);
+}
+
+
+static int copy_supp_rates(const struct wpa_eapol_ie_parse *kde,
+			   struct wpa_tdls_peer *peer)
+{
+	if (!kde->supp_rates) {
+		wpa_printf(MSG_DEBUG, "TDLS: No supported rates received");
+		return -1;
+	}
+
+	peer->supp_rates_len = kde->supp_rates_len - 2;
+	if (peer->supp_rates_len > IEEE80211_MAX_SUPP_RATES)
+		peer->supp_rates_len = IEEE80211_MAX_SUPP_RATES;
+	os_memcpy(peer->supp_rates, kde->supp_rates + 2, peer->supp_rates_len);
+
+	if (kde->ext_supp_rates) {
+		int clen = kde->ext_supp_rates_len - 2;
+		if (peer->supp_rates_len + clen > IEEE80211_MAX_SUPP_RATES)
+			clen = IEEE80211_MAX_SUPP_RATES - peer->supp_rates_len;
+		os_memcpy(peer->supp_rates + peer->supp_rates_len,
+			  kde->ext_supp_rates + 2, clen);
+		peer->supp_rates_len += clen;
+	}
+
+	return 0;
+}
+
+
 static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
 				   const u8 *buf, size_t len)
 {
@@ -1166,6 +1356,7 @@
 	u16 ielen;
 	u16 status = WLAN_STATUS_UNSPECIFIED_FAILURE;
 	int tdls_prohibited = sm->tdls_prohibited;
+	int existing_peer = 0;
 
 	if (len < 3 + 3)
 		return -1;
@@ -1178,7 +1369,22 @@
 
 	wpa_printf(MSG_INFO, "TDLS: Dialog Token in TPK M1 %d", dtoken);
 
-	cpos += 2; /* capability information */
+	for (peer = sm->tdls; peer; peer = peer->next) {
+		if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0) {
+			existing_peer = 1;
+			break;
+		}
+	}
+
+	if (peer == NULL) {
+		peer = wpa_tdls_add_peer(sm, src_addr);
+		if (peer == NULL)
+			goto error;
+	}
+
+	/* capability information */
+	peer->capability = WPA_GET_LE16(cpos);
+	cpos += 2;
 
 	ielen = len - (cpos - buf); /* start of IE in buf */
 	if (wpa_supplicant_parse_ies(cpos, ielen, &kde) < 0) {
@@ -1203,6 +1409,9 @@
 	wpa_printf(MSG_DEBUG, "TDLS: TPK M1 - TPK initiator " MACSTR,
 		   MAC2STR(src_addr));
 
+	if (copy_supp_rates(&kde, peer) < 0)
+		goto error;
+
 #ifdef CONFIG_TDLS_TESTING
 	if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
 		for (peer = sm->tdls; peer; peer = peer->next) {
@@ -1210,12 +1419,9 @@
 				break;
 		}
 		if (peer == NULL) {
-			peer = os_zalloc(sizeof(*peer));
+			peer = wpa_tdls_add_peer(sm, src_addr);
 			if (peer == NULL)
 				goto error;
-			os_memcpy(peer->addr, src_addr, ETH_ALEN);
-			peer->next = sm->tdls;
-			sm->tdls = peer;
 		}
 		wpa_printf(MSG_DEBUG, "TDLS: Testing concurrent initiation of "
 			   "TDLS setup - send own request");
@@ -1302,26 +1508,10 @@
 	}
 
 skip_rsn:
-	/* Find existing entry and if found, use that instead of adding
-	 * a new one; how to handle the case where both ends initiate at the
+	/* If found, use existing entry instead of adding a new one;
+	 * how to handle the case where both ends initiate at the
 	 * same time? */
-	for (peer = sm->tdls; peer; peer = peer->next) {
-		if (os_memcmp(peer->addr, src_addr, ETH_ALEN) == 0)
-			break;
-	}
-
-	if (peer == NULL) {
-		wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
-			   "peer, creating one for " MACSTR,
-			   MAC2STR(src_addr));
-		peer = os_malloc(sizeof(*peer));
-		if (peer == NULL)
-			goto error;
-		os_memset(peer, 0, sizeof(*peer));
-		os_memcpy(peer->addr, src_addr, ETH_ALEN);
-		peer->next = sm->tdls;
-		sm->tdls = peer;
-	} else {
+	if (existing_peer) {
 		if (peer->tpk_success) {
 			wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
 				   "direct link is enabled - tear down the "
@@ -1332,7 +1522,11 @@
 			 * some drivers handling the new request frame. */
 			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 #else
-			wpa_tdls_del_key(sm, peer);
+			if (sm->tdls_external_setup)
+				wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+						 src_addr);
+			else
+				wpa_tdls_del_key(sm, peer);
 #endif
 			wpa_tdls_peer_free(sm, peer);
 		}
@@ -1360,6 +1554,19 @@
 		}
 	}
 
+#ifdef CONFIG_TDLS_TESTING
+	if (tdls_testing & TDLS_TESTING_CONCURRENT_INIT) {
+		if (os_memcmp(sm->own_addr, peer->addr, ETH_ALEN) < 0) {
+			/*
+			 * The request frame from us is going to win, so do not
+			 * replace information based on this request frame from
+			 * the peer.
+			 */
+			goto skip_rsn_check;
+		}
+	}
+#endif /* CONFIG_TDLS_TESTING */
+
 	peer->initiator = 0; /* Need to check */
 	peer->dtoken = dtoken;
 
@@ -1433,8 +1640,14 @@
 	wpa_tdls_generate_tpk(peer, sm->own_addr, sm->bssid);
 
 skip_rsn_check:
+	/* add the peer to the driver as a "setup in progress" peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
 	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
-	wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer);
+	if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
+		wpa_tdls_disable_link(sm, peer->addr);
+		goto error;
+	}
 
 	return 0;
 
@@ -1467,6 +1680,11 @@
 	}
 #endif /* CONFIG_TDLS_TESTING */
 	}
+
+	/* add supported rates and capabilities to the TDLS peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->capability,
+				peer->supp_rates, peer->supp_rates_len);
+
 	wpa_sm_tdls_oper(sm, TDLS_ENABLE_LINK, peer->addr);
 }
 
@@ -1510,6 +1728,8 @@
 	if (status != WLAN_STATUS_SUCCESS) {
 		wpa_printf(MSG_INFO, "TDLS: Status code in TPK M2: %u",
 			   status);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 		return -1;
 	}
 
@@ -1522,7 +1742,10 @@
 
 	if (len < 3 + 2 + 1 + 2)
 		return -1;
-	pos += 2; /* capability information */
+
+	/* capability information */
+	peer->capability = WPA_GET_LE16(pos);
+	pos += 2;
 
 	ielen = len - (pos - buf); /* start of IE in buf */
 	if (wpa_supplicant_parse_ies(pos, ielen, &kde) < 0) {
@@ -1553,6 +1776,9 @@
 		goto error;
 	}
 
+	if (copy_supp_rates(&kde, peer) < 0)
+		goto error;
+
 	if (!wpa_tdls_get_privacy(sm)) {
 		peer->rsnie_p_len = 0;
 		peer->cipher = WPA_CIPHER_NONE;
@@ -1644,6 +1870,8 @@
 		/* Discard the frame */
 		wpa_tdls_del_key(sm, peer);
 		wpa_tdls_peer_free(sm, peer);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 		return -1;
 	}
 
@@ -1663,6 +1891,8 @@
 error:
 	wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
 			    status);
+	if (sm->tdls_external_setup)
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 	return -1;
 }
 
@@ -1703,6 +1933,8 @@
 	if (status != 0) {
 		wpa_printf(MSG_INFO, "TDLS: Status code in TPK M3: %u",
 			   status);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 		return -1;
 	}
 	pos += 2 /* status code */ + 1 /* dialog token */;
@@ -1775,6 +2007,8 @@
 	if (lifetime != peer->lifetime) {
 		wpa_printf(MSG_INFO, "TDLS: Unexpected TPK lifetime %u in "
 			   "TPK M3 (expected %u)", lifetime, peer->lifetime);
+		if (sm->tdls_external_setup)
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
 		return -1;
 	}
 
@@ -1823,7 +2057,7 @@
 	struct wpa_tdls_peer *peer;
 	int tdls_prohibited = sm->tdls_prohibited;
 
-	if (sm->tdls_disabled)
+	if (sm->tdls_disabled || !sm->tdls_supported)
 		return -1;
 
 #ifdef CONFIG_TDLS_TESTING
@@ -1849,20 +2083,22 @@
 	}
 
 	if (peer == NULL) {
-		wpa_printf(MSG_INFO, "TDLS: No matching entry found for "
-			   "peer, creating one for " MACSTR, MAC2STR(addr));
-		peer = os_malloc(sizeof(*peer));
+		peer = wpa_tdls_add_peer(sm, addr);
 		if (peer == NULL)
 			return -1;
-		os_memset(peer, 0, sizeof(*peer));
-		os_memcpy(peer->addr, addr, ETH_ALEN);
-		peer->next = sm->tdls;
-		sm->tdls = peer;
 	}
 
 	peer->initiator = 1;
 
-	return wpa_tdls_send_tpk_m1(sm, peer);
+	/* add the peer to the driver as a "setup in progress" peer */
+	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, NULL, 0);
+
+	if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
+		wpa_tdls_disable_link(sm, peer->addr);
+		return -1;
+	}
+
+	return 0;
 }
 
 
@@ -1870,7 +2106,7 @@
 {
 	struct wpa_tdls_peer *peer;
 
-	if (sm->tdls_disabled)
+	if (sm->tdls_disabled || !sm->tdls_supported)
 		return -1;
 
 	for (peer = sm->tdls; peer; peer = peer->next) {
@@ -1881,6 +2117,14 @@
 	if (peer == NULL || !peer->tpk_success)
 		return -1;
 
+	if (sm->tdls_external_setup) {
+		/*
+		 * Disable previous link to allow renegotiation to be completed
+		 * on AP path.
+		 */
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+	}
+
 	return wpa_tdls_start(sm, addr);
 }
 
@@ -1899,8 +2143,9 @@
 	wpa_hexdump(MSG_DEBUG, "TDLS: Received Data frame encapsulation",
 		    buf, len);
 
-	if (sm->tdls_disabled) {
-		wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled");
+	if (sm->tdls_disabled || !sm->tdls_supported) {
+		wpa_printf(MSG_DEBUG, "TDLS: Discard message - TDLS disabled "
+			   "or unsupported by driver");
 		return;
 	}
 
@@ -1937,6 +2182,9 @@
 	case WLAN_TDLS_TEARDOWN:
 		wpa_tdls_recv_teardown(sm, src_addr, buf, len);
 		break;
+	case WLAN_TDLS_DISCOVERY_REQUEST:
+		wpa_tdls_process_discovery_request(sm, src_addr, buf, len);
+		break;
 	default:
 		/* Kernel code will process remaining frames */
 		wpa_printf(MSG_DEBUG, "TDLS: Ignore TDLS frame action code %u",
@@ -1969,6 +2217,21 @@
 		return -1;
 	}
 
+	/*
+	 * Drivers that support TDLS but don't implement the get_capa callback
+	 * are assumed to perform everything internally
+	 */
+	if (wpa_sm_tdls_get_capa(sm, &sm->tdls_supported,
+				 &sm->tdls_external_setup) < 0) {
+		sm->tdls_supported = 1;
+		sm->tdls_external_setup = 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "TDLS: TDLS operation%s supported by "
+		   "driver", sm->tdls_supported ? "" : " not");
+	wpa_printf(MSG_DEBUG, "TDLS: Driver uses %s link setup",
+		   sm->tdls_external_setup ? "external" : "internal");
+
 	return 0;
 }
 
@@ -2067,3 +2330,9 @@
 	wpa_printf(MSG_DEBUG, "TDLS: %s", enabled ? "enabled" : "disabled");
 	sm->tdls_disabled = !enabled;
 }
+
+
+int wpa_tdls_is_external_setup(struct wpa_sm *sm)
+{
+	return sm->tdls_external_setup;
+}
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index 7c0ac87..f35f9ee 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -396,7 +396,8 @@
 		const u8 *_buf = (const u8 *) (key + 1);
 		size_t len = WPA_GET_BE16(key->key_data_length);
 		wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
-		wpa_supplicant_parse_ies(_buf, len, &ie);
+		if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0)
+			goto failed;
 		if (ie.pmkid) {
 			wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
 				    "Authenticator", ie.pmkid, PMKID_LEN);
@@ -476,7 +477,7 @@
 		 * Start preauthentication after a short wait to avoid a
 		 * possible race condition between the data receive and key
 		 * configuration after the 4-Way Handshake. This increases the
-		 * likelyhood of the first preauth EAPOL-Start frame getting to
+		 * likelihood of the first preauth EAPOL-Start frame getting to
 		 * the target AP.
 		 */
 		eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
@@ -1085,7 +1086,8 @@
 	pos = (const u8 *) (key + 1);
 	len = WPA_GET_BE16(key->key_data_length);
 	wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
-	wpa_supplicant_parse_ies(pos, len, &ie);
+	if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
+		goto failed;
 	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: GTK IE in unencrypted key data");
@@ -1174,6 +1176,8 @@
 		goto failed;
 	}
 
+	wpa_sm_set_rekey_offload(sm);
+
 	return;
 
 failed:
@@ -1191,7 +1195,8 @@
 	struct wpa_eapol_ie_parse ie;
 
 	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
-	wpa_supplicant_parse_ies(keydata, keydatalen, &ie);
+	if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0)
+		return -1;
 	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
 		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
 			"WPA: GTK IE in unencrypted key data");
@@ -1392,6 +1397,8 @@
 			MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
 		wpa_sm_cancel_auth_timeout(sm);
 		wpa_sm_set_state(sm, WPA_COMPLETED);
+
+		wpa_sm_set_rekey_offload(sm);
 	} else {
 		wpa_supplicant_key_neg_complete(sm, sm->bssid,
 						key_info &
@@ -2265,8 +2272,6 @@
 		sm->ssid_len = 0;
 		sm->wpa_ptk_rekey = 0;
 	}
-	if (config == NULL || config->network_ctx != sm->network_ctx)
-		pmksa_cache_notify_reconfig(sm->pmksa);
 }
 
 
@@ -2644,3 +2649,17 @@
 		return 0;
 	return sm->ptk_set;
 }
+
+
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
+{
+	os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
+}
+
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
+{
+#ifndef CONFIG_NO_WPA2
+	pmksa_cache_flush(sm->pmksa, network_ctx);
+#endif /* CONFIG_NO_WPA2 */
+}
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 111597c..4c1750f 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -56,11 +56,18 @@
 			      const u8 *ies, size_t ies_len);
 	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 (*send_tdls_mgmt)(void *ctx, const u8 *dst,
 			      u8 action_code, u8 dialog_token,
 			      u16 status_code, const u8 *buf, size_t len);
 	int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
+	int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
+				u16 capability, const u8 *supp_rates,
+				size_t supp_rates_len);
 #endif /* CONFIG_TDLS */
+	void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+				  const u8 *replay_ctr);
 };
 
 
@@ -132,6 +139,10 @@
 void wpa_sm_drop_sa(struct wpa_sm *sm);
 int wpa_sm_has_ptk(struct wpa_sm *sm);
 
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
+
 #else /* CONFIG_NO_WPA */
 
 static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
@@ -277,6 +288,16 @@
 	return 0;
 }
 
+static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm,
+					    const u8 *replay_ctr)
+{
+}
+
+static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm,
+					    void *network_ctx)
+{
+}
+
 #endif /* CONFIG_NO_WPA */
 
 #ifdef CONFIG_PEERKEY
@@ -342,10 +363,13 @@
 void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
 int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr);
 int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr);
-int wpa_tdls_recv_teardown_notify(struct wpa_sm *sm, const u8 *addr,
-				  u16 reason_code);
+int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
 int wpa_tdls_init(struct wpa_sm *sm);
 void wpa_tdls_deinit(struct wpa_sm *sm);
 void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
+void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_is_external_setup(struct wpa_sm *sm);
 
 #endif /* WPA_H */
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index da6e966..dbf5996 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -21,35 +21,9 @@
 #include "common/ieee802_11_common.h"
 #include "wpa.h"
 #include "wpa_i.h"
-#include "wpa_ie.h"
 
 #ifdef CONFIG_IEEE80211R
 
-struct wpa_ft_ies {
-	const u8 *mdie;
-	size_t mdie_len;
-	const u8 *ftie;
-	size_t ftie_len;
-	const u8 *r1kh_id;
-	const u8 *gtk;
-	size_t gtk_len;
-	const u8 *r0kh_id;
-	size_t r0kh_id_len;
-	const u8 *rsn;
-	size_t rsn_len;
-	const u8 *rsn_pmkid;
-	const u8 *tie;
-	size_t tie_len;
-	const u8 *igtk;
-	size_t igtk_len;
-	const u8 *ric;
-	size_t ric_len;
-};
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse);
-
-
 int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
 		      const struct wpa_eapol_key *key,
 		      struct wpa_ptk *ptk, size_t ptk_len)
@@ -347,155 +321,6 @@
 }
 
 
-static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
-			     struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-
-	parse->ftie = ie;
-	parse->ftie_len = ie_len;
-
-	pos = ie + sizeof(struct rsn_ftie);
-	end = ie + ie_len;
-
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		case FTIE_SUBELEM_R1KH_ID:
-			if (pos[1] != FT_R1KH_ID_LEN) {
-				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
-					   "length in FTIE: %d", pos[1]);
-				return -1;
-			}
-			parse->r1kh_id = pos + 2;
-			break;
-		case FTIE_SUBELEM_GTK:
-			parse->gtk = pos + 2;
-			parse->gtk_len = pos[1];
-			break;
-		case FTIE_SUBELEM_R0KH_ID:
-			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
-				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
-					   "length in FTIE: %d", pos[1]);
-				return -1;
-			}
-			parse->r0kh_id = pos + 2;
-			parse->r0kh_id_len = pos[1];
-			break;
-#ifdef CONFIG_IEEE80211W
-		case FTIE_SUBELEM_IGTK:
-			parse->igtk = pos + 2;
-			parse->igtk_len = pos[1];
-			break;
-#endif /* CONFIG_IEEE80211W */
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	return 0;
-}
-
-
-static int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
-			    struct wpa_ft_ies *parse)
-{
-	const u8 *end, *pos;
-	struct wpa_ie_data data;
-	int ret;
-	const struct rsn_ftie *ftie;
-	int prot_ie_count = 0;
-
-	os_memset(parse, 0, sizeof(*parse));
-	if (ies == NULL)
-		return 0;
-
-	pos = ies;
-	end = ies + ies_len;
-	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
-		switch (pos[0]) {
-		case WLAN_EID_RSN:
-			parse->rsn = pos + 2;
-			parse->rsn_len = pos[1];
-			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
-						   parse->rsn_len + 2,
-						   &data);
-			if (ret < 0) {
-				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
-					   "RSN IE: %d", ret);
-				return -1;
-			}
-			if (data.num_pmkid == 1 && data.pmkid)
-				parse->rsn_pmkid = data.pmkid;
-			break;
-		case WLAN_EID_MOBILITY_DOMAIN:
-			parse->mdie = pos + 2;
-			parse->mdie_len = pos[1];
-			break;
-		case WLAN_EID_FAST_BSS_TRANSITION:
-			if (pos[1] < sizeof(*ftie))
-				return -1;
-			ftie = (const struct rsn_ftie *) (pos + 2);
-			prot_ie_count = ftie->mic_control[1];
-			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
-				return -1;
-			break;
-		case WLAN_EID_TIMEOUT_INTERVAL:
-			parse->tie = pos + 2;
-			parse->tie_len = pos[1];
-			break;
-		case WLAN_EID_RIC_DATA:
-			if (parse->ric == NULL)
-				parse->ric = pos;
-		}
-
-		pos += 2 + pos[1];
-	}
-
-	if (prot_ie_count == 0)
-		return 0; /* no MIC */
-
-	/*
-	 * Check that the protected IE count matches with IEs included in the
-	 * frame.
-	 */
-	if (parse->rsn)
-		prot_ie_count--;
-	if (parse->mdie)
-		prot_ie_count--;
-	if (parse->ftie)
-		prot_ie_count--;
-	if (parse->tie)
-		prot_ie_count--;
-	if (prot_ie_count < 0) {
-		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
-			   "the protected IE count");
-		return -1;
-	}
-
-	if (prot_ie_count == 0 && parse->ric) {
-		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
-			   "included in protected IE count");
-		return -1;
-	}
-
-	/* Determine the end of the RIC IE(s) */
-	pos = parse->ric;
-	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
-	       prot_ie_count) {
-		prot_ie_count--;
-		pos += 2 + pos[1];
-	}
-	parse->ric_len = pos - parse->ric;
-	if (prot_ie_count) {
-		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
-			   "frame", (int) prot_ie_count);
-		return -1;
-	}
-
-	return 0;
-}
-
-
 static int wpa_ft_install_ptk(struct wpa_sm *sm, const u8 *bssid)
 {
 	int keylen;
@@ -950,8 +775,8 @@
 	}
 
 	count = 3;
-	if (parse.tie)
-		count++;
+	if (parse.ric)
+		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
 	if (ftie->mic_control[1] != count) {
 		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
 			   "Control: received %u expected %u",
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 09a2e4f..39124c4 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -98,6 +98,15 @@
 	struct wpa_tdls_peer *tdls;
 	int tdls_prohibited;
 	int tdls_disabled;
+
+	/* The driver supports TDLS */
+	int tdls_supported;
+
+	/*
+	 * The driver requires explicit discovery/setup/teardown frames sent
+	 * to it via tdls_mgmt.
+	 */
+	int tdls_external_setup;
 #endif /* CONFIG_TDLS */
 
 #ifdef CONFIG_IEEE80211R
@@ -244,7 +253,25 @@
 	return -1;
 }
 
+static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm)
+{
+	if (!sm->ctx->set_rekey_offload)
+		return;
+	sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
+				   sm->ptk.kck, sm->rx_replay_counter);
+}
+
 #ifdef CONFIG_TDLS
+static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
+				       int *tdls_supported,
+				       int *tdls_ext_setup)
+{
+	if (sm->ctx->tdls_get_capa)
+		return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported,
+					      tdls_ext_setup);
+	return -1;
+}
+
 static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
 					u8 action_code, u8 dialog_token,
 					u16 status_code, const u8 *buf,
@@ -264,6 +291,18 @@
 		return sm->ctx->tdls_oper(sm->ctx->ctx, oper, peer);
 	return -1;
 }
+
+static inline int
+wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
+			u16 capability, const u8 *supp_rates,
+			size_t supp_rates_len)
+{
+	if (sm->ctx->tdls_peer_addset)
+		return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
+						 capability, supp_rates,
+						 supp_rates_len);
+	return -1;
+}
 #endif /* CONFIG_TDLS */
 
 void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
diff --git a/src/rsn_supp/wpa_ie.c b/src/rsn_supp/wpa_ie.c
index 654cc1f..cbbc54f 100644
--- a/src/rsn_supp/wpa_ie.c
+++ b/src/rsn_supp/wpa_ie.c
@@ -424,11 +424,19 @@
 					    pos, 2 + pos[1]);
 			}
 		} else if (*pos == WLAN_EID_LINK_ID) {
-			ie->lnkid = pos;
-			ie->lnkid_len = pos[1] + 2;
+			if (pos[1] >= 18) {
+				ie->lnkid = pos;
+				ie->lnkid_len = pos[1] + 2;
+			}
 		} else if (*pos == WLAN_EID_EXT_CAPAB) {
 			ie->ext_capab = pos;
 			ie->ext_capab_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_SUPP_RATES) {
+			ie->supp_rates = pos;
+			ie->supp_rates_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+			ie->ext_supp_rates = pos;
+			ie->ext_supp_rates_len = pos[1] + 2;
 		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
 			ret = wpa_parse_generic(pos, end, ie);
 			if (ret < 0)
diff --git a/src/rsn_supp/wpa_ie.h b/src/rsn_supp/wpa_ie.h
index f939b13..c13d94c 100644
--- a/src/rsn_supp/wpa_ie.h
+++ b/src/rsn_supp/wpa_ie.h
@@ -51,6 +51,10 @@
 	size_t lnkid_len;
 	const u8 *ext_capab;
 	size_t ext_capab_len;
+	const u8 *supp_rates;
+	size_t supp_rates_len;
+	const u8 *ext_supp_rates;
+	size_t ext_supp_rates_len;
 };
 
 int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
diff --git a/src/tls/Makefile b/src/tls/Makefile
index a2da096..27cdfca 100644
--- a/src/tls/Makefile
+++ b/src/tls/Makefile
@@ -11,6 +11,8 @@
 
 CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
 CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+CFLAGS += -DCONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV12
 
 LIB_OBJS= \
 	asn1.o \
diff --git a/src/tls/libtommath.c b/src/tls/libtommath.c
index 1374264..7c9857f 100644
--- a/src/tls/libtommath.c
+++ b/src/tls/libtommath.c
@@ -572,7 +572,7 @@
 
 /* this is a shell function that calls either the normal or Montgomery
  * exptmod functions.  Originally the call to the montgomery code was
- * embedded in the normal function but that wasted alot of stack space
+ * embedded in the normal function but that wasted a lot of stack space
  * for nothing (since 99% of the time the Montgomery code would be called)
  */
 static int mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
@@ -2207,7 +2207,7 @@
   /* zero a as per default */
   mp_zero (a);
 
-  /* grow a to accomodate the single bit */
+  /* grow a to accommodate the single bit */
   if ((res = mp_grow (a, b / DIGIT_BIT + 1)) != MP_OKAY) {
     return res;
   }
@@ -2319,7 +2319,7 @@
 }
 
 
-/* multiplies |a| * |b| and only computes upto digs digits of result
+/* multiplies |a| * |b| and only computes up to digs digits of result
  * HAC pp. 595, Algorithm 14.12  Modified so you can control how 
  * many digits of output are created.
  */
@@ -2678,7 +2678,7 @@
  *
  * Based on Algorithm 14.32 on pp.601 of HAC.
 */
-int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
+static int fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
 {
   int     ix, res, olduse;
   mp_word W[MP_WARRAY];
@@ -2829,7 +2829,7 @@
 {
   int     x, res, oldused;
 
-  /* grow to accomodate result */
+  /* grow to accommodate result */
   if (b->alloc < a->used + 1) {
     if ((res = mp_grow (b, a->used + 1)) != MP_OKAY) {
       return res;
@@ -2891,8 +2891,8 @@
 /*
  * shifts with subtractions when the result is greater than b.
  *
- * The method is slightly modified to shift B unconditionally upto just under
- * the leading bit of b.  This saves alot of multiple precision shifting.
+ * The method is slightly modified to shift B unconditionally up to just under
+ * the leading bit of b.  This saves a lot of multiple precision shifting.
  */
 static int mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
 {
diff --git a/src/tls/pkcs5.c b/src/tls/pkcs5.c
index 4291b84..fd9e346 100644
--- a/src/tls/pkcs5.c
+++ b/src/tls/pkcs5.c
@@ -32,7 +32,7 @@
 };
 
 
-enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
+static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
 {
 	if (oid->len == 7 &&
 	    oid->oid[0] == 1 /* iso */ &&
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 8b7e26f..d0da588 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -1,5 +1,5 @@
 /*
- * TLSv1 client (RFC 2246)
+ * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -67,7 +67,8 @@
 		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
 		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
 			  TLS_RANDOM_LEN);
-		if (tls_prf(pre_master_secret, pre_master_secret_len,
+		if (tls_prf(conn->rl.tls_version,
+			    pre_master_secret, pre_master_secret_len,
 			    "master secret", seed, 2 * TLS_RANDOM_LEN,
 			    conn->master_secret, TLS_MASTER_SECRET_LEN)) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
@@ -80,9 +81,11 @@
 
 	os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
 	os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
-	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
-			     conn->rl.iv_size);
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len);
+	if (conn->rl.tls_version == TLS_VERSION_1)
+		key_block_len += 2 * conn->rl.iv_size;
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
 		    "key expansion", seed, 2 * TLS_RANDOM_LEN,
 		    key_block, key_block_len)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
@@ -107,12 +110,21 @@
 	os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
 	pos += conn->rl.key_material_len;
 
-	/* client_write_IV */
-	os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
-	pos += conn->rl.iv_size;
-	/* server_write_IV */
-	os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
-	pos += conn->rl.iv_size;
+	if (conn->rl.tls_version == TLS_VERSION_1) {
+		/* client_write_IV */
+		os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
+		pos += conn->rl.iv_size;
+		/* server_write_IV */
+		os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
+		pos += conn->rl.iv_size;
+	} else {
+		/*
+		 * Use IV field to set the mask value for TLS v1.1. A fixed
+		 * mask of zero is used per the RFC 4346, 6.2.3.2 CBC Block
+		 * Cipher option 2a.
+		 */
+		os_memset(conn->rl.write_iv, 0, conn->rl.iv_size);
+	}
 
 	return 0;
 }
@@ -126,17 +138,23 @@
  * @out_len: Length of the output buffer.
  * @appl_data: Pointer to application data pointer, or %NULL if dropped
  * @appl_data_len: Pointer to variable that is set to appl_data length
+ * @need_more_data: Set to 1 if more data would be needed to complete
+ *	processing
  * Returns: Pointer to output data, %NULL on failure
  */
 u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
 			    const u8 *in_data, size_t in_len,
 			    size_t *out_len, u8 **appl_data,
-			    size_t *appl_data_len)
+			    size_t *appl_data_len, int *need_more_data)
 {
 	const u8 *pos, *end;
-	u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
+	u8 *msg = NULL, *in_msg = NULL, *in_pos, *in_end, alert, ct;
 	size_t in_msg_len;
 	int no_appl_data;
+	int used;
+
+	if (need_more_data)
+		*need_more_data = 0;
 
 	if (conn->state == CLIENT_HELLO) {
 		if (in_len)
@@ -144,6 +162,19 @@
 		return tls_send_client_hello(conn, out_len);
 	}
 
+	if (conn->partial_input) {
+		if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+				   "memory for pending record");
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			goto failed;
+		}
+		wpabuf_put_data(conn->partial_input, in_data, in_len);
+		in_data = wpabuf_head(conn->partial_input);
+		in_len = wpabuf_len(conn->partial_input);
+	}
+
 	if (in_data == NULL || in_len == 0)
 		return NULL;
 
@@ -156,13 +187,33 @@
 	/* Each received packet may include multiple records */
 	while (pos < end) {
 		in_msg_len = in_len;
-		if (tlsv1_record_receive(&conn->rl, pos, end - pos,
-					 in_msg, &in_msg_len, &alert)) {
+		used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+					    in_msg, &in_msg_len, &alert);
+		if (used < 0) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
 				   "record failed");
 			tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
 			goto failed;
 		}
+		if (used == 0) {
+			struct wpabuf *partial;
+			wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
+			partial = wpabuf_alloc_copy(pos, end - pos);
+			wpabuf_free(conn->partial_input);
+			conn->partial_input = partial;
+			if (conn->partial_input == NULL) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+					   "allocate memory for pending "
+					   "record");
+				tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					  TLS_ALERT_INTERNAL_ERROR);
+				goto failed;
+			}
+			os_free(in_msg);
+			if (need_more_data)
+				*need_more_data = 1;
+			return NULL;
+		}
 		ct = pos[0];
 
 		in_pos = in_msg;
@@ -180,7 +231,7 @@
 			in_pos += in_msg_len;
 		}
 
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+		pos += used;
 	}
 
 	os_free(in_msg);
@@ -192,6 +243,8 @@
 failed:
 	os_free(in_msg);
 	if (conn->alert_level) {
+		wpabuf_free(conn->partial_input);
+		conn->partial_input = NULL;
 		conn->state = FAILED;
 		os_free(msg);
 		msg = tlsv1_client_send_alert(conn, conn->alert_level,
@@ -202,6 +255,11 @@
 		*out_len = 0;
 	}
 
+	if (need_more_data == NULL || !(*need_more_data)) {
+		wpabuf_free(conn->partial_input);
+		conn->partial_input = NULL;
+	}
+
 	return msg;
 }
 
@@ -227,10 +285,8 @@
 	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
 			in_data, in_len);
 
-	os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
-
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
-			      out_data, out_len, in_len, &rlen) < 0) {
+			      out_data, out_len, in_data, in_len, &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -246,58 +302,116 @@
  * @conn: TLSv1 client connection data from tlsv1_client_init()
  * @in_data: Pointer to input buffer (encrypted TLS data)
  * @in_len: Input buffer length
- * @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
- * @out_len: Maximum out_data length
- * Returns: Number of bytes written to out_data, -1 on failure
+ * @need_more_data: Set to 1 if more data would be needed to complete
+ *	processing
+ * Returns: Decrypted data or %NULL on failure
  *
  * This function is used after TLS handshake has been completed successfully to
  * receive data from the encrypted tunnel.
  */
-int tlsv1_client_decrypt(struct tlsv1_client *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len)
+struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
+				     const u8 *in_data, size_t in_len,
+				     int *need_more_data)
 {
 	const u8 *in_end, *pos;
-	int res;
-	u8 alert, *out_end, *out_pos;
+	int used;
+	u8 alert, *out_pos, ct;
 	size_t olen;
+	struct wpabuf *buf = NULL;
+
+	if (need_more_data)
+		*need_more_data = 0;
+
+	if (conn->partial_input) {
+		if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
+				   "memory for pending record");
+			alert = TLS_ALERT_INTERNAL_ERROR;
+			goto fail;
+		}
+		wpabuf_put_data(conn->partial_input, in_data, in_len);
+		in_data = wpabuf_head(conn->partial_input);
+		in_len = wpabuf_len(conn->partial_input);
+	}
 
 	pos = in_data;
 	in_end = in_data + in_len;
-	out_pos = out_data;
-	out_end = out_data + out_len;
 
 	while (pos < in_end) {
-		if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
-				   "0x%x", pos[0]);
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_UNEXPECTED_MESSAGE);
-			return -1;
+		ct = pos[0];
+		if (wpabuf_resize(&buf, in_end - pos) < 0) {
+			alert = TLS_ALERT_INTERNAL_ERROR;
+			goto fail;
 		}
-
-		olen = out_end - out_pos;
-		res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
-					   out_pos, &olen, &alert);
-		if (res < 0) {
+		out_pos = wpabuf_put(buf, 0);
+		olen = wpabuf_tailroom(buf);
+		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+					    out_pos, &olen, &alert);
+		if (used < 0) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
 				   "failed");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
-			return -1;
+			goto fail;
 		}
-		out_pos += olen;
-		if (out_pos > out_end) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
-				   "for processing the received record");
-			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
-				  TLS_ALERT_INTERNAL_ERROR);
-			return -1;
+		if (used == 0) {
+			struct wpabuf *partial;
+			wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
+			partial = wpabuf_alloc_copy(pos, in_end - pos);
+			wpabuf_free(conn->partial_input);
+			conn->partial_input = partial;
+			if (conn->partial_input == NULL) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
+					   "allocate memory for pending "
+					   "record");
+				alert = TLS_ALERT_INTERNAL_ERROR;
+				goto fail;
+			}
+			if (need_more_data)
+				*need_more_data = 1;
+			return buf;
 		}
 
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+		if (ct == TLS_CONTENT_TYPE_ALERT) {
+			if (olen < 2) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+					   "underflow");
+				alert = TLS_ALERT_DECODE_ERROR;
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+				   out_pos[0], out_pos[1]);
+			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+				/* Continue processing */
+				pos += used;
+				continue;
+			}
+
+			alert = out_pos[1];
+			goto fail;
+		}
+
+		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
+				   "0x%x when decrypting application data",
+				   pos[0]);
+			alert = TLS_ALERT_UNEXPECTED_MESSAGE;
+			goto fail;
+		}
+
+		wpabuf_put(buf, olen);
+
+		pos += used;
 	}
 
-	return out_pos - out_data;
+	wpabuf_free(conn->partial_input);
+	conn->partial_input = NULL;
+	return buf;
+
+fail:
+	wpabuf_free(buf);
+	wpabuf_free(conn->partial_input);
+	conn->partial_input = NULL;
+	tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+	return NULL;
 }
 
 
@@ -352,14 +466,18 @@
 	count = 0;
 	suites = conn->cipher_suites;
 #ifndef CONFIG_CRYPTO_INTERNAL
+	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
 	suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
 #endif /* CONFIG_CRYPTO_INTERNAL */
+	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
 	suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
 	suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
 	conn->num_cipher_suites = count;
 
+	conn->rl.tls_version = TLS_VERSION;
+
 	return conn;
 }
 
@@ -378,6 +496,7 @@
 	os_free(conn->client_hello_ext);
 	tlsv1_client_free_dh(conn);
 	tlsv1_cred_free(conn->cred);
+	wpabuf_free(conn->partial_input);
 	os_free(conn);
 }
 
@@ -421,7 +540,8 @@
 			  TLS_RANDOM_LEN);
 	}
 
-	return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+	return tls_prf(conn->rl.tls_version,
+		       conn->master_secret, TLS_MASTER_SECRET_LEN,
 		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
 }
 
@@ -453,15 +573,24 @@
 	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";
+		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_256_CBC_SHA256:
+		cipher = "AES-256-SHA256";
+		break;
 	case TLS_RSA_WITH_AES_128_CBC_SHA:
 		cipher = "AES-128-SHA";
 		break;
+	case TLS_RSA_WITH_AES_128_CBC_SHA256:
+		cipher = "AES-128-SHA256";
+		break;
 	default:
 		return -1;
 	}
@@ -613,8 +742,10 @@
 		count = 0;
 		suites = conn->cipher_suites;
 #ifndef CONFIG_CRYPTO_INTERNAL
+		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA256;
 		suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
 #endif /* CONFIG_CRYPTO_INTERNAL */
+		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA256;
 		suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
 		suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
 		suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
diff --git a/src/tls/tlsv1_client.h b/src/tls/tlsv1_client.h
index a620d62..ef5e694 100644
--- a/src/tls/tlsv1_client.h
+++ b/src/tls/tlsv1_client.h
@@ -1,5 +1,5 @@
 /*
- * TLSv1 client (RFC 2246)
+ * TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
  * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
@@ -29,13 +29,13 @@
 u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
 			    const u8 *in_data, size_t in_len,
 			    size_t *out_len, u8 **appl_data,
-			    size_t *appl_data_len);
+			    size_t *appl_data_len, int *need_more_data);
 int tlsv1_client_encrypt(struct tlsv1_client *conn,
 			 const u8 *in_data, size_t in_len,
 			 u8 *out_data, size_t out_len);
-int tlsv1_client_decrypt(struct tlsv1_client *conn,
-			 const u8 *in_data, size_t in_len,
-			 u8 *out_data, size_t out_len);
+struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
+				     const u8 *in_data, size_t in_len,
+				     int *need_more_data);
 int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
 			    size_t buflen);
 int tlsv1_client_shutdown(struct tlsv1_client *conn);
diff --git a/src/tls/tlsv1_client_i.h b/src/tls/tlsv1_client_i.h
index f091bcf..92912ca 100644
--- a/src/tls/tlsv1_client_i.h
+++ b/src/tls/tlsv1_client_i.h
@@ -68,6 +68,8 @@
 
 	tlsv1_client_session_ticket_cb session_ticket_cb;
 	void *session_ticket_cb_ctx;
+
+	struct wpabuf *partial_input;
 };
 
 
diff --git a/src/tls/tlsv1_client_read.c b/src/tls/tlsv1_client_read.c
index faa891a..eb0cbef 100644
--- a/src/tls/tlsv1_client_read.c
+++ b/src/tls/tlsv1_client_read.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - read handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
@@ -38,6 +39,7 @@
 	const u8 *pos, *end;
 	size_t left, len, i;
 	u16 cipher_suite;
+	u16 tls_version;
 
 	if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
@@ -79,15 +81,20 @@
 	/* ProtocolVersion server_version */
 	if (end - pos < 2)
 		goto decode_error;
-	if (WPA_GET_BE16(pos) != TLS_VERSION) {
+	tls_version = WPA_GET_BE16(pos);
+	if (!tls_version_ok(tls_version)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
-			   "ServerHello");
+			   "ServerHello %u.%u", pos[0], pos[1]);
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_PROTOCOL_VERSION);
 		return -1;
 	}
 	pos += 2;
 
+	wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
+		   tls_version_str(tls_version));
+	conn->rl.tls_version = tls_version;
+
 	/* Random random */
 	if (end - pos < TLS_RANDOM_LEN)
 		goto decode_error;
@@ -816,6 +823,21 @@
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
 		    pos, TLS_VERIFY_DATA_LEN);
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_server == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+		    < 0) {
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.sha256_server = NULL;
+			return -1;
+		}
+		conn->verify.sha256_server = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	hlen = MD5_MAC_LEN;
 	if (conn->verify.md5_server == NULL ||
 	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
@@ -837,9 +859,15 @@
 		return -1;
 	}
 	conn->verify.sha1_server = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
 
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "server finished", hash, hlen,
 		    verify_data, TLS_VERIFY_DATA_LEN)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
diff --git a/src/tls/tlsv1_client_write.c b/src/tls/tlsv1_client_write.c
index 0898df9..35a238b 100644
--- a/src/tls/tlsv1_client_write.c
+++ b/src/tls/tlsv1_client_write.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 client - write handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
 #include "crypto/random.h"
 #include "x509v3.h"
@@ -116,7 +117,8 @@
 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, out_len) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      out_len) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -192,7 +194,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -413,7 +416,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -433,7 +437,7 @@
 {
 	u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
 	size_t rlen, hlen, clen;
-	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN], *hpos;
+	u8 hash[100], *hpos;
 	enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
 
 	pos = *msgpos;
@@ -473,6 +477,40 @@
 
 	hpos = hash;
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version == TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_cert == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
+		    0) {
+			conn->verify.sha256_cert = NULL;
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		conn->verify.sha256_cert = NULL;
+
+		/*
+		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+		 *
+		 * DigestInfo ::= SEQUENCE {
+		 *   digestAlgorithm DigestAlgorithm,
+		 *   digest OCTET STRING
+		 * }
+		 *
+		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+		 *
+		 * DER encoded DigestInfo for SHA256 per RFC 3447:
+		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+		 * H
+		 */
+		os_memmove(hash + 19, hash, hlen);
+		hlen += 19;
+		os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
+			  "\x03\x04\x02\x01\x05\x00\x04\x20", 19);
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	if (alg == SIGN_ALG_RSA) {
 		hlen = MD5_MAC_LEN;
 		if (conn->verify.md5_cert == NULL ||
@@ -503,8 +541,29 @@
 	if (alg == SIGN_ALG_RSA)
 		hlen += MD5_MAC_LEN;
 
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		/*
+		 * RFC 5246, 4.7:
+		 * TLS v1.2 adds explicit indication of the used signature and
+		 * hash algorithms.
+		 *
+		 * struct {
+		 *   HashAlgorithm hash;
+		 *   SignatureAlgorithm signature;
+		 * } SignatureAndHashAlgorithm;
+		 */
+		*pos++ = TLS_HASH_ALG_SHA256;
+		*pos++ = TLS_SIGN_ALG_RSA;
+	}
+#endif /* CONFIG_TLSV12 */
+
 	/*
 	 * RFC 2246, 4.7:
 	 * In digital signing, one-way hash functions are used as input for a
@@ -534,7 +593,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -553,17 +613,16 @@
 static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
 					       u8 **msgpos, u8 *end)
 {
-	u8 *pos, *rhdr;
 	size_t rlen;
-
-	pos = *msgpos;
+	u8 payload[1];
 
 	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-	*pos = TLS_CHANGE_CIPHER_SPEC;
+
+	payload[0] = TLS_CHANGE_CIPHER_SPEC;
+
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
-			      rhdr, end - rhdr, 1, &rlen) < 0) {
+			      *msgpos, end - *msgpos, payload, sizeof(payload),
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
@@ -578,7 +637,7 @@
 		return -1;
 	}
 
-	*msgpos = rhdr + rlen;
+	*msgpos += rlen;
 
 	return 0;
 }
@@ -587,17 +646,30 @@
 static int tls_write_client_finished(struct tlsv1_client *conn,
 				     u8 **msgpos, u8 *end)
 {
-	u8 *pos, *rhdr, *hs_start, *hs_length;
+	u8 *pos, *hs_start;
 	size_t rlen, hlen;
-	u8 verify_data[TLS_VERIFY_DATA_LEN];
+	u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
 	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
 
-	pos = *msgpos;
-
 	wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
 
 	/* Encrypted Handshake Message: Finished */
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_client == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
+		    < 0) {
+			tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				  TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.sha256_client = NULL;
+			return -1;
+		}
+		conn->verify.sha256_client = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	hlen = MD5_MAC_LEN;
 	if (conn->verify.md5_client == NULL ||
 	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
@@ -619,43 +691,44 @@
 		return -1;
 	}
 	conn->verify.sha1_client = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
 
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-		    verify_data, TLS_VERIFY_DATA_LEN)) {
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "client finished", hash, hlen,
+		    verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
 		return -1;
 	}
 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
-			verify_data, TLS_VERIFY_DATA_LEN);
+			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
 
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
 	/* Handshake */
-	hs_start = pos;
+	pos = hs_start = verify_data;
 	/* HandshakeType msg_type */
 	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
+	/* uint24 length */
+	WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
 	pos += 3;
-	os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
-	pos += TLS_VERIFY_DATA_LEN;
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
+	pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */
 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      *msgpos, end - *msgpos, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
 			  TLS_ALERT_INTERNAL_ERROR);
 		return -1;
 	}
 
-	pos = rhdr + rlen;
-
-	*msgpos = pos;
+	*msgpos += rlen;
 
 	return 0;
 }
@@ -778,7 +851,8 @@
 	/* ContentType type */
 	*pos++ = TLS_CONTENT_TYPE_ALERT;
 	/* ProtocolVersion version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
+	WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
+		     TLS_VERSION);
 	pos += 2;
 	/* uint16 length (to be filled) */
 	length = pos;
diff --git a/src/tls/tlsv1_common.c b/src/tls/tlsv1_common.c
index 2f9dd0f..871359a 100644
--- a/src/tls/tlsv1_common.c
+++ b/src/tls/tlsv1_common.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 common routines
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -15,6 +15,8 @@
 #include "includes.h"
 
 #include "common.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
 
@@ -50,7 +52,15 @@
 	{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
 	  TLS_HASH_SHA },
 	{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
-	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA }
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
+	{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
+	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+	{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
+	{ TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
+	  TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
+	{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
+	  TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
 };
 
 #define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
@@ -202,6 +212,19 @@
 		tls_verify_hash_free(verify);
 		return -1;
 	}
+#ifdef CONFIG_TLSV12
+	verify->sha256_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+						 0);
+	verify->sha256_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+						 0);
+	verify->sha256_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL,
+					       0);
+	if (verify->sha256_client == NULL || verify->sha256_server == NULL ||
+	    verify->sha256_cert == NULL) {
+		tls_verify_hash_free(verify);
+		return -1;
+	}
+#endif /* CONFIG_TLSV12 */
 	return 0;
 }
 
@@ -221,6 +244,14 @@
 		crypto_hash_update(verify->md5_cert, buf, len);
 		crypto_hash_update(verify->sha1_cert, buf, len);
 	}
+#ifdef CONFIG_TLSV12
+	if (verify->sha256_client)
+		crypto_hash_update(verify->sha256_client, buf, len);
+	if (verify->sha256_server)
+		crypto_hash_update(verify->sha256_server, buf, len);
+	if (verify->sha256_cert)
+		crypto_hash_update(verify->sha256_cert, buf, len);
+#endif /* CONFIG_TLSV12 */
 }
 
 
@@ -238,4 +269,60 @@
 	verify->sha1_client = NULL;
 	verify->sha1_server = NULL;
 	verify->sha1_cert = NULL;
+#ifdef CONFIG_TLSV12
+	crypto_hash_finish(verify->sha256_client, NULL, NULL);
+	crypto_hash_finish(verify->sha256_server, NULL, NULL);
+	crypto_hash_finish(verify->sha256_cert, NULL, NULL);
+	verify->sha256_client = NULL;
+	verify->sha256_server = NULL;
+	verify->sha256_cert = NULL;
+#endif /* CONFIG_TLSV12 */
+}
+
+
+int tls_version_ok(u16 ver)
+{
+	if (ver == TLS_VERSION_1)
+		return 1;
+#ifdef CONFIG_TLSV11
+	if (ver == TLS_VERSION_1_1)
+		return 1;
+#endif /* CONFIG_TLSV11 */
+#ifdef CONFIG_TLSV12
+	if (ver == TLS_VERSION_1_2)
+		return 1;
+#endif /* CONFIG_TLSV12 */
+
+	return 0;
+}
+
+
+const char * tls_version_str(u16 ver)
+{
+	switch (ver) {
+	case TLS_VERSION_1:
+		return "1.0";
+	case TLS_VERSION_1_1:
+		return "1.1";
+	case TLS_VERSION_1_2:
+		return "1.2";
+	}
+
+	return "?";
+}
+
+
+int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
+	    const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+#ifdef CONFIG_TLSV12
+	if (ver >= TLS_VERSION_1_2) {
+		tls_prf_sha256(secret, secret_len, label, seed, seed_len,
+			       out, outlen);
+		return 0;
+	}
+#endif /* CONFIG_TLSV12 */
+
+	return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
+				outlen);
 }
diff --git a/src/tls/tlsv1_common.h b/src/tls/tlsv1_common.h
index 763a4af..027daa4 100644
--- a/src/tls/tlsv1_common.h
+++ b/src/tls/tlsv1_common.h
@@ -1,6 +1,6 @@
 /*
  * TLSv1 common definitions
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,7 +17,18 @@
 
 #include "crypto/crypto.h"
 
-#define TLS_VERSION 0x0301 /* TLSv1 */
+#define TLS_VERSION_1 0x0301 /* TLSv1 */
+#define TLS_VERSION_1_1 0x0302 /* TLSv1.1 */
+#define TLS_VERSION_1_2 0x0303 /* TLSv1.2 */
+#ifdef CONFIG_TLSV12
+#define TLS_VERSION TLS_VERSION_1_2
+#else /* CONFIG_TLSV12 */
+#ifdef CONFIG_TLSV11
+#define TLS_VERSION TLS_VERSION_1_1
+#else /* CONFIG_TLSV11 */
+#define TLS_VERSION TLS_VERSION_1
+#endif /* CONFIG_TLSV11 */
+#endif /* CONFIG_TLSV12 */
 #define TLS_RANDOM_LEN 32
 #define TLS_PRE_MASTER_SECRET_LEN 48
 #define TLS_MASTER_SECRET_LEN 48
@@ -82,10 +93,42 @@
 #define TLS_DHE_DSS_WITH_AES_256_CBC_SHA	0x0038 /* RFC 3268 */
 #define TLS_DHE_RSA_WITH_AES_256_CBC_SHA	0x0039 /* RFC 3268 */
 #define TLS_DH_anon_WITH_AES_256_CBC_SHA	0x003A /* RFC 3268 */
+#define TLS_RSA_WITH_NULL_SHA256		0x003B /* RFC 5246 */
+#define TLS_RSA_WITH_AES_128_CBC_SHA256		0x003C /* RFC 5246 */
+#define TLS_RSA_WITH_AES_256_CBC_SHA256		0x003D /* RFC 5246 */
+#define TLS_DH_DSS_WITH_AES_128_CBC_SHA256	0x003E /* RFC 5246 */
+#define TLS_DH_RSA_WITH_AES_128_CBC_SHA256	0x003F /* RFC 5246 */
+#define TLS_DHE_DSS_WITH_AES_128_CBC_SHA256	0x0040 /* RFC 5246 */
+#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256	0x0067 /* RFC 5246 */
+#define TLS_DH_DSS_WITH_AES_256_CBC_SHA256	0x0068 /* RFC 5246 */
+#define TLS_DH_RSA_WITH_AES_256_CBC_SHA256	0x0069 /* RFC 5246 */
+#define TLS_DHE_DSS_WITH_AES_256_CBC_SHA256	0x006A /* RFC 5246 */
+#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256	0x006B /* RFC 5246 */
+#define TLS_DH_anon_WITH_AES_128_CBC_SHA256	0x006C /* RFC 5246 */
+#define TLS_DH_anon_WITH_AES_256_CBC_SHA256	0x006D /* RFC 5246 */
 
 /* CompressionMethod */
 #define TLS_COMPRESSION_NULL 0
 
+/* HashAlgorithm */
+enum {
+	TLS_HASH_ALG_NONE = 0,
+	TLS_HASH_ALG_MD5 = 1,
+	TLS_HASH_ALG_SHA1 = 2,
+	TLS_HASH_ALG_SHA224 = 3,
+	TLS_HASH_ALG_SHA256 = 4,
+	TLS_HASH_ALG_SHA384 = 5,
+	TLS_HASH_ALG_SHA512 = 6
+};
+
+/* SignatureAlgorithm */
+enum {
+	TLS_SIGN_ALG_ANONYMOUS = 0,
+	TLS_SIGN_ALG_RSA = 1,
+	TLS_SIGN_ALG_DSA = 2,
+	TLS_SIGN_ALG_ECDSA = 3,
+};
+
 /* AlertLevel */
 #define TLS_ALERT_LEVEL_WARNING 1
 #define TLS_ALERT_LEVEL_FATAL 2
@@ -169,7 +212,8 @@
 typedef enum {
 	TLS_HASH_NULL,
 	TLS_HASH_MD5,
-	TLS_HASH_SHA
+	TLS_HASH_SHA,
+	TLS_HASH_SHA256
 } tls_hash;
 
 struct tls_cipher_suite {
@@ -197,10 +241,13 @@
 struct tls_verify_hash {
 	struct crypto_hash *md5_client;
 	struct crypto_hash *sha1_client;
+	struct crypto_hash *sha256_client;
 	struct crypto_hash *md5_server;
 	struct crypto_hash *sha1_server;
+	struct crypto_hash *sha256_server;
 	struct crypto_hash *md5_cert;
 	struct crypto_hash *sha1_cert;
+	struct crypto_hash *sha256_cert;
 };
 
 
@@ -212,5 +259,9 @@
 void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
 			 size_t len);
 void tls_verify_hash_free(struct tls_verify_hash *verify);
+int tls_version_ok(u16 ver);
+const char * tls_version_str(u16 ver);
+int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
+	    const u8 *seed, size_t seed_len, u8 *out, size_t outlen);
 
 #endif /* TLSV1_COMMON_H */
diff --git a/src/tls/tlsv1_cred.c b/src/tls/tlsv1_cred.c
index aa467ef..d846480 100644
--- a/src/tls/tlsv1_cred.c
+++ b/src/tls/tlsv1_cred.c
@@ -46,7 +46,7 @@
 static int tlsv1_add_cert_der(struct x509_certificate **chain,
 			      const u8 *buf, size_t len)
 {
-	struct x509_certificate *cert;
+	struct x509_certificate *cert, *p;
 	char name[128];
 
 	cert = x509_certificate_parse(buf, len);
@@ -56,8 +56,20 @@
 		return -1;
 	}
 
-	cert->next = *chain;
-	*chain = cert;
+	p = *chain;
+	while (p && p->next)
+		p = p->next;
+	if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) {
+		/*
+		 * The new certificate is the issuer of the last certificate in
+		 * the chain - add the new certificate to the end.
+		 */
+		p->next = cert;
+	} else {
+		/* Add to the beginning of the chain */
+		cert->next = *chain;
+		*chain = cert;
+	}
 
 	x509_name_string(&cert->subject, name, sizeof(name));
 	wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
@@ -232,10 +244,17 @@
 		if (!end)
 			return NULL;
 	} else {
+		const u8 *pos2;
 		pos += os_strlen(pem_key_begin);
 		end = search_tag(pem_key_end, pos, key + len - pos);
 		if (!end)
 			return NULL;
+		pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos);
+		if (pos2) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key "
+				   "format (Proc-Type/DEK-Info)");
+			return NULL;
+		}
 	}
 
 	der = base64_decode(pos, end - pos, &der_len);
diff --git a/src/tls/tlsv1_record.c b/src/tls/tlsv1_record.c
index e811f0e..0314551 100644
--- a/src/tls/tlsv1_record.c
+++ b/src/tls/tlsv1_record.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 Record Protocol
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "tlsv1_common.h"
 #include "tlsv1_record.h"
 
@@ -52,6 +53,9 @@
 	} else if (suite->hash == TLS_HASH_SHA) {
 		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
 		rl->hash_size = SHA1_MAC_LEN;
+	} else if (suite->hash == TLS_HASH_SHA256) {
+		rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA256;
+		rl->hash_size = SHA256_MAC_LEN;
 	}
 
 	data = tls_get_cipher_data(suite->cipher);
@@ -138,10 +142,10 @@
  * tlsv1_record_send - TLS record layer: Send a message
  * @rl: Pointer to TLS record layer data
  * @content_type: Content type (TLS_CONTENT_TYPE_*)
- * @buf: Buffer to send (with TLS_RECORD_HEADER_LEN octets reserved in the
- * beginning for record layer to fill in; payload filled in after this and
- * extra space in the end for HMAC).
+ * @buf: Buffer for the generated TLS message (needs to have extra space for
+ * header, IV (TLS v1.1), and HMAC)
  * @buf_size: Maximum buf size
+ * @payload: Payload to be sent
  * @payload_len: Length of the payload
  * @out_len: Buffer for returning the used buf length
  * Returns: 0 on success, -1 on failure
@@ -150,29 +154,62 @@
  * the data using the current write cipher.
  */
 int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
-		      size_t buf_size, size_t payload_len, size_t *out_len)
+		      size_t buf_size, const u8 *payload, size_t payload_len,
+		      size_t *out_len)
 {
-	u8 *pos, *ct_start, *length, *payload;
+	u8 *pos, *ct_start, *length, *cpayload;
 	struct crypto_hash *hmac;
 	size_t clen;
+	int explicit_iv;
 
 	pos = buf;
+	if (pos + TLS_RECORD_HEADER_LEN > buf + buf_size)
+		return -1;
+
 	/* ContentType type */
 	ct_start = pos;
 	*pos++ = content_type;
 	/* ProtocolVersion version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
+	WPA_PUT_BE16(pos, rl->tls_version);
 	pos += 2;
 	/* uint16 length */
 	length = pos;
 	WPA_PUT_BE16(length, payload_len);
 	pos += 2;
 
-	/* opaque fragment[TLSPlaintext.length] */
-	payload = pos;
+	cpayload = pos;
+	explicit_iv = rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL &&
+		rl->iv_size && rl->tls_version >= TLS_VERSION_1_1;
+	if (explicit_iv) {
+		/* opaque IV[Cipherspec.block_length] */
+		if (pos + rl->iv_size > buf + buf_size)
+			return -1;
+
+		/*
+		 * Use random number R per the RFC 4346, 6.2.3.2 CBC Block
+		 * Cipher option 2a.
+		 */
+
+		if (os_get_random(pos, rl->iv_size))
+			return -1;
+		pos += rl->iv_size;
+	}
+
+	/*
+	 * opaque fragment[TLSPlaintext.length]
+	 * (opaque content[TLSCompressed.length] in GenericBlockCipher)
+	 */
+	if (pos + payload_len > buf + buf_size)
+		return -1;
+	os_memmove(pos, payload, payload_len);
 	pos += payload_len;
 
 	if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
+		/*
+		 * MAC calculated over seq_num + TLSCompressed.type +
+		 * TLSCompressed.version + TLSCompressed.length +
+		 * TLSCompressed.fragment
+		 */
 		hmac = crypto_hash_init(rl->hash_alg, rl->write_mac_secret,
 					rl->hash_size);
 		if (hmac == NULL) {
@@ -182,7 +219,8 @@
 		}
 		crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
 		/* type + version + length + fragment */
-		crypto_hash_update(hmac, ct_start, pos - ct_start);
+		crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN);
+		crypto_hash_update(hmac, payload, payload_len);
 		clen = buf + buf_size - pos;
 		if (clen < rl->hash_size) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
@@ -200,7 +238,7 @@
 			    pos, clen);
 		pos += clen;
 		if (rl->iv_size) {
-			size_t len = pos - payload;
+			size_t len = pos - cpayload;
 			size_t pad;
 			pad = (len + 1) % rl->iv_size;
 			if (pad)
@@ -214,8 +252,8 @@
 			pos += pad + 1;
 		}
 
-		if (crypto_cipher_encrypt(rl->write_cbc, payload,
-					  payload, pos - payload) < 0)
+		if (crypto_cipher_encrypt(rl->write_cbc, cpayload,
+					  cpayload, pos - cpayload) < 0)
 			return -1;
 	}
 
@@ -237,7 +275,8 @@
  * @out_len: Set to maximum out_data length by caller; used to return the
  * length of the used data
  * @alert: Buffer for returning an alert value on failure
- * Returns: 0 on success, -1 on failure
+ * Returns: Number of bytes used from in_data on success, 0 if record was not
+ *	complete (more data needed), or -1 on failure
  *
  * This function decrypts the received message, verifies HMAC and TLS record
  * layer header.
@@ -250,40 +289,35 @@
 	u8 padlen;
 	struct crypto_hash *hmac;
 	u8 len[2], hash[100];
-
-	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
-		    in_data, in_len);
+	int force_mac_error = 0;
+	u8 ct;
 
 	if (in_len < TLS_RECORD_HEADER_LEN) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu)",
+		wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu) - "
+			   "need more data",
 			   (unsigned long) in_len);
-		*alert = TLS_ALERT_DECODE_ERROR;
-		return -1;
+		wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+			    in_data, in_len);
+		return 0;
 	}
 
+	ct = in_data[0];
+	rlen = WPA_GET_BE16(in_data + 3);
 	wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
-		   "length %d", in_data[0], in_data[1], in_data[2],
-		   WPA_GET_BE16(in_data + 3));
+		   "length %d", ct, in_data[1], in_data[2], (int) rlen);
 
-	if (in_data[0] != TLS_CONTENT_TYPE_HANDSHAKE &&
-	    in_data[0] != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
-	    in_data[0] != TLS_CONTENT_TYPE_ALERT &&
-	    in_data[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
-		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type 0x%x",
-			   in_data[0]);
-		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
-		return -1;
-	}
-
-	if (WPA_GET_BE16(in_data + 1) != TLS_VERSION) {
+	/*
+	 * TLS v1.0 and v1.1 RFCs were not exactly clear on the use of the
+	 * protocol version in record layer. As such, accept any {03,xx} value
+	 * to remain compatible with existing implementations.
+	 */
+	if (in_data[1] != 0x03) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
-			   "%d.%d", in_data[1], in_data[2]);
+			   "%u.%u", in_data[1], in_data[2]);
 		*alert = TLS_ALERT_PROTOCOL_VERSION;
 		return -1;
 	}
 
-	rlen = WPA_GET_BE16(in_data + 3);
-
 	/* TLSCiphertext must not be more than 2^14+2048 bytes */
 	if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
@@ -299,7 +333,19 @@
 		wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
 			   "(rlen=%lu > in_len=%lu)",
 			   (unsigned long) rlen, (unsigned long) in_len);
-		*alert = TLS_ALERT_DECODE_ERROR;
+		return 0;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
+		    in_data, rlen);
+
+	if (ct != TLS_CONTENT_TYPE_HANDSHAKE &&
+	    ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
+	    ct != TLS_CONTENT_TYPE_ALERT &&
+	    ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Ignore record with unknown "
+			   "content type 0x%x", ct);
+		*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
 		return -1;
 	}
 
@@ -312,58 +358,86 @@
 		return -1;
 	}
 
-	os_memcpy(out_data, in_data, in_len);
-	*out_len = in_len;
-
 	if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
-		if (crypto_cipher_decrypt(rl->read_cbc, out_data,
+		size_t plen;
+		if (crypto_cipher_decrypt(rl->read_cbc, in_data,
 					  out_data, in_len) < 0) {
 			*alert = TLS_ALERT_DECRYPTION_FAILED;
 			return -1;
 		}
+		plen = in_len;
+		wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
+				"data", out_data, plen);
+
 		if (rl->iv_size) {
-			if (in_len == 0) {
+			/*
+			 * TLS v1.0 defines different alert values for various
+			 * failures. That may information to aid in attacks, so
+			 * use the same bad_record_mac alert regardless of the
+			 * issues.
+			 *
+			 * In addition, instead of returning immediately on
+			 * error, run through the MAC check to make timing
+			 * attacks more difficult.
+			 */
+
+			if (rl->tls_version >= TLS_VERSION_1_1) {
+				/* Remove opaque IV[Cipherspec.block_length] */
+				if (plen < rl->iv_size) {
+					wpa_printf(MSG_DEBUG, "TLSv1.1: Not "
+						   "enough room for IV");
+					force_mac_error = 1;
+					goto check_mac;
+				}
+				os_memmove(out_data, out_data + rl->iv_size,
+					   plen - rl->iv_size);
+				plen -= rl->iv_size;
+			}
+
+			/* Verify and remove padding */
+			if (plen == 0) {
 				wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
 					   " (no pad)");
-				*alert = TLS_ALERT_DECODE_ERROR;
-				return -1;
+				force_mac_error = 1;
+				goto check_mac;
 			}
-			padlen = out_data[in_len - 1];
-			if (padlen >= in_len) {
+			padlen = out_data[plen - 1];
+			if (padlen >= plen) {
 				wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
-					   "length (%u, in_len=%lu) in "
+					   "length (%u, plen=%lu) in "
 					   "received record",
-					   padlen, (unsigned long) in_len);
-				*alert = TLS_ALERT_DECRYPTION_FAILED;
-				return -1;
+					   padlen, (unsigned long) plen);
+				force_mac_error = 1;
+				goto check_mac;
 			}
-			for (i = in_len - padlen; i < in_len; i++) {
+			for (i = plen - padlen - 1; i < plen - 1; i++) {
 				if (out_data[i] != padlen) {
 					wpa_hexdump(MSG_DEBUG,
 						    "TLSv1: Invalid pad in "
 						    "received record",
-						    out_data + in_len - padlen,
-						    padlen);
-					*alert = TLS_ALERT_DECRYPTION_FAILED;
-					return -1;
+						    out_data + plen - padlen -
+						    1, padlen + 1);
+					force_mac_error = 1;
+					goto check_mac;
 				}
 			}
 
-			*out_len -= padlen + 1;
+			plen -= padlen + 1;
+
+			wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - "
+					"Decrypted data with IV and padding "
+					"removed", out_data, plen);
 		}
 
-		wpa_hexdump(MSG_MSGDUMP,
-			    "TLSv1: Record Layer - Decrypted data",
-			    out_data, in_len);
-
-		if (*out_len < rl->hash_size) {
+	check_mac:
+		if (plen < rl->hash_size) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
 				   "hash value");
-			*alert = TLS_ALERT_INTERNAL_ERROR;
+			*alert = TLS_ALERT_BAD_RECORD_MAC;
 			return -1;
 		}
 
-		*out_len -= rl->hash_size;
+		plen -= rl->hash_size;
 
 		hmac = crypto_hash_init(rl->hash_alg, rl->read_mac_secret,
 					rl->hash_size);
@@ -377,22 +451,30 @@
 		crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
 		/* type + version + length + fragment */
 		crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
-		WPA_PUT_BE16(len, *out_len);
+		WPA_PUT_BE16(len, plen);
 		crypto_hash_update(hmac, len, 2);
-		crypto_hash_update(hmac, out_data, *out_len);
+		crypto_hash_update(hmac, out_data, plen);
 		hlen = sizeof(hash);
 		if (crypto_hash_finish(hmac, hash, &hlen) < 0) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
 				   "to calculate HMAC");
+			*alert = TLS_ALERT_INTERNAL_ERROR;
 			return -1;
 		}
 		if (hlen != rl->hash_size ||
-		    os_memcmp(hash, out_data + *out_len, hlen) != 0) {
+		    os_memcmp(hash, out_data + plen, hlen) != 0 ||
+		    force_mac_error) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
-				   "received message");
+				   "received message (force_mac_error=%d)",
+				   force_mac_error);
 			*alert = TLS_ALERT_BAD_RECORD_MAC;
 			return -1;
 		}
+
+		*out_len = plen;
+	} else {
+		os_memcpy(out_data, in_data, in_len);
+		*out_len = in_len;
 	}
 
 	/* TLSCompressed must not be more than 2^14+1024 bytes */
@@ -405,5 +487,5 @@
 
 	inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
 
-	return 0;
+	return TLS_RECORD_HEADER_LEN + rlen;
 }
diff --git a/src/tls/tlsv1_record.h b/src/tls/tlsv1_record.h
index 9c7c0a4..9eb9bfd 100644
--- a/src/tls/tlsv1_record.h
+++ b/src/tls/tlsv1_record.h
@@ -1,6 +1,6 @@
 /*
  * TLSv1 Record Protocol
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,7 +17,7 @@
 
 #include "crypto/crypto.h"
 
-#define TLS_MAX_WRITE_MAC_SECRET_LEN 20
+#define TLS_MAX_WRITE_MAC_SECRET_LEN 32
 #define TLS_MAX_WRITE_KEY_LEN 32
 #define TLS_MAX_IV_LEN 16
 #define TLS_MAX_KEY_BLOCK_LEN (2 * (TLS_MAX_WRITE_MAC_SECRET_LEN + \
@@ -35,6 +35,8 @@
 };
 
 struct tlsv1_record_layer {
+	u16 tls_version;
+
 	u8 write_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
 	u8 read_mac_secret[TLS_MAX_WRITE_MAC_SECRET_LEN];
 	u8 write_key[TLS_MAX_WRITE_KEY_LEN];
@@ -66,7 +68,8 @@
 int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl);
 int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl);
 int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
-		      size_t buf_size, size_t payload_len, size_t *out_len);
+		      size_t buf_size, const u8 *payload, size_t payload_len,
+		      size_t *out_len);
 int tlsv1_record_receive(struct tlsv1_record_layer *rl,
 			 const u8 *in_data, size_t in_len,
 			 u8 *out_data, size_t *out_len, u8 *alert);
diff --git a/src/tls/tlsv1_server.c b/src/tls/tlsv1_server.c
index 6a61235..96e160c 100644
--- a/src/tls/tlsv1_server.c
+++ b/src/tls/tlsv1_server.c
@@ -1,6 +1,6 @@
 /*
- * TLSv1 server (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -49,7 +49,8 @@
 		os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
 		os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
 			  TLS_RANDOM_LEN);
-		if (tls_prf(pre_master_secret, pre_master_secret_len,
+		if (tls_prf(conn->rl.tls_version,
+			    pre_master_secret, pre_master_secret_len,
 			    "master secret", seed, 2 * TLS_RANDOM_LEN,
 			    conn->master_secret, TLS_MASTER_SECRET_LEN)) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
@@ -64,7 +65,8 @@
 	os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
 	key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
 			     conn->rl.iv_size);
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
 		    "key expansion", seed, 2 * TLS_RANDOM_LEN,
 		    key_block, key_block_len)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
@@ -115,6 +117,7 @@
 	const u8 *pos, *end;
 	u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
 	size_t in_msg_len;
+	int used;
 
 	if (in_data == NULL || in_len == 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
@@ -130,13 +133,21 @@
 	/* Each received packet may include multiple records */
 	while (pos < end) {
 		in_msg_len = in_len;
-		if (tlsv1_record_receive(&conn->rl, pos, end - pos,
-					 in_msg, &in_msg_len, &alert)) {
+		used = tlsv1_record_receive(&conn->rl, pos, end - pos,
+					    in_msg, &in_msg_len, &alert);
+		if (used < 0) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
 				   "record failed");
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
 			goto failed;
 		}
+		if (used == 0) {
+			/* need more data */
+			wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+				   "yet supported");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			goto failed;
+		}
 		ct = pos[0];
 
 		in_pos = in_msg;
@@ -152,7 +163,7 @@
 			in_pos += in_msg_len;
 		}
 
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+		pos += used;
 	}
 
 	os_free(in_msg);
@@ -201,10 +212,8 @@
 	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
 			in_data, in_len);
 
-	os_memcpy(out_data + TLS_RECORD_HEADER_LEN, in_data, in_len);
-
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
-			      out_data, out_len, in_len, &rlen) < 0) {
+			      out_data, out_len, in_data, in_len, &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -232,8 +241,8 @@
 			 u8 *out_data, size_t out_len)
 {
 	const u8 *in_end, *pos;
-	int res;
-	u8 alert, *out_end, *out_pos;
+	int used;
+	u8 alert, *out_end, *out_pos, ct;
 	size_t olen;
 
 	pos = in_data;
@@ -242,7 +251,46 @@
 	out_end = out_data + out_len;
 
 	while (pos < in_end) {
-		if (pos[0] != TLS_CONTENT_TYPE_APPLICATION_DATA) {
+		ct = pos[0];
+		olen = out_end - out_pos;
+		used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
+					    out_pos, &olen, &alert);
+		if (used < 0) {
+			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
+				   "failed");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			return -1;
+		}
+		if (used == 0) {
+			/* need more data */
+			wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
+				   "yet supported");
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
+			return -1;
+		}
+
+		if (ct == TLS_CONTENT_TYPE_ALERT) {
+			if (olen < 2) {
+				wpa_printf(MSG_DEBUG, "TLSv1: Alert "
+					   "underflow");
+				tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+						   TLS_ALERT_DECODE_ERROR);
+				return -1;
+			}
+			wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
+				   out_pos[0], out_pos[1]);
+			if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
+				/* Continue processing */
+				pos += used;
+				continue;
+			}
+
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   out_pos[1]);
+			return -1;
+		}
+
+		if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
 				   "0x%x", pos[0]);
 			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
@@ -250,15 +298,6 @@
 			return -1;
 		}
 
-		olen = out_end - out_pos;
-		res = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
-					   out_pos, &olen, &alert);
-		if (res < 0) {
-			wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
-				   "failed");
-			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
-			return -1;
-		}
 		out_pos += olen;
 		if (out_pos > out_end) {
 			wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
@@ -268,7 +307,7 @@
 			return -1;
 		}
 
-		pos += TLS_RECORD_HEADER_LEN + WPA_GET_BE16(pos + 3);
+		pos += used;
 	}
 
 	return out_pos - out_data;
@@ -412,7 +451,8 @@
 			  TLS_RANDOM_LEN);
 	}
 
-	return tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
+	return tls_prf(conn->rl.tls_version,
+		       conn->master_secret, TLS_MASTER_SECRET_LEN,
 		       label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
 }
 
diff --git a/src/tls/tlsv1_server.h b/src/tls/tlsv1_server.h
index 00c536c..daa4353 100644
--- a/src/tls/tlsv1_server.h
+++ b/src/tls/tlsv1_server.h
@@ -1,6 +1,6 @@
 /*
- * TLSv1 server (RFC 2246)
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index fd74436..443c028 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 server - read handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
 #include "x509v3.h"
 #include "tlsv1_common.h"
@@ -85,15 +86,30 @@
 	conn->client_version = WPA_GET_BE16(pos);
 	wpa_printf(MSG_DEBUG, "TLSv1: Client version %d.%d",
 		   conn->client_version >> 8, conn->client_version & 0xff);
-	if (conn->client_version < TLS_VERSION) {
+	if (conn->client_version < TLS_VERSION_1) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version in "
-			   "ClientHello");
+			   "ClientHello %u.%u",
+			   conn->client_version >> 8,
+			   conn->client_version & 0xff);
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_PROTOCOL_VERSION);
 		return -1;
 	}
 	pos += 2;
 
+	if (TLS_VERSION == TLS_VERSION_1)
+		conn->rl.tls_version = TLS_VERSION_1;
+#ifdef CONFIG_TLSV12
+	else if (conn->client_version >= TLS_VERSION_1_2)
+		conn->rl.tls_version = TLS_VERSION_1_2;
+#endif /* CONFIG_TLSV12 */
+	else if (conn->client_version > TLS_VERSION_1_1)
+		conn->rl.tls_version = TLS_VERSION_1_1;
+	else
+		conn->rl.tls_version = conn->client_version;
+	wpa_printf(MSG_DEBUG, "TLSv1: Using TLS v%s",
+		   tls_version_str(conn->rl.tls_version));
+
 	/* Random random */
 	if (end - pos < TLS_RANDOM_LEN)
 		goto decode_error;
@@ -483,6 +499,14 @@
 
 	encr_len = WPA_GET_BE16(pos);
 	pos += 2;
+	if (pos + encr_len > end) {
+		wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientKeyExchange "
+			   "format: encr_len=%u left=%u",
+			   encr_len, (unsigned int) (end - pos));
+		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+				   TLS_ALERT_DECODE_ERROR);
+		return -1;
+	}
 
 	outbuflen = outlen = end - pos;
 	out = os_malloc(outlen >= TLS_PRE_MASTER_SECRET_LEN ?
@@ -512,21 +536,21 @@
 	 */
 
 	if (crypto_private_key_decrypt_pkcs1_v15(conn->cred->key,
-						 pos, end - pos,
+						 pos, encr_len,
 						 out, &outlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
-			   "PreMasterSecret (encr_len=%d outlen=%lu)",
-			   (int) (end - pos), (unsigned long) outlen);
+			   "PreMasterSecret (encr_len=%u outlen=%lu)",
+			   encr_len, (unsigned long) outlen);
 		use_random = 1;
 	}
 
-	if (outlen != TLS_PRE_MASTER_SECRET_LEN) {
+	if (!use_random && outlen != TLS_PRE_MASTER_SECRET_LEN) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Unexpected PreMasterSecret "
 			   "length %lu", (unsigned long) outlen);
 		use_random = 1;
 	}
 
-	if (WPA_GET_BE16(out) != conn->client_version) {
+	if (!use_random && WPA_GET_BE16(out) != conn->client_version) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Client version in "
 			   "ClientKeyExchange does not match with version in "
 			   "ClientHello");
@@ -822,6 +846,47 @@
 
 	hpos = hash;
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version == TLS_VERSION_1_2) {
+		/*
+		 * RFC 5246, 4.7:
+		 * TLS v1.2 adds explicit indication of the used signature and
+		 * hash algorithms.
+		 *
+		 * struct {
+		 *   HashAlgorithm hash;
+		 *   SignatureAlgorithm signature;
+		 * } SignatureAndHashAlgorithm;
+		 */
+		if (end - pos < 2) {
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECODE_ERROR);
+			return -1;
+		}
+		if (pos[0] != TLS_HASH_ALG_SHA256 ||
+		    pos[1] != TLS_SIGN_ALG_RSA) {
+			wpa_printf(MSG_DEBUG, "TLSv1.2: Unsupported hash(%u)/"
+				   "signature(%u) algorithm",
+				   pos[0], pos[1]);
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		pos += 2;
+
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_cert == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
+		    0) {
+			conn->verify.sha256_cert = NULL;
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		conn->verify.sha256_cert = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	if (alg == SIGN_ALG_RSA) {
 		hlen = MD5_MAC_LEN;
 		if (conn->verify.md5_cert == NULL ||
@@ -852,6 +917,10 @@
 	if (alg == SIGN_ALG_RSA)
 		hlen += MD5_MAC_LEN;
 
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
 
 	if (end - pos < 2) {
@@ -891,6 +960,41 @@
 	wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Decrypted Signature",
 			buf, buflen);
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		/*
+		 * RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
+		 *
+		 * DigestInfo ::= SEQUENCE {
+		 *   digestAlgorithm DigestAlgorithm,
+		 *   digest OCTET STRING
+		 * }
+		 *
+		 * SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
+		 *
+		 * DER encoded DigestInfo for SHA256 per RFC 3447:
+		 * 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
+		 * H
+		 */
+		if (buflen >= 19 + 32 &&
+		    os_memcmp(buf, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01"
+			      "\x65\x03\x04\x02\x01\x05\x00\x04\x20", 19) == 0)
+		{
+			wpa_printf(MSG_DEBUG, "TLSv1.2: DigestAlgorithn = "
+				   "SHA-256");
+			os_memmove(buf, buf + 19, buflen - 19);
+			buflen -= 19;
+		} else {
+			wpa_printf(MSG_DEBUG, "TLSv1.2: Unrecognized "
+				   "DigestInfo");
+			os_free(buf);
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_DECRYPT_ERROR);
+			return -1;
+		}
+	}
+#endif /* CONFIG_TLSV12 */
+
 	if (buflen != hlen || os_memcmp(buf, hash, buflen) != 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Invalid Signature in "
 			   "CertificateVerify - did not match with calculated "
@@ -1022,6 +1126,21 @@
 	wpa_hexdump(MSG_MSGDUMP, "TLSv1: verify_data in Finished",
 		    pos, TLS_VERIFY_DATA_LEN);
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_client == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
+		    < 0) {
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			conn->verify.sha256_client = NULL;
+			return -1;
+		}
+		conn->verify.sha256_client = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	hlen = MD5_MAC_LEN;
 	if (conn->verify.md5_client == NULL ||
 	    crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
@@ -1043,9 +1162,15 @@
 		return -1;
 	}
 	conn->verify.sha1_client = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
 
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "client finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "client finished", hash, hlen,
 		    verify_data, TLS_VERIFY_DATA_LEN)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive verify_data");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
diff --git a/src/tls/tlsv1_server_write.c b/src/tls/tlsv1_server_write.c
index e89e52e..0ca3b23 100644
--- a/src/tls/tlsv1_server_write.c
+++ b/src/tls/tlsv1_server_write.c
@@ -1,6 +1,6 @@
 /*
  * TLSv1 server - write handshake message
- * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "crypto/md5.h"
 #include "crypto/sha1.h"
+#include "crypto/sha256.h"
 #include "crypto/tls.h"
 #include "crypto/random.h"
 #include "x509v3.h"
@@ -87,7 +88,7 @@
 	pos += 3;
 	/* body - ServerHello */
 	/* ProtocolVersion server_version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
+	WPA_PUT_BE16(pos, conn->rl.tls_version);
 	pos += 2;
 	/* Random random: uint32 gmt_unix_time, opaque random_bytes */
 	os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
@@ -143,7 +144,8 @@
 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -227,7 +229,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -418,7 +421,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -483,7 +487,8 @@
 	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      rhdr, end - rhdr, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -502,40 +507,35 @@
 static int tls_write_server_hello_done(struct tlsv1_server *conn,
 				       u8 **msgpos, u8 *end)
 {
-	u8 *pos, *rhdr, *hs_start, *hs_length;
+	u8 *pos;
 	size_t rlen;
-
-	pos = *msgpos;
+	u8 payload[4];
 
 	wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
 
 	/* opaque fragment[TLSPlaintext.length] */
 
 	/* Handshake */
-	hs_start = pos;
+	pos = payload;
 	/* HandshakeType msg_type */
 	*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
+	/* uint24 length */
+	WPA_PUT_BE24(pos, 0);
 	pos += 3;
 	/* body - ServerHelloDone (empty) */
 
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
-
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      *msgpos, end - *msgpos, payload, pos - payload,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
 		return -1;
 	}
-	pos = rhdr + rlen;
 
-	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
+	tls_verify_hash_add(&conn->verify, payload, pos - payload);
 
-	*msgpos = pos;
+	*msgpos += rlen;
 
 	return 0;
 }
@@ -544,17 +544,16 @@
 static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
 					       u8 **msgpos, u8 *end)
 {
-	u8 *pos, *rhdr;
 	size_t rlen;
-
-	pos = *msgpos;
+	u8 payload[1];
 
 	wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
-	*pos = TLS_CHANGE_CIPHER_SPEC;
+
+	payload[0] = TLS_CHANGE_CIPHER_SPEC;
+
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
-			      rhdr, end - rhdr, 1, &rlen) < 0) {
+			      *msgpos, end - *msgpos, payload, sizeof(payload),
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
@@ -569,7 +568,7 @@
 		return -1;
 	}
 
-	*msgpos = rhdr + rlen;
+	*msgpos += rlen;
 
 	return 0;
 }
@@ -578,9 +577,9 @@
 static int tls_write_server_finished(struct tlsv1_server *conn,
 				     u8 **msgpos, u8 *end)
 {
-	u8 *pos, *rhdr, *hs_start, *hs_length;
+	u8 *pos, *hs_start;
 	size_t rlen, hlen;
-	u8 verify_data[TLS_VERIFY_DATA_LEN];
+	u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
 	u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
 
 	pos = *msgpos;
@@ -589,6 +588,21 @@
 
 	/* Encrypted Handshake Message: Finished */
 
+#ifdef CONFIG_TLSV12
+	if (conn->rl.tls_version >= TLS_VERSION_1_2) {
+		hlen = SHA256_MAC_LEN;
+		if (conn->verify.sha256_server == NULL ||
+		    crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
+		    < 0) {
+			conn->verify.sha256_server = NULL;
+			tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
+					   TLS_ALERT_INTERNAL_ERROR);
+			return -1;
+		}
+		conn->verify.sha256_server = NULL;
+	} else {
+#endif /* CONFIG_TLSV12 */
+
 	hlen = MD5_MAC_LEN;
 	if (conn->verify.md5_server == NULL ||
 	    crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
@@ -610,43 +624,44 @@
 		return -1;
 	}
 	conn->verify.sha1_server = NULL;
+	hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
 
-	if (tls_prf(conn->master_secret, TLS_MASTER_SECRET_LEN,
-		    "server finished", hash, MD5_MAC_LEN + SHA1_MAC_LEN,
-		    verify_data, TLS_VERIFY_DATA_LEN)) {
+#ifdef CONFIG_TLSV12
+	}
+#endif /* CONFIG_TLSV12 */
+
+	if (tls_prf(conn->rl.tls_version,
+		    conn->master_secret, TLS_MASTER_SECRET_LEN,
+		    "server finished", hash, hlen,
+		    verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
 		return -1;
 	}
 	wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
-			verify_data, TLS_VERIFY_DATA_LEN);
+			verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
 
-	rhdr = pos;
-	pos += TLS_RECORD_HEADER_LEN;
 	/* Handshake */
-	hs_start = pos;
+	pos = hs_start = verify_data;
 	/* HandshakeType msg_type */
 	*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
-	/* uint24 length (to be filled) */
-	hs_length = pos;
+	/* uint24 length */
+	WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
 	pos += 3;
-	os_memcpy(pos, verify_data, TLS_VERIFY_DATA_LEN);
 	pos += TLS_VERIFY_DATA_LEN;
-	WPA_PUT_BE24(hs_length, pos - hs_length - 3);
 	tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
 
 	if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
-			      rhdr, end - rhdr, pos - hs_start, &rlen) < 0) {
+			      *msgpos, end - *msgpos, hs_start, pos - hs_start,
+			      &rlen) < 0) {
 		wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
 		tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
 				   TLS_ALERT_INTERNAL_ERROR);
 		return -1;
 	}
 
-	pos = rhdr + rlen;
-
-	*msgpos = pos;
+	*msgpos += rlen;
 
 	return 0;
 }
@@ -771,7 +786,8 @@
 	/* ContentType type */
 	*pos++ = TLS_CONTENT_TYPE_ALERT;
 	/* ProtocolVersion version */
-	WPA_PUT_BE16(pos, TLS_VERSION);
+	WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
+		     TLS_VERSION);
 	pos += 2;
 	/* uint16 length (to be filled) */
 	length = pos;
diff --git a/src/utils/base64.c b/src/utils/base64.c
index 155bfce..fb1224b 100644
--- a/src/utils/base64.c
+++ b/src/utils/base64.c
@@ -1,6 +1,6 @@
 /*
  * Base64 encoding/decoding (RFC1341)
- * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -103,8 +103,9 @@
 unsigned char * base64_decode(const unsigned char *src, size_t len,
 			      size_t *out_len)
 {
-	unsigned char dtable[256], *out, *pos, in[4], block[4], tmp;
+	unsigned char dtable[256], *out, *pos, block[4], tmp;
 	size_t i, count, olen;
+	int pad = 0;
 
 	os_memset(dtable, 0x80, 256);
 	for (i = 0; i < sizeof(base64_table) - 1; i++)
@@ -131,7 +132,8 @@
 		if (tmp == 0x80)
 			continue;
 
-		in[count] = src[i];
+		if (src[i] == '=')
+			pad++;
 		block[count] = tmp;
 		count++;
 		if (count == 4) {
@@ -139,16 +141,21 @@
 			*pos++ = (block[1] << 4) | (block[2] >> 2);
 			*pos++ = (block[2] << 6) | block[3];
 			count = 0;
+			if (pad) {
+				if (pad == 1)
+					pos--;
+				else if (pad == 2)
+					pos -= 2;
+				else {
+					/* Invalid padding */
+					os_free(out);
+					return NULL;
+				}
+				break;
+			}
 		}
 	}
 
-	if (pos > out) {
-		if (in[2] == '=')
-			pos -= 2;
-		else if (in[3] == '=')
-			pos--;
-	}
-
 	*out_len = pos - out;
 	return out;
 }
diff --git a/src/utils/edit.c b/src/utils/edit.c
index 8f9e4ed..c5b17ac 100644
--- a/src/utils/edit.c
+++ b/src/utils/edit.c
@@ -1,6 +1,6 @@
 /*
  * Command line editing and history
- * Copyright (c) 2010, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -24,6 +24,8 @@
 static char cmdbuf[CMD_BUF_LEN];
 static int cmdbuf_pos = 0;
 static int cmdbuf_len = 0;
+static char currbuf[CMD_BUF_LEN];
+static int currbuf_valid = 0;
 
 #define HISTORY_MAX 100
 
@@ -231,18 +233,22 @@
 
 	if (history_curr ==
 	    dl_list_first(&history_list, struct edit_history, list)) {
-		cmdbuf[cmdbuf_len] = '\0';
-		history_add(cmdbuf);
+		if (!currbuf_valid) {
+			cmdbuf[cmdbuf_len] = '\0';
+			os_memcpy(currbuf, cmdbuf, cmdbuf_len + 1);
+			currbuf_valid = 1;
+			history_use();
+			return;
+		}
 	}
 
-	history_use();
-
 	if (history_curr ==
 	    dl_list_last(&history_list, struct edit_history, list))
 		return;
 
 	history_curr = dl_list_entry(history_curr->list.next,
 				     struct edit_history, list);
+	history_use();
 }
 
 
@@ -250,8 +256,16 @@
 {
 	if (history_curr == NULL ||
 	    history_curr ==
-	    dl_list_first(&history_list, struct edit_history, list))
+	    dl_list_first(&history_list, struct edit_history, list)) {
+		if (currbuf_valid) {
+			currbuf_valid = 0;
+			edit_clear_line();
+			cmdbuf_len = cmdbuf_pos = os_strlen(currbuf);
+			os_memcpy(cmdbuf, currbuf, cmdbuf_len);
+			edit_redraw();
+		}
 		return;
+	}
 
 	history_curr = dl_list_entry(history_curr->list.prev,
 				     struct edit_history, list);
@@ -309,6 +323,8 @@
 	printf("\r");
 	dl_list_for_each_reverse(h, &history_list, struct edit_history, list)
 		printf("%s%s\n", h == history_curr ? "[C]" : "", h->str);
+	if (currbuf_valid)
+		printf("{%s}\n", currbuf);
 	edit_redraw();
 }
 
@@ -1104,6 +1120,7 @@
 	      char ** (*completion_cb)(void *ctx, const char *cmd, int pos),
 	      void *ctx, const char *history_file)
 {
+	currbuf[0] = '\0';
 	dl_list_init(&history_list);
 	history_curr = NULL;
 	if (history_file)
diff --git a/src/utils/eloop.h b/src/utils/eloop.h
index 1228f24..a656bf8 100644
--- a/src/utils/eloop.h
+++ b/src/utils/eloop.h
@@ -144,7 +144,7 @@
  * Returns: 0 on success, -1 on failure
  *
  * Register an event handler for the given event. This function is used to
- * register eloop implementation specific events which are mainly targetted for
+ * register eloop implementation specific events which are mainly targeted for
  * operating system specific code (driver interface and l2_packet) since the
  * portable code will not be able to use such an OS-specific call. The handler
  * function will be called whenever the event is triggered. The handler
diff --git a/src/utils/includes.h b/src/utils/includes.h
index 63b5c23..cf2a42b 100644
--- a/src/utils/includes.h
+++ b/src/utils/includes.h
@@ -34,7 +34,6 @@
 #include <errno.h>
 #endif /* _WIN32_WCE */
 #include <ctype.h>
-#include <time.h>
 
 #ifndef CONFIG_TI_COMPILER
 #ifndef _MSC_VER
diff --git a/src/utils/list.h b/src/utils/list.h
index ded7846..c8dccee 100644
--- a/src/utils/list.h
+++ b/src/utils/list.h
@@ -95,4 +95,7 @@
 	     &item->member != (list); \
 	     item = dl_list_entry(item->member.prev, type, member))
 
+#define DEFINE_DL_LIST(name) \
+	struct dl_list name = { &(name), &(name) }
+
 #endif /* LIST_H */
diff --git a/src/utils/os.h b/src/utils/os.h
index f4723d8..f69478a 100644
--- a/src/utils/os.h
+++ b/src/utils/os.h
@@ -70,6 +70,16 @@
 int os_mktime(int year, int month, int day, int hour, int min, int sec,
 	      os_time_t *t);
 
+struct os_tm {
+	int sec; /* 0..59 or 60 for leap seconds */
+	int min; /* 0..59 */
+	int hour; /* 0..23 */
+	int day; /* 1..31 */
+	int month; /* 1..12 */
+	int year; /* Four digit year */
+};
+
+int os_gmtime(os_time_t t, struct os_tm *tm);
 
 /**
  * os_daemonize - Run in the background (detach from the controlling terminal)
diff --git a/src/utils/os_internal.c b/src/utils/os_internal.c
index 5260e23..8024a30 100644
--- a/src/utils/os_internal.c
+++ b/src/utils/os_internal.c
@@ -70,6 +70,24 @@
 }
 
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	struct tm *tm2;
+	time_t t2 = t;
+
+	tm2 = gmtime(&t2);
+	if (tm2 == NULL)
+		return -1;
+	tm->sec = tm2->tm_sec;
+	tm->min = tm2->tm_min;
+	tm->hour = tm2->tm_hour;
+	tm->day = tm2->tm_mday;
+	tm->month = tm2->tm_mon + 1;
+	tm->year = tm2->tm_year + 1900;
+	return 0;
+}
+
+
 int os_daemonize(const char *pid_file)
 {
 	if (daemon(0, 0)) {
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
index bab8f17..3fbb777 100644
--- a/src/utils/os_none.c
+++ b/src/utils/os_none.c
@@ -38,6 +38,11 @@
 	return -1;
 }
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	return -1;
+}
+
 
 int os_daemonize(const char *pid_file)
 {
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 4e11758..9b16b33 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -14,6 +14,8 @@
 
 #include "includes.h"
 
+#include <time.h>
+
 #ifdef ANDROID
 #include <linux/capability.h>
 #include <linux/prctl.h>
@@ -25,9 +27,9 @@
 #ifdef WPA_TRACE
 
 #include "common.h"
-#include "list.h"
 #include "wpa_debug.h"
 #include "trace.h"
+#include "list.h"
 
 static struct dl_list alloc_list;
 
@@ -104,6 +106,24 @@
 }
 
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	struct tm *tm2;
+	time_t t2 = t;
+
+	tm2 = gmtime(&t2);
+	if (tm2 == NULL)
+		return -1;
+	tm->sec = tm2->tm_sec;
+	tm->min = tm2->tm_min;
+	tm->hour = tm2->tm_hour;
+	tm->day = tm2->tm_mday;
+	tm->month = tm2->tm_mon + 1;
+	tm->year = tm2->tm_year + 1900;
+	return 0;
+}
+
+
 #ifdef __APPLE__
 #include <fcntl.h>
 static int os_daemon(int nochdir, int noclose)
diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c
index 0740964..51bd545 100644
--- a/src/utils/os_win32.c
+++ b/src/utils/os_win32.c
@@ -13,6 +13,7 @@
  */
 
 #include "includes.h"
+#include <time.h>
 #include <winsock2.h>
 #include <wincrypt.h>
 
@@ -92,6 +93,24 @@
 }
 
 
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	struct tm *tm2;
+	time_t t2 = t;
+
+	tm2 = gmtime(&t2);
+	if (tm2 == NULL)
+		return -1;
+	tm->sec = tm2->tm_sec;
+	tm->min = tm2->tm_min;
+	tm->hour = tm2->tm_hour;
+	tm->day = tm2->tm_mday;
+	tm->month = tm2->tm_mon + 1;
+	tm->year = tm2->tm_year + 1900;
+	return 0;
+}
+
+
 int os_daemonize(const char *pid_file)
 {
 	/* TODO */
diff --git a/src/utils/pcsc_funcs.c b/src/utils/pcsc_funcs.c
index bf9f04a..c36193e 100644
--- a/src/utils/pcsc_funcs.c
+++ b/src/utils/pcsc_funcs.c
@@ -812,7 +812,7 @@
 	wpa_hexdump(MSG_DEBUG, "SCARD: file length determination response",
 		    buf, blen);
 
-	if (blen < 2 || buf[0] != 0x6c) {
+	if (blen < 2 || (buf[0] != 0x6c && buf[0] != 0x67)) {
 		wpa_printf(MSG_DEBUG, "SCARD: unexpected response to file "
 			   "length determination");
 		return -1;
diff --git a/src/utils/radiotap.h b/src/utils/radiotap.h
index 508264c..137288f 100644
--- a/src/utils/radiotap.h
+++ b/src/utils/radiotap.h
@@ -238,5 +238,6 @@
 						 * retries */
 #define IEEE80211_RADIOTAP_F_TX_CTS	0x0002	/* used cts 'protection' */
 #define IEEE80211_RADIOTAP_F_TX_RTS	0x0004	/* used rts/cts handshake */
+#define IEEE80211_RADIOTAP_F_TX_NOACK	0x0008	/* don't expect an ACK */
 
 #endif				/* IEEE80211_RADIOTAP_H */
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index 0588fc6..5b56d83 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -34,7 +34,7 @@
 
 #ifndef ANDROID_LOG_NAME
 #define ANDROID_LOG_NAME	"wpa_supplicant"
-#endif
+#endif /* ANDROID_LOG_NAME */
 
 void android_printf(int level, char *format, ...)
 {
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index ae36afe..64ada57 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -136,7 +136,7 @@
 static inline void wpa_hexdump_buf_key(int level, const char *title,
 				       const struct wpabuf *buf)
 {
-	wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : 0,
+	wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL,
 			buf ? wpabuf_len(buf) : 0);
 }
 
diff --git a/src/wps/upnp_xml.c b/src/wps/upnp_xml.c
index b1b1e2b..a9958ee 100644
--- a/src/wps/upnp_xml.c
+++ b/src/wps/upnp_xml.c
@@ -75,8 +75,8 @@
  * Note that angle brackets present in the original data must have been encoded
  * as &lt; and &gt; so they will not trouble us.
  */
-static int xml_next_tag(const char *in, const char **out,
-			const char **out_tagname, const char **end)
+int xml_next_tag(const char *in, const char **out,
+		 const char **out_tagname, const char **end)
 {
 	while (*in && *in != '<')
 		in++;
diff --git a/src/wps/upnp_xml.h b/src/wps/upnp_xml.h
index 62dbe60..616af3d 100644
--- a/src/wps/upnp_xml.h
+++ b/src/wps/upnp_xml.h
@@ -16,6 +16,8 @@
 void xml_data_encode(struct wpabuf *buf, const char *data, int len);
 void xml_add_tagged_data(struct wpabuf *buf, const char *tag,
 			 const char *data);
+int xml_next_tag(const char *in, const char **out,
+		 const char **out_tagname, const char **end);
 char * xml_get_first_item(const char *doc, const char *item);
 struct wpabuf * xml_get_base64_item(const char *data, const char *name,
 				    enum http_reply_code *ret);
diff --git a/src/wps/wps.c b/src/wps/wps.c
index 5c8c25f..2ba3d4b 100644
--- a/src/wps/wps.c
+++ b/src/wps/wps.c
@@ -67,12 +67,11 @@
 		/* Use special PIN '00000000' for PBC */
 		data->dev_pw_id = DEV_PW_PUSHBUTTON;
 		os_free(data->dev_password);
-		data->dev_password = os_malloc(8);
+		data->dev_password = (u8 *) os_strdup("00000000");
 		if (data->dev_password == NULL) {
 			os_free(data);
 			return NULL;
 		}
-		os_memset(data->dev_password, '0', 8);
 		data->dev_password_len = 8;
 	}
 
@@ -355,6 +354,19 @@
 
 
 /**
+ * wps_is_20 - Check whether WPS attributes claim support for WPS 2.0
+ */
+int wps_is_20(const struct wpabuf *msg)
+{
+	struct wps_parse_attr attr;
+
+	if (msg == NULL || wps_parse_msg(msg, &attr) < 0)
+		return 0;
+	return attr.version2 != NULL;
+}
+
+
+/**
  * wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
  * @req_type: Value for Request Type attribute
  * Returns: WPS IE or %NULL on failure
@@ -443,7 +455,6 @@
 				       const u8 *req_dev_types)
 {
 	struct wpabuf *ie;
-	u16 methods = 0;
 
 	wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request");
 
@@ -451,35 +462,9 @@
 	if (ie == NULL)
 		return NULL;
 
-	methods |= WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
-	/*
-	 * TODO: Should figure out whether this device has a physical or
-	 * virtual pushbutton.
-	 */
-	methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
-#endif /* CONFIG_WPS2 */
-
-	/*
-	 * TODO: Should figure out whether this Probe Request was triggered
-	 * using physical or virtual display. Also, if the device has a PIN on
-	 * a label, that should be indicated here.
-	 */
-	methods |= WPS_CONFIG_DISPLAY |
-#ifdef CONFIG_WPS2
-		WPS_CONFIG_VIRT_DISPLAY |
-#endif /* CONFIG_WPS2 */
-		WPS_CONFIG_KEYPAD;
-#ifdef CONFIG_WPS_UFD
-	methods |= WPS_CONFIG_USBA;
-#endif /* CONFIG_WPS_UFD */
-#ifdef CONFIG_WPS_NFC
-	methods |= WPS_CONFIG_NFC_INTERFACE;
-#endif /* CONFIG_WPS_NFC */
-
 	if (wps_build_version(ie) ||
 	    wps_build_req_type(ie, req_type) ||
-	    wps_build_config_methods(ie, methods) ||
+	    wps_build_config_methods(ie, dev->config_methods) ||
 	    wps_build_uuid_e(ie, uuid) ||
 	    wps_build_primary_dev_type(dev, ie) ||
 	    wps_build_rf_bands(dev, ie) ||
diff --git a/src/wps/wps.h b/src/wps/wps.h
index 3e4c218..4986881 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -99,6 +99,7 @@
 	u8 num_sec_dev_types;
 	u32 os_version;
 	u8 rf_bands;
+	u16 config_methods;
 	struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
 
 	int p2p;
@@ -239,6 +240,7 @@
 int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
 			   int ver1_compat);
 const u8 * wps_get_uuid_e(const struct wpabuf *msg);
+int wps_is_20(const struct wpabuf *msg);
 
 struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
 struct wpabuf * wps_build_assoc_resp_ie(void);
@@ -782,6 +784,7 @@
 int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
 int wps_registrar_button_pushed(struct wps_registrar *reg,
 				const u8 *p2p_dev_addr);
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e);
 void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
 				const struct wpabuf *wps_data,
 				int p2p_wildcard);
@@ -791,6 +794,9 @@
 int wps_registrar_config_ap(struct wps_registrar *reg,
 			    struct wps_credential *cred);
 
+int wps_build_credential_wrap(struct wpabuf *msg,
+			      const struct wps_credential *cred);
+
 unsigned int wps_pin_checksum(unsigned int pin);
 unsigned int wps_pin_valid(unsigned int pin);
 unsigned int wps_generate_pin(void);
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index 7b462d3..55b5573 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
@@ -557,7 +557,9 @@
 {
 	const u8 *pos, *end;
 	u16 type, len;
+#ifdef WPS_WORKAROUNDS
 	u16 prev_type = 0;
+#endif /* WPS_WORKAROUNDS */
 
 	os_memset(attr, 0, sizeof(*attr));
 	pos = wpabuf_head(msg);
@@ -622,7 +624,9 @@
 		if (wps_set_attr(attr, type, pos, len) < 0)
 			return -1;
 
+#ifdef WPS_WORKAROUNDS
 		prev_type = type;
+#endif /* WPS_WORKAROUNDS */
 		pos += len;
 	}
 
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 5d0508c..505837b 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -22,7 +22,6 @@
 #include "crypto/sha256.h"
 #include "crypto/random.h"
 #include "wps_i.h"
-#include "wps_dev_attr.h"
 
 
 void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 5b3c045..0fbaa3f 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -967,7 +967,7 @@
 		return WPS_CONTINUE;
 	}
 
-	if (wps_validate_m4_encr(decrypted, attr->version2 != 0) < 0) {
+	if (wps_validate_m4_encr(decrypted, attr->version2 != NULL) < 0) {
 		wpabuf_free(decrypted);
 		wps->state = SEND_WSC_NACK;
 		return WPS_CONTINUE;
@@ -1020,7 +1020,7 @@
 		return WPS_CONTINUE;
 	}
 
-	if (wps_validate_m6_encr(decrypted, attr->version2 != 0) < 0) {
+	if (wps_validate_m6_encr(decrypted, attr->version2 != NULL) < 0) {
 		wpabuf_free(decrypted);
 		wps->state = SEND_WSC_NACK;
 		return WPS_CONTINUE;
@@ -1086,8 +1086,8 @@
 		return WPS_CONTINUE;
 	}
 
-	if (wps_validate_m8_encr(decrypted, wps->wps->ap, attr->version2 != 0)
-	    < 0) {
+	if (wps_validate_m8_encr(decrypted, wps->wps->ap,
+				 attr->version2 != NULL) < 0) {
 		wpabuf_free(decrypted);
 		wps->state = SEND_WSC_NACK;
 		return WPS_CONTINUE;
diff --git a/src/wps/wps_er.c b/src/wps/wps_er.c
index a461836..856e9fb 100644
--- a/src/wps/wps_er.c
+++ b/src/wps/wps_er.c
@@ -502,16 +502,61 @@
 }
 
 
+static const char * wps_er_find_wfadevice(const char *data)
+{
+	const char *tag, *tagname, *end;
+	char *val;
+	int found = 0;
+
+	while (!found) {
+		/* Find next <device> */
+		for (;;) {
+			if (xml_next_tag(data, &tag, &tagname, &end))
+				return NULL;
+			data = end;
+			if (!os_strncasecmp(tagname, "device", 6) &&
+			    *tag != '/' &&
+			    (tagname[6] == '>' || !isgraph(tagname[6]))) {
+				break;
+			}
+		}
+
+		/* Check whether deviceType is WFADevice */
+		val = xml_get_first_item(data, "deviceType");
+		if (val == NULL)
+			return NULL;
+		wpa_printf(MSG_DEBUG, "WPS ER: Found deviceType '%s'", val);
+		found = os_strcasecmp(val, "urn:schemas-wifialliance-org:"
+				      "device:WFADevice:1") == 0;
+		os_free(val);
+	}
+
+	return data;
+}
+
+
 static void wps_er_parse_device_description(struct wps_er_ap *ap,
 					    struct wpabuf *reply)
 {
 	/* Note: reply includes null termination after the buffer data */
-	const char *data = wpabuf_head(reply);
+	const char *tmp, *data = wpabuf_head(reply);
 	char *pos;
 
 	wpa_hexdump_ascii(MSG_MSGDUMP, "WPS ER: Device info",
 			  wpabuf_head(reply), wpabuf_len(reply));
 
+	/*
+	 * The root device description may include multiple devices, so first
+	 * find the beginning of the WFADevice description to allow the
+	 * simplistic parser to pick the correct entries.
+	 */
+	tmp = wps_er_find_wfadevice(data);
+	if (tmp == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS ER: WFADevice:1 device not found - "
+			   "trying to parse invalid data");
+	} else
+		data = tmp;
+
 	ap->friendly_name = xml_get_first_item(data, "friendlyName");
 	wpa_printf(MSG_DEBUG, "WPS ER: friendlyName='%s'", ap->friendly_name);
 
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index 65ff40d..eda1c70 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -310,13 +310,17 @@
 
 
 static void wps_registrar_remove_pbc_session(struct wps_registrar *reg,
-					     const u8 *uuid_e)
+					     const u8 *uuid_e,
+					     const u8 *p2p_dev_addr)
 {
 	struct wps_pbc_session *pbc, *prev = NULL, *tmp;
 
 	pbc = reg->pbc_sessions;
 	while (pbc) {
-		if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0) {
+		if (os_memcmp(pbc->uuid_e, uuid_e, WPS_UUID_LEN) == 0 ||
+		    (p2p_dev_addr && !is_zero_ether_addr(reg->p2p_dev_addr) &&
+		     os_memcmp(reg->p2p_dev_addr, p2p_dev_addr, ETH_ALEN) ==
+		     0)) {
 			if (prev)
 				prev->next = pbc->next;
 			else
@@ -485,10 +489,8 @@
 		*methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
 	if (conf_methods & WPS_CONFIG_PHY_PUSHBUTTON)
 		*methods |= WPS_CONFIG_PHY_PUSHBUTTON;
-	if ((*methods & WPS_CONFIG_VIRT_PUSHBUTTON) !=
-	    WPS_CONFIG_VIRT_PUSHBUTTON ||
-	    (*methods & WPS_CONFIG_PHY_PUSHBUTTON) !=
-	    WPS_CONFIG_PHY_PUSHBUTTON) {
+	if (!(*methods & (WPS_CONFIG_VIRT_PUSHBUTTON |
+			  WPS_CONFIG_PHY_PUSHBUTTON))) {
 		/*
 		 * Required to include virtual/physical flag, but we were not
 		 * configured with push button type, so have to default to one
@@ -549,15 +551,7 @@
 static int wps_build_config_methods_r(struct wps_registrar *reg,
 				      struct wpabuf *msg)
 {
-	u16 methods;
-	methods = reg->wps->config_methods & ~WPS_CONFIG_PUSHBUTTON;
-#ifdef CONFIG_WPS2
-	methods &= ~(WPS_CONFIG_VIRT_PUSHBUTTON |
-		     WPS_CONFIG_PHY_PUSHBUTTON);
-#endif /* CONFIG_WPS2 */
-	if (reg->pbc)
-		wps_set_pushbutton(&methods, reg->wps->config_methods);
-	return wps_build_config_methods(msg, methods);
+	return wps_build_config_methods(msg, reg->wps->config_methods);
 }
 
 
@@ -901,8 +895,8 @@
  * PBC mode. The PBC mode will be stopped after walk time (2 minutes) timeout
  * or when a PBC registration is completed. If more than one Enrollee in active
  * PBC mode has been detected during the monitor time (previous 2 minutes), the
- * PBC mode is not actived and -2 is returned to indicate session overlap. This
- * is skipped if a specific Enrollee is selected.
+ * PBC mode is not activated and -2 is returned to indicate session overlap.
+ * This is skipped if a specific Enrollee is selected.
  */
 int wps_registrar_button_pushed(struct wps_registrar *reg,
 				const u8 *p2p_dev_addr)
@@ -951,6 +945,18 @@
 }
 
 
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e)
+{
+	if (registrar->pbc) {
+		wps_registrar_remove_pbc_session(registrar,
+						 uuid_e, NULL);
+		wps_registrar_pbc_completed(registrar);
+	} else {
+		wps_registrar_pin_completed(registrar);
+	}
+}
+
+
 int wps_registrar_wps_cancel(struct wps_registrar *reg)
 {
 	if (reg->pbc) {
@@ -1420,6 +1426,25 @@
 }
 
 
+int wps_build_credential_wrap(struct wpabuf *msg,
+			      const struct wps_credential *cred)
+{
+	struct wpabuf *wbuf;
+	wbuf = wpabuf_alloc(200);
+	if (wbuf == NULL)
+		return -1;
+	if (wps_build_credential(wbuf, cred)) {
+		wpabuf_free(wbuf);
+		return -1;
+	}
+	wpabuf_put_be16(msg, ATTR_CRED);
+	wpabuf_put_be16(msg, wpabuf_len(wbuf));
+	wpabuf_put_buf(msg, wbuf);
+	wpabuf_free(wbuf);
+	return 0;
+}
+
+
 int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
 {
 	struct wpabuf *cred;
@@ -1593,6 +1618,35 @@
 }
 
 
+static struct wpabuf * wps_build_ap_cred(struct wps_data *wps)
+{
+	struct wpabuf *msg, *plain;
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return NULL;
+
+	plain = wpabuf_alloc(200);
+	if (plain == NULL) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	if (wps_build_ap_settings(wps, plain)) {
+		wpabuf_free(plain);
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	wpabuf_put_be16(msg, ATTR_CRED);
+	wpabuf_put_be16(msg, wpabuf_len(plain));
+	wpabuf_put_buf(msg, plain);
+	wpabuf_free(plain);
+
+	return msg;
+}
+
+
 static struct wpabuf * wps_build_m2(struct wps_data *wps)
 {
 	struct wpabuf *msg;
@@ -2551,6 +2605,8 @@
 static int wps_process_ap_settings_r(struct wps_data *wps,
 				     struct wps_parse_attr *attr)
 {
+	struct wpabuf *msg;
+
 	if (wps->wps->ap || wps->er)
 		return 0;
 
@@ -2577,12 +2633,24 @@
 		 */
 		wps_registrar_pin_completed(wps->wps->registrar);
 
+		msg = wps_build_ap_cred(wps);
+		if (msg == NULL)
+			return -1;
+		wps->cred.cred_attr = wpabuf_head(msg);
+		wps->cred.cred_attr_len = wpabuf_len(msg);
+
 		if (wps->ap_settings_cb) {
 			wps->ap_settings_cb(wps->ap_settings_cb_ctx,
 					    &wps->cred);
+			wpabuf_free(msg);
 			return 1;
 		}
 		wps_sta_cred_cb(wps);
+
+		wps->cred.cred_attr = NULL;
+		wps->cred.cred_attr_len = 0;
+		wpabuf_free(msg);
+
 		return 1;
 	}
 }
@@ -2983,7 +3051,8 @@
 
 	if (wps->pbc) {
 		wps_registrar_remove_pbc_session(wps->wps->registrar,
-						 wps->uuid_e);
+						 wps->uuid_e,
+						 wps->p2p_dev_addr);
 		wps_registrar_pbc_completed(wps->wps->registrar);
 	} else {
 		wps_registrar_pin_completed(wps->wps->registrar);
diff --git a/src/wps/wps_ufd.c b/src/wps/wps_ufd.c
index 1a911e1..61f6553 100644
--- a/src/wps/wps_ufd.c
+++ b/src/wps/wps_ufd.c
@@ -16,7 +16,6 @@
 #include "common.h"
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 #include <fcntl.h>
 #include <dirent.h>
 
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 763dcaf..06dcd20 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -47,7 +47,7 @@
  * -- Needs renaming with module prefix to avoid polluting the debugger
  * namespace and causing possible collisions with other static fncs
  * and structure declarations when using the debugger.
- * -- The http error code generation is pretty bogus, hopefully noone cares.
+ * -- The http error code generation is pretty bogus, hopefully no one cares.
  *
  * Author: Ted Merrill, Atheros Communications, based upon earlier work
  * as explained above and below.
@@ -172,7 +172,7 @@
 
 #include "includes.h"
 
-#include <assert.h>
+#include <time.h>
 #include <net/if.h>
 #include <netdb.h>
 #include <sys/ioctl.h>
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index c7fb158..4c4aebf 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -97,16 +97,6 @@
 }
 
 
-/* No. of chars excluding trailing whitespace */
-static int line_length_stripped(const char *l)
-{
-	const char *lp = l + line_length(l);
-	while (lp > l && !isgraph(lp[-1]))
-		lp--;
-	return lp - l;
-}
-
-
 static int str_starts(const char *str, const char *start)
 {
 	return os_strncmp(str, start, os_strlen(start)) == 0;
@@ -530,7 +520,6 @@
 #ifndef CONFIG_NO_STDOUT_DEBUG
 	const char *start = data;
 #endif /* CONFIG_NO_STDOUT_DEBUG */
-	const char *end;
 	int got_host = 0;
 	int got_st = 0, st_match = 0;
 	int got_man = 0;
@@ -545,7 +534,6 @@
 
 	/* Parse remaining lines */
 	for (; *data != '\0'; data += line_length(data)) {
-		end = data + line_length_stripped(data);
 		if (token_eq(data, "host")) {
 			/* The host line indicates who the packet
 			 * is addressed to... but do we really care?
diff --git a/src/wps/wps_upnp_web.c b/src/wps/wps_upnp_web.c
index 917f60b..ce0bede 100644
--- a/src/wps/wps_upnp_web.c
+++ b/src/wps/wps_upnp_web.c
@@ -956,7 +956,7 @@
 			break; /* no unterminated lines allowed */
 
 		/* NT assures that it is our type of subscription;
-		 * not used for a renewl.
+		 * not used for a renewal.
 		 **/
 		match = "NT:";
 		match_len = os_strlen(match);
diff --git a/wpa_supplicant/.config b/wpa_supplicant/.config
index 14e509f..29f4dbe 100644
--- a/wpa_supplicant/.config
+++ b/wpa_supplicant/.config
@@ -398,5 +398,7 @@
 #CONFIG_DELAYED_MIC_ERROR_REPORT=y
 
 # Enable P2P
+# IEEE 802.11n (High Throughput) support (mainly for AP mode)
+CONFIG_IEEE80211N=y
 CONFIG_P2P=y
 CONFIG_AP=y
diff --git a/wpa_supplicant/.gitignore b/wpa_supplicant/.gitignore
new file mode 100644
index 0000000..0e3ad1b
--- /dev/null
+++ b/wpa_supplicant/.gitignore
@@ -0,0 +1 @@
+*.service
diff --git a/wpa_supplicant/Android.mk b/wpa_supplicant/Android.mk
index f1ef67f..ac92248 100644
--- a/wpa_supplicant/Android.mk
+++ b/wpa_supplicant/Android.mk
@@ -31,19 +31,10 @@
 # To ignore possible wrong network configurations
 L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
 
-L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\"
-
+L_CFLAGS += -DANDROID_P2P
 # Set Android log name
 L_CFLAGS += -DANDROID_LOG_NAME=\"wpa_supplicant\"
 
-ifeq ($(BOARD_WLAN_DEVICE), bcmdhd)
-L_CFLAGS += -DANDROID_BRCM_P2P_PATCH
-endif
-
-ifdef CONFIG_ROAMING
-L_CFLAGS += -DCONFIG_ROAMING
-endif
-
 # Use Android specific directory for control interface sockets
 L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
 L_CFLAGS += -DCONFIG_CTRL_IFACE_DIR=\"/data/system/wpa_supplicant\"
@@ -94,6 +85,7 @@
 OBJS_p += src/utils/wpabuf.c
 OBJS_c = wpa_cli.c src/common/wpa_ctrl.c
 OBJS_c += src/utils/wpa_debug.c
+OBJS_c += src/utils/common.c
 OBJS_d =
 OBJS_priv =
 
@@ -187,11 +179,15 @@
 
 ifdef CONFIG_TDLS
 L_CFLAGS += -DCONFIG_TDLS
-OBJS += src/rsn_supp/tdls.o
+OBJS += src/rsn_supp/tdls.c
 NEED_SHA256=y
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_TDLS_TESTING
+L_CFLAGS += -DCONFIG_TDLS_TESTING
+endif
+
 ifdef CONFIG_PEERKEY
 L_CFLAGS += -DCONFIG_PEERKEY
 endif
@@ -231,12 +227,22 @@
 OBJS += src/p2p/p2p_group.c
 OBJS += src/ap/p2p_hostapd.c
 L_CFLAGS += -DCONFIG_P2P
+NEED_GAS=y
+NEED_OFFCHANNEL=y
 NEED_80211_COMMON=y
+CONFIG_WPS=y
+CONFIG_AP=y
 ifdef CONFIG_P2P_STRICT
 L_CFLAGS += -DCONFIG_P2P_STRICT
 endif
 endif
 
+ifdef CONFIG_INTERWORKING
+OBJS += interworking.c
+L_CFLAGS += -DCONFIG_INTERWORKING
+NEED_GAS=y
+endif
+
 ifdef CONFIG_NO_WPA2
 L_CFLAGS += -DCONFIG_NO_WPA2
 endif
@@ -701,8 +707,10 @@
 OBJS += src/ap/ieee802_1x.c
 OBJS += src/eapol_auth/eapol_auth_sm.c
 OBJS += src/ap/ieee802_11_auth.c
+OBJS += src/ap/ieee802_11_shared.c
 OBJS += src/ap/drv_callbacks.c
 OBJS += src/ap/ap_drv_ops.c
+OBJS += src/ap/beacon.c
 ifdef CONFIG_IEEE80211N
 OBJS += src/ap/ieee802_11_ht.c
 endif
@@ -720,7 +728,6 @@
 endif
 
 ifdef NEED_AP_MLME
-OBJS += src/ap/beacon.c
 OBJS += src/ap/wmm.c
 OBJS += src/ap/ap_list.c
 OBJS += src/ap/ieee802_11.c
@@ -804,6 +811,7 @@
 
 ifdef NEED_MILENAGE
 OBJS += src/crypto/milenage.c
+NEED_AES_ENCBLOCK=y
 endif
 
 ifdef CONFIG_PKCS12
@@ -836,6 +844,10 @@
 CONFIG_TLS=openssl
 endif
 
+ifdef CONFIG_TLSV11
+L_CFLAGS += -DCONFIG_TLSV11
+endif
+
 ifeq ($(CONFIG_TLS), openssl)
 ifdef TLS_FUNCS
 L_CFLAGS += -DEAP_TLS_OPENSSL
@@ -855,10 +867,6 @@
 ifdef TLS_FUNCS
 OBJS += src/crypto/tls_gnutls.c
 LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-L_CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
 endif
 OBJS += src/crypto/crypto_gnutls.c
 OBJS_p += src/crypto/crypto_gnutls.c
@@ -1259,12 +1267,6 @@
 L_CFLAGS += -DCONFIG_SME
 endif
 
-ifdef CONFIG_CLIENT_MLME
-OBJS += mlme.c
-L_CFLAGS += -DCONFIG_CLIENT_MLME
-NEED_80211_COMMON=y
-endif
-
 ifdef NEED_80211_COMMON
 OBJS += src/common/ieee802_11_common.c
 endif
@@ -1317,7 +1319,21 @@
 OBJS += bgscan.c
 endif
 
-OBJS_wpa_rm := ctrl_iface.c mlme.c ctrl_iface_unix.c
+ifdef NEED_GAS
+OBJS += ../src/common/gas.c
+OBJS += gas_query.c
+L_CFLAGS += -DCONFIG_GAS
+NEED_OFFCHANNEL=y
+endif
+
+ifdef NEED_OFFCHANNEL
+OBJS += offchannel.c
+L_CFLAGS += -DCONFIG_OFFCHANNEL
+endif
+
+OBJS += src/drivers/driver_common.c
+
+OBJS_wpa_rm := ctrl_iface.c ctrl_iface_unix.c
 OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.c
 ifdef CONFIG_AUTHENTICATOR
 OBJS_wpa += tests/link_test.c
@@ -1405,7 +1421,10 @@
 ifneq ($(BOARD_WPA_SUPPLICANT_PRIVATE_LIB),)
 LOCAL_STATIC_LIBRARIES += $(BOARD_WPA_SUPPLICANT_PRIVATE_LIB)
 endif
-LOCAL_SHARED_LIBRARIES := libc libcutils libcrypto libssl
+LOCAL_SHARED_LIBRARIES := libc libcutils
+ifeq ($(CONFIG_TLS), openssl)
+LOCAL_SHARED_LIBRARIES += libcrypto libssl
+endif
 ifdef CONFIG_DRIVER_NL80211
 LOCAL_STATIC_LIBRARIES += libnl_2
 endif
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 3536084..0832f10 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -21,6 +21,14 @@
 ALL += wpa_passphrase
 endif
 
+ALL += systemd/wpa_supplicant.service
+ALL += systemd/wpa_supplicant@.service
+ALL += systemd/wpa_supplicant-nl80211@.service
+ALL += systemd/wpa_supplicant-wired@.service
+ALL += dbus/fi.epitest.hostap.WPASupplicant.service
+ALL += dbus/fi.w1.wpa_supplicant1.service
+
+
 all: verify_config $(ALL) dynamic_eap_methods
 
 verify_config:
@@ -58,6 +66,7 @@
 OBJS_p += ../src/utils/wpabuf.o
 OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
 OBJS_c += ../src/utils/wpa_debug.o
+OBJS_c += ../src/utils/common.o
 
 ifndef CONFIG_OS
 ifdef CONFIG_NATIVE_WINDOWS
@@ -80,6 +89,7 @@
 OBJS += ../src/utils/trace.o
 OBJS_p += ../src/utils/trace.o
 OBJS_c += ../src/utils/trace.o
+OBJS_priv += ../src/utils/trace.o
 LDFLAGS += -rdynamic
 CFLAGS += -funwind-tables
 ifdef CONFIG_WPA_TRACE_BFD
@@ -154,6 +164,10 @@
 NEED_AES_OMAC1=y
 endif
 
+ifdef CONFIG_TDLS_TESTING
+CFLAGS += -DCONFIG_TDLS_TESTING
+endif
+
 ifdef CONFIG_PEERKEY
 CFLAGS += -DCONFIG_PEERKEY
 endif
@@ -193,12 +207,22 @@
 OBJS += ../src/p2p/p2p_group.o
 OBJS += ../src/ap/p2p_hostapd.o
 CFLAGS += -DCONFIG_P2P
+NEED_GAS=y
+NEED_OFFCHANNEL=y
 NEED_80211_COMMON=y
+CONFIG_WPS=y
+CONFIG_AP=y
 ifdef CONFIG_P2P_STRICT
 CFLAGS += -DCONFIG_P2P_STRICT
 endif
 endif
 
+ifdef CONFIG_INTERWORKING
+OBJS += interworking.o
+CFLAGS += -DCONFIG_INTERWORKING
+NEED_GAS=y
+endif
+
 ifdef CONFIG_NO_WPA2
 CFLAGS += -DCONFIG_NO_WPA2
 endif
@@ -662,8 +686,10 @@
 OBJS += ../src/ap/ieee802_1x.o
 OBJS += ../src/eapol_auth/eapol_auth_sm.o
 OBJS += ../src/ap/ieee802_11_auth.o
+OBJS += ../src/ap/ieee802_11_shared.o
 OBJS += ../src/ap/drv_callbacks.o
 OBJS += ../src/ap/ap_drv_ops.o
+OBJS += ../src/ap/beacon.o
 ifdef CONFIG_IEEE80211N
 OBJS += ../src/ap/ieee802_11_ht.o
 endif
@@ -681,7 +707,6 @@
 endif
 
 ifdef NEED_AP_MLME
-OBJS += ../src/ap/beacon.o
 OBJS += ../src/ap/wmm.o
 OBJS += ../src/ap/ap_list.o
 OBJS += ../src/ap/ieee802_11.o
@@ -765,6 +790,7 @@
 
 ifdef NEED_MILENAGE
 OBJS += ../src/crypto/milenage.o
+NEED_AES_ENCBLOCK=y
 endif
 
 ifdef CONFIG_PKCS12
@@ -797,6 +823,15 @@
 CONFIG_TLS=openssl
 endif
 
+ifdef CONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
 ifeq ($(CONFIG_TLS), openssl)
 ifdef TLS_FUNCS
 CFLAGS += -DEAP_TLS_OPENSSL
@@ -816,10 +851,6 @@
 ifdef TLS_FUNCS
 OBJS += ../src/crypto/tls_gnutls.o
 LIBS += -lgnutls -lgpg-error
-ifdef CONFIG_GNUTLS_EXTRA
-CFLAGS += -DCONFIG_GNUTLS_EXTRA
-LIBS += -lgnutls-extra
-endif
 endif
 OBJS += ../src/crypto/crypto_gnutls.o
 OBJS_p += ../src/crypto/crypto_gnutls.o
@@ -885,6 +916,9 @@
 NEED_SHA256=y
 NEED_BASE64=y
 NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
 NEED_MODEXP=y
 NEED_CIPHER=y
 CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
@@ -1068,6 +1102,9 @@
 ifdef CONFIG_INTERNAL_SHA256
 SHA256OBJS += ../src/crypto/sha256-internal.o
 endif
+ifdef NEED_TLS_PRF_SHA256
+SHA256OBJS += ../src/crypto/sha256-tlsprf.o
+endif
 OBJS += $(SHA256OBJS)
 endif
 
@@ -1215,12 +1252,6 @@
 CFLAGS += -DCONFIG_SME
 endif
 
-ifdef CONFIG_CLIENT_MLME
-OBJS += mlme.o
-CFLAGS += -DCONFIG_CLIENT_MLME
-NEED_80211_COMMON=y
-endif
-
 ifdef NEED_80211_COMMON
 OBJS += ../src/common/ieee802_11_common.o
 endif
@@ -1255,6 +1286,7 @@
 OBJS += $(SHA1OBJS) $(DESOBJS)
 
 OBJS_p += $(SHA1OBJS)
+OBJS_p += $(SHA256OBJS)
 
 ifdef CONFIG_BGSCAN_SIMPLE
 CFLAGS += -DCONFIG_BGSCAN_SIMPLE
@@ -1273,7 +1305,21 @@
 OBJS += bgscan.o
 endif
 
-OBJS_wpa_rm := ctrl_iface.o mlme.o ctrl_iface_unix.o
+ifdef NEED_GAS
+OBJS += ../src/common/gas.o
+OBJS += gas_query.o
+CFLAGS += -DCONFIG_GAS
+NEED_OFFCHANNEL=y
+endif
+
+ifdef NEED_OFFCHANNEL
+OBJS += offchannel.o
+CFLAGS += -DCONFIG_OFFCHANNEL
+endif
+
+OBJS += ../src/drivers/driver_common.o
+
+OBJS_wpa_rm := ctrl_iface.o ctrl_iface_unix.o
 OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o
 ifdef CONFIG_AUTHENTICATOR
 OBJS_wpa += tests/link_test.o
@@ -1298,6 +1344,9 @@
 OBJS_priv += ../src/utils/wpa_debug.o
 OBJS_priv += ../src/utils/wpabuf.o
 OBJS_priv += wpa_priv.o
+ifdef CONFIG_DRIVER_NL80211
+OBJS_priv += ../src/common/ieee802_11_common.o
+endif
 ifdef CONFIG_DRIVER_TEST
 OBJS_priv += $(SHA1OBJS)
 OBJS_priv += $(MD5OBJS)
@@ -1362,15 +1411,17 @@
 	$(Q)$(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
 	@$(E) "  LD " $@
 
-wpa_supplicant: .config $(BCHECK) $(OBJS) $(EXTRA_progs)
+$(OBJS_c) $(OBJS_t) $(OBJS_t2) $(OBJS) $(BCHECK) $(EXTRA_progs): .config
+
+wpa_supplicant: $(BCHECK) $(OBJS) $(EXTRA_progs)
 	$(Q)$(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
 	@$(E) "  LD " $@
 
-eapol_test: .config $(OBJS_t)
+eapol_test: $(OBJS_t)
 	$(Q)$(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
 	@$(E) "  LD " $@
 
-preauth_test: .config $(OBJS_t2) 
+preauth_test: $(OBJS_t2)
 	$(Q)$(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
 	@$(E) "  LD " $@
 
@@ -1422,6 +1473,9 @@
 	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
 	@$(E) "  CC " $<
 
+%.service: %.service.in
+	sed -e 's|\@BINDIR\@|$(BINDIR)|g' $< >$@
+
 wpa_supplicant.exe: wpa_supplicant
 	mv -f $< $@
 wpa_cli.exe: wpa_cli
@@ -1438,11 +1492,8 @@
 windows-bin: $(WINALL)
 	$(STRIP) $(WINALL)
 
-wpa_gui/Makefile:
-	qmake -o wpa_gui/Makefile wpa_gui/wpa_gui.pro 
-
-wpa_gui: wpa_gui/Makefile
-	$(MAKE) -C wpa_gui
+wpa_gui:
+	@echo "wpa_gui has been removed - see wpa_gui-qt4 for replacement"
 
 wpa_gui-qt4/Makefile:
 	qmake -o wpa_gui-qt4/Makefile wpa_gui-qt4/wpa_gui.pro 
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 506a907..4d02f8f 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -138,39 +138,6 @@
 	default option to start with before falling back to driver specific
 	interface.
 
-	Host AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)
-	(http://hostap.epitest.fi/)
-	Driver need to be set in Managed mode ('iwconfig wlan0 mode managed').
-	Please note that station firmware version needs to be 1.7.0 or newer
-	to work in WPA mode.
-
-	Linuxant DriverLoader (http://www.linuxant.com/driverloader/)
-	with Windows NDIS driver for your wlan card supporting WPA.
-
-	madwifi driver for cards based on Atheros chip set (ar521x)
-	(http://sourceforge.net/projects/madwifi/)
-	Please note that you will need to modify the wpa_supplicant .config
-	file to use the correct path for the madwifi driver root directory
-	(CFLAGS += -I../madwifi/wpa line in example defconfig).
-
-	Linux ndiswrapper (http://ndiswrapper.sourceforge.net/) with
-	Windows NDIS driver.
-
-	Broadcom wl.o driver (old version only)
-	This is a generic Linux driver for Broadcom IEEE 802.11a/g cards.
-	However, it is proprietary driver that is not publicly available
-	except for couple of exceptions, mainly Broadcom-based APs/wireless
-	routers that use Linux. The driver binary can be downloaded, e.g.,
-	from Linksys support site (http://www.linksys.com/support/gpl.asp)
-	for Linksys WRT54G. The GPL tarball includes cross-compiler and
-	the needed header file, wlioctl.h, for compiling wpa_supplicant.
-	This driver support in wpa_supplicant is expected to work also with
-	other devices based on Broadcom driver (assuming the driver includes
-	client mode support). Please note that the newer Broadcom driver
-	("hybrid Linux driver") supports Linux wireless extensions and does
-	not need (or even work) with the specific driver wrapper. Use -Dwext
-	with that driver.
-
 	In theory, any driver that supports Linux wireless extensions can be
 	used with IEEE 802.1X (i.e., not WPA) when using ap_scan=0 option in
 	configuration file.
@@ -347,7 +314,7 @@
 The build time configuration can be used to select only the needed
 features and limit the binary size and requirements for external
 libraries. The main configuration parts are the selection of which
-driver interfaces (e.g., hostap, madwifi, ..) and which authentication
+driver interfaces (e.g., nl80211, wext, ..) and which authentication
 methods (e.g., EAP-TLS, EAP-PEAP, ..) are included.
 
 Following build time configuration options are used to control IEEE
@@ -382,21 +349,16 @@
 Following options can be added to .config to select which driver
 interfaces are included.
 
-CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_MADWIFI=y
+CONFIG_DRIVER_NL80211=y
 CONFIG_DRIVER_WEXT=y
-CONFIG_DRIVER_RALINK=y
-CONFIG_DRIVER_BROADCOM=y
 CONFIG_DRIVER_BSD=y
 CONFIG_DRIVER_NDIS=y
 
-Following example includes all features and driver interfaces that are
-included in the wpa_supplicant package:
+Following example includes some more features and driver interfaces that
+are included in the wpa_supplicant package:
 
-CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_MADWIFI=y
+CONFIG_DRIVER_NL80211=y
 CONFIG_DRIVER_WEXT=y
-CONFIG_DRIVER_BROADCOM=y
 CONFIG_DRIVER_BSD=y
 CONFIG_DRIVER_NDIS=y
 CONFIG_IEEE8021X_EAPOL=y
@@ -489,12 +451,7 @@
   -N = start describing new interface
 
 drivers:
-  hostap = Host AP driver (Intersil Prism2/2.5/3) [default]
-	(this can also be used with Linuxant DriverLoader)
-  madwifi = MADWIFI 802.11 support (Atheros, etc.) (deprecated; use wext)
   wext = Linux wireless extensions (generic)
-  ralink = Ralink Client driver
-  broadcom = Broadcom wl.o driver
   wired = wpa_supplicant wired Ethernet driver
   roboswitch = wpa_supplicant Broadcom switch driver
   bsd = BSD 802.11 support (Atheros, etc.)
@@ -527,15 +484,15 @@
 start wpa_supplicant for two interfaces:
 
 wpa_supplicant \
-	-c wpa1.conf -i wlan0 -D hostap -N \
-	-c wpa2.conf -i ath0 -D madwifi
+	-c wpa1.conf -i wlan0 -D nl80211 -N \
+	-c wpa2.conf -i wlan1 -D wext
 
 
 If the interface is added in a Linux bridge (e.g., br0), the bridge
 interface needs to be configured to wpa_supplicant in addition to the
 main interface:
 
-wpa_supplicant -cw.conf -Dmadwifi -iath0 -bbr0
+wpa_supplicant -cw.conf -Dwext -iwlan0 -bbr0
 
 
 Configuration file
diff --git a/wpa_supplicant/README-P2P b/wpa_supplicant/README-P2P
index 0c1ca03..db6e4ae 100644
--- a/wpa_supplicant/README-P2P
+++ b/wpa_supplicant/README-P2P
@@ -101,7 +101,7 @@
 
 Group Formation
 
-p2p_prov_disc <peer device address> <display|keypad|pbc>
+p2p_prov_disc <peer device address> <display|keypad|pbc> [join]
 
 Send P2P provision discovery request to the specified peer. The
 parameters for this command are the P2P device address of the peer and
@@ -110,7 +110,11 @@
 us and "p2p_prov_disc 02:01:02:03:04:05 keypad" would request the peer
 to enter a PIN that we display.
 
-p2p_connect <peer device address> <pbc|pin|PIN#> [label|display|keypad]
+The optional "join" parameter can be used to indicate that this command
+is requesting an already running GO to prepare for a new client. This is
+mainly used with "display" to request it to display a PIN.
+
+p2p_connect <peer device address> <pbc|pin|PIN#> [display|keypad]
 	[persistent] [join|auth] [go_intent=<0..15>] [freq=<in MHz>]
 
 Start P2P group formation with a discovered P2P peer. This includes
@@ -121,10 +125,9 @@
 method. "pbc" string starts pushbutton method, "pin" string start PIN
 method using an automatically generated PIN (which will be returned as
 the command return code), PIN# means that a pre-selected PIN can be
-used (e.g., 12345670). [label|display|keypad] is used with PIN method
-to specify which PIN is used (label=PIN from local label,
-display=dynamically generated random PIN from local display,
-keypad=PIN entered from peer device label or display). "persistent"
+used (e.g., 12345670). [display|keypad] is used with PIN method
+to specify which PIN is used (display=dynamically generated random PIN
+from local display, keypad=PIN entered from peer display). "persistent"
 parameter can be used to request a persistent group to be formed.
 
 "join" indicates that this is a command to join an existing group as a
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index 313e873..bf75cb4 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -127,6 +127,11 @@
 generated PIN.
 
 
+If a random PIN is needed for a user interface, "wpa_cli wps_pin get"
+can be used to generate a new PIN without starting WPS negotiation.
+This random PIN can then be passed as an argument to another wps_pin
+call when the actual operation should be started.
+
 If the client design wants to support optional WPS PBC mode, this can
 be enabled by either a physical button in the client device or a
 virtual button in the user interface. The PBC operation requires that
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index 6d9037a..1386d0c 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -23,16 +23,13 @@
 #include "ap/hostapd.h"
 #include "ap/ap_config.h"
 #include "ap/ap_drv_ops.h"
-#if  defined (NEED_AP_MLME) || defined (ANDROID_BRCM_P2P_PATCH)
+#ifdef NEED_AP_MLME
 #include "ap/ieee802_11.h"
 #endif /* NEED_AP_MLME */
 #include "ap/beacon.h"
 #include "ap/ieee802_1x.h"
 #include "ap/wps_hostapd.h"
 #include "ap/ctrl_iface_ap.h"
-#include "eap_common/eap_defs.h"
-#include "eap_server/eap_methods.h"
-#include "eap_common/eap_wsc_common.h"
 #include "wps/wps.h"
 #include "common/ieee802_11_defs.h"
 #include "config_ssid.h"
@@ -56,10 +53,6 @@
 {
 	struct hostapd_bss_config *bss = &conf->bss[0];
 	int pairwise;
-#ifdef CONFIG_IEEE80211N
-	struct hostapd_hw_modes *modes;
-	u16 num_modes, flags;
-#endif /* CONFIG_IEEE80211N */
 
 	conf->driver = wpa_s->driver;
 
@@ -87,24 +80,35 @@
 
 #ifdef CONFIG_IEEE80211N
 	/*
-	 * Enable HT20 if the driver supports it, by setting conf->ieee80211n.
+	 * Enable HT20 if the driver supports it, by setting conf->ieee80211n
+	 * and a mask of allowed capabilities within conf->ht_capab.
 	 * Using default config settings for: conf->ht_op_mode_fixed,
-	 * conf->ht_capab, conf->secondary_channel, conf->require_ht
+	 * conf->secondary_channel, conf->require_ht
 	 */
-	modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, &flags);
-	if (modes) {
+	if (wpa_s->hw.modes) {
 		struct hostapd_hw_modes *mode = NULL;
 		int i;
-		for (i = 0; i < num_modes; i++) {
-			if (modes[i].mode == conf->hw_mode) {
-				mode = &modes[i];
+		for (i = 0; i < wpa_s->hw.num_modes; i++) {
+			if (wpa_s->hw.modes[i].mode == conf->hw_mode) {
+				mode = &wpa_s->hw.modes[i];
 				break;
 			}
 		}
-		if (mode && mode->ht_capab)
+		if (mode && mode->ht_capab) {
 			conf->ieee80211n = 1;
-		ieee80211_sta_free_hw_features(modes, num_modes);
-		modes = NULL;
+
+			/*
+			 * white-list capabilities that won't cause issues
+			 * to connecting stations, while leaving the current
+			 * capabilities intact (currently disabled SMPS).
+			 */
+			conf->ht_capab |= mode->ht_capab &
+				(HT_CAP_INFO_GREEN_FIELD |
+				 HT_CAP_INFO_SHORT_GI20MHZ |
+				 HT_CAP_INFO_SHORT_GI40MHZ |
+				 HT_CAP_INFO_RX_STBC_MASK |
+				 HT_CAP_INFO_MAX_AMSDU_SIZE);
+		}
 	}
 #endif /* CONFIG_IEEE80211N */
 
@@ -134,6 +138,8 @@
 		}
 		conf->supported_rates = list;
 	}
+
+	bss->isolate = !wpa_s->conf->p2p_intra_bss;
 #endif /* CONFIG_P2P */
 
 	if (ssid->ssid_len == 0) {
@@ -145,6 +151,9 @@
 	bss->ssid.ssid_len = ssid->ssid_len;
 	bss->ssid.ssid_set = 1;
 
+	if (ssid->auth_alg)
+		bss->auth_algs = ssid->auth_alg;
+
 	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt))
 		bss->wpa = ssid->proto;
 	bss->wpa_key_mgmt = ssid->key_mgmt;
@@ -158,6 +167,22 @@
 			return -1;
 		os_memcpy(bss->ssid.wpa_psk->psk, ssid->psk, PMK_LEN);
 		bss->ssid.wpa_psk->group = 1;
+	} else if (ssid->wep_key_len[0] || ssid->wep_key_len[1] ||
+		   ssid->wep_key_len[2] || ssid->wep_key_len[3]) {
+		struct hostapd_wep_keys *wep = &bss->ssid.wep;
+		int i;
+		for (i = 0; i < NUM_WEP_KEYS; i++) {
+			if (ssid->wep_key_len[i] == 0)
+				continue;
+			wep->key[i] = os_malloc(ssid->wep_key_len[i]);
+			if (wep->key[i] == NULL)
+				return -1;
+			os_memcpy(wep->key[i], ssid->wep_key[i],
+				  ssid->wep_key_len[i]);
+			wep->len[i] = ssid->wep_key_len[i];
+		}
+		wep->idx = ssid->wep_tx_keyidx;
+		wep->keys_set = 1;
 	}
 
 	/* Select group cipher based on the enabled pairwise cipher suites */
@@ -179,18 +204,45 @@
 	else if (bss->wpa)
 		bss->ssid.security_policy = SECURITY_WPA_PSK;
 	else if (bss->ieee802_1x) {
+		int cipher = WPA_CIPHER_NONE;
 		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
 		bss->ssid.wep.default_len = bss->default_wep_key_len;
-	} else if (bss->ssid.wep.keys_set)
+		if (bss->default_wep_key_len)
+			cipher = bss->default_wep_key_len >= 13 ?
+				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else if (bss->ssid.wep.keys_set) {
+		int cipher = WPA_CIPHER_WEP40;
+		if (bss->ssid.wep.len[0] >= 13)
+			cipher = WPA_CIPHER_WEP104;
 		bss->ssid.security_policy = SECURITY_STATIC_WEP;
-	else
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else {
 		bss->ssid.security_policy = SECURITY_PLAINTEXT;
+		bss->wpa_group = WPA_CIPHER_NONE;
+		bss->wpa_pairwise = WPA_CIPHER_NONE;
+		bss->rsn_pairwise = WPA_CIPHER_NONE;
+	}
 
 #ifdef CONFIG_WPS
 	/*
-	 * Enable WPS by default, but require user interaction to actually use
-	 * it. Only the internal Registrar is supported.
+	 * Enable WPS by default for open and WPA/WPA2-Personal network, but
+	 * require user interaction to actually use it. Only the internal
+	 * Registrar is supported.
 	 */
+	if (bss->ssid.security_policy != SECURITY_WPA_PSK &&
+	    bss->ssid.security_policy != SECURITY_PLAINTEXT)
+		goto no_wps;
+#ifdef CONFIG_WPS2
+	if (bss->ssid.security_policy == SECURITY_WPA_PSK &&
+	    (!(pairwise & WPA_CIPHER_CCMP) || !(bss->wpa & 2)))
+		goto no_wps; /* WPS2 does not allow WPA/TKIP-only
+			      * configuration */
+#endif /* CONFIG_WPS2 */
 	bss->eap_server = 1;
 	bss->wps_state = 2;
 	bss->ap_setup_locked = 2;
@@ -215,6 +267,7 @@
 	else
 		os_memcpy(bss->uuid, wpa_s->conf->uuid, WPS_UUID_LEN);
 	os_memcpy(bss->os_version, wpa_s->conf->os_version, 4);
+no_wps:
 #endif /* CONFIG_WPS */
 
 	if (wpa_s->max_stations &&
@@ -275,9 +328,9 @@
 
 
 static void ap_sta_authorized_cb(void *ctx, const u8 *mac_addr,
-				 int authorized)
+				 int authorized, const u8 *p2p_dev_addr)
 {
-	wpas_notify_sta_authorized(ctx, mac_addr, authorized);
+	wpas_notify_sta_authorized(ctx, mac_addr, authorized, p2p_dev_addr);
 }
 
 
@@ -301,12 +354,12 @@
 }
 
 
-static int ap_probe_req_rx(void *ctx, const u8 *addr, const u8 *ie,
-			   size_t ie_len)
+static int ap_probe_req_rx(void *ctx, const u8 *sa, const u8 *da,
+			   const u8 *bssid, const u8 *ie, size_t ie_len)
 {
 #ifdef CONFIG_P2P
 	struct wpa_supplicant *wpa_s = ctx;
-	return wpas_p2p_probe_req_rx(wpa_s, addr, ie, ie_len);
+	return wpas_p2p_probe_req_rx(wpa_s, sa, da, bssid, ie, ie_len);
 #else /* CONFIG_P2P */
 	return 0;
 #endif /* CONFIG_P2P */
@@ -371,6 +424,7 @@
 	}
 	params.freq = ssid->frequency;
 
+	params.wpa_proto = ssid->proto;
 	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
 		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
 	else
@@ -395,7 +449,6 @@
 	if (ssid->mode == WPAS_MODE_P2P_GO ||
 	    ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION)
 		params.p2p = 1;
-	wpa_drv_set_intra_bss(wpa_s, wpa_s->conf->p2p_intra_bss);
 #endif /* CONFIG_P2P */
 
 	if (wpa_s->parent->set_ap_uapsd)
@@ -412,6 +465,8 @@
 	if (hapd_iface == NULL)
 		return -1;
 	hapd_iface->owner = wpa_s;
+	hapd_iface->drv_flags = wpa_s->drv_flags;
+	hapd_iface->probe_resp_offloads = wpa_s->probe_resp_offloads;
 
 	wpa_s->ap_iface->conf = conf = hostapd_config_defaults();
 	if (conf == NULL) {
@@ -419,6 +474,11 @@
 		return -1;
 	}
 
+	if (params.uapsd > 0) {
+		conf->bss->wmm_enabled = 1;
+		conf->bss->wmm_uapsd = 1;
+	}
+
 	if (wpa_supplicant_conf_ap(wpa_s, ssid, conf)) {
 		wpa_printf(MSG_ERROR, "Failed to create AP configuration");
 		wpa_supplicant_ap_deinit(wpa_s);
@@ -451,10 +511,7 @@
 		}
 
 		hapd_iface->bss[i]->msg_ctx = wpa_s;
-#ifdef ANDROID_BRCM_P2P_PATCH
-		/* Sending the event to parent is required as SSL listens on parent ctrl iface */
 		hapd_iface->bss[i]->msg_ctx_parent = wpa_s->parent;
-#endif
 		hapd_iface->bss[i]->public_action_cb = ap_public_action_rx;
 		hapd_iface->bss[i]->public_action_cb_ctx = wpa_s;
 		hapd_iface->bss[i]->vendor_action_cb = ap_vendor_action_rx;
@@ -490,14 +547,6 @@
 		wpa_supplicant_ap_deinit(wpa_s);
 		return -1;
 	}
-	
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if (wpa_drv_probe_req_report(wpa_s, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Failed to request the driver to "
-			   "report received Probe Request frames");
-		return -1;
-	}
-#endif
 
 	return 0;
 }
@@ -537,23 +586,38 @@
 }
 
 
-void ap_rx_from_unknown_sta(void *ctx, const u8 *frame, size_t len)
+void ap_eapol_tx_status(void *ctx, const u8 *dst,
+			const u8 *data, size_t len, int ack)
 {
 #ifdef NEED_AP_MLME
 	struct wpa_supplicant *wpa_s = ctx;
-	const struct ieee80211_hdr *hdr =
-		(const struct ieee80211_hdr *) frame;
-	u16 fc = le_to_host16(hdr->frame_control);
-	ieee802_11_rx_from_unknown(wpa_s->ap_iface->bss[0], hdr->addr2,
-				   (fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) ==
-				   (WLAN_FC_TODS | WLAN_FC_FROMDS));
+	hostapd_tx_status(wpa_s->ap_iface->bss[0], dst, data, len, ack);
+#endif /* NEED_AP_MLME */
+}
+
+
+void ap_client_poll_ok(void *ctx, const u8 *addr)
+{
+#ifdef NEED_AP_MLME
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s->ap_iface)
+		hostapd_client_poll_ok(wpa_s->ap_iface->bss[0], addr);
+#endif /* NEED_AP_MLME */
+}
+
+
+void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds)
+{
+#ifdef NEED_AP_MLME
+	struct wpa_supplicant *wpa_s = ctx;
+	ieee802_11_rx_from_unknown(wpa_s->ap_iface->bss[0], addr, wds);
 #endif /* NEED_AP_MLME */
 }
 
 
 void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt)
 {
-#if  defined (NEED_AP_MLME) || defined (ANDROID_BRCM_P2P_PATCH)
+#ifdef NEED_AP_MLME
 	struct wpa_supplicant *wpa_s = ctx;
 	struct hostapd_frame_info fi;
 	os_memset(&fi, 0, sizeof(fi));
@@ -561,7 +625,7 @@
 	fi.ssi_signal = rx_mgmt->ssi_signal;
 	ieee802_11_mgmt(wpa_s->ap_iface->bss[0], rx_mgmt->frame,
 			rx_mgmt->frame_len, &fi);
-#endif /* defined (NEED_AP_MLME) || defined (ANDROID_BRCM_P2P_PATCH) */
+#endif /* NEED_AP_MLME */
 }
 
 
@@ -648,7 +712,7 @@
 
 	if (pin == NULL) {
 		unsigned int rpin = wps_generate_pin();
-		ret_len = os_snprintf(buf, buflen, "%d", rpin);
+		ret_len = os_snprintf(buf, buflen, "%08d", rpin);
 		pin = buf;
 	} else
 		ret_len = os_snprintf(buf, buflen, "%s", pin);
@@ -709,7 +773,7 @@
 		return NULL;
 	hapd = wpa_s->ap_iface->bss[0];
 	pin = wps_generate_pin();
-	os_snprintf(pin_txt, sizeof(pin_txt), "%u", pin);
+	os_snprintf(pin_txt, sizeof(pin_txt), "%08u", pin);
 	os_free(hapd->conf->ap_pin);
 	hapd->conf->ap_pin = os_strdup(pin_txt);
 	if (hapd->conf->ap_pin == NULL)
@@ -849,7 +913,9 @@
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 	struct hostapd_data *hapd;
 
-	if (ssid == NULL || wpa_s->ap_iface == NULL)
+	if (ssid == NULL || wpa_s->ap_iface == NULL ||
+	    ssid->mode == WPAS_MODE_INFRA ||
+	    ssid->mode == WPAS_MODE_IBSS)
 		return -1;
 
 #ifdef CONFIG_P2P
@@ -860,8 +926,10 @@
 			P2P_GROUP_FORMATION;
 #endif /* CONFIG_P2P */
 
-	ieee802_11_set_beacons(iface);
 	hapd = iface->bss[0];
+	if (hapd->drv_priv == NULL)
+		return -1;
+	ieee802_11_set_beacons(iface);
 	hostapd_set_ap_wps_ie(hapd);
 
 	return 0;
diff --git a/wpa_supplicant/ap.h b/wpa_supplicant/ap.h
index b913be3..aa4c362 100644
--- a/wpa_supplicant/ap.h
+++ b/wpa_supplicant/ap.h
@@ -41,7 +41,10 @@
 				 size_t buflen, int verbose);
 void ap_tx_status(void *ctx, const u8 *addr,
 		  const u8 *buf, size_t len, int ack);
-void ap_rx_from_unknown_sta(void *ctx, const u8 *frame, size_t len);
+void ap_eapol_tx_status(void *ctx, const u8 *dst,
+			const u8 *data, size_t len, int ack);
+void ap_client_poll_ok(void *ctx, const u8 *addr);
+void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds);
 void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt);
 void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok);
 int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/bgscan_learn.c b/wpa_supplicant/bgscan_learn.c
index ee79511..5385cce 100644
--- a/wpa_supplicant/bgscan_learn.c
+++ b/wpa_supplicant/bgscan_learn.c
@@ -355,20 +355,19 @@
 static int * bgscan_learn_get_supp_freqs(struct wpa_supplicant *wpa_s)
 {
 	struct hostapd_hw_modes *modes;
-	u16 num_modes, flags;
 	int i, j, *freqs = NULL, *n;
 	size_t count = 0;
 
-	modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, &flags);
-	if (!modes)
+	modes = wpa_s->hw.modes;
+	if (modes == NULL)
 		return NULL;
 
-	for (i = 0; i < num_modes; i++) {
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
 		for (j = 0; j < modes[i].num_channels; j++) {
 			if (modes[i].channels[j].flag & HOSTAPD_CHAN_DISABLED)
 				continue;
 			n = os_realloc(freqs, (count + 2) * sizeof(int));
-			if (!n)
+			if (n == NULL)
 				continue;
 
 			freqs = n;
@@ -376,10 +375,7 @@
 			count++;
 			freqs[count] = 0;
 		}
-		os_free(modes[i].channels);
-		os_free(modes[i].rates);
 	}
-	os_free(modes);
 
 	return freqs;
 }
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 5b48951..078e22d 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -50,6 +50,15 @@
 		" SSID '%s'", bss->id, MAC2STR(bss->bssid),
 		wpa_ssid_txt(bss->ssid, bss->ssid_len));
 	wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
+#ifdef CONFIG_INTERWORKING
+	wpabuf_free(bss->anqp_venue_name);
+	wpabuf_free(bss->anqp_network_auth_type);
+	wpabuf_free(bss->anqp_roaming_consortium);
+	wpabuf_free(bss->anqp_ip_addr_type_availability);
+	wpabuf_free(bss->anqp_nai_realm);
+	wpabuf_free(bss->anqp_3gpp);
+	wpabuf_free(bss->anqp_domain_name);
+#endif /* CONFIG_INTERWORKING */
 	os_free(bss);
 }
 
@@ -93,6 +102,55 @@
 }
 
 
+static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid->ssid == NULL || ssid->ssid_len == 0)
+			continue;
+		if (ssid->ssid_len == bss->ssid_len &&
+		    os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (!wpa_bss_known(wpa_s, bss)) {
+			wpa_bss_remove(wpa_s, bss);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+static void wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
+{
+	/*
+	 * Remove the oldest entry that does not match with any configured
+	 * network.
+	 */
+	if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
+		return;
+
+	/*
+	 * Remove the oldest entry since no better candidate for removal was
+	 * found.
+	 */
+	wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
+					    struct wpa_bss, list));
+}
+
+
 static void wpa_bss_add(struct wpa_supplicant *wpa_s,
 			const u8 *ssid, size_t ssid_len,
 			struct wpa_scan_res *res)
@@ -118,11 +176,8 @@
 		" SSID '%s'",
 		bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
 	wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
-	if (wpa_s->num_bss > wpa_s->conf->bss_max_count) {
-		/* Remove the oldest entry */
-		wpa_bss_remove(wpa_s, dl_list_first(&wpa_s->bss,
-						    struct wpa_bss, list));
-	}
+	if (wpa_s->num_bss > wpa_s->conf->bss_max_count)
+		wpa_bss_remove_oldest(wpa_s);
 }
 
 
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 992b9c0..bb19f49 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -23,6 +23,7 @@
 #define WPA_BSS_LEVEL_DBM		BIT(3)
 #define WPA_BSS_AUTHENTICATED		BIT(4)
 #define WPA_BSS_ASSOCIATED		BIT(5)
+#define WPA_BSS_ANQP_FETCH_TRIED	BIT(6)
 
 /**
  * struct wpa_bss - BSS table
@@ -65,6 +66,15 @@
 	int level;
 	u64 tsf;
 	struct os_time last_update;
+#ifdef CONFIG_INTERWORKING
+	struct wpabuf *anqp_venue_name;
+	struct wpabuf *anqp_network_auth_type;
+	struct wpabuf *anqp_roaming_consortium;
+	struct wpabuf *anqp_ip_addr_type_availability;
+	struct wpabuf *anqp_nai_realm;
+	struct wpabuf *anqp_3gpp;
+	struct wpabuf *anqp_domain_name;
+#endif /* CONFIG_INTERWORKING */
 	size_t ie_len;
 	size_t beacon_ie_len;
 	/* followed by ie_len octets of IEs */
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c
index 19c810b..9cd26dd 100644
--- a/wpa_supplicant/config.c
+++ b/wpa_supplicant/config.c
@@ -1371,6 +1371,90 @@
 #endif /* NO_CONFIG_WRITE */
 
 
+#ifdef CONFIG_P2P
+
+static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
+					    struct wpa_ssid *ssid, int line,
+					    const char *value)
+{
+	const char *pos;
+	u8 *buf, *n, addr[ETH_ALEN];
+	size_t count;
+
+	buf = NULL;
+	count = 0;
+
+	pos = value;
+	while (pos && *pos) {
+		while (*pos == ' ')
+			pos++;
+
+		if (hwaddr_aton(pos, addr)) {
+			wpa_printf(MSG_ERROR, "Line %d: Invalid "
+				   "p2p_client_list address '%s'.",
+				   line, value);
+			/* continue anyway */
+		} else {
+			n = os_realloc(buf, (count + 1) * ETH_ALEN);
+			if (n == NULL) {
+				os_free(buf);
+				return -1;
+			}
+			buf = n;
+			os_memcpy(buf + count * ETH_ALEN, addr, ETH_ALEN);
+			count++;
+			wpa_hexdump(MSG_MSGDUMP, "p2p_client_list",
+				    addr, ETH_ALEN);
+		}
+
+		pos = os_strchr(pos, ' ');
+	}
+
+	os_free(ssid->p2p_client_list);
+	ssid->p2p_client_list = buf;
+	ssid->num_p2p_clients = count;
+
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
+					       struct wpa_ssid *ssid)
+{
+	char *value, *end, *pos;
+	int res;
+	size_t i;
+
+	if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0)
+		return NULL;
+
+	value = os_malloc(20 * ssid->num_p2p_clients);
+	if (value == NULL)
+		return NULL;
+	pos = value;
+	end = value + 20 * ssid->num_p2p_clients;
+
+	for (i = 0; i < ssid->num_p2p_clients; i++) {
+		res = os_snprintf(pos, end - pos, MACSTR " ",
+				  MAC2STR(ssid->p2p_client_list +
+					  i * ETH_ALEN));
+		if (res < 0 || res >= end - pos) {
+			os_free(value);
+			return NULL;
+		}
+		pos += res;
+	}
+
+	if (pos > value)
+		pos[-1] = '\0';
+
+	return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_P2P */
+
 /* Helper macros for network block parser */
 
 #ifdef OFFSET
@@ -1544,6 +1628,9 @@
 	{ INT_RANGE(frequency, 0, 10000) },
 	{ INT(wpa_ptk_rekey) },
 	{ STR(bgscan) },
+#ifdef CONFIG_P2P
+	{ FUNC(p2p_client_list) },
+#endif /* CONFIG_P2P */
 };
 
 #ifdef WPA_UNICODE_SSID
@@ -1719,6 +1806,7 @@
 	os_free(ssid->scan_freq);
 	os_free(ssid->freq_list);
 	os_free(ssid->bgscan);
+	os_free(ssid->p2p_client_list);
 	os_free(ssid);
 }
 
@@ -1768,6 +1856,12 @@
 	os_free(config->config_methods);
 	os_free(config->p2p_ssid_postfix);
 	os_free(config->pssid);
+	os_free(config->home_realm);
+	os_free(config->home_username);
+	os_free(config->home_password);
+	os_free(config->home_ca_cert);
+	os_free(config->home_imsi);
+	os_free(config->home_milenage);
 	os_free(config);
 }
 
@@ -1951,6 +2045,27 @@
 }
 
 
+int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
+			  const char *value)
+{
+	size_t len;
+	char *buf;
+	int ret;
+
+	len = os_strlen(value);
+	buf = os_malloc(len + 3);
+	if (buf == NULL)
+		return -1;
+	buf[0] = '"';
+	os_memcpy(buf + 1, value, len);
+	buf[len + 1] = '"';
+	buf[len + 2] = '\0';
+	ret = wpa_config_set(ssid, var, buf, 0);
+	os_free(buf);
+	return ret;
+}
+
+
 /**
  * wpa_config_get_all - Get all options from network configuration
  * @ssid: Pointer to network configuration data
@@ -2215,6 +2330,7 @@
 	config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
 	config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
 	config->max_num_sta = DEFAULT_MAX_NUM_STA;
+	config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
 
 	if (ctrl_interface)
 		config->ctrl_interface = os_strdup(ctrl_interface);
@@ -2423,6 +2539,20 @@
 #endif /* CONFIG_P2P */
 
 
+static int wpa_config_process_hessid(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	if (hwaddr_aton2(pos, config->hessid) < 0) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'",
+			   line, pos);
+		return -1;
+	}
+
+	return 0;
+}
+
+
 #ifdef OFFSET
 #undef OFFSET
 #endif /* OFFSET */
@@ -2487,7 +2617,16 @@
 	{ INT(bss_expiration_scan_count), 0 },
 	{ INT_RANGE(filter_ssids, 0, 1), 0 },
 	{ INT(max_num_sta), 0 },
-	{ INT_RANGE(disassoc_low_ack, 0, 1), 0 }
+	{ INT_RANGE(disassoc_low_ack, 0, 1), 0 },
+	{ STR(home_realm), 0 },
+	{ STR(home_username), 0 },
+	{ STR(home_password), 0 },
+	{ STR(home_ca_cert), 0 },
+	{ STR(home_imsi), 0 },
+	{ STR(home_milenage), 0 },
+	{ INT_RANGE(interworking, 0, 1), 0 },
+	{ FUNC(hessid), 0 },
+	{ INT_RANGE(access_network_type, 0, 15), 0 }
 };
 
 #undef FUNC
diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h
index 10abdad..f9e5043 100644
--- a/wpa_supplicant/config.h
+++ b/wpa_supplicant/config.h
@@ -28,6 +28,7 @@
 #define DEFAULT_BSS_EXPIRATION_AGE 180
 #define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
 #define DEFAULT_MAX_NUM_STA 128
+#define DEFAULT_ACCESS_NETWORK_TYPE 15
 
 #include "config_ssid.h"
 #include "wps/wps.h"
@@ -123,7 +124,7 @@
 	 * If this is specified, %wpa_supplicant will open a control interface
 	 * that is available for external programs to manage %wpa_supplicant.
 	 * The meaning of this string depends on which control interface
-	 * mechanism is used. For all cases, the existance of this parameter
+	 * mechanism is used. For all cases, the existence of this parameter
 	 * in configuration is used to determine whether the control interface
 	 * is enabled.
 	 *
@@ -376,7 +377,10 @@
 	 * stations in the group. As a P2P client, this means no GO seen in
 	 * scan results. The maximum idle time is specified in seconds with 0
 	 * indicating no time limit, i.e., the P2P group remains in active
-	 * state indefinitely until explicitly removed.
+	 * state indefinitely until explicitly removed. As a P2P client, the
+	 * maximum idle time of P2P_MAX_CLIENT_IDLE seconds is enforced, i.e.,
+	 * this parameter is mainly meant for GO use and for P2P client, it can
+	 * only be used to reduce the default timeout to smaller value.
 	 */
 	unsigned int p2p_group_idle;
 
@@ -426,6 +430,60 @@
 	 * disassoc_low_ack - Disassocicate stations with massive packet loss
 	 */
 	int disassoc_low_ack;
+
+	/**
+	 * interworking - Whether Interworking (IEEE 802.11u) is enabled
+	 */
+	int interworking;
+
+	/**
+	 * access_network_type - Access Network Type
+	 *
+	 * When Interworking is enabled, scans will be limited to APs that
+	 * advertise the specified Access Network Type (0..15; with 15
+	 * indicating wildcard match).
+	 */
+	int access_network_type;
+
+	/**
+	 * hessid - Homogenous ESS identifier
+	 *
+	 * If this is set (any octet is non-zero), scans will be used to
+	 * request response only from BSSes belonging to the specified
+	 * Homogeneous ESS. This is used only if interworking is enabled.
+	 */
+	u8 hessid[ETH_ALEN];
+
+	/**
+	 * home_realm - Home Realm for Interworking
+	 */
+	char *home_realm;
+
+	/**
+	 * home_username - Username for Interworking network selection
+	 */
+	char *home_username;
+
+	/**
+	 * home_password - Password for Interworking network selection
+	 */
+	char *home_password;
+
+	/**
+	 * home_ca_cert - CA certificate for Interworking network selection
+	 */
+	char *home_ca_cert;
+
+	/**
+	 * home_imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+	 */
+	char *home_imsi;
+
+	/**
+	 * home_milenage - Milenage parameters for SIM/USIM simulator in
+	 *	<Ki>:<OPc>:<SQN> format
+	 */
+	char *home_milenage;
 };
 
 
@@ -442,6 +500,8 @@
 void wpa_config_set_network_defaults(struct wpa_ssid *ssid);
 int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
 		   int line);
+int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
+			  const char *value);
 char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys);
 char * wpa_config_get(struct wpa_ssid *ssid, const char *var);
 char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var);
diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c
index 2d5fdd6..f3a7291 100644
--- a/wpa_supplicant/config_file.c
+++ b/wpa_supplicant/config_file.c
@@ -104,9 +104,7 @@
 		wpa_config_update_psk(ssid);
 	}
 
-	if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
-			       WPA_KEY_MGMT_PSK_SHA256)) &&
-	    !ssid->psk_set) {
+	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set) {
 		wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
 			   "management, but no PSK configured.", line);
 		errors++;
@@ -495,6 +493,18 @@
 }
 
 
+#ifdef CONFIG_P2P
+static void write_p2p_client_list(FILE *f, struct wpa_ssid *ssid)
+{
+	char *value = wpa_config_get(ssid, "p2p_client_list");
+	if (value == NULL)
+		return;
+	fprintf(f, "\tp2p_client_list=%s\n", value);
+	os_free(value);
+}
+#endif /* CONFIG_P2P */
+
+
 static void wpa_config_write_network(FILE *f, struct wpa_ssid *ssid)
 {
 	int i;
@@ -569,6 +579,9 @@
 	INT(ieee80211w);
 #endif /* CONFIG_IEEE80211W */
 	STR(id_str);
+#ifdef CONFIG_P2P
+	write_p2p_client_list(f, ssid);
+#endif /* CONFIG_P2P */
 
 #undef STR
 #undef INT
@@ -649,7 +662,8 @@
 		char _buf[WPS_DEV_TYPE_BUFSIZE], *buf;
 		buf = wps_dev_type_bin2str(config->device_type,
 					   _buf, sizeof(_buf));
-		fprintf(f, "device_type=%s\n", buf);
+		if (os_strcmp(buf, "0-00000000-0") != 0)
+			fprintf(f, "device_type=%s\n", buf);
 	}
 	if (WPA_GET_BE32(config->os_version))
 		fprintf(f, "os_version=%08x\n",
@@ -703,6 +717,27 @@
 		fprintf(f, "max_num_sta=%u\n", config->max_num_sta);
 	if (config->disassoc_low_ack)
 		fprintf(f, "disassoc_low_ack=%u\n", config->disassoc_low_ack);
+#ifdef CONFIG_INTERWORKING
+	if (config->home_realm)
+		fprintf(f, "home_realm=%s\n", config->home_realm);
+	if (config->home_username)
+		fprintf(f, "home_username=%s\n", config->home_username);
+	if (config->home_password)
+		fprintf(f, "home_password=%s\n", config->home_password);
+	if (config->home_ca_cert)
+		fprintf(f, "home_ca_cert=%s\n", config->home_ca_cert);
+	if (config->home_imsi)
+		fprintf(f, "home_imsi=%s\n", config->home_imsi);
+	if (config->home_milenage)
+		fprintf(f, "home_milenage=%s\n", config->home_milenage);
+	if (config->interworking)
+		fprintf(f, "interworking=%u\n", config->interworking);
+	if (!is_zero_ether_addr(config->hessid))
+		fprintf(f, "hessid=" MACSTR "\n", MAC2STR(config->hessid));
+	if (config->access_network_type != DEFAULT_ACCESS_NETWORK_TYPE)
+		fprintf(f, "access_network_type=%d\n",
+			config->access_network_type);
+#endif /* CONFIG_INTERWORKING */
 }
 
 #endif /* CONFIG_NO_CONFIG_WRITE */
@@ -731,6 +766,9 @@
 	for (ssid = config->ssid; ssid; ssid = ssid->next) {
 		if (ssid->key_mgmt == WPA_KEY_MGMT_WPS || ssid->temporary)
 			continue; /* do not save temporary networks */
+		if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
+		    !ssid->passphrase)
+			continue; /* do not save invalid network */
 		fprintf(f, "\nnetwork={\n");
 		wpa_config_write_network(f, ssid);
 		fprintf(f, "}\n");
diff --git a/wpa_supplicant/config_ssid.h b/wpa_supplicant/config_ssid.h
index 8419f43..8a47c0b 100644
--- a/wpa_supplicant/config_ssid.h
+++ b/wpa_supplicant/config_ssid.h
@@ -387,6 +387,20 @@
 	int *freq_list;
 
 	/**
+	 * p2p_client_list - List of P2P Clients in a persistent group (GO)
+	 *
+	 * This is a list of P2P Clients (P2P Device Address) that have joined
+	 * the persistent group. This is maintained on the GO for persistent
+	 * group entries (disabled == 2).
+	 */
+	u8 *p2p_client_list;
+
+	/**
+	 * num_p2p_clients - Number of entries in p2p_client_list
+	 */
+	size_t num_p2p_clients;
+
+	/**
 	 * p2p_group - Network generated as a P2P group (used internally)
 	 */
 	int p2p_group;
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
index ea3a2ac..5fb2580 100644
--- a/wpa_supplicant/config_winreg.c
+++ b/wpa_supplicant/config_winreg.c
@@ -350,9 +350,7 @@
 		wpa_config_update_psk(ssid);
 	}
 
-	if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
-			       WPA_KEY_MGMT_PSK_SHA256)) &&
-	    !ssid->psk_set) {
+	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set) {
 		wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, "
 			   "but no PSK configured for network '" TSTR "'.",
 			   netw);
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index e05602c..522472f 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -38,7 +38,9 @@
 #include "bss.h"
 #include "scan.h"
 #include "ctrl_iface.h"
+#include "interworking.h"
 #include "blacklist.h"
+#include "wpas_glue.h"
 
 extern struct wpa_driver_ops *wpa_drivers[];
 
@@ -48,6 +50,76 @@
 						  char *buf, int len);
 
 
+static int pno_start(struct wpa_supplicant *wpa_s)
+{
+	int ret;
+	size_t i, num_ssid;
+	struct wpa_ssid *ssid;
+	struct wpa_driver_scan_params params;
+
+	if (wpa_s->pno)
+		return 0;
+
+	os_memset(&params, 0, sizeof(params));
+
+	num_ssid = 0;
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		if (!ssid->disabled)
+			num_ssid++;
+		ssid = ssid->next;
+	}
+	if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
+		wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
+			   "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
+		num_ssid = WPAS_MAX_SCAN_SSIDS;
+	}
+
+	if (num_ssid == 0) {
+		wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
+		return -1;
+	}
+
+	params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
+					num_ssid);
+	if (params.filter_ssids == NULL)
+		return -1;
+	i = 0;
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		if (!ssid->disabled) {
+			params.ssids[i].ssid = ssid->ssid;
+			params.ssids[i].ssid_len = ssid->ssid_len;
+			params.num_ssids++;
+			os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
+				  ssid->ssid_len);
+			params.filter_ssids[i].ssid_len = ssid->ssid_len;
+			params.num_filter_ssids++;
+			i++;
+			if (i == num_ssid)
+				break;
+		}
+		ssid = ssid->next;
+	}
+
+	ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
+	os_free(params.filter_ssids);
+	if (ret == 0)
+		wpa_s->pno = 1;
+	return ret;
+}
+
+
+static int pno_stop(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->pno) {
+		wpa_s->pno = 0;
+		return wpa_drv_stop_sched_scan(wpa_s);
+	}
+	return 0;
+}
+
+
 static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
 					 char *cmd)
 {
@@ -126,6 +198,11 @@
 			ret = -1;
 		wpa_tdls_enable(wpa_s->wpa, !disabled);
 #endif /* CONFIG_TDLS */
+	} else if (os_strcasecmp(cmd, "pno") == 0) {
+		if (atoi(value))
+			ret = pno_start(wpa_s);
+		else
+			ret = pno_stop(wpa_s);
 	} else {
 		value[-1] = '=';
 		ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
@@ -209,6 +286,7 @@
 	struct wpa_supplicant *wpa_s, char *addr)
 {
 	u8 peer[ETH_ALEN];
+	int ret;
 
 	if (hwaddr_aton(addr, peer)) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
@@ -219,7 +297,12 @@
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
 		   MAC2STR(peer));
 
-	return wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+	if (wpa_tdls_is_external_setup(wpa_s->wpa))
+		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
+	else
+		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+
+	return ret;
 }
 
 
@@ -239,8 +322,13 @@
 		   MAC2STR(peer));
 
 	ret = wpa_tdls_reneg(wpa_s->wpa, peer);
-	if (ret)
-		ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+	if (ret) {
+		if (wpa_tdls_is_external_setup(wpa_s->wpa))
+			ret = wpa_tdls_start(wpa_s->wpa, peer);
+		else
+			ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+	}
+
 	return ret;
 }
 
@@ -259,7 +347,8 @@
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
 		   MAC2STR(peer));
 
-	return wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN, peer);
+	return wpa_tdls_teardown_link(wpa_s->wpa, peer,
+				      WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
 }
 
 #endif /* CONFIG_TDLS */
@@ -303,9 +392,7 @@
 #ifdef CONFIG_AP
 	u8 *_p2p_dev_addr = NULL;
 #endif /* CONFIG_AP */
-#ifdef ANDROID_BRCM_P2P_PATCH	
-	struct wpa_supplicant *iface;
-#endif
+
 	if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
 		_bssid = NULL;
 #ifdef CONFIG_P2P
@@ -324,17 +411,7 @@
 		return -1;
 	}
 
-#if defined(ANDROID_BRCM_P2P_PATCH) && defined(CONFIG_AP)
-	for (iface = wpa_s->global->ifaces; iface; iface = iface->next)	{
-		if (iface->ap_iface){
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: iface 0x%08x wpa_s->ap_iface %p", (u32)iface, iface->ap_iface);
-			wpa_supplicant_ap_wps_pbc(iface, _bssid, _p2p_dev_addr);
-			return 0;
-		}
-		else
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: ap_iface is not set iface 0x%08x", (u32)iface);
-	}
-#elif defined CONFIG_AP
+#ifdef CONFIG_AP
 	if (wpa_s->ap_iface)
 		return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
 #endif /* CONFIG_AP */
@@ -351,35 +428,22 @@
 	char *pin;
 	int ret;
 
-#if defined(ANDROID_BRCM_P2P_PATCH) && defined(CONFIG_AP)
-	struct wpa_supplicant *iface;
-#endif
-
 	pin = os_strchr(cmd, ' ');
 	if (pin)
 		*pin++ = '\0';
 
 	if (os_strcmp(cmd, "any") == 0)
 		_bssid = NULL;
-	else if (hwaddr_aton(cmd, bssid)) {
+	else if (os_strcmp(cmd, "get") == 0) {
+		ret = wps_generate_pin();
+		goto done;
+	} else if (hwaddr_aton(cmd, bssid)) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
 			   cmd);
 		return -1;
 	}
 
-#if defined(ANDROID_BRCM_P2P_PATCH) && defined(CONFIG_AP)
-	for (iface = wpa_s->global->ifaces; iface; iface = iface->next)	{
-		if (iface->ap_iface){
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: iface 0x%08x wpa_s->ap_iface %p", (u32)iface, iface->ap_iface);
-			/* Call the wps registrar for the main interface */
-			wpa_supplicant_ap_wps_pin(iface, _bssid, pin,
-							 buf, buflen);
-			return 0;
-		}
-		else
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: ap_iface is not set iface 0x%08x", (u32)iface);
-	}
-#elif defined CONFIG_AP
+#ifdef CONFIG_AP
 	if (wpa_s->ap_iface)
 		return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
 						 buf, buflen);
@@ -400,6 +464,7 @@
 	if (ret < 0)
 		return -1;
 
+done:
 	/* Return the generated PIN */
 	ret = os_snprintf(buf, buflen, "%08d", ret);
 	if (ret < 0 || (size_t) ret >= buflen)
@@ -699,6 +764,78 @@
 #endif /* CONFIG_IBSS_RSN */
 
 
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+					      struct wpa_ssid *ssid,
+					      const char *field,
+					      const char *value)
+{
+#ifdef IEEE8021X_EAPOL
+	struct eap_peer_config *eap = &ssid->eap;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
+			      (const u8 *) value, os_strlen(value));
+
+	switch (wpa_supplicant_ctrl_req_from_string(field)) {
+	case WPA_CTRL_REQ_EAP_IDENTITY:
+		os_free(eap->identity);
+		eap->identity = (u8 *) os_strdup(value);
+		eap->identity_len = os_strlen(value);
+		eap->pending_req_identity = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_PASSWORD:
+		os_free(eap->password);
+		eap->password = (u8 *) os_strdup(value);
+		eap->password_len = os_strlen(value);
+		eap->pending_req_password = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+		os_free(eap->new_password);
+		eap->new_password = (u8 *) os_strdup(value);
+		eap->new_password_len = os_strlen(value);
+		eap->pending_req_new_password = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_PIN:
+		os_free(eap->pin);
+		eap->pin = os_strdup(value);
+		eap->pending_req_pin = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_OTP:
+		os_free(eap->otp);
+		eap->otp = (u8 *) os_strdup(value);
+		eap->otp_len = os_strlen(value);
+		os_free(eap->pending_req_otp);
+		eap->pending_req_otp = NULL;
+		eap->pending_req_otp_len = 0;
+		break;
+	case WPA_CTRL_REQ_EAP_PASSPHRASE:
+		os_free(eap->private_key_passwd);
+		eap->private_key_passwd = (u8 *) os_strdup(value);
+		eap->pending_req_passphrase = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
+		return -1;
+	}
+
+	return 0;
+#else /* IEEE8021X_EAPOL */
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
+	return -1;
+#endif /* IEEE8021X_EAPOL */
+}
+
+
 static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
 					      char *rsp)
 {
@@ -706,7 +843,6 @@
 	char *pos, *id_pos;
 	int id;
 	struct wpa_ssid *ssid;
-	struct eap_peer_config *eap;
 
 	pos = os_strchr(rsp, '-');
 	if (pos == NULL)
@@ -728,54 +864,9 @@
 			   "to update", id);
 		return -1;
 	}
-	eap = &ssid->eap;
 
-	if (os_strcmp(rsp, "IDENTITY") == 0) {
-		os_free(eap->identity);
-		eap->identity = (u8 *) os_strdup(pos);
-		eap->identity_len = os_strlen(pos);
-		eap->pending_req_identity = 0;
-		if (ssid == wpa_s->current_ssid)
-			wpa_s->reassociate = 1;
-	} else if (os_strcmp(rsp, "PASSWORD") == 0) {
-		os_free(eap->password);
-		eap->password = (u8 *) os_strdup(pos);
-		eap->password_len = os_strlen(pos);
-		eap->pending_req_password = 0;
-		if (ssid == wpa_s->current_ssid)
-			wpa_s->reassociate = 1;
-	} else if (os_strcmp(rsp, "NEW_PASSWORD") == 0) {
-		os_free(eap->new_password);
-		eap->new_password = (u8 *) os_strdup(pos);
-		eap->new_password_len = os_strlen(pos);
-		eap->pending_req_new_password = 0;
-		if (ssid == wpa_s->current_ssid)
-			wpa_s->reassociate = 1;
-	} else if (os_strcmp(rsp, "PIN") == 0) {
-		os_free(eap->pin);
-		eap->pin = os_strdup(pos);
-		eap->pending_req_pin = 0;
-		if (ssid == wpa_s->current_ssid)
-			wpa_s->reassociate = 1;
-	} else if (os_strcmp(rsp, "OTP") == 0) {
-		os_free(eap->otp);
-		eap->otp = (u8 *) os_strdup(pos);
-		eap->otp_len = os_strlen(pos);
-		os_free(eap->pending_req_otp);
-		eap->pending_req_otp = NULL;
-		eap->pending_req_otp_len = 0;
-	} else if (os_strcmp(rsp, "PASSPHRASE") == 0) {
-		os_free(eap->private_key_passwd);
-		eap->private_key_passwd = (u8 *) os_strdup(pos);
-		eap->pending_req_passphrase = 0;
-		if (ssid == wpa_s->current_ssid)
-			wpa_s->reassociate = 1;
-	} else {
-		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", rsp);
-		return -1;
-	}
-
-	return 0;
+	return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
+							 pos);
 #else /* IEEE8021X_EAPOL */
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
 	return -1;
@@ -788,22 +879,10 @@
 					    char *buf, size_t buflen)
 {
 	char *pos, *end, tmp[30];
-	int res, verbose, ret;
-
-#if defined(ANDROID_BRCM_P2P_PATCH) && defined(CONFIG_P2P)
-	/* We have to send status command to p2p interface if p2p_interface is started 
-	 * otherwise we can send it to primary interface
-	*/
-	struct wpa_supplicant* ifs;
-	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-		if ( (ifs->p2p_group_interface == P2P_GROUP_INTERFACE_GO ) ||(ifs->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT )) {
-			wpa_s = ifs;
-			break;
-		}
-	}
-#endif /* defined ANDROID_BRCM_P2P_PATCH && defined CONFIG_P2P */
+	int res, verbose, wps, ret;
 
 	verbose = os_strcmp(params, "-VERBOSE") == 0;
+	wps = os_strcmp(params, "-WPS") == 0;
 	pos = buf;
 	end = buf + buflen;
 	if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
@@ -832,6 +911,17 @@
 				return pos - buf;
 			pos += ret;
 
+			if (wps && ssid->passphrase &&
+			    wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
+			    (ssid->mode == WPAS_MODE_AP ||
+			     ssid->mode == WPAS_MODE_P2P_GO)) {
+				ret = os_snprintf(pos, end - pos,
+						  "passphrase=%s\n",
+						  ssid->passphrase);
+				if (ret < 0 || ret >= end - pos)
+					return pos - buf;
+				pos += ret;
+			}
 			if (ssid->id_str) {
 				ret = os_snprintf(pos, end - pos,
 						  "id_str=%s\n",
@@ -977,50 +1067,9 @@
 }
 
 
-extern int wpa_debug_level;
-extern int wpa_debug_timestamp;
-
-static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
-					char *cmd, char *buf, size_t buflen)
-{
-	char *pos, *end, *stamp;
-	int ret;
-
-	if (cmd == NULL)
-		return -1;
-	/* cmd: "LOG_LEVEL [<level>]" */
-	if (*cmd == '\0') {
-		pos = buf;
-		end = buf + buflen;
-		ret = os_snprintf(pos, end-pos, "Current level: %d\n"
-			"{0-EXCESSIVE, 1-MSGDUMP, 2-DEBUG, 3-INFO, 4-WARNING, 5-ERROR}\n"
-			"Timestamp: %d\n", wpa_debug_level, wpa_debug_timestamp);
-		if ((ret < 0) || (ret >= end - pos))
-			ret = 0;
-		return ret;
-	}
-
-	cmd++;
-	stamp = os_strchr(cmd, ' ');
-	if (stamp) {
-		*stamp++ = '\0';
-		while (*stamp == ' ')
-			stamp++;
-	}
-
-	if (cmd && os_strlen(cmd))
-		wpa_debug_level = atoi(cmd);
-
-	if (stamp && os_strlen(stamp))
-		wpa_debug_timestamp = atoi(stamp);
-
-	os_memcpy(buf, "OK\n", 3);
-	return 3;
-}
-
-
 static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
-					char *cmd, char *buf, size_t buflen)
+					       char *cmd, char *buf,
+					       size_t buflen)
 {
 	u8 bssid[ETH_ALEN];
 	struct wpa_blacklist *e;
@@ -1033,8 +1082,9 @@
 		end = buf + buflen;
 		e = wpa_s->blacklist;
 		while (e) {
-			ret = os_snprintf(pos, end-pos, MACSTR"\n", MAC2STR(e->bssid));
-			if ((ret < 0) || (ret >= end - pos))
+			ret = os_snprintf(pos, end - pos, MACSTR "\n",
+					  MAC2STR(e->bssid));
+			if (ret < 0 || ret >= end - pos)
 				return pos - buf;
 			pos += ret;
 			e = e->next;
@@ -1051,23 +1101,118 @@
 
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
 	if (hwaddr_aton(cmd, bssid)) {
-		wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", cmd);
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
 		return -1;
 	}
 
-	/* Add the BSSID twice, so its count will be 2, causing it to be
-	   skipped when processing scan results. */
+	/*
+	 * Add the BSSID twice, so its count will be 2, causing it to be
+	 * skipped when processing scan results.
+	 */
 	ret = wpa_blacklist_add(wpa_s, bssid);
-	if (ret < 0)
+	if (ret != 0)
 		return -1;
 	ret = wpa_blacklist_add(wpa_s, bssid);
-	if (ret < 0)
+	if (ret != 0)
 		return -1;
 	os_memcpy(buf, "OK\n", 3);
 	return 3;
 }
 
 
+extern int wpa_debug_level;
+extern int wpa_debug_timestamp;
+
+static const char * debug_level_str(int level)
+{
+	switch (level) {
+	case MSG_EXCESSIVE:
+		return "EXCESSIVE";
+	case MSG_MSGDUMP:
+		return "MSGDUMP";
+	case MSG_DEBUG:
+		return "DEBUG";
+	case MSG_INFO:
+		return "INFO";
+	case MSG_WARNING:
+		return "WARNING";
+	case MSG_ERROR:
+		return "ERROR";
+	default:
+		return "?";
+	}
+}
+
+
+static int str_to_debug_level(const char *s)
+{
+	if (os_strcasecmp(s, "EXCESSIVE") == 0)
+		return MSG_EXCESSIVE;
+	if (os_strcasecmp(s, "MSGDUMP") == 0)
+		return MSG_MSGDUMP;
+	if (os_strcasecmp(s, "DEBUG") == 0)
+		return MSG_DEBUG;
+	if (os_strcasecmp(s, "INFO") == 0)
+		return MSG_INFO;
+	if (os_strcasecmp(s, "WARNING") == 0)
+		return MSG_WARNING;
+	if (os_strcasecmp(s, "ERROR") == 0)
+		return MSG_ERROR;
+	return -1;
+}
+
+
+static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
+					       char *cmd, char *buf,
+					       size_t buflen)
+{
+	char *pos, *end, *stamp;
+	int ret;
+
+	if (cmd == NULL) {
+		return -1;
+	}
+
+	/* cmd: "LOG_LEVEL [<level>]" */
+	if (*cmd == '\0') {
+		pos = buf;
+		end = buf + buflen;
+		ret = os_snprintf(pos, end - pos, "Current level: %s\n"
+				  "Timestamp: %d\n",
+				  debug_level_str(wpa_debug_level),
+				  wpa_debug_timestamp);
+		if (ret < 0 || ret >= end - pos)
+			ret = 0;
+
+		return ret;
+	}
+
+	while (*cmd == ' ')
+		cmd++;
+
+	stamp = os_strchr(cmd, ' ');
+	if (stamp) {
+		*stamp++ = '\0';
+		while (*stamp == ' ') {
+			stamp++;
+		}
+	}
+
+	if (cmd && os_strlen(cmd)) {
+		int level = str_to_debug_level(cmd);
+		if (level < 0)
+			return -1;
+		wpa_debug_level = level;
+	}
+
+	if (stamp && os_strlen(stamp))
+		wpa_debug_timestamp = atoi(stamp);
+
+	os_memcpy(buf, "OK\n", 3);
+	return 3;
+}
+
+
 static int wpa_supplicant_ctrl_iface_list_networks(
 	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
 {
@@ -1544,8 +1689,8 @@
 			wpas_notify_network_removed(wpa_s, remove_ssid);
 			wpa_config_remove_network(wpa_s->conf, id);
 		}
+		eapol_sm_invalidate_cached_session(wpa_s->eapol);
 		if (wpa_s->current_ssid) {
-			eapol_sm_invalidate_cached_session(wpa_s->eapol);
 			wpa_sm_set_config(wpa_s->wpa, NULL);
 			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 			wpa_supplicant_disassociate(wpa_s,
@@ -1558,6 +1703,8 @@
 	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
 
 	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid)
+		wpas_notify_network_removed(wpa_s, ssid);
 	if (ssid == NULL ||
 	    wpa_config_remove_network(wpa_s->conf, id) < 0) {
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
@@ -1565,12 +1712,15 @@
 		return -1;
 	}
 
-	if (ssid == wpa_s->current_ssid) {
+	if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
 		/*
-		 * Invalidate the EAP session cache if the current network is
-		 * removed.
+		 * Invalidate the EAP session cache if the current or
+		 * previously used network is removed.
 		 */
 		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+	}
+
+	if (ssid == wpa_s->current_ssid) {
 		wpa_sm_set_config(wpa_s->wpa, NULL);
 		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 
@@ -1618,10 +1768,12 @@
 		return -1;
 	}
 
-	if (wpa_s->current_ssid == ssid) {
+	wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+
+	if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
 		/*
 		 * Invalidate the EAP session cache if anything in the current
-		 * configuration changes.
+		 * or previously used configuration changes.
 		 */
 		eapol_sm_invalidate_cached_session(wpa_s->eapol);
 	}
@@ -2012,6 +2164,41 @@
 }
 
 
+#ifdef CONFIG_INTERWORKING
+static char * anqp_add_hex(char *pos, char *end, const char *title,
+			   struct wpabuf *data)
+{
+	char *start = pos;
+	size_t i;
+	int ret;
+	const u8 *d;
+
+	if (data == NULL)
+		return start;
+
+	ret = os_snprintf(pos, end - pos, "%s=", title);
+	if (ret < 0 || ret >= end - pos)
+		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)
+			return start;
+		pos += ret;
+	}
+
+	ret = os_snprintf(pos, end - pos, "\n");
+	if (ret < 0 || ret >= end - pos)
+		return start;
+	pos += ret;
+
+	return pos;
+}
+#endif /* CONFIG_INTERWORKING */
+
+
 static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
 					 const char *cmd, char *buf,
 					 size_t buflen)
@@ -2085,12 +2272,6 @@
 			return pos - buf;
 		pos += ret;
 	}
-	if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
-		ret = os_snprintf(pos, end - pos, "[P2P]");
-		if (ret < 0 || ret >= end - pos)
-			return pos - buf;
-		pos += ret;
-	}
 
 	ret = os_snprintf(pos, end - pos, "\n");
 	if (ret < 0 || ret >= end - pos)
@@ -2127,6 +2308,12 @@
 			return pos - buf;
 		pos += ret;
 	}
+	if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
+		ret = os_snprintf(pos, end - pos, "[P2P]");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
 
 	ret = os_snprintf(pos, end - pos, "\n");
 	if (ret < 0 || ret >= end - pos)
@@ -2155,6 +2342,20 @@
 	pos += ret;
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_INTERWORKING
+	pos = anqp_add_hex(pos, end, "anqp_venue_name", bss->anqp_venue_name);
+	pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
+			   bss->anqp_network_auth_type);
+	pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
+			   bss->anqp_roaming_consortium);
+	pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
+			   bss->anqp_ip_addr_type_availability);
+	pos = anqp_add_hex(pos, end, "anqp_nai_realm", bss->anqp_nai_realm);
+	pos = anqp_add_hex(pos, end, "anqp_3gpp", bss->anqp_3gpp);
+	pos = anqp_add_hex(pos, end, "anqp_domain_name",
+			   bss->anqp_domain_name);
+#endif /* CONFIG_INTERWORKING */
+
 	return pos - buf;
 }
 
@@ -2220,6 +2421,9 @@
 static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
 					  char *addr)
 {
+#ifdef CONFIG_NO_SCAN_PROCESSING
+	return -1;
+#else /* CONFIG_NO_SCAN_PROCESSING */
 	u8 bssid[ETH_ALEN];
 	struct wpa_bss *bss;
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
@@ -2254,6 +2458,7 @@
 	wpa_supplicant_connect(wpa_s, bss, ssid);
 
 	return 0;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
 }
 
 
@@ -2329,9 +2534,7 @@
 		wps_method = WPS_PIN_KEYPAD;
 		if (pos) {
 			*pos++ = '\0';
-			if (os_strncmp(pos, "label", 5) == 0)
-				wps_method = WPS_PIN_LABEL;
-			else if (os_strncmp(pos, "display", 7) == 0)
+			if (os_strncmp(pos, "display", 7) == 0)
 				wps_method = WPS_PIN_DISPLAY;
 		}
 	}
@@ -2373,7 +2576,7 @@
 	u8 addr[ETH_ALEN];
 	char *pos;
 
-	/* <addr> <config method> */
+	/* <addr> <config method> [join] */
 
 	if (hwaddr_aton(cmd, addr))
 		return -1;
@@ -2383,7 +2586,8 @@
 		return -1;
 	pos++;
 
-	return wpas_p2p_prov_disc(wpa_s, addr, pos);
+	return wpas_p2p_prov_disc(wpa_s, addr, pos,
+				  os_strstr(pos, "join") != NULL);
 }
 
 
@@ -2392,16 +2596,6 @@
 {
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 
-#ifdef ANDROID_BRCM_P2P_PATCH
-	struct wpa_supplicant *ifs = NULL;
-	
-	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-		if((ifs->ap_iface) && 
-			(ifs->p2p_group_interface == P2P_GROUP_INTERFACE_GO)) {
-			ssid = ifs->current_ssid;
-		}
-	}
-#endif
 	if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
 	    ssid->passphrase == NULL)
 		return -1;
@@ -2441,8 +2635,7 @@
 		if (*pos != ' ')
 			return -1;
 		pos++;
-		ref = (unsigned long) wpas_p2p_sd_request_upnp(wpa_s, dst,
-							       version, pos);
+		ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
 	} else {
 		len = os_strlen(pos);
 		if (len & 1)
@@ -2456,9 +2649,11 @@
 			return -1;
 		}
 
-		ref = (unsigned long) wpas_p2p_sd_request(wpa_s, dst, tlvs);
+		ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
 		wpabuf_free(tlvs);
 	}
+	if (ref == 0)
+		return -1;
 	res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
 	if (res < 0 || (unsigned) res >= buflen)
 		return -1;
@@ -2474,7 +2669,7 @@
 	if (sscanf(cmd, "%llx", &val) != 1)
 		return -1;
 	req = val;
-	return wpas_p2p_sd_cancel_request(wpa_s, (void *) (unsigned long) req);
+	return wpas_p2p_sd_cancel_request(wpa_s, req);
 }
 
 
@@ -2806,7 +3001,11 @@
 			 char *buf, size_t buflen)
 {
 	u8 addr[ETH_ALEN], *addr_ptr;
-	int next;
+	int next, res;
+	const struct p2p_peer_info *info;
+	char *pos, *end;
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+	struct wpa_ssid *ssid;
 
 	if (!wpa_s->global->p2p)
 		return -1;
@@ -2826,28 +3025,56 @@
 		next = 0;
 	}
 
-	return p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next,
-				 buf, buflen);
+	info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
+	if (info == NULL)
+		return -1;
+
+	pos = buf;
+	end = buf + buflen;
+
+	res = os_snprintf(pos, end - pos, MACSTR "\n"
+			  "pri_dev_type=%s\n"
+			  "device_name=%s\n"
+			  "manufacturer=%s\n"
+			  "model_name=%s\n"
+			  "model_number=%s\n"
+			  "serial_number=%s\n"
+			  "config_methods=0x%x\n"
+			  "dev_capab=0x%x\n"
+			  "group_capab=0x%x\n"
+			  "level=%d\n",
+			  MAC2STR(info->p2p_device_addr),
+			  wps_dev_type_bin2str(info->pri_dev_type,
+					       devtype, sizeof(devtype)),
+			  info->device_name,
+			  info->manufacturer,
+			  info->model_name,
+			  info->model_number,
+			  info->serial_number,
+			  info->config_methods,
+			  info->dev_capab,
+			  info->group_capab,
+			  info->level);
+	if (res < 0 || res >= end - pos)
+		return pos - buf;
+	pos += res;
+
+	ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr);
+	if (ssid) {
+		res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
+		if (res < 0 || res >= end - pos)
+			return pos - buf;
+		pos += res;
+	}
+
+	res = p2p_get_peer_info_txt(info, pos, end - pos);
+	if (res < 0)
+		return pos - buf;
+	pos += res;
+
+	return pos - buf;
 }
 
-#ifdef ANDROID_BRCM_P2P_PATCH
-struct wpa_supplicant* p2p_get_apif(struct wpa_supplicant* wpa_s)
-{
-	struct wpa_supplicant* iface;
-	for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
-		if (iface->ap_iface)
-			return iface;
-	return wpa_s;
-}
-struct wpa_supplicant* p2p_get_clientif(struct wpa_supplicant* wpa_s)
-{
-	struct wpa_supplicant* iface;
-	for (iface = wpa_s->global->ifaces; iface; iface = iface->next)
-		if (iface->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT)
-			return iface;
-	return wpa_s;
-}
-#endif
 
 static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
 {
@@ -2903,46 +3130,17 @@
 			return -1;
 		wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
 			   "start=%d duration=%d", count, start, duration);
-#ifdef ANDROID_BRCM_P2P_PATCH
-		return wpas_p2p_set_noa(p2p_get_apif(wpa_s), count, start, duration);
-#else
 		return wpas_p2p_set_noa(wpa_s, count, start, duration);
-#endif
 	}
 
 	if (os_strcmp(cmd, "ps") == 0)
-#ifdef ANDROID_BRCM_P2P_PATCH
-		return wpas_drv_set_p2p_powersave(p2p_get_clientif(wpa_s), atoi(param), -1, -1);
-#else
 		return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
-#endif
 
 	if (os_strcmp(cmd, "oppps") == 0)
-#ifdef ANDROID_BRCM_P2P_PATCH
-		return wpas_drv_set_p2p_powersave(p2p_get_apif(wpa_s), -1, atoi(param), -1);
-#else
 		return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
-#endif
 
 	if (os_strcmp(cmd, "ctwindow") == 0)
-#ifdef ANDROID_BRCM_P2P_PATCH
-		return wpa_drv_set_p2p_powersave(p2p_get_apif(wpa_s), -1, -1, atoi(param));
-#else
 		return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
-#endif
-
-	if (os_strcmp(cmd, "disabled") == 0) {
-		wpa_s->global->p2p_disabled = atoi(param);
-		wpa_printf(MSG_DEBUG, "P2P functionality %s",
-			   wpa_s->global->p2p_disabled ?
-			   "disabled" : "enabled");
-		if (wpa_s->global->p2p_disabled) {
-			wpas_p2p_stop_find(wpa_s);
-			os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
-			p2p_flush(wpa_s->global->p2p);
-		}
-		return 0;
-	}
 
 	if (os_strcmp(cmd, "disabled") == 0) {
 		wpa_s->global->p2p_disabled = atoi(param);
@@ -3081,6 +3279,59 @@
 #endif /* CONFIG_P2P */
 
 
+#ifdef CONFIG_INTERWORKING
+static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
+{
+	u8 bssid[ETH_ALEN];
+	struct wpa_bss *bss;
+
+	if (hwaddr_aton(dst, bssid)) {
+		wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
+		return -1;
+	}
+
+	bss = wpa_bss_get_bssid(wpa_s, bssid);
+	if (bss == NULL) {
+		wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
+			   MAC2STR(bssid));
+		return -1;
+	}
+
+	return interworking_connect(wpa_s, bss);
+}
+
+
+static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
+{
+	u8 dst_addr[ETH_ALEN];
+	int used;
+	char *pos;
+#define MAX_ANQP_INFO_ID 100
+	u16 id[MAX_ANQP_INFO_ID];
+	size_t num_id = 0;
+
+	used = hwaddr_aton2(dst, dst_addr);
+	if (used < 0)
+		return -1;
+	pos = dst + used;
+	while (num_id < MAX_ANQP_INFO_ID) {
+		id[num_id] = atoi(pos);
+		if (id[num_id])
+			num_id++;
+		pos = os_strchr(pos + 1, ',');
+		if (pos == NULL)
+			break;
+		pos++;
+	}
+
+	if (num_id == 0)
+		return -1;
+
+	return anqp_send_req(wpa_s, dst_addr, id, num_id);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
 static int wpa_supplicant_ctrl_iface_sta_autoconnect(
 	struct wpa_supplicant *wpa_s, char *cmd)
 {
@@ -3108,7 +3359,7 @@
 	return ret;
 }
 
-
+#ifdef ANDROID
 static int wpa_supplicant_driver_cmd(struct wpa_supplicant *wpa_s, char *cmd,
 				     char *buf, size_t buflen)
 {
@@ -3119,7 +3370,7 @@
 		ret = sprintf(buf, "%s\n", "OK");
 	return ret;
 }
-
+#endif
 
 char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
 					 char *buf, size_t *resp_len)
@@ -3186,6 +3437,7 @@
 	} else if (os_strcmp(buf, "LOGOFF") == 0) {
 		eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
 	} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
+		wpa_s->normal_scans = 0;
 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
 			reply_len = -1;
 		else {
@@ -3194,6 +3446,7 @@
 			wpa_supplicant_req_scan(wpa_s, 0, 0);
 		}
 	} else if (os_strcmp(buf, "RECONNECT") == 0) {
+		wpa_s->normal_scans = 0;
 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
 			reply_len = -1;
 		else if (wpa_s->disconnected) {
@@ -3375,18 +3628,6 @@
 		if (wpas_p2p_cancel(wpa_s))
 			reply_len = -1;
 	} else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
-	#if defined(ANDROID_BRCM_P2P_PATCH) && defined(CONFIG_P2P)
-		/* We have to send presence command to p2p interface if p2p_interface is started 
-		 * otherwise we can send it to primary interface
-		*/
-		struct wpa_supplicant* ifs;
-		for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-			if ( (ifs->p2p_group_interface == P2P_GROUP_INTERFACE_GO ) ||(ifs->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT )) {
-				wpa_s = ifs;
-				break;
-			}
-		}
-	#endif /* defined ANDROID_BRCM_P2P_PATCH && defined CONFIG_P2P */
 		if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
 			reply_len = -1;
 	} else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
@@ -3399,6 +3640,23 @@
 		if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
 			reply_len = -1;
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+	} else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
+		if (interworking_fetch_anqp(wpa_s) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
+		interworking_stop_fetch_anqp(wpa_s);
+	} else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
+		if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
+					NULL) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
+		if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
+		if (get_anqp(wpa_s, buf + 9) < 0)
+			reply_len = -1;
+#endif /* CONFIG_INTERWORKING */
 	} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
 	{
 		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
@@ -3414,21 +3672,23 @@
 	} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
 		if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
 			reply_len = -1;
-	} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
-		reply_len = wpa_supplicant_ctrl_iface_log_level(wpa_s, buf + 9,
-							reply, reply_size);
 	} else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
-		reply_len = wpa_supplicant_ctrl_iface_blacklist(wpa_s, buf + 9,
-							reply, reply_size);
+		reply_len = wpa_supplicant_ctrl_iface_blacklist(
+			wpa_s, buf + 9, reply, reply_size);
+	} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_log_level(
+			wpa_s, buf + 9, reply, reply_size);
 	} else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
 		reply_len = wpa_supplicant_ctrl_iface_list_networks(
 			wpa_s, reply, reply_size);
 	} else if (os_strcmp(buf, "DISCONNECT") == 0) {
 		wpa_s->reassociate = 0;
 		wpa_s->disconnected = 1;
+		wpa_supplicant_cancel_sched_scan(wpa_s);
 		wpa_supplicant_deauthenticate(wpa_s,
 					      WLAN_REASON_DEAUTH_LEAVING);
 	} else if (os_strcmp(buf, "SCAN") == 0) {
+		wpa_s->normal_scans = 0;
 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
 			reply_len = -1;
 		else {
@@ -3534,9 +3794,13 @@
 	} else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
 		reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
 						       reply_size);
+#ifdef ANDROID							   
 	} else if (os_strncmp(buf, "DRIVER ", 7) == 0) {
 		reply_len = wpa_supplicant_driver_cmd(wpa_s, buf + 7, reply,
 						      reply_size);
+#endif							  
+	} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
+		eapol_sm_request_reauth(wpa_s->eapol);
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
@@ -3733,8 +3997,11 @@
 	char *reply;
 	const int reply_size = 2048;
 	int reply_len;
+	int level = MSG_DEBUG;
 
-	wpa_hexdump_ascii(MSG_DEBUG, "RX global ctrl_iface",
+	if (os_strcmp(buf, "PING") == 0)
+		level = MSG_EXCESSIVE;
+	wpa_hexdump_ascii(level, "RX global ctrl_iface",
 			  (const u8 *) buf, os_strlen(buf));
 
 	reply = os_malloc(reply_size);
diff --git a/wpa_supplicant/ctrl_iface.h b/wpa_supplicant/ctrl_iface.h
index 051d99a..88ae6b7 100644
--- a/wpa_supplicant/ctrl_iface.h
+++ b/wpa_supplicant/ctrl_iface.h
@@ -95,6 +95,21 @@
 void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv);
 
 /**
+ * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @ssid: Pointer to the network block the reply is for
+ * @field: field the response is a reply for
+ * @value: value (ie, password, etc) for @field
+ * Returns: 0 on success, non-zero on error
+ *
+ * Helper function to handle replies to control interface requests.
+ */
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+					      struct wpa_ssid *ssid,
+					      const char *field,
+					      const char *value);
+
+/**
  * wpa_supplicant_global_ctrl_iface_init - Initialize global control interface
  * @global: Pointer to global data from wpa_supplicant_init()
  * Returns: Pointer to private data on success, %NULL on failure
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index 9ad75d4..306a222 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -281,7 +281,7 @@
 		goto fail;
 #ifdef ANDROID
 	os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
-		    wpa_s->ifname);
+		    wpa_s->conf->ctrl_interface);
 	priv->sock = android_get_control_socket(addr.sun_path);
 	if (priv->sock >= 0)
 		goto havesock;
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.c b/wpa_supplicant/dbus/dbus_dict_helpers.c
index 788f736..5f9e64a 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.c
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.c
@@ -705,18 +705,26 @@
  * @param iter A valid DBusMessageIter pointing to the start of the dict
  * @param iter_dict (out) A DBusMessageIter to be passed to
  *    wpa_dbus_dict_read_next_entry()
+ * @error on failure a descriptive error
  * @return TRUE on success, FALSE on failure
  *
  */
 dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
-				    DBusMessageIter *iter_dict)
+				    DBusMessageIter *iter_dict,
+				    DBusError *error)
 {
-	if (!iter || !iter_dict)
+	if (!iter || !iter_dict) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+		                     "[internal] missing message iterators");
 		return FALSE;
+	}
 
 	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
-	    dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY)
+	    dbus_message_iter_get_element_type(iter) != DBUS_TYPE_DICT_ENTRY) {
+		dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+		                     "unexpected message argument types");
 		return FALSE;
+	}
 
 	dbus_message_iter_recurse(iter, iter_dict);
 	return TRUE;
@@ -1087,13 +1095,13 @@
 				os_free(entry->strarray_value[i]);
 			os_free(entry->strarray_value);
 			break;
+		case WPAS_DBUS_TYPE_BINARRAY:
+			for (i = 0; i < entry->array_len; i++)
+				wpabuf_free(entry->binarray_value[i]);
+			os_free(entry->binarray_value);
+			break;
 		}
 		break;
-	case WPAS_DBUS_TYPE_BINARRAY:
-		for (i = 0; i < entry->array_len; i++)
-			wpabuf_free(entry->binarray_value[i]);
-		os_free(entry->binarray_value);
-		break;
 	}
 
 	memset(entry, 0, sizeof(struct wpa_dbus_dict_entry));
diff --git a/wpa_supplicant/dbus/dbus_dict_helpers.h b/wpa_supplicant/dbus/dbus_dict_helpers.h
index 9e90c50..2f6eb45 100644
--- a/wpa_supplicant/dbus/dbus_dict_helpers.h
+++ b/wpa_supplicant/dbus/dbus_dict_helpers.h
@@ -156,7 +156,8 @@
 };
 
 dbus_bool_t wpa_dbus_dict_open_read(DBusMessageIter *iter,
-				    DBusMessageIter *iter_dict);
+				    DBusMessageIter *iter_dict,
+				    DBusError *error);
 
 dbus_bool_t wpa_dbus_dict_get_entry(DBusMessageIter *iter_dict,
 				    struct wpa_dbus_dict_entry *entry);
diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c
index 533cb32..2bf9be8 100644
--- a/wpa_supplicant/dbus/dbus_new.c
+++ b/wpa_supplicant/dbus/dbus_new.c
@@ -22,11 +22,11 @@
 #include "../config.h"
 #include "../wpa_supplicant_i.h"
 #include "../bss.h"
+#include "../wpas_glue.h"
 #include "dbus_new_helpers.h"
 #include "dbus_dict_helpers.h"
 #include "dbus_new.h"
 #include "dbus_new_handlers.h"
-#include "dbus_common.h"
 #include "dbus_common_i.h"
 #include "dbus_new_handlers_p2p.h"
 #include "p2p/p2p.h"
@@ -45,7 +45,7 @@
 {
 	struct wpas_dbus_priv *iface;
 	DBusMessage *msg;
-	DBusMessageIter iter, iter_dict;
+	DBusMessageIter iter;
 
 	iface = wpa_s->global->dbus;
 
@@ -64,14 +64,9 @@
 		goto err;
 
 	if (properties) {
-		if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-			goto err;
-
-		wpa_dbus_get_object_properties(iface, wpa_s->dbus_new_path,
-					       WPAS_DBUS_NEW_IFACE_INTERFACE,
-					       &iter_dict);
-
-		if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+		if (!wpa_dbus_get_object_properties(
+			    iface, wpa_s->dbus_new_path,
+			    WPAS_DBUS_NEW_IFACE_INTERFACE, &iter))
 			goto err;
 	}
 
@@ -160,7 +155,7 @@
 {
 	struct wpas_dbus_priv *iface;
 	DBusMessage *msg;
-	DBusMessageIter iter, iter_dict;
+	DBusMessageIter iter;
 
 	iface = wpa_s->global->dbus;
 
@@ -180,14 +175,9 @@
 		goto err;
 
 	if (properties) {
-		if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-			goto err;
-
-		wpa_dbus_get_object_properties(iface, bss_obj_path,
-					       WPAS_DBUS_NEW_IFACE_BSS,
-					       &iter_dict);
-
-		if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+		if (!wpa_dbus_get_object_properties(iface, bss_obj_path,
+						    WPAS_DBUS_NEW_IFACE_BSS,
+						    &iter))
 			goto err;
 	}
 
@@ -307,7 +297,7 @@
 {
 	struct wpas_dbus_priv *iface;
 	DBusMessage *msg;
-	DBusMessageIter iter, iter_dict;
+	DBusMessageIter iter;
 	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
 
 	iface = wpa_s->global->dbus;
@@ -333,14 +323,9 @@
 		goto err;
 
 	if (properties) {
-		if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-			goto err;
-
-		wpa_dbus_get_object_properties(iface, net_obj_path,
-					       WPAS_DBUS_NEW_IFACE_NETWORK,
-					       &iter_dict);
-
-		if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+		if (!wpa_dbus_get_object_properties(
+			    iface, net_obj_path, WPAS_DBUS_NEW_IFACE_NETWORK,
+			    &iter))
 			goto err;
 	}
 
@@ -397,6 +382,67 @@
 
 
 /**
+ * wpas_dbus_signal_network_request - Indicate that additional information
+ * (EAP password, etc.) is required to complete the association to this SSID
+ * @wpa_s: %wpa_supplicant network interface data
+ * @rtype: The specific additional information required
+ * @default_text: Optional description of required information
+ *
+ * Request additional information or passwords to complete an association
+ * request.
+ */
+void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
+				      struct wpa_ssid *ssid,
+				      enum wpa_ctrl_req_type rtype,
+				      const char *default_txt)
+{
+	struct wpas_dbus_priv *iface;
+	DBusMessage *msg;
+	DBusMessageIter iter;
+	char net_obj_path[WPAS_DBUS_OBJECT_PATH_MAX];
+	const char *field, *txt = NULL, *net_ptr;
+
+	iface = wpa_s->global->dbus;
+
+	/* Do nothing if the control interface is not turned on */
+	if (iface == NULL)
+		return;
+
+	field = wpa_supplicant_ctrl_req_to_string(rtype, default_txt, &txt);
+	if (field == NULL)
+		return;
+
+	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
+				      WPAS_DBUS_NEW_IFACE_INTERFACE,
+				      "NetworkRequest");
+	if (msg == NULL)
+		return;
+
+	os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
+		    "%s/" WPAS_DBUS_NEW_NETWORKS_PART "/%u",
+		    wpa_s->dbus_new_path, ssid->id);
+	net_ptr = &net_obj_path[0];
+
+	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");
+	dbus_message_unref(msg);
+}
+
+
+/**
  * wpas_dbus_signal_network_enabled_changed - Signals Enabled property changes
  * @wpa_s: %wpa_supplicant network interface data
  * @ssid: configured network which Enabled property has changed
@@ -821,7 +867,7 @@
 		return;
 
 	/* Check if this is a known peer */
-	if (p2p_get_peer_info(wpa_s->global->p2p, dev_addr, 0, NULL, 0) < 0)
+	if (!p2p_peer_known(wpa_s->global->p2p, dev_addr))
 		goto error;
 
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -920,7 +966,7 @@
 
 /**
  * wpas_dbus_signal_p2p_group_started - Signals P2P group has
- * started.Emitted when a group is succesfully started
+ * started. Emitted when a group is successfully started
  * irrespective of the role (client/GO) of the current device
  *
  * @wpa_s: %wpa_supplicant network interface data
@@ -998,35 +1044,118 @@
  * on status.
  * @status: Status of the GO neg request. 0 for success, other for errors.
  */
-void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, int status)
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+				      struct p2p_go_neg_results *res)
 {
 	DBusMessage *msg;
-	DBusMessageIter iter;
+	DBusMessageIter iter, dict_iter;
+	DBusMessageIter iter_dict_entry, iter_dict_val, iter_dict_array;
 	struct wpas_dbus_priv *iface;
+	char peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
+	dbus_int32_t freqs[P2P_MAX_CHANNELS];
+	dbus_int32_t *f_array = freqs;
+
 
 	iface = wpa_s->global->dbus;
 
+	os_memset(freqs, 0, sizeof(freqs));
 	/* Do nothing if the control interface is not turned on */
 	if (iface == NULL)
 		return;
 
+	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(res->peer_device_addr));
+	path = peer_obj_path;
+
 	msg = dbus_message_new_signal(wpa_s->dbus_new_path,
 				      WPAS_DBUS_NEW_IFACE_P2PDEVICE,
-				      status ? "GONegotiationFailure" :
-					       "GONegotiationSuccess");
+				      res->status ? "GONegotiationFailure" :
+						    "GONegotiationSuccess");
 	if (msg == NULL)
 		return;
 
-	if (status) {
-		dbus_message_iter_init_append(msg, &iter);
-		if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_INT32,
-						    &status)) {
-			wpa_printf(MSG_ERROR,
-				   "dbus: Failed to construct signal");
-			goto err;
+	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",
+					      path) ||
+	    !wpa_dbus_dict_append_int32(&dict_iter, "status", res->status))
+		goto err;
+
+	if (!res->status) {
+		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",
+						 res->role_go ? "GO" :
+						 "client") ||
+		    !wpa_dbus_dict_append_int32(&dict_iter, "frequency",
+						res->freq) ||
+		    !wpa_dbus_dict_append_byte_array(&dict_iter, "ssid",
+						     (const char *) res->ssid,
+						     res->ssid_len) ||
+		    !wpa_dbus_dict_append_byte_array(&dict_iter,
+						     "peer_device_addr",
+						     (const char *)
+						     res->peer_device_addr,
+						     ETH_ALEN) ||
+		    !wpa_dbus_dict_append_byte_array(&dict_iter,
+						     "peer_interface_addr",
+						     (const char *)
+						     res->peer_interface_addr,
+						     ETH_ALEN) ||
+		    !wpa_dbus_dict_append_string(&dict_iter, "wps_method",
+						 p2p_wps_method_text(
+							 res->wps_method)))
+			goto err;
+
+		for (i = 0; i < P2P_MAX_CHANNELS; i++) {
+			if (res->freq_list[i]) {
+				freqs[i] = res->freq_list[i];
+				freq_list_num++;
+			}
+		}
+
+		if (!wpa_dbus_dict_begin_array(&dict_iter,
+					       "frequency_list",
+					       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,
+							  DBUS_TYPE_INT32,
+							  &f_array,
+							  freq_list_num))
+			goto err;
+
+		if (!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",
+						res->persistent_group) ||
+		    !wpa_dbus_dict_append_uint32(&dict_iter,
+						 "peer_config_timeout",
+						 res->peer_config_timeout))
+			goto err;
 	}
 
+	if (!wpa_dbus_dict_close_write(&iter, &dict_iter))
+		goto err;
+
 	dbus_connection_send(iface->con, msg, NULL);
 err:
 	dbus_message_unref(msg);
@@ -1228,7 +1357,7 @@
 		return;
 
 	/* Check if this is a known peer */
-	if (p2p_get_peer_info(wpa_s->global->p2p, sa, 0, NULL, 0) < 0)
+	if (!p2p_peer_known(wpa_s->global->p2p, sa))
 		goto error;
 
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -1297,7 +1426,7 @@
 		return;
 
 	/* Check if this is a known peer */
-	if (p2p_get_peer_info(wpa_s->global->p2p, sa, 0, NULL, 0) < 0)
+	if (!p2p_peer_known(wpa_s->global->p2p, sa))
 		goto error;
 
 	os_snprintf(peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
@@ -1345,7 +1474,7 @@
 {
 	struct wpas_dbus_priv *iface;
 	DBusMessage *msg;
-	DBusMessageIter iter, iter_dict;
+	DBusMessageIter iter;
 	char pgrp_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
 
 	iface = wpa_s->global->dbus;
@@ -1371,15 +1500,9 @@
 		goto err;
 
 	if (properties) {
-		if (!wpa_dbus_dict_open_write(&iter, &iter_dict))
-			goto err;
-
-		wpa_dbus_get_object_properties(
-			iface, pgrp_obj_path,
-			WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP,
-			&iter_dict);
-
-		if (!wpa_dbus_dict_close_write(&iter, &iter_dict))
+		if (!wpa_dbus_get_object_properties(
+			    iface, pgrp_obj_path,
+			    WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, &iter))
 			goto err;
 	}
 
@@ -1483,7 +1606,6 @@
 void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
 				   enum wpas_dbus_prop property)
 {
-	WPADBusPropertyAccessor getter;
 	char *prop;
 
 	if (wpa_s->dbus_new_path == NULL)
@@ -1491,34 +1613,24 @@
 
 	switch (property) {
 	case WPAS_DBUS_PROP_AP_SCAN:
-		getter = (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan;
 		prop = "ApScan";
 		break;
 	case WPAS_DBUS_PROP_SCANNING:
-		getter = (WPADBusPropertyAccessor) wpas_dbus_getter_scanning;
 		prop = "Scanning";
 		break;
 	case WPAS_DBUS_PROP_STATE:
-		getter = (WPADBusPropertyAccessor) wpas_dbus_getter_state;
 		prop = "State";
 		break;
 	case WPAS_DBUS_PROP_CURRENT_BSS:
-		getter = (WPADBusPropertyAccessor)
-			wpas_dbus_getter_current_bss;
 		prop = "CurrentBSS";
 		break;
 	case WPAS_DBUS_PROP_CURRENT_NETWORK:
-		getter = (WPADBusPropertyAccessor)
-			wpas_dbus_getter_current_network;
 		prop = "CurrentNetwork";
 		break;
 	case WPAS_DBUS_PROP_BSSS:
-		getter = (WPADBusPropertyAccessor) wpas_dbus_getter_bsss;
 		prop = "BSSs";
 		break;
 	case WPAS_DBUS_PROP_CURRENT_AUTH_MODE:
-		getter = (WPADBusPropertyAccessor)
-			wpas_dbus_getter_current_auth_mode;
 		prop = "CurrentAuthMode";
 		break;
 	default:
@@ -1685,31 +1797,26 @@
 
 static const struct wpa_dbus_property_desc wpas_dbus_global_properties[] = {
 	{ "DebugLevel", WPAS_DBUS_NEW_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_debug_level,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_debug_level,
-	  RW
+	  wpas_dbus_getter_debug_level,
+	  wpas_dbus_setter_debug_level
 	},
 	{ "DebugTimestamp", WPAS_DBUS_NEW_INTERFACE, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_debug_timestamp,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_debug_timestamp,
-	  RW
+	  wpas_dbus_getter_debug_timestamp,
+	  wpas_dbus_setter_debug_timestamp
 	},
 	{ "DebugShowKeys", WPAS_DBUS_NEW_INTERFACE, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_debug_show_keys,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_debug_show_keys,
-	  RW
+	  wpas_dbus_getter_debug_show_keys,
+	  wpas_dbus_setter_debug_show_keys
 	},
 	{ "Interfaces", WPAS_DBUS_NEW_INTERFACE, "ao",
-	  (WPADBusPropertyAccessor) &wpas_dbus_getter_interfaces,
-	  NULL,
-	  R
+	  wpas_dbus_getter_interfaces,
+	  NULL
 	},
 	{ "EapMethods", WPAS_DBUS_NEW_INTERFACE, "as",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_eap_methods,
-	  NULL,
-	  R
+	  wpas_dbus_getter_eap_methods,
+	  NULL
 	},
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
+	{ NULL, NULL, NULL, NULL, NULL }
 };
 
 static const struct wpa_dbus_signal_desc wpas_dbus_global_signals[] = {
@@ -1726,6 +1833,15 @@
 		  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,
 	  {
 		  { "properties", "a{sv}", ARG_OUT },
@@ -1802,20 +1918,19 @@
 
 static const struct wpa_dbus_property_desc wpas_dbus_network_properties[] = {
 	{ "Properties", WPAS_DBUS_NEW_IFACE_NETWORK, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_network_properties,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_network_properties,
-	  RW
+	  wpas_dbus_getter_network_properties,
+	  wpas_dbus_setter_network_properties
 	},
 	{ "Enabled", WPAS_DBUS_NEW_IFACE_NETWORK, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_enabled,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_enabled,
-	  RW
+	  wpas_dbus_getter_enabled,
+	  wpas_dbus_setter_enabled
 	},
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
+	{ NULL, NULL, NULL, NULL, NULL }
 };
 
 
 static const struct wpa_dbus_signal_desc wpas_dbus_network_signals[] = {
+	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
 	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_NETWORK,
 	  {
 		  { "properties", "a{sv}", ARG_OUT },
@@ -1925,8 +2040,7 @@
 #endif /* CONFIG_P2P */
 
 	/* Do nothing if the control interface is not turned on */
-	if (wpa_s == NULL || wpa_s->global == NULL ||
-	    wpa_s->dbus_new_path == NULL)
+	if (wpa_s->global == NULL || wpa_s->dbus_new_path == NULL)
 		return 0;
 	ctrl_iface = wpa_s->global->dbus;
 	if (ctrl_iface == NULL)
@@ -1949,60 +2063,51 @@
 
 static const struct wpa_dbus_property_desc wpas_dbus_bss_properties[] = {
 	{ "SSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_ssid,
-	  NULL,
-	  R
+	  wpas_dbus_getter_bss_ssid,
+	  NULL
 	},
 	{ "BSSID", WPAS_DBUS_NEW_IFACE_BSS, "ay",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_bssid,
-	  NULL,
-	  R
+	  wpas_dbus_getter_bss_bssid,
+	  NULL
 	},
 	{ "Privacy", WPAS_DBUS_NEW_IFACE_BSS, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_privacy,
-	  NULL,
-	  R
+	  wpas_dbus_getter_bss_privacy,
+	  NULL
 	},
 	{ "Mode", WPAS_DBUS_NEW_IFACE_BSS, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_mode,
-	  NULL,
-	  R
+	  wpas_dbus_getter_bss_mode,
+	  NULL
 	},
 	{ "Signal", WPAS_DBUS_NEW_IFACE_BSS, "n",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_signal,
-	  NULL,
-	  R
+	  wpas_dbus_getter_bss_signal,
+	  NULL
 	},
 	{ "Frequency", WPAS_DBUS_NEW_IFACE_BSS, "q",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_frequency,
-	  NULL,
-	  R
+	  wpas_dbus_getter_bss_frequency,
+	  NULL
 	},
 	{ "Rates", WPAS_DBUS_NEW_IFACE_BSS, "au",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_rates,
-	  NULL,
-	  R
+	  wpas_dbus_getter_bss_rates,
+	  NULL
 	},
 	{ "WPA", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_wpa,
-	  NULL,
-	  R
+	  wpas_dbus_getter_bss_wpa,
+	  NULL
 	},
 	{ "RSN", WPAS_DBUS_NEW_IFACE_BSS, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_rsn,
-	  NULL,
-	  R
+	  wpas_dbus_getter_bss_rsn,
+	  NULL
 	},
 	{ "IEs", WPAS_DBUS_NEW_IFACE_BSS, "ay",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_ies,
-	  NULL,
-	  R
+	  wpas_dbus_getter_bss_ies,
+	  NULL
 	},
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
+	{ NULL, NULL, NULL, NULL, NULL }
 };
 
 
 static const struct wpa_dbus_signal_desc wpas_dbus_bss_signals[] = {
+	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
 	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_BSS,
 	  {
 		  { "properties", "a{sv}", ARG_OUT },
@@ -2165,6 +2270,15 @@
 		  END_ARGS
 	  }
 	},
+	{ "NetworkReply", WPAS_DBUS_NEW_IFACE_INTERFACE,
+	  (WPADBusMethodHandler) &wpas_dbus_handler_network_reply,
+	  {
+		  { "path", "o", ARG_IN },
+		  { "field", "s", ARG_IN },
+		  { "value", "s", ARG_IN },
+		  END_ARGS
+	  }
+	},
 	{ "AddBlob", WPAS_DBUS_NEW_IFACE_INTERFACE,
 	  (WPADBusMethodHandler) &wpas_dbus_handler_add_blob,
 	  {
@@ -2245,7 +2359,7 @@
 	  (WPADBusMethodHandler)wpas_dbus_handler_p2p_connect,
 	  {
 		  { "args", "a{sv}", ARG_IN },
-		  { "generated_pin", "i", ARG_OUT },
+		  { "generated_pin", "s", ARG_OUT },
 		  END_ARGS
 	  }
 	},
@@ -2378,108 +2492,102 @@
 
 static const struct wpa_dbus_property_desc wpas_dbus_interface_properties[] = {
 	{ "Capabilities", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_capabilities,
-	  NULL, R
+	  wpas_dbus_getter_capabilities,
+	  NULL
 	},
 	{ "State", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_state,
-	  NULL, R
+	  wpas_dbus_getter_state,
+	  NULL
 	},
 	{ "Scanning", WPAS_DBUS_NEW_IFACE_INTERFACE, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_scanning,
-	  NULL, R
+	  wpas_dbus_getter_scanning,
+	  NULL
 	},
 	{ "ApScan", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_ap_scan,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_ap_scan,
-	  RW
+	  wpas_dbus_getter_ap_scan,
+	  wpas_dbus_setter_ap_scan
 	},
 	{ "BSSExpireAge", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_expire_age,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_bss_expire_age,
-	  RW
+	  wpas_dbus_getter_bss_expire_age,
+	  wpas_dbus_setter_bss_expire_age
 	},
 	{ "BSSExpireCount", WPAS_DBUS_NEW_IFACE_INTERFACE, "u",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bss_expire_count,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_bss_expire_count,
-	  RW
+	  wpas_dbus_getter_bss_expire_count,
+	  wpas_dbus_setter_bss_expire_count
 	},
 	{ "Country", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_country,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_country,
-	  RW
+	  wpas_dbus_getter_country,
+	  wpas_dbus_setter_country
 	},
 	{ "Ifname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_ifname,
-	  NULL, R
+	  wpas_dbus_getter_ifname,
+	  NULL
 	},
 	{ "Driver", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_driver,
-	  NULL, R
+	  wpas_dbus_getter_driver,
+	  NULL
 	},
 	{ "BridgeIfname", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bridge_ifname,
-	  NULL, R
+	  wpas_dbus_getter_bridge_ifname,
+	  NULL
 	},
 	{ "CurrentBSS", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_current_bss,
-	  NULL, R
+	  wpas_dbus_getter_current_bss,
+	  NULL
 	},
 	{ "CurrentNetwork", WPAS_DBUS_NEW_IFACE_INTERFACE, "o",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_current_network,
-	  NULL, R
+	  wpas_dbus_getter_current_network,
+	  NULL
 	},
 	{ "CurrentAuthMode", WPAS_DBUS_NEW_IFACE_INTERFACE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_current_auth_mode,
-	  NULL, R
+	  wpas_dbus_getter_current_auth_mode,
+	  NULL
 	},
 	{ "Blobs", WPAS_DBUS_NEW_IFACE_INTERFACE, "a{say}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_blobs,
-	  NULL, R
+	  wpas_dbus_getter_blobs,
+	  NULL
 	},
 	{ "BSSs", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_bsss,
-	  NULL, R
+	  wpas_dbus_getter_bsss,
+	  NULL
 	},
 	{ "Networks", WPAS_DBUS_NEW_IFACE_INTERFACE, "ao",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_networks,
-	  NULL, R
+	  wpas_dbus_getter_networks,
+	  NULL
 	},
 #ifdef CONFIG_WPS
 	{ "ProcessCredentials", WPAS_DBUS_NEW_IFACE_WPS, "b",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_process_credentials,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_process_credentials,
-	  RW
+	  wpas_dbus_getter_process_credentials,
+	  wpas_dbus_setter_process_credentials
 	},
 #endif /* CONFIG_WPS */
 #ifdef CONFIG_P2P
 	{ "P2PDeviceProperties", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_device_properties,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_p2p_device_properties,
-	  RW
+	  wpas_dbus_getter_p2p_device_properties,
+	  wpas_dbus_setter_p2p_device_properties
 	},
 	{ "Peers", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peers,
-	  NULL, R
+	  wpas_dbus_getter_p2p_peers,
+	  NULL
 	},
 	{ "Role", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "s",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_role,
-	  NULL, R
+	  wpas_dbus_getter_p2p_role,
+	  NULL
 	},
 	{ "Group", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group,
-	  NULL, R
+	  wpas_dbus_getter_p2p_group,
+	  NULL
 	},
 	{ "PeerGO", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "o",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peergo,
-	  NULL, R
+	  wpas_dbus_getter_p2p_peergo,
+	  NULL
 	},
 	{ "PersistentGroups", WPAS_DBUS_NEW_IFACE_P2PDEVICE, "ao",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_persistent_groups,
-	  NULL, R
+	  wpas_dbus_getter_persistent_groups,
+	  NULL
 	},
 #endif /* CONFIG_P2P */
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
+	{ NULL, NULL, NULL, NULL, NULL }
 };
 
 static const struct wpa_dbus_signal_desc wpas_dbus_interface_signals[] = {
@@ -2533,6 +2641,7 @@
 		  END_ARGS
 	  }
 	},
+	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
 	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_INTERFACE,
 	  {
 		  { "properties", "a{sv}", ARG_OUT },
@@ -2553,6 +2662,7 @@
 		  END_ARGS
 	  }
 	},
+	/* Deprecated: use org.freedesktop.DBus.Properties.PropertiesChanged */
 	{ "PropertiesChanged", WPAS_DBUS_NEW_IFACE_WPS,
 	  {
 		  { "properties", "a{sv}", ARG_OUT },
@@ -2784,14 +2894,14 @@
 
 static const struct wpa_dbus_property_desc wpas_dbus_p2p_peer_properties[] = {
 	{ "Properties", WPAS_DBUS_NEW_IFACE_P2P_PEER, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peer_properties,
-	  NULL, R
+	  wpas_dbus_getter_p2p_peer_properties,
+	  NULL
 	},
 	{ "IEs", WPAS_DBUS_NEW_IFACE_P2P_PEER, "ay",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_peer_ies,
-	  NULL, R
+	  wpas_dbus_getter_p2p_peer_ies,
+	  NULL
 	},
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
+	{ NULL, NULL, NULL, NULL, NULL }
 };
 
 static const struct wpa_dbus_signal_desc wpas_dbus_p2p_peer_signals[] = {
@@ -2981,16 +3091,15 @@
 
 static const struct wpa_dbus_property_desc wpas_dbus_p2p_group_properties[] = {
 	{ "Members", WPAS_DBUS_NEW_IFACE_P2P_GROUP, "ao",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group_members,
-	  NULL, R
+	  wpas_dbus_getter_p2p_group_members,
+	  NULL
 	},
 	{ "Properties",
 	  WPAS_DBUS_NEW_IFACE_P2P_GROUP, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group_properties,
-	  (WPADBusPropertyAccessor) wpas_dbus_setter_p2p_group_properties,
-	  RW
+	  wpas_dbus_getter_p2p_group_properties,
+	  wpas_dbus_setter_p2p_group_properties
 	},
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
+	{ NULL, NULL, NULL, NULL, NULL }
 };
 
 static const struct wpa_dbus_signal_desc wpas_dbus_p2p_group_signals[] = {
@@ -3111,10 +3220,10 @@
 static const struct wpa_dbus_property_desc
 wpas_dbus_p2p_groupmember_properties[] = {
 	{ "Properties", WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER, "a{sv}",
-	  (WPADBusPropertyAccessor) wpas_dbus_getter_p2p_group_properties,
-	  NULL, R
+	  wpas_dbus_getter_p2p_group_properties,
+	  NULL
 	},
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
+	{ NULL, NULL, NULL, NULL, NULL }
 };
 
 /**
@@ -3218,13 +3327,10 @@
 static const struct wpa_dbus_property_desc
 	wpas_dbus_persistent_group_properties[] = {
 	{ "Properties", WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP, "a{sv}",
-	  (WPADBusPropertyAccessor)
 	  wpas_dbus_getter_persistent_group_properties,
-	  (WPADBusPropertyAccessor)
-	  wpas_dbus_setter_persistent_group_properties,
-	  RW
+	  wpas_dbus_setter_persistent_group_properties
 	},
-	{ NULL, NULL, NULL, NULL, NULL, 0 }
+	{ NULL, NULL, NULL, NULL, NULL }
 };
 
 /* No signals intended for persistent group objects */
diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h
index 080000c..93ce722 100644
--- a/wpa_supplicant/dbus/dbus_new.h
+++ b/wpa_supplicant/dbus/dbus_new.h
@@ -16,6 +16,7 @@
 #ifndef CTRL_IFACE_DBUS_NEW_H
 #define CTRL_IFACE_DBUS_NEW_H
 
+#include "common/defs.h"
 #include "p2p/p2p.h"
 
 struct wpa_global;
@@ -24,7 +25,6 @@
 struct wps_event_m2d;
 struct wps_event_fail;
 struct wps_credential;
-enum wpa_states;
 
 enum wpas_dbus_prop {
 	WPAS_DBUS_PROP_AP_SCAN,
@@ -131,6 +131,10 @@
 void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s,
 					      struct wpa_ssid *ssid);
 void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id);
+void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
+				      struct wpa_ssid *ssid,
+				      enum wpa_ctrl_req_type rtype,
+				      const char *default_text);
 void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success);
 void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
 			       const struct wps_credential *cred);
@@ -175,7 +179,8 @@
 					int client, int network_id);
 void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid);
-void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, int status);
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+				      struct p2p_go_neg_results *res);
 void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
 				    const struct wpa_ssid *ssid);
 int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
@@ -241,6 +246,12 @@
 {
 }
 
+static inline void wpas_dbus_signal_network_request(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+	enum wpa_ctrl_req_type rtype, const char *default_txt)
+{
+}
+
 static inline void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s,
 					      int success)
 {
@@ -375,7 +386,8 @@
 }
 
 static inline void
-wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s, int status)
+wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+				 struct p2p_go_neg_results *res)
 {
 }
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c
index ee8757a..e3526d4 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers.c
@@ -25,9 +25,9 @@
 #include "../wpa_supplicant_i.h"
 #include "../driver_i.h"
 #include "../notify.h"
-#include "../wpas_glue.h"
 #include "../bss.h"
 #include "../scan.h"
+#include "../ctrl_iface.h"
 #include "dbus_new_helpers.h"
 #include "dbus_new.h"
 #include "dbus_new_handlers.h"
@@ -163,36 +163,35 @@
 
 /**
  * set_network_properties - Set properties of a configured network
- * @message: Pointer to incoming dbus message
  * @wpa_s: wpa_supplicant structure for a network interface
  * @ssid: wpa_ssid structure for a configured network
  * @iter: DBus message iterator containing dictionary of network
  * properties to set.
- * Returns: NULL when succeed or DBus error on failure
+ * @error: On failure, an error describing the failure
+ * Returns: TRUE if the request succeeds, FALSE if it failed
  *
  * Sets network configuration with parameters given id DBus dictionary
  */
-DBusMessage * set_network_properties(DBusMessage *message,
-				     struct wpa_supplicant *wpa_s,
-				     struct wpa_ssid *ssid,
-				     DBusMessageIter *iter)
+dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid,
+				   DBusMessageIter *iter,
+				   DBusError *error)
 {
-
 	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
-	DBusMessage *reply = NULL;
 	DBusMessageIter	iter_dict;
+	char *value = NULL;
 
-	if (!wpa_dbus_dict_open_read(iter, &iter_dict))
-		return wpas_dbus_error_invalid_args(message, NULL);
+	if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
+		return FALSE;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-		char *value = NULL;
 		size_t size = 50;
 		int ret;
-		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
-			reply = wpas_dbus_error_invalid_args(message, NULL);
-			break;
-		}
+
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+			goto error;
+
+		value = NULL;
 		if (entry.type == DBUS_TYPE_ARRAY &&
 		    entry.array_type == DBUS_TYPE_BYTE) {
 			if (entry.array_len <= 0)
@@ -261,71 +260,59 @@
 
 		os_free(value);
 		wpa_dbus_dict_entry_clear(&entry);
-		continue;
-
-	error:
-		os_free(value);
-		reply = wpas_dbus_error_invalid_args(message, entry.key);
-		wpa_dbus_dict_entry_clear(&entry);
-		break;
 	}
 
-	return reply;
+	return TRUE;
+
+error:
+	os_free(value);
+	wpa_dbus_dict_entry_clear(&entry);
+	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+			     "invalid message format");
+	return FALSE;
 }
 
 
 /**
  * wpas_dbus_simple_property_getter - Get basic type property
- * @message: Pointer to incoming dbus message
+ * @iter: Message iter to use when appending arguments
  * @type: DBus type of property (must be basic type)
  * @val: pointer to place holding property value
- * Returns: The DBus message containing response for Properties.Get call
- * or DBus error message if error occurred.
+ * @error: On failure an error describing the failure
+ * Returns: TRUE if the request was successful, FALSE if it failed
  *
  * Generic getter for basic type properties. Type is required to be basic.
  */
-DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message,
-					       const int type, const void *val)
+dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
+					     const int type,
+					     const void *val,
+					     DBusError *error)
 {
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, variant_iter;
+	DBusMessageIter variant_iter;
 
 	if (!dbus_type_is_basic(type)) {
-		wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:"
-			   " given type is not basic");
-		return wpas_dbus_error_unknown_error(message, NULL);
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: given type is not basic", __func__);
+		return FALSE;
 	}
 
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+	                                      wpa_dbus_type_as_string(type),
+	                                      &variant_iter))
+		goto error;
 
-	if (reply != NULL) {
-		dbus_message_iter_init_append(reply, &iter);
-		if (!dbus_message_iter_open_container(
-			    &iter, DBUS_TYPE_VARIANT,
-			    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)) {
-			wpa_printf(MSG_ERROR, "dbus: "
-				   "wpas_dbus_simple_property_getter: out of "
-				   "memory to put property value into "
-				   "message");
-			dbus_message_unref(reply);
-			reply = dbus_message_new_error(message,
-						       DBUS_ERROR_NO_MEMORY,
-						       NULL);
-		}
-	} else {
-		wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_getter:"
-			   " out of memory to return property value");
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-	}
+	if (!dbus_message_iter_append_basic(&variant_iter, type, val))
+		goto error;
 
-	return reply;
+	if (!dbus_message_iter_close_container(iter, &variant_iter))
+		goto error;
+
+	return TRUE;
+
+error:
+	dbus_set_error(error, DBUS_ERROR_FAILED,
+	               "%s: error constructing reply", __func__);
+	return FALSE;
 }
 
 
@@ -334,102 +321,79 @@
  * @message: Pointer to incoming dbus message
  * @type: DBus type of property (must be basic type)
  * @val: pointer to place where value being set will be stored
- * Returns: NULL or DBus error message if error occurred.
+ * Returns: TRUE if the request was successful, FALSE if it failed
  *
  * Generic setter for basic type properties. Type is required to be basic.
  */
-DBusMessage * wpas_dbus_simple_property_setter(DBusMessage *message,
-					       const int type, void *val)
+dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
+					     DBusError *error,
+					     const int type, void *val)
 {
-	DBusMessageIter iter, variant_iter;
+	DBusMessageIter variant_iter;
 
 	if (!dbus_type_is_basic(type)) {
-		wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:"
-			   " given type is not basic");
-		return wpas_dbus_error_unknown_error(message, NULL);
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: given type is not basic", __func__);
+		return FALSE;
 	}
 
-	if (!dbus_message_iter_init(message, &iter)) {
-		wpa_printf(MSG_ERROR, "dbus: wpas_dbus_simple_property_setter:"
-			   " out of memory to return scanning state");
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-	}
-
-	/* omit first and second argument and get value from third */
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_recurse(&iter, &variant_iter);
-
+	/* Look at the new value */
+	dbus_message_iter_recurse(iter, &variant_iter);
 	if (dbus_message_iter_get_arg_type(&variant_iter) != type) {
-		wpa_printf(MSG_DEBUG, "dbus: wpas_dbus_simple_property_setter:"
-			   " wrong property type");
-		return wpas_dbus_error_invalid_args(message,
-						    "wrong property type");
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "wrong property type");
+		return FALSE;
 	}
 	dbus_message_iter_get_basic(&variant_iter, val);
 
-	return NULL;
+	return TRUE;
 }
 
 
 /**
  * wpas_dbus_simple_array_property_getter - Get array type property
- * @message: Pointer to incoming dbus message
+ * @iter: Pointer to incoming dbus message iterator
  * @type: DBus type of property array elements (must be basic type)
  * @array: pointer to array of elements to put into response message
  * @array_len: length of above array
- * Returns: The DBus message containing response for Properties.Get call
- * or DBus error message if error occurred.
+ * @error: a pointer to an error to fill on failure
+ * Returns: TRUE if the request succeeded, FALSE if it failed
  *
  * Generic getter for array type properties. Array elements type is
  * required to be basic.
  */
-DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message,
-						     const int type,
-						     const void *array,
-						     size_t array_len)
+dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
+						   const int type,
+						   const void *array,
+						   size_t array_len,
+						   DBusError *error)
 {
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, variant_iter, array_iter;
+	DBusMessageIter variant_iter, array_iter;
 	char type_str[] = "a?"; /* ? will be replaced with subtype letter; */
 	const char *sub_type_str;
 	size_t element_size, i;
 
 	if (!dbus_type_is_basic(type)) {
-		wpa_printf(MSG_ERROR, "dbus: "
-			   "wpas_dbus_simple_array_property_getter: given "
-			   "type is not basic");
-		return wpas_dbus_error_unknown_error(message, NULL);
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: given type is not basic", __func__);
+		return FALSE;
 	}
 
 	sub_type_str = wpa_dbus_type_as_string(type);
 	type_str[1] = sub_type_str[0];
 
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-	if (reply == NULL) {
-		wpa_printf(MSG_ERROR, "dbus: "
-			   "wpas_dbus_simple_array_property_getter: out of "
-			   "memory to create return message");
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+	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;
 	}
 
-	dbus_message_iter_init_append(reply, &iter);
-
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-					      type_str, &variant_iter) ||
-	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
+	if (!dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
 					      sub_type_str, &array_iter)) {
-		wpa_printf(MSG_ERROR, "dbus: "
-			   "wpas_dbus_simple_array_property_getter: out of "
-			   "memory to open container");
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: failed to construct message 2", __func__);
+		return FALSE;
 	}
 
 	switch(type) {
@@ -457,11 +421,9 @@
 		element_size = sizeof(char *);
 		break;
 	default:
-		wpa_printf(MSG_ERROR, "dbus: "
-			   "wpas_dbus_simple_array_property_getter: "
-			   "fatal: unknown element type");
-		element_size = 1;
-		break;
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: unknown element type %d", __func__, type);
+		return FALSE;
 	}
 
 	for (i = 0; i < array_len; i++) {
@@ -469,17 +431,19 @@
 					       array + i * element_size);
 	}
 
-	if (!dbus_message_iter_close_container(&variant_iter, &array_iter) ||
-	    !dbus_message_iter_close_container(&iter, &variant_iter)) {
-		wpa_printf(MSG_ERROR, "dbus: "
-			   "wpas_dbus_simple_array_property_getter: out of "
-			   "memory to close container");
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+	if (!dbus_message_iter_close_container(&variant_iter, &array_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: failed to construct message 3", __func__);
+		return FALSE;
 	}
 
-	return reply;
+	if (!dbus_message_iter_close_container(iter, &variant_iter)) {
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+		               "%s: failed to construct message 4", __func__);
+		return FALSE;
+	}
+
+	return TRUE;
 }
 
 
@@ -508,7 +472,7 @@
 
 	dbus_message_iter_init(message, &iter);
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto error;
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
@@ -612,7 +576,7 @@
 	wpa_s = get_iface_by_dbus_path(global, path);
 	if (wpa_s == NULL)
 		reply = wpas_dbus_error_iface_unknown(message);
-	else if (wpa_supplicant_remove_iface(global, wpa_s, 0)) {
+	else if (wpa_supplicant_remove_iface(global, wpa_s)) {
 		reply = wpas_dbus_error_unknown_error(
 			message, "wpa_supplicant couldn't remove this "
 			"interface.");
@@ -664,79 +628,86 @@
 
 /**
  * wpas_dbus_getter_debug_level - Get debug level
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug level
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "DebugLevel" property.
  */
-DBusMessage * wpas_dbus_getter_debug_level(DBusMessage *message,
-					   struct wpa_global *global)
+dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
+					 DBusError *error,
+					 void *user_data)
 {
 	const char *str;
 	int idx = wpa_debug_level;
+
 	if (idx < 0)
 		idx = 0;
 	if (idx > 5)
 		idx = 5;
 	str = debug_strings[idx];
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&str);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&str, error);
 }
 
 
 /**
  * wpas_dbus_getter_debug_timestamp - Get debug timestamp
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug timestamp
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "DebugTimestamp" property.
  */
-DBusMessage * wpas_dbus_getter_debug_timestamp(DBusMessage *message,
-					       struct wpa_global *global)
+dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
+                                             DBusError *error,
+                                             void *user_data)
 {
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&wpa_debug_timestamp);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&wpa_debug_timestamp, error);
 
 }
 
 
 /**
  * wpas_dbus_getter_debug_show_keys - Get debug show keys
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: DBus message with value of debug show_keys
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "DebugShowKeys" property.
  */
-DBusMessage * wpas_dbus_getter_debug_show_keys(DBusMessage *message,
-					       struct wpa_global *global)
+dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data)
 {
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&wpa_debug_show_keys);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&wpa_debug_show_keys, error);
 
 }
 
 /**
  * wpas_dbus_setter_debug_level - Set debug level
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "DebugLevel" property.
  */
-DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message,
-					   struct wpa_global *global)
+dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
+					 DBusError *error, void *user_data)
 {
-	DBusMessage *reply;
+	struct wpa_global *global = user_data;
 	const char *str = NULL;
 	int i, val = -1;
 
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_STRING,
-						 &str);
-	if (reply)
-		return reply;
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+					      &str))
+		return FALSE;
 
 	for (i = 0; debug_strings[i]; i++)
 		if (os_strcmp(debug_strings[i], str) == 0) {
@@ -747,137 +718,142 @@
 	if (val < 0 ||
 	    wpa_supplicant_set_debug_params(global, val, wpa_debug_timestamp,
 					    wpa_debug_show_keys)) {
-		return wpas_dbus_error_invalid_args(
-			message, "Wrong debug level value");
+		dbus_set_error_const(error, DBUS_ERROR_FAILED, "wrong debug "
+				     "level value");
+		return FALSE;
 	}
 
-	return NULL;
+	return TRUE;
 }
 
 
 /**
  * wpas_dbus_setter_debug_timestamp - Set debug timestamp
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "DebugTimestamp" property.
  */
-DBusMessage * wpas_dbus_setter_debug_timestamp(DBusMessage *message,
-					       struct wpa_global *global)
+dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data)
 {
-	DBusMessage *reply;
+	struct wpa_global *global = user_data;
 	dbus_bool_t val;
 
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-						 &val);
-	if (reply)
-		return reply;
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+					      &val))
+		return FALSE;
 
 	wpa_supplicant_set_debug_params(global, wpa_debug_level, val ? 1 : 0,
 					wpa_debug_show_keys);
-
-	return NULL;
+	return TRUE;
 }
 
 
 /**
  * wpas_dbus_setter_debug_show_keys - Set debug show keys
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: %NULL or DBus error message
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "DebugShowKeys" property.
  */
-DBusMessage * wpas_dbus_setter_debug_show_keys(DBusMessage *message,
-					       struct wpa_global *global)
+dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data)
 {
-	DBusMessage *reply;
+	struct wpa_global *global = user_data;
 	dbus_bool_t val;
 
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-						 &val);
-	if (reply)
-		return reply;
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+					      &val))
+		return FALSE;
 
 	wpa_supplicant_set_debug_params(global, wpa_debug_level,
 					wpa_debug_timestamp,
 					val ? 1 : 0);
-
-	return NULL;
+	return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_interfaces - Request registered interfaces list
- * @message: Pointer to incoming dbus message
- * @global: %wpa_supplicant global data structure
- * Returns: The object paths array containing registered interfaces
- * objects paths or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Interfaces" property. Handles requests
  * by dbus clients to return list of registered interfaces objects
  * paths
  */
-DBusMessage * wpas_dbus_getter_interfaces(DBusMessage *message,
-					  struct wpa_global *global)
+dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
+					DBusError *error,
+					void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_global *global = user_data;
 	struct wpa_supplicant *wpa_s;
 	const char **paths;
 	unsigned int i = 0, num = 0;
+	dbus_bool_t success;
 
 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
 		num++;
 
 	paths = os_zalloc(num * sizeof(char*));
 	if (!paths) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
 	}
 
 	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
 		paths[i++] = wpa_s->dbus_new_path;
 
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_OBJECT_PATH,
-						       paths, num);
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 paths, num, error);
 
 	os_free(paths);
-	return reply;
+	return success;
 }
 
 
 /**
  * wpas_dbus_getter_eap_methods - Request supported EAP methods list
- * @message: Pointer to incoming dbus message
- * @nothing: not used argument. may be NULL or anything else
- * Returns: The object paths array containing supported EAP methods
- * represented by strings or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "EapMethods" property. Handles requests
  * by dbus clients to return list of strings with supported EAP methods
  */
-DBusMessage * wpas_dbus_getter_eap_methods(DBusMessage *message, void *nothing)
+dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
+					 DBusError *error, void *user_data)
 {
-	DBusMessage *reply = NULL;
 	char **eap_methods;
 	size_t num_items = 0;
+	dbus_bool_t success;
 
 	eap_methods = eap_get_names_as_string_array(&num_items);
 	if (!eap_methods) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
 	}
 
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_STRING,
-						       eap_methods, num_items);
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_STRING,
+							 eap_methods,
+							 num_items, error);
 
 	while (num_items)
 		os_free(eap_methods[--num_items]);
 	os_free(eap_methods);
-	return reply;
+	return success;
 }
 
 
@@ -1288,6 +1264,7 @@
 	DBusMessageIter	iter;
 	struct wpa_ssid *ssid = NULL;
 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
+	DBusError error;
 
 	dbus_message_iter_init(message, &iter);
 
@@ -1305,11 +1282,15 @@
 	ssid->disabled = 1;
 	wpa_config_set_network_defaults(ssid);
 
-	reply = set_network_properties(message, wpa_s, ssid, &iter);
-	if (reply) {
+	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");
+		reply = wpas_dbus_reply_new_from_error(message, &error,
+						       DBUS_ERROR_INVALID_ARGS,
+						       "Failed to add network");
+		dbus_error_free(&error);
 		goto err;
 	}
 
@@ -1493,6 +1474,70 @@
 
 
 /**
+ * wpas_dbus_handler_network_reply - Reply to a NetworkRequest signal
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "NetworkReply" method call of network interface.
+ */
+DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s)
+{
+#ifdef IEEE8021X_EAPOL
+	DBusMessage *reply = NULL;
+	const char *op, *field, *value;
+	char *iface = NULL, *net_id = NULL;
+	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))
+		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);
+	if (iface == NULL || os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+		reply = wpas_dbus_error_invalid_args(message, op);
+		goto out;
+	}
+
+	id = strtoul(net_id, NULL, 10);
+	if (errno == EINVAL) {
+		reply = wpas_dbus_error_invalid_args(message, net_id);
+		goto out;
+	}
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		reply = wpas_dbus_error_network_unknown(message);
+		goto out;
+	}
+
+	if (wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid,
+						      field, value) < 0)
+		reply = wpas_dbus_error_invalid_args(message, field);
+	else {
+		/* Tell EAP to retry immediately */
+		eapol_sm_notify_ctrl_response(wpa_s->eapol);
+	}
+
+out:
+	os_free(iface);
+	os_free(net_id);
+	return reply;
+#else /* IEEE8021X_EAPOL */
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
+	return wpas_dbus_error_unknown_error(message, "802.1X not included");
+#endif /* IEEE8021X_EAPOL */
+}
+
+
+/**
  * wpas_dbus_handler_add_blob - Store named binary blob (ie, for certificates)
  * @message: Pointer to incoming dbus message
  * @wpa_s: %wpa_supplicant data structure
@@ -1683,32 +1728,24 @@
 
 /**
  * wpas_dbus_getter_capabilities - Return interface capabilities
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a dict of strings
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Capabilities" property of an interface.
  */
-DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
-					    struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
+					  DBusError *error, void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	struct wpa_driver_capa capa;
 	int res;
-	DBusMessageIter iter, iter_dict;
-	DBusMessageIter iter_dict_entry, iter_dict_val, iter_array,
+	DBusMessageIter iter_dict, iter_dict_entry, iter_dict_val, iter_array,
 		variant_iter;
 	const char *scans[] = { "active", "passive", "ssid" };
 
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-	if (!reply)
-		goto nomem;
-
-	dbus_message_iter_init_append(reply, &iter);
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
 					      "a{sv}", &variant_iter))
 		goto nomem;
 
@@ -2004,36 +2041,43 @@
 		goto nomem;
 	/***** Modes end */
 
+	if (res >= 0) {
+		dbus_int32_t max_scan_ssid = capa.max_scan_ssids;
+
+		if (!wpa_dbus_dict_append_int32(&iter_dict, "MaxScanSSID",
+						max_scan_ssid))
+			goto nomem;
+	}
+
 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
 		goto nomem;
-	if (!dbus_message_iter_close_container(&iter, &variant_iter))
+	if (!dbus_message_iter_close_container(iter, &variant_iter))
 		goto nomem;
 
-	return reply;
+	return TRUE;
 
 nomem:
-	if (reply)
-		dbus_message_unref(reply);
-
-	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	return FALSE;
 }
 
 
 /**
  * wpas_dbus_getter_state - Get interface state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a STRING representing the current
- *          interface state
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "State" property.
  */
-DBusMessage * wpas_dbus_getter_state(DBusMessage *message,
-				     struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
+				   void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	const char *str_state;
 	char *state_ls, *tmp;
+	dbus_bool_t success = FALSE;
 
 	str_state = wpa_supplicant_state_txt(wpa_s->wpa_state);
 
@@ -2041,183 +2085,204 @@
 	 */
 	state_ls = tmp = os_strdup(str_state);
 	if (!tmp) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
 	}
 	while (*tmp) {
 		*tmp = tolower(*tmp);
 		tmp++;
 	}
 
-	reply = wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						 &state_ls);
+	success = wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						   &state_ls, error);
 
 	os_free(state_ls);
 
-	return reply;
+	return success;
 }
 
 
 /**
  * wpas_dbus_new_iface_get_scanning - Get interface scanning state
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing whether the interface is scanning
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "scanning" property.
  */
-DBusMessage * wpas_dbus_getter_scanning(DBusMessage *message,
-					struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
+                                      void *user_data)
 {
+	struct wpa_supplicant *wpa_s = user_data;
 	dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&scanning);
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&scanning, error);
 }
 
 
 /**
  * wpas_dbus_getter_ap_scan - Control roaming mode
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A message containong value of ap_scan variable
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter function for "ApScan" property.
  */
-DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
 {
+	struct wpa_supplicant *wpa_s = user_data;
 	dbus_uint32_t ap_scan = wpa_s->conf->ap_scan;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32,
-						&ap_scan);
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+						&ap_scan, error);
 }
 
 
 /**
  * wpas_dbus_setter_ap_scan - Control roaming mode
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter function for "ApScan" property.
  */
-DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	dbus_uint32_t ap_scan;
 
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32,
-						 &ap_scan);
-	if (reply)
-		return reply;
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
+					      &ap_scan))
+		return FALSE;
 
 	if (wpa_supplicant_set_ap_scan(wpa_s, ap_scan)) {
-		return wpas_dbus_error_invalid_args(
-			message, "ap_scan must equal 0, 1 or 2");
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "ap_scan must be 0, 1, or 2");
+		return FALSE;
 	}
-	return NULL;
+	return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_bss_expire_age - Get BSS entry expiration age
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A message containing value of bss_expiration_age variable
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter function for "BSSExpireAge" property.
  */
-DBusMessage * wpas_dbus_getter_bss_expire_age(DBusMessage *message,
-					      struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
+					    DBusError *error,
+					    void *user_data)
 {
+	struct wpa_supplicant *wpa_s = user_data;
 	dbus_uint32_t expire_age = wpa_s->conf->bss_expiration_age;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32,
-						&expire_age);
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+						&expire_age, error);
 }
 
 
 /**
  * wpas_dbus_setter_bss_expire_age - Control BSS entry expiration age
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter function for "BSSExpireAge" property.
  */
-DBusMessage * wpas_dbus_setter_bss_expire_age(DBusMessage *message,
-					      struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
+					    DBusError *error,
+					    void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	dbus_uint32_t expire_age;
 
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32,
-						 &expire_age);
-	if (reply)
-		return reply;
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
+					      &expire_age))
+		return FALSE;
 
 	if (wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age)) {
-		return wpas_dbus_error_invalid_args(
-			message, "BSSExpireAge must be >=10");
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "BSSExpireAge must be >= 10");
+		return FALSE;
 	}
-	return NULL;
+	return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_bss_expire_count - Get BSS entry expiration scan count
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A message containing value of bss_expire_count variable
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter function for "BSSExpireCount" property.
  */
-DBusMessage * wpas_dbus_getter_bss_expire_count(DBusMessage *message,
-						struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
+					      DBusError *error,
+					      void *user_data)
 {
+	struct wpa_supplicant *wpa_s = user_data;
 	dbus_uint32_t expire_count = wpa_s->conf->bss_expiration_age;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT32,
-						&expire_count);
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT32,
+						&expire_count, error);
 }
 
 
 /**
  * wpas_dbus_setter_bss_expire_count - Control BSS entry expiration scan count
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter function for "BSSExpireCount" property.
  */
-DBusMessage * wpas_dbus_setter_bss_expire_count(DBusMessage *message,
-						struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
+					      DBusError *error,
+					      void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	dbus_uint32_t expire_count;
 
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_UINT32,
-						 &expire_count);
-	if (reply)
-		return reply;
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_UINT32,
+					      &expire_count))
+		return FALSE;
 
 	if (wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count)) {
-		return wpas_dbus_error_invalid_args(
-			message, "BSSExpireCount must be >0");
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "BSSExpireCount must be > 0");
+		return FALSE;
 	}
-	return NULL;
+	return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_country - Control country code
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A message containong value of country variable
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter function for "Country" property.
  */
-DBusMessage * wpas_dbus_getter_country(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
 {
+	struct wpa_supplicant *wpa_s = user_data;
 	char country[3];
 	char *str = country;
 
@@ -2225,103 +2290,112 @@
 	country[1] = wpa_s->conf->country[1];
 	country[2] = '\0';
 
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&str);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&str, error);
 }
 
 
 /**
  * wpas_dbus_setter_country - Control country code
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: NULL
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter function for "Country" property.
  */
-DBusMessage * wpas_dbus_setter_country(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	const char *country;
 
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_STRING,
-						 &country);
-	if (reply)
-		return reply;
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_STRING,
+					      &country))
+		return FALSE;
 
-	if (!country[0] || !country[1])
-		return wpas_dbus_error_invalid_args(message,
-						    "invalid country code");
+	if (!country[0] || !country[1]) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "invalid country code");
+		return FALSE;
+	}
 
 	if (wpa_s->drv_priv != NULL && wpa_drv_set_country(wpa_s, country)) {
 		wpa_printf(MSG_DEBUG, "Failed to set country");
-		return wpas_dbus_error_invalid_args(
-			message, "failed to set country code");
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "failed to set country code");
+		return FALSE;
 	}
 
 	wpa_s->conf->country[0] = country[0];
 	wpa_s->conf->country[1] = country[1];
-	return NULL;
+	return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_ifname - Get interface name
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of network interface
- * associated with with wpa_s
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Ifname" property.
  */
-DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
+				    void *user_data)
 {
+	struct wpa_supplicant *wpa_s = user_data;
 	const char *ifname = wpa_s->ifname;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&ifname);
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&ifname, error);
 }
 
 
 /**
  * wpas_dbus_getter_driver - Get interface name
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of network interface
- * driver associated with with wpa_s
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Driver" property.
  */
-DBusMessage * wpas_dbus_getter_driver(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
+				    void *user_data)
 {
+	struct wpa_supplicant *wpa_s = user_data;
 	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");
-		return wpas_dbus_error_unknown_error(message, NULL);
+		dbus_set_error(error, DBUS_ERROR_FAILED, "%s: no driver set",
+			       __func__);
+		return FALSE;
 	}
 
 	driver = wpa_s->driver->name;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&driver);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&driver, error);
 }
 
 
 /**
  * wpas_dbus_getter_current_bss - Get current bss object path
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a DBus object path to
- * current BSS
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "CurrentBSS" property.
  */
-DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
+					 DBusError *error,
+					 void *user_data)
 {
-	DBusMessage *reply;
+	struct wpa_supplicant *wpa_s = user_data;
 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *bss_obj_path = path_buf;
 
 	if (wpa_s->current_bss)
@@ -2331,27 +2405,25 @@
 	else
 		os_snprintf(bss_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
 
-	reply = wpas_dbus_simple_property_getter(message,
-						 DBUS_TYPE_OBJECT_PATH,
-						 &bss_obj_path);
-
-	return reply;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+						&bss_obj_path, error);
 }
 
 
 /**
  * wpas_dbus_getter_current_network - Get current network object path
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a DBus object path to
- * current network
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "CurrentNetwork" property.
  */
-DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message,
-					       struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data)
 {
-	DBusMessage *reply;
+	struct wpa_supplicant *wpa_s = user_data;
 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *net_obj_path = path_buf;
 
 	if (wpa_s->current_ssid)
@@ -2361,27 +2433,25 @@
 	else
 		os_snprintf(net_obj_path, WPAS_DBUS_OBJECT_PATH_MAX, "/");
 
-	reply = wpas_dbus_simple_property_getter(message,
-						 DBUS_TYPE_OBJECT_PATH,
-						 &net_obj_path);
-
-	return reply;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+						&net_obj_path, error);
 }
 
 
 /**
  * wpas_dbus_getter_current_auth_mode - Get current authentication type
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a string indicating the current
- * authentication type.
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "CurrentAuthMode" property.
  */
-DBusMessage * wpas_dbus_getter_current_auth_mode(DBusMessage *message,
-						 struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data)
 {
-	DBusMessage *reply;
+	struct wpa_supplicant *wpa_s = user_data;
 	const char *eap_mode;
 	const char *auth_mode;
 	char eap_mode_buf[WPAS_DBUS_AUTH_MODE_MAX];
@@ -2400,70 +2470,61 @@
 					     wpa_s->current_ssid->proto);
 	}
 
-	reply = wpas_dbus_simple_property_getter(message,
-						 DBUS_TYPE_STRING,
-						 &auth_mode);
-
-	return reply;
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&auth_mode, error);
 }
 
 
 /**
  * wpas_dbus_getter_bridge_ifname - Get interface name
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: A dbus message containing a name of bridge network
- * interface associated with with wpa_s
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "BridgeIfname" property.
  */
-DBusMessage * wpas_dbus_getter_bridge_ifname(DBusMessage *message,
-					     struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
+					   DBusError *error,
+					   void *user_data)
 {
-	const char *bridge_ifname = NULL;
-
-	bridge_ifname = wpa_s->bridge_ifname;
-	if (bridge_ifname == NULL) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bridge_ifname[dbus]: "
-			   "wpa_s has no bridge interface name set");
-		return wpas_dbus_error_unknown_error(message, NULL);
-	}
-
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&bridge_ifname);
+	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);
 }
 
 
 /**
  * wpas_dbus_getter_bsss - Get array of BSSs objects
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing an array of all known BSS objects
- * dbus paths
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "BSSs" property.
  */
-DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message,
-				    struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
+				  void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	struct wpa_bss *bss;
 	char **paths;
 	unsigned int i = 0;
+	dbus_bool_t success = FALSE;
 
 	paths = os_zalloc(wpa_s->num_bss * sizeof(char *));
 	if (!paths) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
 	}
 
 	/* Loop through scan results and append each result's object path */
 	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
 		if (paths[i] == NULL) {
-			reply = dbus_message_new_error(message,
-						       DBUS_ERROR_NO_MEMORY,
-						       NULL);
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+					     "no memory");
 			goto out;
 		}
 		/* Construct the object path for this BSS. */
@@ -2472,39 +2533,43 @@
 			    wpa_s->dbus_new_path, bss->id);
 	}
 
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_OBJECT_PATH,
-						       paths, wpa_s->num_bss);
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 paths, wpa_s->num_bss,
+							 error);
 
 out:
 	while (i)
 		os_free(paths[--i]);
 	os_free(paths);
-	return reply;
+	return success;
 }
 
 
 /**
  * wpas_dbus_getter_networks - Get array of networks objects
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing an array of all configured
- * networks dbus object paths.
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Networks" property.
  */
-DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
-					struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
+				      void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	struct wpa_ssid *ssid;
 	char **paths;
 	unsigned int i = 0, num = 0;
+	dbus_bool_t success = FALSE;
 
 	if (wpa_s->conf == NULL) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_networks[dbus]: "
-			   "An error occurred getting networks list.");
-		return wpas_dbus_error_unknown_error(message, 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)
@@ -2513,8 +2578,8 @@
 
 	paths = os_zalloc(num * sizeof(char *));
 	if (!paths) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
 	}
 
 	/* Loop through configured networks and append object path of each */
@@ -2523,9 +2588,7 @@
 			continue;
 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
 		if (paths[i] == NULL) {
-			reply = dbus_message_new_error(message,
-						       DBUS_ERROR_NO_MEMORY,
-						       NULL);
+			dbus_set_error(error, DBUS_ERROR_NO_MEMORY, "no memory");
 			goto out;
 		}
 
@@ -2535,50 +2598,40 @@
 			    wpa_s->dbus_new_path, ssid->id);
 	}
 
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_OBJECT_PATH,
-						       paths, num);
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 paths, num, error);
 
 out:
 	while (i)
 		os_free(paths[--i]);
 	os_free(paths);
-	return reply;
+	return success;
 }
 
 
 /**
  * wpas_dbus_getter_blobs - Get all blobs defined for this interface
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing a dictionary of pairs (blob_name, blob)
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Blobs" property.
  */
-DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message,
-				     struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
+				   void *user_data)
 {
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, variant_iter, dict_iter, entry_iter, array_iter;
+	struct wpa_supplicant *wpa_s = user_data;
+	DBusMessageIter variant_iter, dict_iter, entry_iter, array_iter;
 	struct wpa_config_blob *blob;
 
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-	if (!reply)
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
-
-	dbus_message_iter_init_append(reply, &iter);
-
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
 					      "a{say}", &variant_iter) ||
 	    !dbus_message_iter_open_container(&variant_iter, DBUS_TYPE_ARRAY,
 					      "{say}", &dict_iter)) {
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
 	}
 
 	blob = wpa_s->conf->blobs;
@@ -2601,176 +2654,192 @@
 						       &array_iter) ||
 		    !dbus_message_iter_close_container(&dict_iter,
 						       &entry_iter)) {
-			dbus_message_unref(reply);
-			return dbus_message_new_error(message,
-						      DBUS_ERROR_NO_MEMORY,
-						      NULL);
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+					     "no memory");
+			return FALSE;
 		}
 
 		blob = blob->next;
 	}
 
 	if (!dbus_message_iter_close_container(&variant_iter, &dict_iter) ||
-	    !dbus_message_iter_close_container(&iter, &variant_iter)) {
-		dbus_message_unref(reply);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
 	}
 
-	return reply;
+	return TRUE;
+}
+
+
+static struct wpa_bss * get_bss_helper(struct bss_handler_args *args,
+				       DBusError *error, const char *func_name)
+{
+	struct wpa_bss *res = wpa_bss_get_id(args->wpa_s, args->id);
+
+	if (!res) {
+		wpa_printf(MSG_ERROR, "%s[dbus]: no bss with id %d found",
+		           func_name, args->id);
+		dbus_set_error(error, DBUS_ERROR_FAILED,
+			       "%s: BSS %d not found",
+			       func_name, args->id);
+	}
+
+	return res;
 }
 
 
 /**
  * wpas_dbus_getter_bss_bssid - Return the BSSID of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the bssid for the requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "BSSID" property.
  */
-DBusMessage * wpas_dbus_getter_bss_bssid(DBusMessage *message,
-					 struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
+				       void *user_data)
 {
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
 
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_bssid[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
 
-	return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-						      res->bssid, ETH_ALEN);
+	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+						      res->bssid, ETH_ALEN,
+						      error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_ssid - Return the SSID of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the ssid for the requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "SSID" property.
  */
-DBusMessage * wpas_dbus_getter_bss_ssid(DBusMessage *message,
-					      struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
+				      void *user_data)
 {
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
 
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ssid[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
 
-	return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-						      res->ssid,
-						      res->ssid_len);
+	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+						      res->ssid, res->ssid_len,
+						      error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_privacy - Return the privacy flag of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the privacy flag value of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Privacy" property.
  */
-DBusMessage * wpas_dbus_getter_bss_privacy(DBusMessage *message,
-					   struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
+					 DBusError *error, void *user_data)
 {
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
 	dbus_bool_t privacy;
 
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_privacy[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
 
 	privacy = (res->caps & IEEE80211_CAP_PRIVACY) ? TRUE : FALSE;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&privacy);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&privacy, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_mode - Return the mode of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the mode of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Mode" property.
  */
-DBusMessage * wpas_dbus_getter_bss_mode(DBusMessage *message,
-					struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
+				      void *user_data)
 {
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
 	const char *mode;
 
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_mode[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
 
 	if (res->caps & IEEE80211_CAP_IBSS)
 		mode = "ad-hoc";
 	else
 		mode = "infrastructure";
 
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&mode);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING,
+						&mode, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_level - Return the signal strength of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the signal strength of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Level" property.
  */
-DBusMessage * wpas_dbus_getter_bss_signal(DBusMessage *message,
-					  struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
+					DBusError *error, void *user_data)
 {
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
 
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_signal[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
 
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_INT16,
-						&res->level);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_INT16,
+						&res->level, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_frequency - Return the frequency of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the frequency of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Frequency" property.
  */
-DBusMessage * wpas_dbus_getter_bss_frequency(DBusMessage *message,
-					     struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
+					   DBusError *error, void *user_data)
 {
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
 
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_frequency[dbus]: "
-			   "no bss with id %d found", bss->id);
-		return NULL;
-	}
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
 
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_UINT16,
-						&res->freq);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_UINT16,
+						&res->freq, error);
 }
 
 
@@ -2782,72 +2851,64 @@
 
 /**
  * wpas_dbus_getter_bss_rates - Return available bit rates of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing sorted array of bit rates
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Rates" property.
  */
-DBusMessage * wpas_dbus_getter_bss_rates(DBusMessage *message,
-					    struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
+				       DBusError *error, void *user_data)
 {
-	DBusMessage *reply;
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
 	u8 *ie_rates = NULL;
 	u32 *real_rates;
 	int rates_num, i;
+	dbus_bool_t success = FALSE;
 
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rates[dbus]: "
-			   "no bss with id %d found", bss->id);
-		return NULL;
-	}
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
 
 	rates_num = wpa_bss_get_bit_rates(res, &ie_rates);
 	if (rates_num < 0)
-		return NULL;
+		return FALSE;
 
 	qsort(ie_rates, rates_num, 1, cmp_u8s_desc);
 
 	real_rates = os_malloc(sizeof(u32) * rates_num);
 	if (!real_rates) {
 		os_free(ie_rates);
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
 	}
 
 	for (i = 0; i < rates_num; i++)
 		real_rates[i] = ie_rates[i] * 500000;
 
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_UINT32,
-						       real_rates, rates_num);
+	success = wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_UINT32,
+							 real_rates, rates_num,
+							 error);
 
 	os_free(ie_rates);
 	os_free(real_rates);
-	return reply;
+	return success;
 }
 
 
-static DBusMessage * wpas_dbus_get_bss_security_prop(
-	DBusMessage *message, struct wpa_ie_data *ie_data)
+static dbus_bool_t wpas_dbus_get_bss_security_prop(DBusMessageIter *iter,
+						   struct wpa_ie_data *ie_data,
+						   DBusError *error)
 {
-	DBusMessage *reply;
-	DBusMessageIter iter, iter_dict, variant_iter;
+	DBusMessageIter iter_dict, variant_iter;
 	const char *group;
 	const char *pairwise[2]; /* max 2 pairwise ciphers is supported */
 	const char *key_mgmt[7]; /* max 7 key managements may be supported */
 	int n;
 
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-	if (!reply)
-		goto nomem;
-
-	dbus_message_iter_init_append(reply, &iter);
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
 					      "a{sv}", &variant_iter))
 		goto nomem;
 
@@ -2928,152 +2989,152 @@
 
 	if (!wpa_dbus_dict_close_write(&variant_iter, &iter_dict))
 		goto nomem;
-	if (!dbus_message_iter_close_container(&iter, &variant_iter))
+	if (!dbus_message_iter_close_container(iter, &variant_iter))
 		goto nomem;
 
-	return reply;
+	return TRUE;
 
 nomem:
-	if (reply)
-		dbus_message_unref(reply);
-
-	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	return FALSE;
 }
 
 
 /**
  * wpas_dbus_getter_bss_wpa - Return the WPA options of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the WPA options of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "WPA" property.
  */
-DBusMessage * wpas_dbus_getter_bss_wpa(DBusMessage *message,
-				       struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
 {
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
 	struct wpa_ie_data wpa_data;
 	const u8 *ie;
 
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_wpa[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
 
 	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)
-			return wpas_dbus_error_unknown_error(message,
-							     "invalid WPA 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;
+		}
 	}
 
-	return wpas_dbus_get_bss_security_prop(message, &wpa_data);
+	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_rsn - Return the RSN options of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing the RSN options of requested bss
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "RSN" property.
  */
-DBusMessage * wpas_dbus_getter_bss_rsn(DBusMessage *message,
-				       struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
 {
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
 	struct wpa_ie_data wpa_data;
 	const u8 *ie;
 
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_rsn[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
 
 	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)
-			return wpas_dbus_error_unknown_error(message,
-							     "invalid RSN 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;
+		}
 	}
 
-	return wpas_dbus_get_bss_security_prop(message, &wpa_data);
+	return wpas_dbus_get_bss_security_prop(iter, &wpa_data, error);
 }
 
 
 /**
  * wpas_dbus_getter_bss_ies - Return all IEs of a BSS
- * @message: Pointer to incoming dbus message
- * @bss: a pair of interface describing structure and bss's id
- * Returns: a dbus message containing IEs byte array
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "IEs" property.
  */
-DBusMessage * wpas_dbus_getter_bss_ies(DBusMessage *message,
-				       struct bss_handler_args *bss)
+dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
 {
-	struct wpa_bss *res = wpa_bss_get_id(bss->wpa_s, bss->id);
+	struct bss_handler_args *args = user_data;
+	struct wpa_bss *res;
 
-	if (!res) {
-		wpa_printf(MSG_ERROR, "wpas_dbus_getter_bss_ies[dbus]: no "
-			   "bss with id %d found", bss->id);
-		return NULL;
-	}
+	res = get_bss_helper(args, error, __func__);
+	if (!res)
+		return FALSE;
 
-	return wpas_dbus_simple_array_property_getter(message, DBUS_TYPE_BYTE,
-						      res + 1, res->ie_len);
+	return wpas_dbus_simple_array_property_getter(iter, DBUS_TYPE_BYTE,
+						      res + 1, res->ie_len,
+						      error);
 }
 
 
 /**
  * wpas_dbus_getter_enabled - Check whether network is enabled or disabled
- * @message: Pointer to incoming dbus message
- * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface
- * and wpa_ssid structure for a configured network
- * Returns: DBus message with boolean indicating state of configured network
- * or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "enabled" property of a configured network.
  */
-DBusMessage * wpas_dbus_getter_enabled(DBusMessage *message,
-				       struct network_handler_args *net)
+dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
 {
+	struct network_handler_args *net = user_data;
 	dbus_bool_t enabled = net->ssid->disabled ? FALSE : TRUE;
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&enabled);
+
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&enabled, error);
 }
 
 
 /**
  * wpas_dbus_setter_enabled - Mark a configured network as enabled or disabled
- * @message: Pointer to incoming dbus message
- * @wpas_dbus_setter_enabled: wpa_supplicant structure for a network interface
- * and wpa_ssid structure for a configured network
- * Returns: NULL indicating success or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "Enabled" property of a configured network.
  */
-DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message,
-				       struct network_handler_args *net)
+dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
+				     void *user_data)
 {
-	DBusMessage *reply = NULL;
-
+	struct network_handler_args *net = user_data;
 	struct wpa_supplicant *wpa_s;
 	struct wpa_ssid *ssid;
-
 	dbus_bool_t enable;
 
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-						 &enable);
-
-	if (reply)
-		return reply;
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+					      &enable))
+		return FALSE;
 
 	wpa_s = net->wpa_s;
 	ssid = net->ssid;
@@ -3083,48 +3144,38 @@
 	else
 		wpa_supplicant_disable_network(wpa_s, ssid);
 
-	return NULL;
+	return TRUE;
 }
 
 
 /**
  * wpas_dbus_getter_network_properties - Get options for a configured network
- * @message: Pointer to incoming dbus message
- * @net: wpa_supplicant structure for a network interface and
- * wpa_ssid structure for a configured network
- * Returns: DBus message with network properties or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Properties" property of a configured network.
  */
-DBusMessage * wpas_dbus_getter_network_properties(
-	DBusMessage *message, struct network_handler_args *net)
+dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
+						DBusError *error,
+						void *user_data)
 {
-	DBusMessage *reply = NULL;
-	DBusMessageIter	iter, variant_iter, dict_iter;
+	struct network_handler_args *net = user_data;
+	DBusMessageIter	variant_iter, dict_iter;
 	char **iterator;
 	char **props = wpa_config_get_all(net->ssid, 1);
-	if (!props)
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+	dbus_bool_t success = FALSE;
 
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-	if (!reply) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
-		goto out;
+	if (!props) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
 	}
 
-	dbus_message_iter_init_append(reply, &iter);
-
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-			"a{sv}", &variant_iter) ||
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
+					      &variant_iter) ||
 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
 		goto out;
 	}
 
@@ -3132,10 +3183,8 @@
 	while (*iterator) {
 		if (!wpa_dbus_dict_append_string(&dict_iter, *iterator,
 						 *(iterator + 1))) {
-			dbus_message_unref(reply);
-			reply = dbus_message_new_error(message,
-						       DBUS_ERROR_NO_MEMORY,
-						       NULL);
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+					     "no memory");
 			goto out;
 		}
 		iterator += 2;
@@ -3143,13 +3192,13 @@
 
 
 	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
-	    !dbus_message_iter_close_container(&iter, &variant_iter)) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+	    !dbus_message_iter_close_container(iter, &variant_iter)) {
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
 		goto out;
 	}
 
+	success = TRUE;
+
 out:
 	iterator = props;
 	while (*iterator) {
@@ -3157,39 +3206,27 @@
 		iterator++;
 	}
 	os_free(props);
-	return reply;
+	return success;
 }
 
 
 /**
  * wpas_dbus_setter_network_properties - Set options for a configured network
- * @message: Pointer to incoming dbus message
- * @net: wpa_supplicant structure for a network interface and
- * wpa_ssid structure for a configured network
- * Returns: NULL indicating success or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "Properties" property of a configured network.
  */
-DBusMessage * wpas_dbus_setter_network_properties(
-	DBusMessage *message, struct network_handler_args *net)
+dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
+						DBusError *error,
+						void *user_data)
 {
+	struct network_handler_args *net = user_data;
 	struct wpa_ssid *ssid = net->ssid;
+	DBusMessageIter	variant_iter;
 
-	DBusMessage *reply = NULL;
-	DBusMessageIter	iter, variant_iter;
-
-	dbus_message_iter_init(message, &iter);
-
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_next(&iter);
-
-	dbus_message_iter_recurse(&iter, &variant_iter);
-
-	reply = set_network_properties(message, net->wpa_s, ssid,
-				       &variant_iter);
-	if (reply)
-		wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
-			   "network properties");
-
-	return reply;
+	dbus_message_iter_recurse(iter, &variant_iter);
+	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
 }
diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h
index 978ee4c..ac3af1f 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers.h
@@ -26,17 +26,20 @@
 	unsigned int id;
 };
 
-DBusMessage * wpas_dbus_simple_property_getter(DBusMessage *message,
-					       const int type,
-					       const void *val);
+dbus_bool_t wpas_dbus_simple_property_getter(DBusMessageIter *iter,
+					     const int type,
+					     const void *val,
+					     DBusError *error);
 
-DBusMessage * wpas_dbus_simple_property_setter(DBusMessage *message,
-					       const int type, void *val);
+dbus_bool_t wpas_dbus_simple_property_setter(DBusMessageIter *iter,
+					     DBusError *error,
+					     const int type, void *val);
 
-DBusMessage * wpas_dbus_simple_array_property_getter(DBusMessage *message,
-						     const int type,
-						     const void *array,
-						     size_t array_len);
+dbus_bool_t wpas_dbus_simple_array_property_getter(DBusMessageIter *iter,
+						   const int type,
+						   const void *array,
+						   size_t array_len,
+						   DBusError *error);
 
 DBusMessage * wpas_dbus_handler_create_interface(DBusMessage *message,
 						 struct wpa_global *global);
@@ -47,29 +50,35 @@
 DBusMessage * wpas_dbus_handler_get_interface(DBusMessage *message,
 					      struct wpa_global *global);
 
-DBusMessage * wpas_dbus_getter_debug_level(DBusMessage *message,
-					   struct wpa_global *global);
+dbus_bool_t wpas_dbus_getter_debug_level(DBusMessageIter *iter,
+					 DBusError *error,
+					 void *user_data);
 
-DBusMessage * wpas_dbus_getter_debug_timestamp(DBusMessage *message,
-					       struct wpa_global *global);
+dbus_bool_t wpas_dbus_getter_debug_timestamp(DBusMessageIter *iter,
+                                             DBusError *error,
+                                             void *user_data);
 
-DBusMessage * wpas_dbus_getter_debug_show_keys(DBusMessage *message,
-					       struct wpa_global *global);
+dbus_bool_t wpas_dbus_getter_debug_show_keys(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data);
 
-DBusMessage * wpas_dbus_setter_debug_level(DBusMessage *message,
-					   struct wpa_global *global);
+dbus_bool_t wpas_dbus_setter_debug_level(DBusMessageIter *iter,
+					 DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_setter_debug_timestamp(DBusMessage *message,
-					       struct wpa_global *global);
+dbus_bool_t wpas_dbus_setter_debug_timestamp(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data);
 
-DBusMessage * wpas_dbus_setter_debug_show_keys(DBusMessage *message,
-					       struct wpa_global *global);
+dbus_bool_t wpas_dbus_setter_debug_show_keys(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data);
 
-DBusMessage * wpas_dbus_getter_interfaces(DBusMessage *message,
-					  struct wpa_global *global);
+dbus_bool_t wpas_dbus_getter_interfaces(DBusMessageIter *iter,
+					DBusError *error,
+					void *user_data);
 
-DBusMessage * wpas_dbus_getter_eap_methods(DBusMessage *message,
-					   void *nothing);
+dbus_bool_t wpas_dbus_getter_eap_methods(DBusMessageIter *iter,
+					 DBusError *error, void *user_data);
 
 DBusMessage * wpas_dbus_handler_scan(DBusMessage *message,
 				     struct wpa_supplicant *wpa_s);
@@ -77,10 +86,10 @@
 DBusMessage * wpas_dbus_handler_disconnect(DBusMessage *message,
 					   struct wpa_supplicant *wpa_s);
 
-DBusMessage * set_network_properties(DBusMessage *message,
-				     struct wpa_supplicant *wpa_s,
-				     struct wpa_ssid *ssid,
-				     DBusMessageIter *iter);
+dbus_bool_t set_network_properties(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid,
+				   DBusMessageIter *iter,
+				   DBusError *error);
 
 DBusMessage * wpas_dbus_handler_add_network(DBusMessage *message,
 					    struct wpa_supplicant *wpa_s);
@@ -94,6 +103,9 @@
 DBusMessage * wpas_dbus_handler_select_network(DBusMessage *message,
 					       struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_handler_network_reply(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s);
+
 DBusMessage * wpas_dbus_handler_add_blob(DBusMessage *message,
 					 struct wpa_supplicant *wpa_s);
 
@@ -106,119 +118,126 @@
 DBusMessage * wpas_dbus_handler_flush_bss(DBusMessage *message,
 					  struct wpa_supplicant *wpa_s);
 
-DBusMessage * wpas_dbus_getter_capabilities(DBusMessage *message,
-					    struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_capabilities(DBusMessageIter *iter,
+					  DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_getter_state(DBusMessage *message,
-				     struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_state(DBusMessageIter *iter, DBusError *error,
+				   void *user_data);
 
-DBusMessage * wpas_dbus_getter_scanning(DBusMessage *message,
-					struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_scanning(DBusMessageIter *iter, DBusError *error,
+				      void *user_data);
 
-DBusMessage * wpas_dbus_getter_ap_scan(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_ap_scan(DBusMessageIter *iter, DBusError *error,
+				     void *user_data);
 
-DBusMessage * wpas_dbus_setter_ap_scan(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_setter_ap_scan(DBusMessageIter *iter, DBusError *error,
+				     void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_expire_age(DBusMessage *message,
-					      struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_bss_expire_age(DBusMessageIter *iter,
+					    DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_setter_bss_expire_age(DBusMessage *message,
-					      struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_setter_bss_expire_age(DBusMessageIter *iter,
+					    DBusError *error,
+					    void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_expire_count(DBusMessage *message,
-						struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_bss_expire_count(DBusMessageIter *iter,
+					      DBusError *error,
+					      void *user_data);
 
-DBusMessage * wpas_dbus_setter_bss_expire_count(DBusMessage *message,
-						struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_setter_bss_expire_count(DBusMessageIter *iter,
+					      DBusError *error,
+					      void *user_data);
 
-DBusMessage * wpas_dbus_getter_country(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_country(DBusMessageIter *iter, DBusError *error,
+				     void *user_data);
 
-DBusMessage * wpas_dbus_setter_country(DBusMessage *message,
-				       struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_setter_country(DBusMessageIter *iter, DBusError *error,
+				     void *user_data);
 
-DBusMessage * wpas_dbus_getter_ifname(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_ifname(DBusMessageIter *iter, DBusError *error,
+				    void *user_data);
 
-DBusMessage * wpas_dbus_getter_driver(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_driver(DBusMessageIter *iter, DBusError *error,
+				    void *user_data);
 
-DBusMessage * wpas_dbus_getter_bridge_ifname(DBusMessage *message,
-					     struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_bridge_ifname(DBusMessageIter *iter,
+					   DBusError *error,
+					   void *user_data);
 
-DBusMessage * wpas_dbus_getter_current_bss(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_current_bss(DBusMessageIter *iter,
+					 DBusError *error,
+					 void *user_data);
 
-DBusMessage * wpas_dbus_getter_current_network(DBusMessage *message,
-					       struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_current_network(DBusMessageIter *iter,
+					     DBusError *error,
+					     void *user_data);
 
-DBusMessage * wpas_dbus_getter_current_auth_mode(DBusMessage *message,
-						 struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_current_auth_mode(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data);
 
-DBusMessage * wpas_dbus_getter_bsss(DBusMessage *message,
-				    struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_bsss(DBusMessageIter *iter, DBusError *error,
+				  void *user_data);
 
-DBusMessage * wpas_dbus_getter_networks(DBusMessage *message,
-					struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_networks(DBusMessageIter *iter, DBusError *error,
+				      void *user_data);
 
-DBusMessage * wpas_dbus_getter_blobs(DBusMessage *message,
-				     struct wpa_supplicant *bss);
+dbus_bool_t wpas_dbus_getter_blobs(DBusMessageIter *iter, DBusError *error,
+				   void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_bssid(DBusMessage *message,
-					 struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_bssid(DBusMessageIter *iter, DBusError *error,
+				       void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_ssid(DBusMessage *message,
-					struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_ssid(DBusMessageIter *iter, DBusError *error,
+				      void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_privacy(DBusMessage *message,
-					   struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_privacy(DBusMessageIter *iter,
+					 DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_mode(DBusMessage *message,
-					struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_mode(DBusMessageIter *iter, DBusError *error,
+				      void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_signal(DBusMessage *message,
-					  struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_signal(DBusMessageIter *iter,
+					DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_frequency(DBusMessage *message,
-					     struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_frequency(DBusMessageIter *iter,
+					   DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_rates(DBusMessage *message,
-					 struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_rates(DBusMessageIter *iter,
+				       DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_wpa(DBusMessage *message,
-				       struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_wpa(DBusMessageIter *iter, DBusError *error,
+				     void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_rsn(DBusMessage *message,
-				       struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_rsn(DBusMessageIter *iter, DBusError *error,
+				     void *user_data);
 
-DBusMessage * wpas_dbus_getter_bss_ies(DBusMessage *message,
-				       struct bss_handler_args *bss);
+dbus_bool_t wpas_dbus_getter_bss_ies(DBusMessageIter *iter, DBusError *error,
+				     void *user_data);
 
-DBusMessage * wpas_dbus_getter_enabled(DBusMessage *message,
-				       struct network_handler_args *net);
+dbus_bool_t wpas_dbus_getter_enabled(DBusMessageIter *iter, DBusError *error,
+				     void *user_data);
 
-DBusMessage * wpas_dbus_setter_enabled(DBusMessage *message,
-				       struct network_handler_args *net);
+dbus_bool_t wpas_dbus_setter_enabled(DBusMessageIter *iter, DBusError *error,
+				     void *user_data);
 
-DBusMessage * wpas_dbus_getter_network_properties(
-	DBusMessage *message, struct network_handler_args *net);
+dbus_bool_t wpas_dbus_getter_network_properties(DBusMessageIter *iter,
+						DBusError *error,
+						void *user_data);
 
-DBusMessage * wpas_dbus_setter_network_properties(
-	DBusMessage *message, struct network_handler_args *net);
+dbus_bool_t wpas_dbus_setter_network_properties(DBusMessageIter *iter,
+						DBusError *error,
+						void *user_data);
 
 DBusMessage * wpas_dbus_handler_wps_start(DBusMessage *message,
 					  struct wpa_supplicant *wpa_s);
 
-DBusMessage * wpas_dbus_getter_process_credentials(
-	DBusMessage *message, struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
+	DBusError *error, void *user_data);
 
-DBusMessage * wpas_dbus_setter_process_credentials(
-	DBusMessage *message, struct wpa_supplicant *wpa_s);
-
-DBusMessage * wpas_dbus_getter_credentials(DBusMessage *message,
-					   struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
+						 DBusError *error,
+						 void *user_data);
 
 DBusMessage * wpas_dbus_error_invalid_args(DBusMessage *message,
 					   const char *arg);
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
index 55482b4..671d0e5 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.c
@@ -70,23 +70,23 @@
 }
 
 
-DBusMessage *wpas_dbus_handler_p2p_find(DBusMessage * message,
-					struct wpa_supplicant * wpa_s)
+DBusMessage * wpas_dbus_handler_p2p_find(DBusMessage *message,
+					 struct wpa_supplicant *wpa_s)
 {
 	struct wpa_dbus_dict_entry entry;
 	DBusMessage *reply = NULL;
 	DBusMessageIter iter;
 	DBusMessageIter iter_dict;
 	unsigned int timeout = 0;
-	unsigned int searchonly = 0;
 	enum p2p_discovery_type type = P2P_FIND_ONLY_SOCIAL;
 	int num_req_dev_types = 0;
 	unsigned int i;
 	u8 *req_dev_types = NULL;
 
 	dbus_message_iter_init(message, &iter);
+	entry.key = NULL;
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto error;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
@@ -96,14 +96,12 @@
 		if (!os_strcmp(entry.key, "Timeout") &&
 		    (entry.type == DBUS_TYPE_INT32)) {
 			timeout = entry.uint32_value;
-		} else if (!os_strcmp(entry.key, "SearchOnly") &&
-			   (entry.type == DBUS_TYPE_BOOLEAN)) {
-			searchonly = (entry.bool_value == TRUE) ? 1 : 0;
 		} else if (os_strcmp(entry.key, "RequestedDeviceTypes") == 0) {
 			if ((entry.type != DBUS_TYPE_ARRAY) ||
 			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY))
 				goto error_clear;
 
+			os_free(req_dev_types);
 			req_dev_types =
 				os_malloc(WPS_DEV_TYPE_LEN * entry.array_len);
 			if (!req_dev_types)
@@ -117,33 +115,45 @@
 					  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"))
+				type = P2P_FIND_START_WITH_FULL;
+			else if (!os_strcmp(entry.str_value, "social"))
+				type = P2P_FIND_ONLY_SOCIAL;
+			else if (!os_strcmp(entry.str_value, "progressive"))
+				type = P2P_FIND_PROGRESSIVE;
+			else
+				goto error_clear;
 		} else
 			goto error_clear;
 		wpa_dbus_dict_entry_clear(&entry);
 	}
 
 	wpas_p2p_find(wpa_s, timeout, type, num_req_dev_types, req_dev_types);
+	os_free(req_dev_types);
 	return reply;
 
 error_clear:
-	os_free(req_dev_types);
 	wpa_dbus_dict_entry_clear(&entry);
 error:
+	os_free(req_dev_types);
 	reply = wpas_dbus_error_invalid_args(message, entry.key);
 	return reply;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_stop_find(DBusMessage * message,
-					     struct wpa_supplicant * wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_stop_find(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s)
 {
 	wpas_p2p_stop_find(wpa_s);
 	return NULL;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_rejectpeer(DBusMessage * message,
-					      struct wpa_supplicant * wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_rejectpeer(DBusMessage *message,
+					       struct wpa_supplicant *wpa_s)
 {
 	DBusMessageIter iter;
 	char *peer_object_path = NULL;
@@ -162,8 +172,9 @@
 	return NULL;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_listen(DBusMessage * message,
-					  struct wpa_supplicant * wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_listen(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
 {
 	dbus_int32_t timeout = 0;
 
@@ -179,8 +190,9 @@
 	return NULL;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_extendedlisten(DBusMessage * message,
-						  struct wpa_supplicant * wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_extendedlisten(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
 {
 	unsigned int period = 0, interval = 0;
 	struct wpa_dbus_dict_entry entry;
@@ -188,18 +200,19 @@
 	DBusMessageIter iter_dict;
 
 	dbus_message_iter_init(message, &iter);
+	entry.key = NULL;
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto error;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!strcmp(entry.key, "period") &&
+		if (!os_strcmp(entry.key, "period") &&
 		    (entry.type == DBUS_TYPE_INT32))
 			period = entry.uint32_value;
-		else if (!strcmp(entry.key, "interval") &&
+		else if (!os_strcmp(entry.key, "interval") &&
 			 (entry.type == DBUS_TYPE_INT32))
 			interval = entry.uint32_value;
 		else
@@ -208,8 +221,8 @@
 	}
 
 	if (wpas_p2p_ext_listen(wpa_s, period, interval))
-		return wpas_dbus_error_unknown_error(message,
-					"failed to initiate a p2p_ext_listen.");
+		return wpas_dbus_error_unknown_error(
+			message, "failed to initiate a p2p_ext_listen.");
 
 	return NULL;
 
@@ -219,9 +232,9 @@
 	return wpas_dbus_error_invalid_args(message, entry.key);
 }
 
-DBusMessage *wpas_dbus_handler_p2p_presence_request(DBusMessage * message,
-						    struct wpa_supplicant *
-						    wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_presence_request(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
 {
 	unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
 	struct wpa_dbus_dict_entry entry;
@@ -229,24 +242,25 @@
 	DBusMessageIter iter_dict;
 
 	dbus_message_iter_init(message, &iter);
+	entry.key = NULL;
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto error;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!strcmp(entry.key, "duration1") &&
+		if (!os_strcmp(entry.key, "duration1") &&
 		    (entry.type == DBUS_TYPE_INT32))
 			dur1 = entry.uint32_value;
-		else if (!strcmp(entry.key, "interval1") &&
+		else if (!os_strcmp(entry.key, "interval1") &&
 			 entry.type == DBUS_TYPE_INT32)
 			int1 = entry.uint32_value;
-		else if (!strcmp(entry.key, "duration2") &&
+		else if (!os_strcmp(entry.key, "duration2") &&
 			 entry.type == DBUS_TYPE_INT32)
 			dur2 = entry.uint32_value;
-		else if (!strcmp(entry.key, "interval2") &&
+		else if (!os_strcmp(entry.key, "interval2") &&
 			 entry.type == DBUS_TYPE_INT32)
 			int2 = entry.uint32_value;
 		else
@@ -266,8 +280,9 @@
 	return wpas_dbus_error_invalid_args(message, entry.key);
 }
 
-DBusMessage *wpas_dbus_handler_p2p_group_add(DBusMessage * message,
-					     struct wpa_supplicant * wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_group_add(DBusMessage *message,
+					      struct wpa_supplicant *wpa_s)
 {
 	DBusMessageIter iter_dict;
 	DBusMessage *reply = NULL;
@@ -283,22 +298,22 @@
 
 	dbus_message_iter_init(message, &iter);
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto inv_args;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto inv_args;
 
-		if (!strcmp(entry.key, "persistent") &&
+		if (!os_strcmp(entry.key, "persistent") &&
 		    (entry.type == DBUS_TYPE_BOOLEAN)) {
 			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!strcmp(entry.key, "frequency") &&
+		} else if (!os_strcmp(entry.key, "frequency") &&
 			   (entry.type == DBUS_TYPE_INT32)) {
 			freq = entry.int32_value;
 			if (freq <= 0)
 				goto inv_args_clear;
-		} else if (!strcmp(entry.key, "persistent_group_object") &&
+		} else if (!os_strcmp(entry.key, "persistent_group_object") &&
 			   entry.type == DBUS_TYPE_OBJECT_PATH)
 			pg_object_path = os_strdup(entry.str_value);
 		else
@@ -330,14 +345,15 @@
 			goto out;
 		}
 
-		/* Get the SSID structure form the persistant group id */
+		/* Get the SSID structure from the persistent group id */
 		ssid = wpa_config_get_network(wpa_s->conf, group_id);
 		if (ssid == NULL || ssid->disabled != 2)
 			goto inv_args;
 
 		if (wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq)) {
-			reply = wpas_dbus_error_unknown_error(message,
-							      "Failed to reinvoke a persistent group");
+			reply = wpas_dbus_error_unknown_error(
+				message,
+				"Failed to reinvoke a persistent group");
 			goto out;
 		}
 	} else if (wpas_p2p_group_add(wpa_s, persistent_group, freq))
@@ -355,8 +371,9 @@
 	goto out;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
-					      struct wpa_supplicant *wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_disconnect(DBusMessage *message,
+					       struct wpa_supplicant *wpa_s)
 {
 	if (wpas_p2p_disconnect(wpa_s))
 		return wpas_dbus_error_unknown_error(message,
@@ -365,9 +382,36 @@
 	return NULL;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_flush(DBusMessage * message,
-					 struct wpa_supplicant * wpa_s)
+
+static dbus_bool_t wpa_dbus_p2p_check_enabled(struct wpa_supplicant *wpa_s,
+					      DBusMessage *message,
+					      DBusMessage **out_reply,
+					      DBusError *error)
 {
+	/* Return an error message or an error if P2P isn't available */
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL) {
+		if (out_reply) {
+			*out_reply = dbus_message_new_error(
+				message, DBUS_ERROR_FAILED,
+				"P2P is not available for this interface");
+		}
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "P2P is not available for this "
+				     "interface");
+		return FALSE;
+	}
+	return TRUE;
+}
+
+
+DBusMessage * wpas_dbus_handler_p2p_flush(DBusMessage *message,
+					  struct wpa_supplicant *wpa_s)
+{
+	DBusMessage *reply = NULL;
+
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
+		return reply;
+
 	os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
 	wpa_s->force_long_sd = 0;
 	p2p_flush(wpa_s->global->p2p);
@@ -375,8 +419,9 @@
 	return NULL;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_connect(DBusMessage * message,
-					   struct wpa_supplicant * wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_connect(DBusMessage *message,
+					    struct wpa_supplicant *wpa_s)
 {
 	DBusMessageIter iter_dict;
 	DBusMessage *reply = NULL;
@@ -395,52 +440,53 @@
 	char *err_msg = NULL;
 	char *iface = NULL;
 
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
+		return reply;
+
 	dbus_message_iter_init(message, &iter);
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto inv_args;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto inv_args;
 
-		if (!strcmp(entry.key, "peer") &&
+		if (!os_strcmp(entry.key, "peer") &&
 		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
 			peer_object_path = os_strdup(entry.str_value);
-		} else if (!strcmp(entry.key, "persistent") &&
+		} else if (!os_strcmp(entry.key, "persistent") &&
 			   (entry.type == DBUS_TYPE_BOOLEAN)) {
 			persistent_group = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!strcmp(entry.key, "join") &&
+		} else if (!os_strcmp(entry.key, "join") &&
 			   (entry.type == DBUS_TYPE_BOOLEAN)) {
 			join = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!strcmp(entry.key, "authorize_only") &&
+		} else if (!os_strcmp(entry.key, "authorize_only") &&
 			   (entry.type == DBUS_TYPE_BOOLEAN)) {
 			authorize_only = (entry.bool_value == TRUE) ? 1 : 0;
-		} else if (!strcmp(entry.key, "frequency") &&
+		} else if (!os_strcmp(entry.key, "frequency") &&
 			   (entry.type == DBUS_TYPE_INT32)) {
 			freq = entry.int32_value;
 			if (freq <= 0)
 				goto inv_args_clear;
-		} else if (!strcmp(entry.key, "go_intent") &&
+		} else if (!os_strcmp(entry.key, "go_intent") &&
 			   (entry.type == DBUS_TYPE_INT32)) {
 			go_intent = entry.int32_value;
 			if ((go_intent < 0) || (go_intent > 15))
 				goto inv_args_clear;
-		} else if (!strcmp(entry.key, "wps_method") &&
+		} else if (!os_strcmp(entry.key, "wps_method") &&
 			   (entry.type == DBUS_TYPE_STRING)) {
-			if (!strcmp(entry.str_value, "pbc"))
+			if (!os_strcmp(entry.str_value, "pbc"))
 				wps_method = WPS_PBC;
-			else if (!strcmp(entry.str_value, "pin"))
+			else if (!os_strcmp(entry.str_value, "pin"))
 				wps_method = WPS_PIN_DISPLAY;
-			else if (!strcmp(entry.str_value, "label"))
-				wps_method = WPS_PIN_LABEL;
-			else if (!strcmp(entry.str_value, "display"))
+			else if (!os_strcmp(entry.str_value, "display"))
 				wps_method = WPS_PIN_DISPLAY;
-			else if (!strcmp(entry.str_value, "keypad"))
+			else if (!os_strcmp(entry.str_value, "keypad"))
 				wps_method = WPS_PIN_KEYPAD;
 			else
 				goto inv_args_clear;
-		} else if (!strcmp(entry.key, "pin") &&
+		} else if (!os_strcmp(entry.key, "pin") &&
 			   (entry.type == DBUS_TYPE_STRING)) {
 			pin = os_strdup(entry.str_value);
 		} else
@@ -451,16 +497,13 @@
 
 	if (!peer_object_path || (wps_method == WPS_NOT_READY) ||
 	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
-	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0)) {
-		reply = wpas_dbus_error_invalid_args(message, NULL);
+	    !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_LABEL) || (wps_method == WPS_PIN_KEYPAD)))
+	if ((!pin || !pin[0]) && (wps_method == WPS_PIN_KEYPAD))
 		goto inv_args;
 
 	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
@@ -468,31 +511,34 @@
 				   go_intent, freq);
 
 	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);
-		dbus_message_append_args(reply, DBUS_TYPE_INT32,
-					 &new_pin, DBUS_TYPE_INVALID);
+		dbus_message_append_args(reply, DBUS_TYPE_STRING,
+					 &generated_pin, DBUS_TYPE_INVALID);
 	} 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;
 
 		case -3:
-			err_msg = "connect failed due to"
-					" unsupported channel.";
+			err_msg = "connect failed due to unsupported channel.";
 			iface = WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED;
 			break;
 
 		default:
-			err_msg = "connect failed due to"
-					" unspecified error.";
+			err_msg = "connect failed due to unspecified error.";
 			iface = WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR;
 			break;
 		}
+
 		/*
-		 * TODO::
+		 * TODO:
 		 * Do we need specialized errors corresponding to above
 		 * error conditions as against just returning a different
 		 * error message?
@@ -511,8 +557,9 @@
 	goto out;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_invite(DBusMessage * message,
-					  struct wpa_supplicant *wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_invite(DBusMessage *message,
+					   struct wpa_supplicant *wpa_s)
 {
 	DBusMessageIter iter_dict;
 	DBusMessage *reply = NULL;
@@ -527,20 +574,23 @@
 	int persistent = 0;
 	struct wpa_ssid *ssid;
 
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, message, &reply, NULL))
+		return reply;
+
 	dbus_message_iter_init(message, &iter);
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto err;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto err;
 
-		if (!strcmp(entry.key, "peer") &&
+		if (!os_strcmp(entry.key, "peer") &&
 		    (entry.type == DBUS_TYPE_OBJECT_PATH)) {
 			peer_object_path = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
-		} else if (!strcmp(entry.key, "persistent_group_object") &&
+		} else if (!os_strcmp(entry.key, "persistent_group_object") &&
 			   (entry.type == DBUS_TYPE_OBJECT_PATH)) {
 			pg_object_path = os_strdup(entry.str_value);
 			persistent = 1;
@@ -553,43 +603,41 @@
 
 	if (!peer_object_path ||
 	    (parse_peer_object_path(peer_object_path, peer_addr) < 0) ||
-	    (p2p_get_peer_info(wpa_s->global->p2p,
-			       peer_addr, 0, NULL, 0) < 0)) {
+	    !p2p_peer_known(wpa_s->global->p2p, peer_addr)) {
 		goto err;
 	}
 
 	if (persistent) {
 		/*
 		 * A group ID is defined meaning we want to re-invoke a
-		 * persisatnt group
+		 * persistent group
 		 */
 
 		iface = wpas_dbus_new_decompose_object_path(pg_object_path, 1,
 							    &net_id_str, NULL);
 		if (iface == NULL ||
 		    os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
-			reply =
-			    wpas_dbus_error_invalid_args(message,
-							 pg_object_path);
+			reply = wpas_dbus_error_invalid_args(message,
+							     pg_object_path);
 			goto out;
 		}
 
 		group_id = strtoul(net_id_str, NULL, 10);
 		if (errno == EINVAL) {
 			reply = wpas_dbus_error_invalid_args(
-						message, pg_object_path);
+				message, pg_object_path);
 			goto out;
 		}
 
-		/* Get the SSID structure form the persistant group id */
+		/* Get the SSID structure from the persistent group id */
 		ssid = wpa_config_get_network(wpa_s->conf, group_id);
 		if (ssid == NULL || ssid->disabled != 2)
 			goto err;
 
 		if (wpas_p2p_invite(wpa_s, peer_addr, ssid, NULL) < 0) {
 			reply = wpas_dbus_error_unknown_error(
-					message,
-					"Failed to reinvoke a persistent group");
+				message,
+				"Failed to reinvoke a persistent group");
 			goto out;
 		}
 	} else {
@@ -597,10 +645,9 @@
 		 * No group ID means propose to a peer to join my active group
 		 */
 		if (wpas_p2p_invite_group(wpa_s, wpa_s->ifname,
-					 peer_addr, NULL)) {
+					  peer_addr, NULL)) {
 			reply = wpas_dbus_error_unknown_error(
-					message,
-					"Failed to join to an active group");
+				message, "Failed to join to an active group");
 			goto out;
 		}
 	}
@@ -615,8 +662,9 @@
 	goto out;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_prov_disc_req(DBusMessage * message,
-						 struct wpa_supplicant *wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_prov_disc_req(DBusMessage *message,
+						  struct wpa_supplicant *wpa_s)
 {
 	DBusMessageIter iter;
 	char *peer_object_path = NULL;
@@ -643,23 +691,24 @@
 	    os_strcmp(config_method, "pushbutton"))
 		return wpas_dbus_error_invalid_args(message, NULL);
 
-	if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method) < 0)
+	if (wpas_p2p_prov_disc(wpa_s, peer_addr, config_method, 0) < 0)
 		return wpas_dbus_error_unknown_error(message,
 				"Failed to send provision discovery request");
 
 	return NULL;
 }
 
+
 /*
  * P2P Device property accessor methods.
  */
 
-DBusMessage *wpas_dbus_getter_p2p_device_properties(DBusMessage * message,
-						    struct wpa_supplicant *
-						    wpa_s)
+dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
+						   DBusError *error,
+						   void *user_data)
 {
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, variant_iter, dict_iter;
+	struct wpa_supplicant *wpa_s = user_data;
+	DBusMessageIter variant_iter, dict_iter;
 	DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
 		iter_secdev_dict_array;
 	const char *dev_name;
@@ -667,17 +716,10 @@
 	int i;
 	const struct wpabuf *vendor_ext[P2P_MAX_WPS_VENDOR_EXT];
 
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
+		return FALSE;
 
-	if (!reply)
-		goto err_no_mem;
-
-	dbus_message_iter_init_append(reply, &iter);
-
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
 					      "a{sv}", &variant_iter) ||
 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
 		goto err_no_mem;
@@ -738,7 +780,7 @@
 					 wpa_s->conf->p2p_go_intent))
 		goto err_no_mem;
 
-	/* Persistant Reconnect */
+	/* Persistent Reconnect */
 	if (!wpa_dbus_dict_append_bool(&dict_iter, "PersistantReconnect",
 				       wpa_s->conf->persistent_reconnect))
 		goto err_no_mem;
@@ -785,44 +827,45 @@
 		goto err_no_mem;
 
 	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
-	    !dbus_message_iter_close_container(&iter, &variant_iter))
+	    !dbus_message_iter_close_container(iter, &variant_iter))
 		goto err_no_mem;
 
-	return reply;
+	return TRUE;
+
 err_no_mem:
-	dbus_message_unref(reply);
-	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	return FALSE;
 }
 
-DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage * message,
-						    struct wpa_supplicant *
-						    wpa_s)
+
+dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
+						   DBusError *error,
+						   void *user_data)
 {
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, variant_iter;
+	struct wpa_supplicant *wpa_s = user_data;
+	DBusMessageIter variant_iter, iter_dict;
 	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
-	DBusMessageIter iter_dict;
 	unsigned int i;
 
-	dbus_message_iter_init(message, &iter);
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
+		return FALSE;
 
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_next(&iter);
-
-	dbus_message_iter_recurse(&iter, &variant_iter);
-
-	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
-		return wpas_dbus_error_invalid_args(message, NULL);
+	dbus_message_iter_recurse(iter, &variant_iter);
+	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
+		return FALSE;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
-		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
-			return wpas_dbus_error_invalid_args(message, NULL);
+		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
+			dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+					     "invalid message format");
+			return FALSE;
+		}
 
 		if (os_strcmp(entry.key, "DeviceName") == 0) {
 			char *devname;
 
 			if (entry.type != DBUS_TYPE_STRING)
-				goto error_clear;
+				goto error;
 
 			devname = os_strdup(entry.str_value);
 			if (devname == NULL)
@@ -832,12 +875,12 @@
 			wpa_s->conf->device_name = devname;
 
 			wpa_s->conf->changed_parameters |=
-							CFG_CHANGED_DEVICE_NAME;
+				CFG_CHANGED_DEVICE_NAME;
 		} else if (os_strcmp(entry.key, "PrimaryDeviceType") == 0) {
 			if (entry.type != DBUS_TYPE_ARRAY ||
 			    entry.array_type != DBUS_TYPE_BYTE ||
 			    entry.array_len != WPS_DEV_TYPE_LEN)
-				goto error_clear;
+				goto error;
 
 			os_memcpy(wpa_s->conf->device_type,
 				  entry.bytearray_value,
@@ -851,7 +894,8 @@
 				goto error;
 
 			for (i = 0; i < entry.array_len; i++)
-				if (wpabuf_len(entry.binarray_value[i]) != WPS_DEV_TYPE_LEN)
+				if (wpabuf_len(entry.binarray_value[i]) !=
+				    WPS_DEV_TYPE_LEN)
 					goto err_no_mem_clear;
 			for (i = 0; i < entry.array_len; i++)
 				os_memcpy(wpa_s->conf->sec_device_type[i],
@@ -864,10 +908,10 @@
 			if ((entry.type != DBUS_TYPE_ARRAY) ||
 			    (entry.array_type != WPAS_DBUS_TYPE_BINARRAY) ||
 			    (entry.array_len > P2P_MAX_WPS_VENDOR_EXT))
-				goto error_clear;
+				goto error;
 
 			wpa_s->conf->changed_parameters |=
-					CFG_CHANGED_VENDOR_EXTENSION;
+				CFG_CHANGED_VENDOR_EXTENSION;
 
 			for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
 				wpabuf_free(wpa_s->conf->wps_vendor_ext[i]);
@@ -882,11 +926,9 @@
 			   (entry.type == DBUS_TYPE_UINT32) &&
 			   (entry.uint32_value <= 15))
 			wpa_s->conf->p2p_go_intent = entry.uint32_value;
-
 		else if ((os_strcmp(entry.key, "PersistantReconnect") == 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)) {
 			wpa_s->conf->p2p_listen_reg_class = entry.uint32_value;
@@ -911,7 +953,7 @@
 			char *postfix;
 
 			if (entry.type != DBUS_TYPE_STRING)
-				goto error_clear;
+				goto error;
 
 			postfix = os_strdup(entry.str_value);
 			if (!postfix)
@@ -926,7 +968,7 @@
 			   (entry.type == DBUS_TYPE_BOOLEAN)) {
 			wpa_s->conf->p2p_intra_bss = entry.bool_value;
 			wpa_s->conf->changed_parameters |=
-						      CFG_CHANGED_P2P_INTRA_BSS;
+				CFG_CHANGED_P2P_INTRA_BSS;
 		} else if ((os_strcmp(entry.key, "GroupIdle") == 0) &&
 			   (entry.type == DBUS_TYPE_UINT32))
 			wpa_s->conf->p2p_group_idle = entry.uint32_value;
@@ -934,7 +976,7 @@
 			 entry.type == DBUS_TYPE_UINT32)
 			wpa_s->conf->disassoc_low_ack = entry.uint32_value;
 		else
-			goto error_clear;
+			goto error;
 
 		wpa_dbus_dict_entry_clear(&entry);
 	}
@@ -944,29 +986,31 @@
 		wpa_supplicant_update_config(wpa_s);
 	}
 
-	return reply;
+	return TRUE;
 
- error_clear:
-	wpa_dbus_dict_entry_clear(&entry);
  error:
-	reply = wpas_dbus_error_invalid_args(message, entry.key);
+	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+			     "invalid message format");
 	wpa_dbus_dict_entry_clear(&entry);
+	return FALSE;
 
-	return reply;
  err_no_mem_clear:
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
 	wpa_dbus_dict_entry_clear(&entry);
-	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+	return FALSE;
 }
 
-DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage * message,
-					struct wpa_supplicant * wpa_s)
+
+dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
+				       void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	struct p2p_data *p2p = wpa_s->global->p2p;
 	int next = 0, i = 0;
 	int num = 0, out_of_mem = 0;
 	const u8 *addr;
 	const struct p2p_peer_info *peer_info = NULL;
+	dbus_bool_t success = FALSE;
 
 	struct dl_list peer_objpath_list;
 	struct peer_objpath_node {
@@ -976,6 +1020,9 @@
 
 	char **peer_obj_paths = NULL;
 
+	if (!wpa_dbus_p2p_check_enabled(wpa_s, NULL, NULL, error))
+		return FALSE;
+
 	dl_list_init(&peer_objpath_list);
 
 	/* Get the first peer info */
@@ -1016,9 +1063,10 @@
 			      struct peer_objpath_node, list)
 		peer_obj_paths[i++] = node->path;
 
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_OBJECT_PATH,
-						       peer_obj_paths, num);
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 peer_obj_paths, num,
+							 error);
 
 error:
 	if (peer_obj_paths)
@@ -1030,12 +1078,12 @@
 		os_free(node);
 	}
 	if (out_of_mem)
-		reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					       NULL);
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
 
-	return reply;
+	return success;
 }
 
+
 enum wpas_p2p_role {
 	WPAS_P2P_ROLE_DEVICE,
 	WPAS_P2P_ROLE_GO,
@@ -1064,9 +1112,11 @@
 	}
 }
 
-DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage * message,
-				       struct wpa_supplicant * wpa_s)
+
+dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
+				      void *user_data)
 {
+	struct wpa_supplicant *wpa_s = user_data;
 	char *str;
 
 	switch (wpas_get_p2p_role(wpa_s)) {
@@ -1080,83 +1130,85 @@
 		str = "device";
 	}
 
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_STRING,
-						&str);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_STRING, &str,
+						error);
 }
 
-DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage * message,
-					struct wpa_supplicant * wpa_s)
+
+dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
+				       void *user_data)
 {
+	struct wpa_supplicant *wpa_s = user_data;
+
 	if (wpa_s->dbus_groupobj_path == NULL)
-		return NULL;
+		return FALSE;
 
-	return wpas_dbus_simple_property_getter(message,
-						DBUS_TYPE_OBJECT_PATH,
-						&wpa_s->dbus_groupobj_path);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+						&wpa_s->dbus_groupobj_path,
+						error);
 }
 
-DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage * message,
-					 struct wpa_supplicant * wpa_s)
+
+dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
+					DBusError *error, void *user_data)
 {
+	struct wpa_supplicant *wpa_s = user_data;
 	char go_peer_obj_path[WPAS_DBUS_OBJECT_PATH_MAX], *path;
 
 	if (wpas_get_p2p_role(wpa_s) != WPAS_P2P_ROLE_CLIENT)
-		return NULL;
+		return FALSE;
 
 	os_snprintf(go_peer_obj_path, WPAS_DBUS_OBJECT_PATH_MAX,
 		    "%s/" WPAS_DBUS_NEW_P2P_PEERS_PART "/" COMPACT_MACSTR,
 		    wpa_s->dbus_new_path, MAC2STR(wpa_s->go_dev_addr));
 	path = go_peer_obj_path;
-	return wpas_dbus_simple_property_getter(message,
-						DBUS_TYPE_OBJECT_PATH, &path);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_OBJECT_PATH,
+						&path, error);
 }
 
+
 /*
  * Peer object properties accessor methods
  */
 
-DBusMessage *wpas_dbus_getter_p2p_peer_properties(DBusMessage * message,
-						  struct peer_handler_args *
-						  peer_args)
+dbus_bool_t wpas_dbus_getter_p2p_peer_properties(DBusMessageIter *iter,
+	DBusError *error, void *user_data)
 {
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, variant_iter, dict_iter;
+	struct peer_handler_args *peer_args = user_data;
+	DBusMessageIter variant_iter, dict_iter;
 	const struct p2p_peer_info *info = NULL;
-	char devtype[WPS_DEV_TYPE_BUFSIZE];
+	const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
+	int i, num;
+
+	if (!wpa_dbus_p2p_check_enabled(peer_args->wpa_s, NULL, NULL, error))
+		return FALSE;
 
 	/* get the peer info */
 	info = p2p_get_peer_found(peer_args->wpa_s->global->p2p,
 				  peer_args->p2p_device_addr, 0);
-	if (info == NULL)
-		return NULL;
+	if (info == NULL) {
+		dbus_set_error(error, DBUS_ERROR_FAILED, "failed to find peer");
+		return FALSE;
+	}
 
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-
-	if (!reply)
-		goto err_no_mem;
-
-	dbus_message_iter_init_append(reply, &iter);
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
 					      "a{sv}", &variant_iter) ||
 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
 		goto err_no_mem;
 
 	/* Fill out the dictionary */
-	wps_dev_type_bin2str(info->pri_dev_type, devtype, sizeof(devtype));
 	if (!wpa_dbus_dict_append_string(&dict_iter, "DeviceName",
 					 info->device_name))
 		goto err_no_mem;
-	if (!wpa_dbus_dict_append_string(&dict_iter, "PrimaryDeviceType",
-					 devtype))
+	if (!wpa_dbus_dict_append_byte_array(&dict_iter, "PrimaryDeviceType",
+					     (char *)info->pri_dev_type,
+					     WPS_DEV_TYPE_LEN))
 		goto err_no_mem;
 	if (!wpa_dbus_dict_append_uint16(&dict_iter, "config_method",
 					 info->config_methods))
 		goto err_no_mem;
 	if (!wpa_dbus_dict_append_int32(&dict_iter, "level",
-					 info->level))
+					info->level))
 		goto err_no_mem;
 	if (!wpa_dbus_dict_append_byte(&dict_iter, "devicecapability",
 				       info->dev_capab))
@@ -1166,115 +1218,97 @@
 		goto err_no_mem;
 
 	if (info->wps_sec_dev_type_list_len) {
-		char *sec_dev_types[MAX_SEC_DEVICE_TYPES];
-		u8 *sec_dev_type_list = NULL;
-		char secdevtype[WPS_DEV_TYPE_BUFSIZE];
-		int num_sec_dev_types = 0;
-		int i;
-
-		sec_dev_type_list = os_zalloc(info->wps_sec_dev_type_list_len);
-
-		if (sec_dev_type_list == NULL)
-			goto err_no_mem;
-
-		os_memcpy(sec_dev_type_list, info->wps_sec_dev_type_list,
-			  info->wps_sec_dev_type_list_len);
-
-		for (i = 0; i < MAX_SEC_DEVICE_TYPES &&
-		       i < (int) (info->wps_sec_dev_type_list_len /
-				  WPS_DEV_TYPE_LEN);
-		     i++) {
-			sec_dev_types[i] = os_zalloc(sizeof(secdevtype));
-
-			if (!sec_dev_types[i] ||
-			    wps_dev_type_bin2str(
-					&sec_dev_type_list[i *
-							   WPS_DEV_TYPE_LEN],
-					sec_dev_types[i],
-					sizeof(secdevtype)) == NULL) {
-				while (--i >= 0)
-					os_free(sec_dev_types[i]);
-				os_free(sec_dev_type_list);
-				goto err_no_mem;
-			}
-
-			num_sec_dev_types++;
-		}
-
-		os_free(sec_dev_type_list);
+		const u8 *sec_dev_type_list = info->wps_sec_dev_type_list;
+		int num_sec_dev_types =
+			info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN;
+		DBusMessageIter iter_secdev_dict_entry, iter_secdev_dict_val,
+				iter_secdev_dict_array;
 
 		if (num_sec_dev_types) {
-			if (!wpa_dbus_dict_append_string_array(&dict_iter,
+			if (!wpa_dbus_dict_begin_array(&dict_iter,
 						"SecondaryDeviceTypes",
-						(const char **)sec_dev_types,
-						num_sec_dev_types)) {
-				for (i = 0; i < num_sec_dev_types; i++)
-					os_free(sec_dev_types[i]);
+						DBUS_TYPE_ARRAY_AS_STRING
+						DBUS_TYPE_BYTE_AS_STRING,
+						&iter_secdev_dict_entry,
+						&iter_secdev_dict_val,
+						&iter_secdev_dict_array))
 				goto err_no_mem;
+			for (i = 0; i < num_sec_dev_types; i++) {
+				wpa_dbus_dict_bin_array_add_element(
+						&iter_secdev_dict_array,
+						sec_dev_type_list,
+						WPS_DEV_TYPE_LEN);
+				sec_dev_type_list += WPS_DEV_TYPE_LEN;
 			}
 
-			for (i = 0; i < num_sec_dev_types; i++)
-				os_free(sec_dev_types[i]);
+			if (!wpa_dbus_dict_end_array(&dict_iter,
+						&iter_secdev_dict_entry,
+						&iter_secdev_dict_val,
+						&iter_secdev_dict_array))
+				goto err_no_mem;
 		}
 	}
 
-	{
-		/* Add WPS vendor extensions attribute */
-		const struct wpabuf *vendor_extension[P2P_MAX_WPS_VENDOR_EXT];
-		int i, num = 0;
-
-		for (i = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
-			if (info->wps_vendor_ext[i] == NULL)
-				continue;
-			vendor_extension[num] = info->wps_vendor_ext[i];
-			num++;
-		}
-
-		if (!wpa_dbus_dict_append_wpabuf_array(
-					&dict_iter, "VendorExtension",
-					vendor_extension, num))
-			goto err_no_mem;
+	/* Add WPS vendor extensions attribute */
+	for (i = 0, num = 0; i < P2P_MAX_WPS_VENDOR_EXT; i++) {
+		if (info->wps_vendor_ext[i] == NULL)
+			continue;
+		vendor_extension[num] = info->wps_vendor_ext[i];
+		num++;
 	}
 
-	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
-	    !dbus_message_iter_close_container(&iter, &variant_iter))
+	if (!wpa_dbus_dict_append_wpabuf_array(&dict_iter, "VendorExtension",
+					       vendor_extension, num))
 		goto err_no_mem;
 
-	return reply;
+	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
+	    !dbus_message_iter_close_container(iter, &variant_iter))
+		goto err_no_mem;
+
+	return TRUE;
+
 err_no_mem:
-	dbus_message_unref(reply);
-	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	return FALSE;
 }
 
-DBusMessage *wpas_dbus_getter_p2p_peer_ies(DBusMessage * message,
-					   struct peer_handler_args * peer_args)
+
+dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
+					  DBusError *error, void *user_data)
 {
-	return NULL;
+	/* struct peer_handler_args *peer_args = user_data; */
+
+	dbus_set_error_const(error, DBUS_ERROR_FAILED, "not implemented");
+	return FALSE;
 }
 
 
 /**
- * wpas_dbus_getter_persistent_groups - Get array of peristent group objects
- * @message: Pointer to incoming dbus message
- * @wpa_s: wpa_supplicant structure for a network interface
- * Returns: a dbus message containing an array of all persistent group
- * dbus object paths.
+ * wpas_dbus_getter_persistent_groups - Get array of persistent group objects
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
- * Getter for "Networks" property.
+ * Getter for "PersistentGroups" property.
  */
-DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
-						 struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	struct wpa_ssid *ssid;
 	char **paths;
 	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__);
-		return wpas_dbus_error_unknown_error(message, NULL);
+		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)
@@ -1283,8 +1317,8 @@
 
 	paths = os_zalloc(num * sizeof(char *));
 	if (!paths) {
-		return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY,
-					      NULL);
+		dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+		return FALSE;
 	}
 
 	/* Loop through configured networks and append object path of each */
@@ -1293,9 +1327,8 @@
 			continue;
 		paths[i] = os_zalloc(WPAS_DBUS_OBJECT_PATH_MAX);
 		if (paths[i] == NULL) {
-			reply = dbus_message_new_error(message,
-						       DBUS_ERROR_NO_MEMORY,
-						       NULL);
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+					     "no memory");
 			goto out;
 		}
 		/* Construct the object path for this network. */
@@ -1304,74 +1337,65 @@
 			    wpa_s->dbus_new_path, ssid->id);
 	}
 
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_OBJECT_PATH,
-						       paths, num);
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 paths, num, error);
 
 out:
 	while (i)
 		os_free(paths[--i]);
 	os_free(paths);
-	return reply;
+	return success;
 }
 
 
 /**
  * wpas_dbus_getter_persistent_group_properties - Get options for a persistent
  *	group
- * @message: Pointer to incoming dbus message
- * @net: wpa_supplicant structure for a network interface and
- * wpa_ssid structure for a configured persistent group (internally network)
- * Returns: DBus message with network properties or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "Properties" property of a persistent group.
  */
-DBusMessage * wpas_dbus_getter_persistent_group_properties(
-	DBusMessage *message, struct network_handler_args *net)
+dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
+							 DBusError *error,
+							 void *user_data)
 {
-	/*
-	 * Leveraging the fact that persistent group object is still
+	struct network_handler_args *net = user_data;
+
+	/* Leveraging the fact that persistent group object is still
 	 * represented in same manner as network within.
 	 */
-	return wpas_dbus_getter_network_properties(message, net);
+	return wpas_dbus_getter_network_properties(iter, error, net);
 }
 
 
 /**
  * wpas_dbus_setter_persistent_group_properties - Get options for a persistent
  *	group
- * @message: Pointer to incoming dbus message
- * @net: wpa_supplicant structure for a network interface and
- * wpa_ssid structure for a configured persistent group (internally network)
- * Returns: DBus message with network properties or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "Properties" property of a persistent group.
  */
-DBusMessage * wpas_dbus_setter_persistent_group_properties(
-	DBusMessage *message, struct network_handler_args *net)
+dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
+							 DBusError *error,
+							 void *user_data)
 {
+	struct network_handler_args *net = user_data;
 	struct wpa_ssid *ssid = net->ssid;
-	DBusMessage *reply = NULL;
-	DBusMessageIter	iter, variant_iter;
-
-	dbus_message_iter_init(message, &iter);
-
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_next(&iter);
-
-	dbus_message_iter_recurse(&iter, &variant_iter);
+	DBusMessageIter	variant_iter;
 
 	/*
 	 * Leveraging the fact that persistent group object is still
 	 * represented in same manner as network within.
 	 */
-	reply = set_network_properties(message, net->wpa_s, ssid,
-				       &variant_iter);
-	if (reply)
-		wpa_printf(MSG_DEBUG, "dbus control interface couldn't set "
-			   "persistent group properties");
-
-	return reply;
+	dbus_message_iter_recurse(iter, &variant_iter);
+	return set_network_properties(net->wpa_s, ssid, &variant_iter, error);
 }
 
 
@@ -1393,6 +1417,7 @@
 	DBusMessageIter	iter;
 	struct wpa_ssid *ssid = NULL;
 	char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
+	DBusError error;
 
 	dbus_message_iter_init(message, &iter);
 
@@ -1414,11 +1439,16 @@
 
 	wpa_config_set_network_defaults(ssid);
 
-	reply = set_network_properties(message, wpa_s, ssid, &iter);
-	if (reply) {
+	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");
+		dbus_error_free(&error);
 		goto err;
 	}
 
@@ -1564,27 +1594,29 @@
  * Group object properties accessor methods
  */
 
-DBusMessage *wpas_dbus_getter_p2p_group_members(DBusMessage * message,
-						struct wpa_supplicant * wpa_s)
+dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	struct wpa_ssid *ssid;
 	unsigned int num_members;
 	char **paths;
 	unsigned int i;
 	void *next = NULL;
 	const u8 *addr;
+	dbus_bool_t success = FALSE;
 
 	/* Ensure we are a GO */
 	if (wpa_s->wpa_state != WPA_COMPLETED)
-		goto out;
+		return FALSE;
 
 	ssid = wpa_s->conf->ssid;
 	/* At present WPAS P2P_GO mode only applicable for p2p_go */
 	if (ssid->mode != WPAS_MODE_P2P_GO &&
 	    ssid->mode != WPAS_MODE_AP &&
 	    ssid->mode != WPAS_MODE_P2P_GROUP_FORMATION)
-		goto out;
+		return FALSE;
 
 	num_members = p2p_get_group_num_members(wpa_s->p2p_group);
 
@@ -1604,50 +1636,45 @@
 		i++;
 	}
 
-	reply = wpas_dbus_simple_array_property_getter(message,
-						       DBUS_TYPE_OBJECT_PATH,
-						       paths, num_members);
+	success = wpas_dbus_simple_array_property_getter(iter,
+							 DBUS_TYPE_OBJECT_PATH,
+							 paths, num_members,
+							 error);
 
-out_free:
 	for (i = 0; i < num_members; i++)
 		os_free(paths[i]);
 	os_free(paths);
-out:
-	return reply;
+	return success;
+
 out_of_memory:
-	reply = dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
-	goto out_free;
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	if (paths) {
+		for (i = 0; i < num_members; i++)
+			os_free(paths[i]);
+		os_free(paths);
+	}
+	return FALSE;
 }
 
 
-DBusMessage *wpas_dbus_getter_p2p_group_properties(
-	DBusMessage *message,
-	struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
+						  DBusError *error,
+						  void *user_data)
 {
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, variant_iter, dict_iter;
+	struct wpa_supplicant *wpa_s = user_data;
+	DBusMessageIter variant_iter, dict_iter;
 	struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
 	const struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
 	int num_vendor_ext = 0;
 	int i;
 
 	if (!hapd) {
-		reply = dbus_message_new_error(message, DBUS_ERROR_FAILED,
-					       NULL);
-		return reply;
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "internal error");
+		return FALSE;
 	}
 
-	if (message == NULL)
-		reply = dbus_message_new(DBUS_MESSAGE_TYPE_SIGNAL);
-	else
-		reply = dbus_message_new_method_return(message);
-
-	if (!reply)
-		goto err_no_mem;
-
-	dbus_message_iter_init_append(reply, &iter);
-
-	if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+	if (!dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
 					      "a{sv}", &variant_iter) ||
 	    !wpa_dbus_dict_open_write(&variant_iter, &dict_iter))
 		goto err_no_mem;
@@ -1665,45 +1692,42 @@
 		goto err_no_mem;
 
 	if (!wpa_dbus_dict_close_write(&variant_iter, &dict_iter) ||
-	    !dbus_message_iter_close_container(&iter, &variant_iter))
+	    !dbus_message_iter_close_container(iter, &variant_iter))
 		goto err_no_mem;
 
-	return reply;
+	return TRUE;
 
 err_no_mem:
-	dbus_message_unref(reply);
-	return dbus_message_new_error(message, DBUS_ERROR_NO_MEMORY, NULL);
+	dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, "no memory");
+	return FALSE;
 }
 
-DBusMessage *wpas_dbus_setter_p2p_group_properties(
-	DBusMessage *message,
-	struct wpa_supplicant *wpa_s)
-{
-	DBusMessage *reply = NULL;
-	DBusMessageIter iter, variant_iter;
-	struct wpa_dbus_dict_entry entry = {.type = DBUS_TYPE_STRING };
-	DBusMessageIter iter_dict;
-	unsigned int i;
 
+dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
+						  DBusError *error,
+						  void *user_data)
+{
+	struct wpa_supplicant *wpa_s = user_data;
+	DBusMessageIter variant_iter, iter_dict;
+	struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
+	unsigned int i;
 	struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
 
-	if (!hapd)
-		goto error;
+	if (!hapd) {
+		dbus_set_error_const(error, DBUS_ERROR_FAILED,
+				     "internal error");
+		return FALSE;
+	}
 
-	dbus_message_iter_init(message, &iter);
-
-	dbus_message_iter_next(&iter);
-	dbus_message_iter_next(&iter);
-
-	dbus_message_iter_recurse(&iter, &variant_iter);
-
-	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict))
-		return wpas_dbus_error_invalid_args(message, NULL);
+	dbus_message_iter_recurse(iter, &variant_iter);
+	if (!wpa_dbus_dict_open_read(&variant_iter, &iter_dict, error))
+		return FALSE;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry)) {
-			reply = wpas_dbus_error_invalid_args(message, NULL);
-			break;
+			dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+					     "invalid message format");
+			return FALSE;
 		}
 
 		if (os_strcmp(entry.key, "WPSVendorExtensions") == 0) {
@@ -1728,17 +1752,18 @@
 		wpa_dbus_dict_entry_clear(&entry);
 	}
 
-	return reply;
+	return TRUE;
 
 error:
-	reply = wpas_dbus_error_invalid_args(message, entry.key);
 	wpa_dbus_dict_entry_clear(&entry);
-
-	return reply;
+	dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+			     "invalid message format");
+	return FALSE;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_add_service(DBusMessage * message,
-					       struct wpa_supplicant * wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_add_service(DBusMessage *message,
+						struct wpa_supplicant *wpa_s)
 {
 	DBusMessageIter iter_dict;
 	DBusMessage *reply = NULL;
@@ -1753,18 +1778,18 @@
 
 	dbus_message_iter_init(message, &iter);
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto error;
 
 	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!strcmp(entry.key, "service_type") &&
+		if (!os_strcmp(entry.key, "service_type") &&
 		    (entry.type == DBUS_TYPE_STRING)) {
-			if (!strcmp(entry.str_value, "upnp"))
+			if (!os_strcmp(entry.str_value, "upnp"))
 				upnp = 1;
-			else if (!strcmp(entry.str_value, "bonjour"))
+			else if (!os_strcmp(entry.str_value, "bonjour"))
 				bonjour = 1;
 			else
 				goto error_clear;
@@ -1777,10 +1802,10 @@
 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 				goto error;
 
-			if (!strcmp(entry.key, "version") &&
+			if (!os_strcmp(entry.key, "version") &&
 			    entry.type == DBUS_TYPE_INT32)
 				version = entry.uint32_value;
-			else if (!strcmp(entry.key, "service") &&
+			else if (!os_strcmp(entry.key, "service") &&
 				 entry.type == DBUS_TYPE_STRING)
 				service = os_strdup(entry.str_value);
 			wpa_dbus_dict_entry_clear(&entry);
@@ -1797,13 +1822,14 @@
 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 				goto error;
 
-			if (!strcmp(entry.key, "query")) {
+			if (!os_strcmp(entry.key, "query")) {
 				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 (!strcmp(entry.key, "response")) {
+				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))
 					goto error_clear;
@@ -1832,8 +1858,9 @@
 	return wpas_dbus_error_invalid_args(message, NULL);
 }
 
-DBusMessage *wpas_dbus_handler_p2p_delete_service(DBusMessage * message,
-						  struct wpa_supplicant * wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_delete_service(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
 {
 	DBusMessageIter iter_dict;
 	DBusMessage *reply = NULL;
@@ -1848,18 +1875,18 @@
 
 	dbus_message_iter_init(message, &iter);
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto error;
 
 	if (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!strcmp(entry.key, "service_type") &&
+		if (!os_strcmp(entry.key, "service_type") &&
 		    (entry.type == DBUS_TYPE_STRING)) {
-			if (!strcmp(entry.str_value, "upnp"))
+			if (!os_strcmp(entry.str_value, "upnp"))
 				upnp = 1;
-			else if (!strcmp(entry.str_value, "bonjour"))
+			else if (!os_strcmp(entry.str_value, "bonjour"))
 				bonjour = 1;
 			else
 				goto error_clear;
@@ -1870,10 +1897,10 @@
 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 				goto error;
-			if (!strcmp(entry.key, "version") &&
+			if (!os_strcmp(entry.key, "version") &&
 			    entry.type == DBUS_TYPE_INT32)
 				version = entry.uint32_value;
-			else if (!strcmp(entry.key, "service") &&
+			else if (!os_strcmp(entry.key, "service") &&
 				 entry.type == DBUS_TYPE_STRING)
 				service = os_strdup(entry.str_value);
 			else
@@ -1894,12 +1921,13 @@
 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 				goto error;
 
-			if (!strcmp(entry.key, "query")) {
+			if (!os_strcmp(entry.key, "query")) {
 				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);
+				query = wpabuf_alloc_copy(
+					entry.bytearray_value,
+					entry.array_len);
 			} else
 				goto error_clear;
 
@@ -1923,15 +1951,17 @@
 	return wpas_dbus_error_invalid_args(message, NULL);
 }
 
-DBusMessage *wpas_dbus_handler_p2p_flush_service(DBusMessage * message,
-						 struct wpa_supplicant * wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_flush_service(DBusMessage *message,
+						  struct wpa_supplicant *wpa_s)
 {
 	wpas_p2p_service_flush(wpa_s);
 	return NULL;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_service_sd_req(DBusMessage * message,
-						  struct wpa_supplicant * wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_service_sd_req(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
 {
 	DBusMessageIter iter_dict;
 	DBusMessage *reply = NULL;
@@ -1947,28 +1977,28 @@
 
 	dbus_message_iter_init(message, &iter);
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto error;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
-		if (!strcmp(entry.key, "peer_object") &&
+		if (!os_strcmp(entry.key, "peer_object") &&
 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
 			peer_object_path = os_strdup(entry.str_value);
-		} else if (!strcmp(entry.key, "service_type") &&
+		} else if (!os_strcmp(entry.key, "service_type") &&
 			   entry.type == DBUS_TYPE_STRING) {
-			if (!strcmp(entry.str_value, "upnp"))
+			if (!os_strcmp(entry.str_value, "upnp"))
 				upnp = 1;
 			else
 				goto error_clear;
-		} else if (!strcmp(entry.key, "version") &&
+		} else if (!os_strcmp(entry.key, "version") &&
 			   entry.type == DBUS_TYPE_INT32) {
 			version = entry.uint32_value;
-		} else if (!strcmp(entry.key, "service") &&
+		} else if (!os_strcmp(entry.key, "service") &&
 			   entry.type == DBUS_TYPE_STRING) {
 			service = os_strdup(entry.str_value);
-		} else if (!strcmp(entry.key, "tlv")) {
+		} else if (!os_strcmp(entry.key, "tlv")) {
 			if (entry.type != DBUS_TYPE_ARRAY ||
 			    entry.array_type != DBUS_TYPE_BYTE)
 				goto error_clear;
@@ -1982,19 +2012,18 @@
 
 	if (!peer_object_path ||
 	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
-	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
+	    !p2p_peer_known(wpa_s->global->p2p, addr))
 		goto error;
 
 	if (upnp == 1) {
 		if (version <= 0 || service == NULL)
 			goto error;
 
-		ref = (unsigned long)wpas_p2p_sd_request_upnp(wpa_s, addr,
-							      version, service);
+		ref = wpas_p2p_sd_request_upnp(wpa_s, addr, version, service);
 	} else {
 		if (tlv == NULL)
 			goto error;
-		ref = (unsigned long)wpas_p2p_sd_request(wpa_s, addr, tlv);
+		ref = wpas_p2p_sd_request(wpa_s, addr, tlv);
 		wpabuf_free(tlv);
 	}
 
@@ -2003,8 +2032,8 @@
 		dbus_message_append_args(reply, DBUS_TYPE_UINT64,
 					 &ref, DBUS_TYPE_INVALID);
 	} else {
-		reply = wpas_dbus_error_unknown_error(message,
-				"Unable to send SD request");
+		reply = wpas_dbus_error_unknown_error(
+			message, "Unable to send SD request");
 	}
 out:
 	os_free(service);
@@ -2019,7 +2048,8 @@
 	goto out;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_service_sd_res(
+
+DBusMessage * wpas_dbus_handler_p2p_service_sd_res(
 	DBusMessage *message, struct wpa_supplicant *wpa_s)
 {
 	DBusMessageIter iter_dict;
@@ -2034,23 +2064,23 @@
 
 	dbus_message_iter_init(message, &iter);
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto error;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 		if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
 			goto error;
 
-		if (!strcmp(entry.key, "peer_object") &&
+		if (!os_strcmp(entry.key, "peer_object") &&
 		    entry.type == DBUS_TYPE_OBJECT_PATH) {
 			peer_object_path = os_strdup(entry.str_value);
-		} else if (!strcmp(entry.key, "frequency") &&
+		} else if (!os_strcmp(entry.key, "frequency") &&
 			   entry.type == DBUS_TYPE_INT32) {
 			freq = entry.uint32_value;
-		} else if (!strcmp(entry.key, "dialog_token") &&
+		} else if (!os_strcmp(entry.key, "dialog_token") &&
 			   entry.type == DBUS_TYPE_UINT32) {
 			dlg_tok = entry.uint32_value;
-		} else if (!strcmp(entry.key, "tlvs")) {
+		} else if (!os_strcmp(entry.key, "tlvs")) {
 			if (entry.type != DBUS_TYPE_ARRAY ||
 			    entry.array_type != DBUS_TYPE_BYTE)
 				goto error_clear;
@@ -2063,7 +2093,7 @@
 	}
 	if (!peer_object_path ||
 	    (parse_peer_object_path(peer_object_path, addr) < 0) ||
-	    (p2p_get_peer_info(wpa_s->global->p2p, addr, 0, NULL, 0) < 0))
+	    !p2p_peer_known(wpa_s->global->p2p, addr))
 		goto error;
 
 	if (tlv == NULL)
@@ -2081,8 +2111,9 @@
 	goto out;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_service_sd_cancel_req(DBusMessage * message, struct wpa_supplicant
-							 *wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_service_sd_cancel_req(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
 {
 	DBusMessageIter iter;
 	u64 req = 0;
@@ -2093,7 +2124,7 @@
 	if (req == 0)
 		goto error;
 
-	if (!wpas_p2p_sd_cancel_request(wpa_s, (void *)(unsigned long)req))
+	if (!wpas_p2p_sd_cancel_request(wpa_s, req))
 		goto error;
 
 	return NULL;
@@ -2101,16 +2132,17 @@
 	return wpas_dbus_error_invalid_args(message, NULL);
 }
 
-DBusMessage *wpas_dbus_handler_p2p_service_update(DBusMessage * message,
-						  struct wpa_supplicant * wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_service_update(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
 {
 	wpas_p2p_sd_service_update(wpa_s);
 	return NULL;
 }
 
-DBusMessage *wpas_dbus_handler_p2p_serv_disc_external(DBusMessage * message,
-						      struct wpa_supplicant *
-						      wpa_s)
+
+DBusMessage * wpas_dbus_handler_p2p_serv_disc_external(
+	DBusMessage *message, struct wpa_supplicant *wpa_s)
 {
 	DBusMessageIter iter;
 	int ext = 0;
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
index ed9a345..206e904 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
+++ b/wpa_supplicant/dbus/dbus_new_handlers_p2p.h
@@ -94,61 +94,69 @@
 /*
  * P2P Device property accessor methods.
  */
-DBusMessage *wpas_dbus_setter_p2p_device_properties(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_setter_p2p_device_properties(DBusMessageIter *iter,
+						   DBusError *error,
+						   void *user_data);
 
-DBusMessage *wpas_dbus_getter_p2p_device_properties(DBusMessage *message,
-				      struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_p2p_device_properties(DBusMessageIter *iter,
+						   DBusError *error,
+						   void *user_data);
 
-DBusMessage *wpas_dbus_getter_p2p_peers(DBusMessage *message,
-					  struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_p2p_peers(DBusMessageIter *iter, DBusError *error,
+				       void *user_data);
 
-DBusMessage *wpas_dbus_getter_p2p_role(DBusMessage *message,
-					  struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_p2p_role(DBusMessageIter *iter, DBusError *error,
+				      void *user_data);
 
-DBusMessage *wpas_dbus_getter_p2p_group(DBusMessage *message,
-					  struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_p2p_group(DBusMessageIter *iter, DBusError *error,
+				       void *user_data);
 
-DBusMessage *wpas_dbus_getter_p2p_peergo(DBusMessage *message,
-					  struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_p2p_peergo(DBusMessageIter *iter,
+					DBusError *error,
+					void *user_data);
 
 /*
  * P2P Peer properties.
  */
-DBusMessage *wpas_dbus_getter_p2p_peer_properties(
-		DBusMessage *message,
-		struct peer_handler_args *peer);
+dbus_bool_t wpas_dbus_getter_p2p_peer_properties(DBusMessageIter *iter,
+						 DBusError *error,
+						 void *user_data);
 
-DBusMessage *wpas_dbus_getter_p2p_peer_ies(
-		DBusMessage *message,
-		struct peer_handler_args *peer);
+dbus_bool_t wpas_dbus_getter_p2p_peer_ies(DBusMessageIter *iter,
+					  DBusError *error,
+					  void *user_data);
 
 /*
  * P2P Group properties
  */
 
-DBusMessage *wpas_dbus_getter_p2p_group_members(
-		DBusMessage *message,
-		struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_p2p_group_members(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data);
 
-DBusMessage *wpas_dbus_getter_p2p_group_properties(
-		DBusMessage *message,
-		struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_getter_p2p_group_properties(DBusMessageIter *iter,
+						  DBusError *error,
+						  void *user_data);
 
-DBusMessage *wpas_dbus_setter_p2p_group_properties(
-		DBusMessage *message,
-		struct wpa_supplicant *wpa_s);
+dbus_bool_t wpas_dbus_setter_p2p_group_properties(DBusMessageIter *iter,
+						  DBusError *error,
+						  void *user_data);
 
 /*
  * P2P Persistent Groups and properties
  */
 
-DBusMessage * wpas_dbus_getter_persistent_groups(DBusMessage *message,
-						 struct wpa_supplicant *wpa_s);
-DBusMessage * wpas_dbus_getter_persistent_group_properties(
-	DBusMessage *message, struct network_handler_args *net);
-DBusMessage * wpas_dbus_setter_persistent_group_properties(
-	DBusMessage *message, struct network_handler_args *net);
+dbus_bool_t wpas_dbus_getter_persistent_groups(DBusMessageIter *iter,
+					       DBusError *error,
+					       void *user_data);
+
+dbus_bool_t wpas_dbus_getter_persistent_group_properties(DBusMessageIter *iter,
+	DBusError *error, void *user_data);
+
+dbus_bool_t wpas_dbus_setter_persistent_group_properties(DBusMessageIter *iter,
+							 DBusError *error,
+							 void *user_data);
+
 DBusMessage * wpas_dbus_handler_add_persistent_group(
 	DBusMessage *message, struct wpa_supplicant *wpa_s);
 
diff --git a/wpa_supplicant/dbus/dbus_new_handlers_wps.c b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
index c118d73..a72cfb3 100644
--- a/wpa_supplicant/dbus/dbus_new_handlers_wps.c
+++ b/wpa_supplicant/dbus/dbus_new_handlers_wps.c
@@ -19,6 +19,8 @@
 #include "../config.h"
 #include "../wpa_supplicant_i.h"
 #include "../wps_supplicant.h"
+#include "../driver_i.h"
+#include "../ap.h"
 #include "dbus_new_helpers.h"
 #include "dbus_new.h"
 #include "dbus_new_handlers.h"
@@ -30,6 +32,7 @@
 	int type; /* 0 - not set, 1 - pin,      2 - pbc       */
 	u8 *bssid;
 	char *pin;
+	u8 *p2p_dev_addr;
 };
 
 
@@ -148,6 +151,41 @@
 }
 
 
+#ifdef CONFIG_P2P
+static int wpas_dbus_handler_wps_p2p_dev_addr(DBusMessage *message,
+					      DBusMessageIter *entry_iter,
+					      struct wps_start_params *params,
+					      DBusMessage **reply)
+{
+	DBusMessageIter variant_iter, array_iter;
+	int len;
+
+	dbus_message_iter_recurse(entry_iter, &variant_iter);
+	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");
+		*reply = wpas_dbus_error_invalid_args(
+			message, "P2PDeviceAddress must be a byte array");
+		return -1;
+	}
+	dbus_message_iter_recurse(&variant_iter, &array_iter);
+	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");
+		return -1;
+	}
+	return 0;
+}
+#endif /* CONFIG_P2P */
+
+
 static int wpas_dbus_handler_wps_start_entry(DBusMessage *message, char *key,
 					     DBusMessageIter *entry_iter,
 					     struct wps_start_params *params,
@@ -165,6 +203,11 @@
 	else if (os_strcmp(key, "Pin") == 0)
 		return wpas_dbus_handler_wps_pin(message, entry_iter,
 						 params, reply);
+#ifdef CONFIG_P2P
+	else if (os_strcmp(key, "P2PDeviceAddress") == 0)
+		return wpas_dbus_handler_wps_p2p_dev_addr(message, entry_iter,
+							  params, reply);
+#endif /* CONFIG_P2P */
 
 	wpa_printf(MSG_DEBUG, "dbus: WPS.Start - unknown key %s", key);
 	*reply = wpas_dbus_error_invalid_args(message, key);
@@ -231,12 +274,31 @@
 		ret = wpas_wps_start_reg(wpa_s, params.bssid, params.pin,
 					 NULL);
 	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_pin(wpa_s,
+							params.bssid,
+							params.pin,
+							npin, sizeof(npin));
+		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 {
+#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 "
@@ -284,40 +346,43 @@
  * wpas_dbus_getter_process_credentials - Check if credentials are processed
  * @message: Pointer to incoming dbus message
  * @wpa_s: %wpa_supplicant data structure
- * Returns: DBus message with a boolean on success or DBus error on failure
+ * Returns: TRUE on success, FALSE on failure
  *
  * Getter for "ProcessCredentials" property. Returns returned boolean will be
  * true if wps_cred_processing configuration field is not equal to 1 or false
  * if otherwise.
  */
-DBusMessage * wpas_dbus_getter_process_credentials(
-	DBusMessage *message, struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_getter_process_credentials(DBusMessageIter *iter,
+						 DBusError *error,
+						 void *user_data)
 {
+	struct wpa_supplicant *wpa_s = user_data;
 	dbus_bool_t process = (wpa_s->conf->wps_cred_processing != 1);
-	return wpas_dbus_simple_property_getter(message, DBUS_TYPE_BOOLEAN,
-						&process);
+	return wpas_dbus_simple_property_getter(iter, DBUS_TYPE_BOOLEAN,
+						&process, error);
 }
 
 
 /**
  * wpas_dbus_setter_process_credentials - Set credentials_processed conf param
- * @message: Pointer to incoming dbus message
- * @wpa_s: %wpa_supplicant data structure
- * Returns: NULL on success or DBus error on failure
+ * @iter: Pointer to incoming dbus message iter
+ * @error: Location to store error on failure
+ * @user_data: Function specific data
+ * Returns: TRUE on success, FALSE on failure
  *
  * Setter for "ProcessCredentials" property. Sets credentials_processed on 2
  * if boolean argument is true or on 1 if otherwise.
  */
-DBusMessage * wpas_dbus_setter_process_credentials(
-	DBusMessage *message, struct wpa_supplicant *wpa_s)
+dbus_bool_t wpas_dbus_setter_process_credentials(DBusMessageIter *iter,
+						 DBusError *error,
+						 void *user_data)
 {
-	DBusMessage *reply = NULL;
+	struct wpa_supplicant *wpa_s = user_data;
 	dbus_bool_t process_credentials, old_pc;
 
-	reply = wpas_dbus_simple_property_setter(message, DBUS_TYPE_BOOLEAN,
-						 &process_credentials);
-	if (reply)
-		return reply;
+	if (!wpas_dbus_simple_property_setter(iter, error, DBUS_TYPE_BOOLEAN,
+					      &process_credentials))
+		return FALSE;
 
 	old_pc = (wpa_s->conf->wps_cred_processing != 1);
 	wpa_s->conf->wps_cred_processing = (process_credentials ? 2 : 1);
@@ -328,5 +393,5 @@
 					       WPAS_DBUS_NEW_IFACE_WPS,
 					       "ProcessCredentials");
 
-	return NULL;
+	return TRUE;
 }
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.c b/wpa_supplicant/dbus/dbus_new_helpers.c
index 78611d4..e254365 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.c
+++ b/wpa_supplicant/dbus/dbus_new_helpers.c
@@ -21,112 +21,50 @@
 #include "dbus_common_i.h"
 #include "dbus_new.h"
 #include "dbus_new_helpers.h"
+#include "dbus_dict_helpers.h"
 
 
-/**
- * recursive_iter_copy - Reads arguments from one iterator and
- * writes to another recursively
- * @from: iterator to read from
- * @to: iterator to write to
- *
- * Copies one iterator's elements to another. If any element in
- * iterator is of container type, its content is copied recursively
- */
-static void recursive_iter_copy(DBusMessageIter *from, DBusMessageIter *to)
+static dbus_bool_t fill_dict_with_properties(
+	DBusMessageIter *dict_iter,
+	const struct wpa_dbus_property_desc *props,
+	const char *interface, void *user_data, DBusError *error)
 {
-
-	char *subtype = NULL;
-	int type;
-
-	/* iterate over iterator to copy */
-	while ((type = dbus_message_iter_get_arg_type(from)) !=
-	       DBUS_TYPE_INVALID) {
-
-		/* simply copy basic type entries */
-		if (dbus_type_is_basic(type)) {
-			if (dbus_type_is_fixed(type)) {
-				/*
-				 * According to DBus documentation all
-				 * fixed-length types are guaranteed to fit
-				 * 8 bytes
-				 */
-				dbus_uint64_t v;
-				dbus_message_iter_get_basic(from, &v);
-				dbus_message_iter_append_basic(to, type, &v);
-			} else {
-				char *v;
-				dbus_message_iter_get_basic(from, &v);
-				dbus_message_iter_append_basic(to, type, &v);
-			}
-		} else {
-			/* recursively copy container type entries */
-			DBusMessageIter write_subiter, read_subiter;
-
-			dbus_message_iter_recurse(from, &read_subiter);
-
-			if (type == DBUS_TYPE_VARIANT ||
-			    type == DBUS_TYPE_ARRAY) {
-				subtype = dbus_message_iter_get_signature(
-					&read_subiter);
-			}
-
-			dbus_message_iter_open_container(to, type, subtype,
-							 &write_subiter);
-
-			recursive_iter_copy(&read_subiter, &write_subiter);
-
-			dbus_message_iter_close_container(to, &write_subiter);
-			if (subtype)
-				dbus_free(subtype);
-		}
-
-		dbus_message_iter_next(from);
-	}
-}
-
-
-static unsigned int fill_dict_with_properties(
-	DBusMessageIter *dict_iter, const struct wpa_dbus_property_desc *props,
-	const char *interface, const void *user_data)
-{
-	DBusMessage *reply;
-	DBusMessageIter entry_iter, ret_iter;
-	unsigned int counter = 0;
+	DBusMessageIter entry_iter;
 	const struct wpa_dbus_property_desc *dsc;
 
 	for (dsc = props; dsc && dsc->dbus_property; dsc++) {
-		if (!os_strncmp(dsc->dbus_interface, interface,
-				WPAS_DBUS_INTERFACE_MAX) &&
-		    dsc->access != W && dsc->getter) {
-			reply = dsc->getter(NULL, user_data);
-			if (!reply)
-				continue;
+		/* Only return properties for the requested D-Bus interface */
+		if (os_strncmp(dsc->dbus_interface, interface,
+			       WPAS_DBUS_INTERFACE_MAX) != 0)
+			continue;
 
-			if (dbus_message_get_type(reply) ==
-			    DBUS_MESSAGE_TYPE_ERROR) {
-				dbus_message_unref(reply);
-				continue;
-			}
+		/* Skip write-only properties */
+		if (dsc->getter == NULL)
+			continue;
 
-			dbus_message_iter_init(reply, &ret_iter);
-
-			dbus_message_iter_open_container(dict_iter,
-							 DBUS_TYPE_DICT_ENTRY,
-							 NULL, &entry_iter);
-			dbus_message_iter_append_basic(
-				&entry_iter, DBUS_TYPE_STRING,
-				&dsc->dbus_property);
-
-			recursive_iter_copy(&ret_iter, &entry_iter);
-
-			dbus_message_iter_close_container(dict_iter,
-							  &entry_iter);
-			dbus_message_unref(reply);
-			counter++;
+		if (!dbus_message_iter_open_container(dict_iter,
+						      DBUS_TYPE_DICT_ENTRY,
+						      NULL, &entry_iter)) {
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+			                     "no memory");
+			return FALSE;
 		}
+		if (!dbus_message_iter_append_basic(&entry_iter,
+						    DBUS_TYPE_STRING,
+						    &dsc->dbus_property)) {
+			dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY,
+			                     "no memory");
+			return FALSE;
+		}
+
+		/* An error getting a property fails the request entirely */
+		if (!dsc->getter(&entry_iter, error, user_data))
+			return FALSE;
+
+		dbus_message_iter_close_container(dict_iter, &entry_iter);
 	}
 
-	return counter;
+	return TRUE;
 }
 
 
@@ -142,37 +80,44 @@
  * specified as argument. Returned message contains one dict argument
  * 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)
+static DBusMessage * get_all_properties(DBusMessage *message, char *interface,
+				        struct wpa_dbus_object_desc *obj_dsc)
 {
-	/* Create and initialize the return message */
-	DBusMessage *reply = dbus_message_new_method_return(message);
+	DBusMessage *reply;
 	DBusMessageIter iter, dict_iter;
-	int props_num;
+	DBusError error;
 
-	dbus_message_iter_init_append(reply, &iter);
-
-	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-					 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-					 DBUS_TYPE_STRING_AS_STRING
-					 DBUS_TYPE_VARIANT_AS_STRING
-					 DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
-					 &dict_iter);
-
-	props_num = fill_dict_with_properties(&dict_iter, obj_dsc->properties,
-					      interface, obj_dsc->user_data);
-
-	dbus_message_iter_close_container(&iter, &dict_iter);
-
-	if (props_num == 0) {
-		dbus_message_unref(reply);
-		reply = dbus_message_new_error(message,
-					       DBUS_ERROR_INVALID_ARGS,
-					       "No readable properties in "
-					       "this interface");
+	reply = dbus_message_new_method_return(message);
+	if (reply == NULL) {
+		wpa_printf(MSG_ERROR, "%s: out of memory creating dbus reply",
+			   __func__);
+		return NULL;
 	}
 
+	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;
+	}
+
+	dbus_error_init(&error);
+	if (!fill_dict_with_properties(&dict_iter, obj_dsc->properties,
+				       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");
+		dbus_error_free(&error);
+		return reply;
+	}
+
+	wpa_dbus_dict_close_write(&iter, &dict_iter);
 	return reply;
 }
 
@@ -219,15 +164,33 @@
 				    const struct wpa_dbus_property_desc *dsc,
 				    void *user_data)
 {
-	if (os_strcmp(dbus_message_get_signature(message), "ss"))
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	DBusError error;
+
+	if (os_strcmp(dbus_message_get_signature(message), "ss")) {
 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
 					      NULL);
+	}
 
-	if (dsc->access != W && dsc->getter)
-		return dsc->getter(message, user_data);
+	if (dsc->getter == NULL) {
+		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					      "Property is write-only");
+	}
 
-	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-				      "Property is write-only");
+	reply = dbus_message_new_method_return(message);
+	dbus_message_iter_init_append(reply, &iter);
+
+	dbus_error_init(&error);
+	if (dsc->getter(&iter, &error, user_data) == FALSE) {
+		dbus_message_unref(reply);
+		reply = wpas_dbus_reply_new_from_error(
+			message, &error, DBUS_ERROR_FAILED,
+			"Failed to read property");
+		dbus_error_free(&error);
+	}
+
+	return reply;
 }
 
 
@@ -235,15 +198,38 @@
 				    const struct wpa_dbus_property_desc *dsc,
 				    void *user_data)
 {
-	if (os_strcmp(dbus_message_get_signature(message), "ssv"))
+	DBusMessage *reply;
+	DBusMessageIter iter;
+	DBusError error;
+
+	if (os_strcmp(dbus_message_get_signature(message), "ssv")) {
 		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
 					      NULL);
+	}
 
-	if (dsc->access != R && dsc->setter)
-		return dsc->setter(message, user_data);
+	if (dsc->setter == NULL) {
+		return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
+					      "Property is read-only");
+	}
 
-	return dbus_message_new_error(message, DBUS_ERROR_INVALID_ARGS,
-				      "Property is read-only");
+	dbus_message_iter_init(message, &iter);
+	/* Skip the interface name and the property name */
+	dbus_message_iter_next(&iter);
+	dbus_message_iter_next(&iter);
+
+	/* Iter will now point to the property's new value */
+	dbus_error_init(&error);
+	if (dsc->setter(&iter, &error, user_data) == TRUE) {
+		/* Success */
+		reply = dbus_message_new_method_return(message);
+	} else {
+		reply = wpas_dbus_reply_new_from_error(
+			message, &error, DBUS_ERROR_FAILED,
+			"Failed to set property");
+		dbus_error_free(&error);
+	}
+
+	return reply;
 }
 
 
@@ -622,14 +608,14 @@
 }
 
 
-static void put_changed_properties(const struct wpa_dbus_object_desc *obj_dsc,
-				   const char *interface,
-				   DBusMessageIter *dict_iter)
+static dbus_bool_t put_changed_properties(
+	const struct wpa_dbus_object_desc *obj_dsc, const char *interface,
+	DBusMessageIter *dict_iter, int clear_changed)
 {
-	DBusMessage *getter_reply;
-	DBusMessageIter prop_iter, entry_iter;
+	DBusMessageIter entry_iter;
 	const struct wpa_dbus_property_desc *dsc;
 	int i;
+	DBusError error;
 
 	for (dsc = obj_dsc->properties, i = 0; dsc && dsc->dbus_property;
 	     dsc++, i++) {
@@ -638,43 +624,94 @@
 			continue;
 		if (os_strcmp(dsc->dbus_interface, interface) != 0)
 			continue;
-		obj_dsc->prop_changed_flags[i] = 0;
+		if (clear_changed)
+			obj_dsc->prop_changed_flags[i] = 0;
 
-		getter_reply = dsc->getter(NULL, obj_dsc->user_data);
-		if (!getter_reply ||
-		    dbus_message_get_type(getter_reply) ==
-		    DBUS_MESSAGE_TYPE_ERROR) {
-			wpa_printf(MSG_ERROR, "dbus: %s: Cannot get new value "
-				   "of property %s", __func__,
-				   dsc->dbus_property);
-			continue;
-		}
-
-		if (!dbus_message_iter_init(getter_reply, &prop_iter) ||
-		    !dbus_message_iter_open_container(dict_iter,
+		if (!dbus_message_iter_open_container(dict_iter,
 						      DBUS_TYPE_DICT_ENTRY,
-						      NULL, &entry_iter) ||
-		    !dbus_message_iter_append_basic(&entry_iter,
+						      NULL, &entry_iter))
+			return FALSE;
+
+		if (!dbus_message_iter_append_basic(&entry_iter,
 						    DBUS_TYPE_STRING,
 						    &dsc->dbus_property))
-			goto err;
+			return FALSE;
 
-		recursive_iter_copy(&prop_iter, &entry_iter);
+		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);
+			} else {
+				wpa_printf(MSG_ERROR, "dbus: %s: Cannot get "
+					   "new value of property %s",
+					   __func__, dsc->dbus_property);
+			}
+			dbus_error_free(&error);
+			return FALSE;
+		}
 
 		if (!dbus_message_iter_close_container(dict_iter, &entry_iter))
-			goto err;
-
-		dbus_message_unref(getter_reply);
+			return FALSE;
 	}
 
-	return;
-
-err:
-	wpa_printf(MSG_ERROR, "dbus: %s: Cannot construct signal", __func__);
+	return TRUE;
 }
 
 
-static void send_prop_changed_signal(
+static void do_send_prop_changed_signal(
+	DBusConnection *con, const char *path, const char *interface,
+	const struct wpa_dbus_object_desc *obj_dsc)
+{
+	DBusMessage *msg;
+	DBusMessageIter signal_iter, dict_iter;
+
+	msg = dbus_message_new_signal(path, DBUS_INTERFACE_PROPERTIES,
+				      "PropertiesChanged");
+	if (msg == NULL)
+		return;
+
+	dbus_message_iter_init_append(msg, &signal_iter);
+
+	if (!dbus_message_iter_append_basic(&signal_iter, DBUS_TYPE_STRING,
+					    &interface))
+		goto err;
+
+	/* 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;
+}
+
+
+static void do_send_deprecated_prop_changed_signal(
 	DBusConnection *con, const char *path, const char *interface,
 	const struct wpa_dbus_object_desc *obj_dsc)
 {
@@ -691,7 +728,8 @@
 					      "{sv}", &dict_iter))
 		goto err;
 
-	put_changed_properties(obj_dsc, interface, &dict_iter);
+	if (!put_changed_properties(obj_dsc, interface, &dict_iter, 1))
+		goto err;
 
 	if (!dbus_message_iter_close_container(&signal_iter, &dict_iter))
 		goto err;
@@ -709,6 +747,29 @@
 }
 
 
+static void send_prop_changed_signal(
+	DBusConnection *con, const char *path, const char *interface,
+	const struct wpa_dbus_object_desc *obj_dsc)
+{
+	/*
+	 * First, send property change notification on the standardized
+	 * org.freedesktop.DBus.Properties interface. This call will not
+	 * clear the property change bits, so that they are preserved for
+	 * the call that follows.
+	 */
+	do_send_prop_changed_signal(con, path, interface, obj_dsc);
+
+	/*
+	 * Now send PropertiesChanged on our own interface for backwards
+	 * compatibility. This is deprecated and will be removed in a future
+	 * release.
+	 */
+	do_send_deprecated_prop_changed_signal(con, path, interface, obj_dsc);
+
+	/* Property change bits have now been cleared. */
+}
+
+
 static void flush_object_timeout_handler(void *eloop_ctx, void *timeout_ctx)
 {
 	DBusConnection *con = eloop_ctx;
@@ -860,29 +921,49 @@
  * @iface: dbus priv struct
  * @path: path to DBus object which properties will be obtained
  * @interface: interface name which properties will be obtained
- * @dict_iter: correct, open DBus dictionary iterator.
+ * @iter: DBus message iter at which to append property dictionary.
  *
  * Iterates over all properties registered with object and execute getters
  * of those, which are readable and which interface matches interface
  * specified as argument. Obtained properties values are stored in
  * dict_iter dictionary.
  */
-void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
-				    const char *path, const char *interface,
-				    DBusMessageIter *dict_iter)
+dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
+					   const char *path,
+					   const char *interface,
+					   DBusMessageIter *iter)
 {
 	struct wpa_dbus_object_desc *obj_desc = NULL;
+	DBusMessageIter dict_iter;
+	DBusError error;
 
 	dbus_connection_get_object_path_data(iface->con, path,
 					     (void **) &obj_desc);
 	if (!obj_desc) {
-		wpa_printf(MSG_ERROR, "dbus: wpa_dbus_get_object_properties: "
-			   "could not obtain object's private data: %s", path);
-		return;
+		wpa_printf(MSG_ERROR, "dbus: %s: could not obtain object's "
+		           "private data: %s", __func__, path);
+		return FALSE;
 	}
 
-	fill_dict_with_properties(dict_iter, obj_desc->properties,
-				  interface, obj_desc->user_data);
+	if (!wpa_dbus_dict_open_write(iter, &dict_iter)) {
+		wpa_printf(MSG_ERROR, "dbus: %s: failed to open message dict",
+			   __func__);
+		return FALSE;
+	}
+
+	dbus_error_init(&error);
+	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");
+		dbus_error_free(&error);
+		return FALSE;
+	}
+
+	return wpa_dbus_dict_close_write(iter, &dict_iter);
 }
 
 /**
@@ -955,3 +1036,32 @@
 
 	return obj_path_only;
 }
+
+
+/**
+ * wpas_dbus_reply_new_from_error - Create a new D-Bus error message from a
+ *   dbus error structure
+ * @message: The original request message for which the error is a reply
+ * @error: The error containing a name and a descriptive error cause
+ * @fallback_name: A generic error name if @error was not set
+ * @fallback_string: A generic error string if @error was not set
+ * Returns: A new D-Bus error message
+ *
+ * Given a DBusMessage structure, creates a new D-Bus error message using
+ * the error name and string contained in that structure.
+ */
+DBusMessage * wpas_dbus_reply_new_from_error(DBusMessage *message,
+					     DBusError *error,
+					     const char *fallback_name,
+					     const char *fallback_string)
+{
+	if (error && error->name && error->message) {
+		return dbus_message_new_error(message, error->name,
+					      error->message);
+	}
+	if (fallback_name && fallback_string) {
+		return dbus_message_new_error(message, fallback_name,
+					      fallback_string);
+	}
+	return NULL;
+}
diff --git a/wpa_supplicant/dbus/dbus_new_helpers.h b/wpa_supplicant/dbus/dbus_new_helpers.h
index fd21c22..d6e7b48 100644
--- a/wpa_supplicant/dbus/dbus_new_helpers.h
+++ b/wpa_supplicant/dbus/dbus_new_helpers.h
@@ -22,8 +22,9 @@
 					       void *user_data);
 typedef void (* WPADBusArgumentFreeFunction)(void *handler_arg);
 
-typedef DBusMessage * (* WPADBusPropertyAccessor)(DBusMessage *message,
-						  const void *user_data);
+typedef dbus_bool_t (* WPADBusPropertyAccessor)(DBusMessageIter *iter,
+                                                DBusError *error,
+						void *user_data);
 
 struct wpa_dbus_object_desc {
 	DBusConnection *connection;
@@ -44,8 +45,6 @@
 	WPADBusArgumentFreeFunction user_data_free_func;
 };
 
-enum dbus_prop_access { R, W, RW };
-
 enum dbus_arg_direction { ARG_IN, ARG_OUT };
 
 struct wpa_dbus_argument {
@@ -67,7 +66,7 @@
 	/* method handling function */
 	WPADBusMethodHandler method_handler;
 	/* array of arguments */
-	struct wpa_dbus_argument args[3];
+	struct wpa_dbus_argument args[4];
 };
 
 /**
@@ -79,7 +78,7 @@
 	/* signal interface */
 	const char *dbus_interface;
 	/* array of arguments */
-	struct wpa_dbus_argument args[3];
+	struct wpa_dbus_argument args[4];
 };
 
 /**
@@ -96,8 +95,6 @@
 	WPADBusPropertyAccessor getter;
 	/* property setter function */
 	WPADBusPropertyAccessor setter;
-	/* property access permissions */
-	enum dbus_prop_access access;
 };
 
 
@@ -128,9 +125,10 @@
 	struct wpas_dbus_priv *ctrl_iface,
 	const char *path);
 
-void wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
-				    const char *path, const char *interface,
-				    DBusMessageIter *dict_iter);
+dbus_bool_t wpa_dbus_get_object_properties(struct wpas_dbus_priv *iface,
+					   const char *path,
+					   const char *interface,
+					   DBusMessageIter *iter);
 
 
 void wpa_dbus_flush_all_changed_properties(DBusConnection *con);
@@ -150,4 +148,9 @@
 					   char **network,
 					   char **bssid);
 
+DBusMessage *wpas_dbus_reply_new_from_error(DBusMessage *message,
+					    DBusError *error,
+					    const char *fallback_name,
+					    const char *fallback_string);
+
 #endif /* WPA_DBUS_CTRL_H */
diff --git a/wpa_supplicant/dbus/dbus_new_introspect.c b/wpa_supplicant/dbus/dbus_new_introspect.c
index fd433df..fb29f20 100644
--- a/wpa_supplicant/dbus/dbus_new_introspect.c
+++ b/wpa_supplicant/dbus/dbus_new_introspect.c
@@ -89,10 +89,11 @@
 static void add_property(struct wpabuf *xml,
 			 const struct wpa_dbus_property_desc *dsc)
 {
-	wpabuf_printf(xml, "<property name=\"%s\" type=\"%s\" access=\"%s\"/>",
+	wpabuf_printf(xml, "<property name=\"%s\" type=\"%s\" "
+		      "access=\"%s%s\"/>",
 		      dsc->dbus_property, dsc->type,
-		      (dsc->access == R ? "read" :
-		       (dsc->access == W ? "write" : "readwrite")));
+		      dsc->getter ? "read" : "",
+		      dsc->setter ? "write" : "");
 }
 
 
diff --git a/wpa_supplicant/dbus/dbus_old.c b/wpa_supplicant/dbus/dbus_old.c
index d255e14..71ab61e 100644
--- a/wpa_supplicant/dbus/dbus_old.c
+++ b/wpa_supplicant/dbus/dbus_old.c
@@ -23,7 +23,6 @@
 #include "../bss.h"
 #include "dbus_old.h"
 #include "dbus_old_handlers.h"
-#include "dbus_common.h"
 #include "dbus_common_i.h"
 
 
diff --git a/wpa_supplicant/dbus/dbus_old_handlers.c b/wpa_supplicant/dbus/dbus_old_handlers.c
index 39fe241..a7eabf3 100644
--- a/wpa_supplicant/dbus/dbus_old_handlers.c
+++ b/wpa_supplicant/dbus/dbus_old_handlers.c
@@ -116,7 +116,7 @@
 		DBusMessageIter iter_dict;
 		struct wpa_dbus_dict_entry entry;
 
-		if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+		if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 			goto error;
 		while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
 			if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
@@ -229,7 +229,7 @@
 		goto out;
 	}
 
-	if (!wpa_supplicant_remove_iface(global, wpa_s, 0)) {
+	if (!wpa_supplicant_remove_iface(global, wpa_s)) {
 		reply = wpas_dbus_new_success_reply(message);
 	} else {
 		reply = dbus_message_new_error(message,
@@ -922,7 +922,7 @@
 
 	dbus_message_iter_init(message, &iter);
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict)) {
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL)) {
 		reply = wpas_dbus_new_invalid_opts_error(message, NULL);
 		goto out;
 	}
@@ -1202,7 +1202,7 @@
 	if (!dbus_message_iter_init(message, &iter))
 		goto error;
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		goto error;
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
@@ -1324,7 +1324,7 @@
 
 	dbus_message_iter_init(message, &iter);
 
-	if (!wpa_dbus_dict_open_read(&iter, &iter_dict))
+	if (!wpa_dbus_dict_open_read(&iter, &iter_dict, NULL))
 		return wpas_dbus_new_invalid_opts_error(message, NULL);
 
 	while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
diff --git a/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service b/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service
deleted file mode 100644
index a9ce1ec..0000000
--- a/wpa_supplicant/dbus/fi.epitest.hostap.WPASupplicant.service
+++ /dev/null
@@ -1,4 +0,0 @@
-[D-BUS Service]
-Name=fi.epitest.hostap.WPASupplicant
-Exec=/sbin/wpa_supplicant -u
-User=root
diff --git a/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service b/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service
deleted file mode 100644
index df78471..0000000
--- a/wpa_supplicant/dbus/fi.w1.wpa_supplicant1.service
+++ /dev/null
@@ -1,4 +0,0 @@
-[D-BUS Service]
-Name=fi.w1.wpa_supplicant1
-Exec=/sbin/wpa_supplicant -u
-User=root
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index 429ff3b..cff25d6 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -114,11 +114,6 @@
 # Driver interface for development testing
 #CONFIG_DRIVER_TEST=y
 
-# Include client MLME (management frame processing) for test driver
-# This can be used to test MLME operations in hostapd with the test interface.
-# space.
-#CONFIG_CLIENT_MLME=y
-
 # Driver interface for wired Ethernet drivers
 CONFIG_DRIVER_WIRED=y
 
@@ -203,6 +198,9 @@
 #CONFIG_WPS2=y
 # Enable WPS external registrar functionality
 #CONFIG_WPS_ER=y
+# Disable credentials for an open network by default when acting as a WPS
+# registrar.
+#CONFIG_WPS_REG_DISABLE_OPEN=y
 
 # EAP-IKEv2
 #CONFIG_EAP_IKEV2=y
@@ -322,18 +320,24 @@
 
 # Select TLS implementation
 # openssl = OpenSSL (default)
-# gnutls = GnuTLS (needed for TLS/IA, see also CONFIG_GNUTLS_EXTRA)
+# gnutls = GnuTLS
 # internal = Internal TLSv1 implementation (experimental)
 # none = Empty template
 #CONFIG_TLS=openssl
 
-# Whether to enable TLS/IA support, which is required for EAP-TTLSv1.
-# You need CONFIG_TLS=gnutls for this to have any effect. Please note that
-# even though the core GnuTLS library is released under LGPL, this extra
-# library uses GPL and as such, the terms of GPL apply to the combination
-# of wpa_supplicant and GnuTLS if this option is enabled. BSD license may not
-# apply for distribution of the resulting binary.
-#CONFIG_GNUTLS_EXTRA=y
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used. It should be noted that some existing TLS v1.0 -based
+# implementation may not be compatible with TLS v1.1 message (ClientHello is
+# sent prior to negotiating which version will be used)
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms. It should be
+# noted that some existing TLS v1.0 -based implementation may not be compatible
+# with TLS v1.2 message (ClientHello is sent prior to negotiating which version
+# will be used)
+#CONFIG_TLSV12=y
 
 # If CONFIG_TLS=internal is used, additional library and include paths are
 # needed for LibTomMath. Alternatively, an integrated, minimal version of
@@ -455,3 +459,12 @@
 # should only be considered for builds that are known to be used on devices
 # that meet the requirements described above.
 #CONFIG_NO_RANDOM_POOL=y
+
+# IEEE 802.11n (High Throughput) support (mainly for AP mode)
+#CONFIG_IEEE80211N=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks (GAS/ANQP to learn more about the networks and network
+# selection based on available credentials).
+#CONFIG_INTERWORKING=y
diff --git a/wpa_supplicant/driver_i.h b/wpa_supplicant/driver_i.h
index b0c5ef0..108599f 100644
--- a/wpa_supplicant/driver_i.h
+++ b/wpa_supplicant/driver_i.h
@@ -79,6 +79,23 @@
 	return -1;
 }
 
+static inline int wpa_drv_sched_scan(struct wpa_supplicant *wpa_s,
+				     struct wpa_driver_scan_params *params,
+				     u32 interval)
+{
+	if (wpa_s->driver->sched_scan)
+		return wpa_s->driver->sched_scan(wpa_s->drv_priv,
+						 params, interval);
+	return -1;
+}
+
+static inline int wpa_drv_stop_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->stop_sched_scan)
+		return wpa_s->driver->stop_sched_scan(wpa_s->drv_priv);
+	return -1;
+}
+
 static inline struct wpa_scan_results * wpa_drv_get_scan_results2(
 	struct wpa_supplicant *wpa_s)
 {
@@ -236,35 +253,6 @@
 	return NULL;
 }
 
-static inline int wpa_drv_set_channel(struct wpa_supplicant *wpa_s,
-				      enum hostapd_hw_mode phymode, int chan,
-				      int freq)
-{
-	if (wpa_s->driver->set_channel)
-		return wpa_s->driver->set_channel(wpa_s->drv_priv, phymode,
-						  chan, freq);
-	return -1;
-}
-
-static inline int wpa_drv_set_ssid(struct wpa_supplicant *wpa_s,
-				   const u8 *ssid, size_t ssid_len)
-{
-	if (wpa_s->driver->set_ssid) {
-		return wpa_s->driver->set_ssid(wpa_s->drv_priv, ssid,
-					       ssid_len);
-	}
-	return -1;
-}
-
-static inline int wpa_drv_set_bssid(struct wpa_supplicant *wpa_s,
-				    const u8 *bssid)
-{
-	if (wpa_s->driver->set_bssid) {
-		return wpa_s->driver->set_bssid(wpa_s->drv_priv, bssid);
-	}
-	return -1;
-}
-
 static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
 				      const char *alpha2)
 {
@@ -274,29 +262,11 @@
 }
 
 static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
-				    const u8 *data, size_t data_len)
+				    const u8 *data, size_t data_len, int noack)
 {
 	if (wpa_s->driver->send_mlme)
 		return wpa_s->driver->send_mlme(wpa_s->drv_priv,
-						data, data_len);
-	return -1;
-}
-
-static inline int wpa_drv_mlme_add_sta(struct wpa_supplicant *wpa_s,
-				       const u8 *addr, const u8 *supp_rates,
-				       size_t supp_rates_len)
-{
-	if (wpa_s->driver->mlme_add_sta)
-		return wpa_s->driver->mlme_add_sta(wpa_s->drv_priv, addr,
-						   supp_rates, supp_rates_len);
-	return -1;
-}
-
-static inline int wpa_drv_mlme_remove_sta(struct wpa_supplicant *wpa_s,
-					  const u8 *addr)
-{
-	if (wpa_s->driver->mlme_remove_sta)
-		return wpa_s->driver->mlme_remove_sta(wpa_s->drv_priv, addr);
+						data, data_len, noack);
 	return -1;
 }
 
@@ -320,15 +290,11 @@
 	return -1;
 }
 
-static inline int wpa_drv_set_beacon(struct wpa_supplicant *wpa_s,
-				     const u8 *head, size_t head_len,
-				     const u8 *tail, size_t tail_len,
-				     int dtim_period, int beacon_int)
+static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s,
+				 struct wpa_driver_ap_params *params)
 {
-	if (wpa_s->driver->set_beacon)
-		return wpa_s->driver->set_beacon(wpa_s->drv_priv, head,
-						 head_len, tail, tail_len,
-						 dtim_period, beacon_int);
+	if (wpa_s->driver->set_ap)
+		return wpa_s->driver->set_ap(wpa_s->drv_priv, params);
 	return -1;
 }
 
@@ -386,12 +352,13 @@
 				      unsigned int wait,
 				      const u8 *dst, const u8 *src,
 				      const u8 *bssid,
-				      const u8 *data, size_t data_len)
+				      const u8 *data, size_t data_len,
+				      int no_cck)
 {
 	if (wpa_s->driver->send_action)
 		return wpa_s->driver->send_action(wpa_s->drv_priv, freq,
 						  wait, dst, src, bssid,
-						  data, data_len);
+						  data, data_len, no_cck);
 	return -1;
 }
 
@@ -431,14 +398,6 @@
 	return -1;
 }
 
-static inline int wpa_drv_set_intra_bss(struct wpa_supplicant *wpa_s,
-					int enabled)
-{
-	if (wpa_s->driver->set_intra_bss)
-		return wpa_s->driver->set_intra_bss(wpa_s->drv_priv, enabled);
-	return -1;
-}
-
 static inline int wpa_drv_remain_on_channel(struct wpa_supplicant *wpa_s,
 					    unsigned int freq,
 					    unsigned int duration)
@@ -467,15 +426,6 @@
 	return -1;
 }
 
-static inline int wpa_drv_disable_11b_rates(struct wpa_supplicant *wpa_s,
-					    int disabled)
-{
-	if (wpa_s->driver->disable_11b_rates)
-		return wpa_s->driver->disable_11b_rates(wpa_s->drv_priv,
-							disabled);
-	return -1;
-}
-
 static inline int wpa_drv_deinit_ap(struct wpa_supplicant *wpa_s)
 {
 	if (wpa_s->driver->deinit_ap)
@@ -619,12 +569,12 @@
 
 static inline int wpa_drv_p2p_prov_disc_req(struct wpa_supplicant *wpa_s,
 					    const u8 *peer_addr,
-					    u16 config_methods)
+					    u16 config_methods, int join)
 {
 	if (!wpa_s->driver->p2p_prov_disc_req)
 		return -1;
 	return wpa_s->driver->p2p_prov_disc_req(wpa_s->drv_priv, peer_addr,
-						config_methods);
+						config_methods, join);
 }
 
 static inline u64 wpa_drv_p2p_sd_request(struct wpa_supplicant *wpa_s,
@@ -704,6 +654,7 @@
 	return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
 }
 
+#ifdef ANDROID
 static inline int wpa_drv_driver_cmd(struct wpa_supplicant *wpa_s,
 				     char *cmd, char *buf, size_t buf_len)
 {
@@ -711,5 +662,24 @@
 		return -1;
 	return wpa_s->driver->driver_cmd(wpa_s->drv_priv, cmd, buf, buf_len);
 }
+#endif
 
+static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
+					  const u8 *kek, const u8 *kck,
+					  const u8 *replay_ctr)
+{
+	if (!wpa_s->driver->set_rekey_info)
+		return;
+	wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
+}
+
+#ifdef ANDROID_P2P
+static inline int wpa_drv_go_switch_channel(struct wpa_supplicant *wpa_s,
+					  int freq)
+{
+	if (!wpa_s->driver->go_switch_channel)
+		return -1;
+	return wpa_s->driver->go_switch_channel(wpa_s->drv_priv, freq);
+}
+#endif
 #endif /* DRIVER_I_H */
diff --git a/wpa_supplicant/eap_register.c b/wpa_supplicant/eap_register.c
index e5f43aa..b3faaa1 100644
--- a/wpa_supplicant/eap_register.c
+++ b/wpa_supplicant/eap_register.c
@@ -17,6 +17,7 @@
 #include "common.h"
 #include "eap_peer/eap_methods.h"
 #include "eap_server/eap_methods.h"
+#include "wpa_supplicant_i.h"
 
 
 /**
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index 332a044..76f7527 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -24,6 +24,7 @@
 #include "eap_peer/eap.h"
 #include "eap_server/eap_methods.h"
 #include "eloop.h"
+#include "utils/base64.h"
 #include "rsn_supp/wpa.h"
 #include "eap_peer/eap_i.h"
 #include "wpa_supplicant_i.h"
@@ -76,6 +77,8 @@
 	char *connect_info;
 	u8 own_addr[ETH_ALEN];
 	struct extra_radius_attr *extra_attrs;
+
+	FILE *server_cert_file;
 };
 
 static struct eapol_test_data eapol_test;
@@ -292,7 +295,6 @@
 static int eapol_test_eapol_send(void *ctx, int type, const u8 *buf,
 				 size_t len)
 {
-	/* struct wpa_supplicant *wpa_s = ctx; */
 	printf("WPA: eapol_test_eapol_send(type=%d len=%lu)\n",
 	       type, (unsigned long) len);
 	if (type == IEEE802_1X_TYPE_EAP_PACKET) {
@@ -306,16 +308,16 @@
 static void eapol_test_set_config_blob(void *ctx,
 				       struct wpa_config_blob *blob)
 {
-	struct wpa_supplicant *wpa_s = ctx;
-	wpa_config_set_blob(wpa_s->conf, blob);
+	struct eapol_test_data *e = ctx;
+	wpa_config_set_blob(e->wpa_s->conf, blob);
 }
 
 
 static const struct wpa_config_blob *
 eapol_test_get_config_blob(void *ctx, const char *name)
 {
-	struct wpa_supplicant *wpa_s = ctx;
-	return wpa_config_get_blob(wpa_s->conf, name);
+	struct eapol_test_data *e = ctx;
+	return wpa_config_get_blob(e->wpa_s->conf, name);
 }
 
 
@@ -384,6 +386,20 @@
 }
 
 
+static void eapol_test_write_cert(FILE *f, const char *subject,
+				  const struct wpabuf *cert)
+{
+	unsigned char *encoded;
+
+	encoded = base64_encode(wpabuf_head(cert), wpabuf_len(cert), NULL);
+	if (encoded == NULL)
+		return;
+	fprintf(f, "%s\n-----BEGIN CERTIFICATE-----\n%s"
+		"-----END CERTIFICATE-----\n\n", subject, encoded);
+	os_free(encoded);
+}
+
+
 static void eapol_test_cert_cb(void *ctx, int depth, const char *subject,
 			       const char *cert_hash,
 			       const struct wpabuf *cert)
@@ -409,6 +425,10 @@
 				     depth, subject, cert_hex);
 			os_free(cert_hex);
 		}
+
+		if (e->server_cert_file)
+			eapol_test_write_cert(e->server_cert_file,
+					      subject, cert);
 	}
 }
 
@@ -424,7 +444,7 @@
 		printf("Failed to allocate EAPOL context.\n");
 		return -1;
 	}
-	ctx->ctx = wpa_s;
+	ctx->ctx = e;
 	ctx->msg_ctx = wpa_s;
 	ctx->scard_ctx = wpa_s->scard;
 	ctx->cb = eapol_sm_cb;
@@ -439,6 +459,7 @@
 	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
 	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
 	ctx->cert_cb = eapol_test_cert_cb;
+	ctx->cert_in_cb = 1;
 
 	wpa_s->eapol = eapol_sm_init(ctx);
 	if (wpa_s->eapol == NULL) {
@@ -995,7 +1016,7 @@
 	       "eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] "
 	       "[-s<AS secret>]\\\n"
 	       "           [-r<count>] [-t<timeout>] [-C<Connect-Info>] \\\n"
-	       "           [-M<client MAC address>] \\\n"
+	       "           [-M<client MAC address>] [-o<server cert file] \\\n"
 	       "           [-N<attr spec>] \\\n"
 	       "           [-A<client IP>]\n"
 	       "eapol_test scard\n"
@@ -1021,6 +1042,8 @@
 	       "  -M<client MAC address> = Set own MAC address "
 	       "(Calling-Station-Id,\n"
 	       "                           default: 02:00:00:00:00:01)\n"
+	       "  -o<server cert file> = Write received server certificate\n"
+	       "                         chain to the specified file\n"
 	       "  -N<attr spec> = send arbitrary attribute specified by:\n"
 	       "                  attr_id:syntax:value or attr_id\n"
 	       "                  attr_id - number id of the attribute\n"
@@ -1062,7 +1085,7 @@
 	wpa_debug_show_keys = 1;
 
 	for (;;) {
-		c = getopt(argc, argv, "a:A:c:C:M:nN:p:r:s:St:W");
+		c = getopt(argc, argv, "a:A:c:C:M:nN:o:p:r:s:St:W");
 		if (c < 0)
 			break;
 		switch (c) {
@@ -1087,6 +1110,16 @@
 		case 'n':
 			eapol_test.no_mppe_keys++;
 			break;
+		case 'o':
+			if (eapol_test.server_cert_file)
+				fclose(eapol_test.server_cert_file);
+			eapol_test.server_cert_file = fopen(optarg, "w");
+			if (eapol_test.server_cert_file == NULL) {
+				printf("Could not open '%s' for writing\n",
+				       optarg);
+				return -1;
+			}
+			break;
 		case 'p':
 			as_port = atoi(optarg);
 			break;
@@ -1229,6 +1262,9 @@
 
 	eloop_destroy();
 
+	if (eapol_test.server_cert_file)
+		fclose(eapol_test.server_cert_file);
+
 	printf("MPPE keys OK: %d  mismatch: %d\n",
 	       eapol_test.num_mppe_ok, eapol_test.num_mppe_mismatch);
 	if (eapol_test.num_mppe_mismatch)
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 2765aef..4bbd2e4 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -38,12 +38,13 @@
 #include "wps_supplicant.h"
 #include "ibss_rsn.h"
 #include "sme.h"
+#include "gas_query.h"
 #include "p2p_supplicant.h"
 #include "bgscan.h"
 #include "ap.h"
 #include "bss.h"
-#include "mlme.h"
 #include "scan.h"
+#include "offchannel.h"
 
 
 static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
@@ -69,11 +70,7 @@
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the "
 		"current AP");
-	if (ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
-			      WPA_KEY_MGMT_WPA_NONE |
-			      WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_FT_IEEE8021X |
-			      WPA_KEY_MGMT_PSK_SHA256 |
-			      WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+	if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
 		u8 wpa_ie[80];
 		size_t wpa_ie_len = sizeof(wpa_ie);
 		wpa_supplicant_set_suites(wpa_s, NULL, ssid,
@@ -95,8 +92,7 @@
 }
 
 
-static void wpa_supplicant_stop_countermeasures(void *eloop_ctx,
-						void *sock_ctx)
+void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 
@@ -230,6 +226,7 @@
 			      struct wpa_ssid *ssid)
 {
 #ifdef IEEE8021X_EAPOL
+#ifdef PCSC_FUNCS
 	int aka = 0, sim = 0, type;
 
 	if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
@@ -281,6 +278,7 @@
 	}
 	wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
 	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* PCSC_FUNCS */
 #endif /* IEEE8021X_EAPOL */
 
 	return 0;
@@ -476,6 +474,115 @@
 }
 
 
+static 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;
+}
+
+
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_scan_res *bss)
+{
+	const struct hostapd_hw_modes *mode = NULL, *modes;
+	const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
+	const u8 *rate_ie;
+	int i, j, k;
+
+	if (bss->freq == 0)
+		return 1; /* Cannot do matching without knowing band */
+
+	modes = wpa_s->hw.modes;
+	if (modes == NULL) {
+		/*
+		 * The driver does not provide any additional information
+		 * about the utilized hardware, so allow the connection attempt
+		 * to continue.
+		 */
+		return 1;
+	}
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		for (j = 0; j < modes[i].num_channels; j++) {
+			int freq = modes[i].channels[j].freq;
+			if (freq == bss->freq) {
+				if (mode &&
+				    mode->mode == HOSTAPD_MODE_IEEE80211G)
+					break; /* do not allow 802.11b replace
+						* 802.11g */
+				mode = &modes[i];
+				break;
+			}
+		}
+	}
+
+	if (mode == NULL)
+		return 0;
+
+	for (i = 0; i < (int) sizeof(scan_ie); i++) {
+		rate_ie = wpa_scan_get_ie(bss, scan_ie[i]);
+		if (rate_ie == NULL)
+			continue;
+
+		for (j = 2; j < rate_ie[1] + 2; j++) {
+			int flagged = !!(rate_ie[j] & 0x80);
+			int r = (rate_ie[j] & 0x7f) * 5;
+
+			/*
+			 * IEEE Std 802.11n-2009 7.3.2.2:
+			 * The new BSS Membership selector value is encoded
+			 * like a legacy basic rate, but it is not a rate and
+			 * only indicates if the BSS members are required to
+			 * support the mandatory features of Clause 20 [HT PHY]
+			 * in order to join the BSS.
+			 */
+			if (flagged && ((rate_ie[j] & 0x7f) ==
+					BSS_MEMBERSHIP_SELECTOR_HT_PHY)) {
+				if (!ht_supported(mode)) {
+					wpa_dbg(wpa_s, MSG_DEBUG,
+						"   hardware does not support "
+						"HT PHY");
+					return 0;
+				}
+				continue;
+			}
+
+			if (!flagged)
+				continue;
+
+			/* check for legacy basic rates */
+			for (k = 0; k < mode->num_rates; k++) {
+				if (mode->rates[k] == r)
+					break;
+			}
+			if (k == mode->num_rates) {
+				/*
+				 * IEEE Std 802.11-2007 7.3.2.2 demands that in
+				 * order to join a BSS all required rates
+				 * have to be supported by the hardware.
+				 */
+				wpa_dbg(wpa_s, MSG_DEBUG, "   hardware does "
+					"not support required rate %d.%d Mbps",
+					r / 10, r % 10);
+				return 0;
+			}
+		}
+	}
+
+	return 1;
+}
+
+
 static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
 					    int i, struct wpa_scan_res *bss,
 					    struct wpa_ssid *group)
@@ -561,6 +668,10 @@
 		}
 #endif /* CONFIG_WPS */
 
+		if (ssid->bssid_set && ssid->ssid_len == 0 &&
+		    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
+			check_ssid = 0;
+
 		if (check_ssid &&
 		    (ssid_len != ssid->ssid_len ||
 		     os_memcmp(ssid_, ssid->ssid, ssid_len) != 0)) {
@@ -604,6 +715,12 @@
 			continue;
 		}
 
+		if (!rate_match(wpa_s, bss)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - rate sets do "
+				"not match");
+			continue;
+		}
+
 #ifdef CONFIG_P2P
 		/*
 		 * TODO: skip the AP if its P2P IE has Group Formation
@@ -672,7 +789,8 @@
 				break;
 		}
 
-		if (selected == NULL && wpa_s->blacklist) {
+		if (selected == NULL && wpa_s->blacklist &&
+		    !wpa_s->countermeasures) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "No APs found - clear "
 				"blacklist and try again");
 			wpa_blacklist_clear(wpa_s);
@@ -700,35 +818,23 @@
 	wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec);
 }
 
-#ifdef ANDROID_BRCM_P2P_PATCH
+
 int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
-#else
-void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
-#endif /* ANDROID_BRCM_P2P_PATCH */
-			    struct wpa_bss *selected,
-			    struct wpa_ssid *ssid)
+			   struct wpa_bss *selected,
+			   struct wpa_ssid *ssid)
 {
 	if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
 		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
 			"PBC session overlap");
 #ifdef CONFIG_P2P
-		if (wpas_p2p_notif_pbc_overlap(wpa_s) == 1) {
-#ifdef ANDROID_BRCM_P2P_PATCH
+		if (wpas_p2p_notif_pbc_overlap(wpa_s) == 1)
 			return -1;
-#else
-			return;
-#endif
-		}
 #endif /* CONFIG_P2P */
 
 #ifdef CONFIG_WPS
 		wpas_wps_cancel(wpa_s);
 #endif /* CONFIG_WPS */
-#ifdef ANDROID_BRCM_P2P_PATCH
 		return -1;
-#else
-		return;
-#endif /* ANDROID_BRCM_P2P_PATCH */
 	}
 
 	/*
@@ -736,12 +842,7 @@
 	 * reassociation is requested. If we are in process of associating with
 	 * the selected BSSID, do not trigger new attempt.
 	 */
-	if ((wpa_s->reassociate
-#ifdef ANDROID_BRCM_P2P_PATCH
-		&& (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0)
-		&& (wpa_s->wpa_state != WPA_COMPLETED)
-#endif
-		)||
+	if (wpa_s->reassociate ||
 	    (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
 	     ((wpa_s->wpa_state != WPA_ASSOCIATING &&
 	       wpa_s->wpa_state != WPA_AUTHENTICATING) ||
@@ -749,11 +850,7 @@
 	      0))) {
 		if (wpa_supplicant_scard_init(wpa_s, ssid)) {
 			wpa_supplicant_req_new_scan(wpa_s, 10, 0);
-#ifdef ANDROID_BRCM_P2P_PATCH
 			return 0;
-#else
-			return;
-#endif
 		}
 		wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
 			"reassociate: %d  selected: "MACSTR "  bssid: " MACSTR
@@ -766,9 +863,8 @@
 		wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
 			"selected AP");
 	}
-#ifdef ANDROID_BRCM_P2P_PATCH
+
 	return 0;
-#endif
 }
 
 
@@ -837,6 +933,9 @@
 	if (wpa_s->current_ssid != ssid)
 		return 1; /* different network block */
 
+	if (wpas_driver_bss_selection(wpa_s))
+		return 0; /* Driver-based roaming */
+
 	for (i = 0; i < scan_res->num; i++) {
 		struct wpa_scan_res *res = scan_res->res[i];
 		const u8 *ie;
@@ -912,6 +1011,18 @@
 
 	wpa_supplicant_notify_scanning(wpa_s, 0);
 
+#ifdef CONFIG_P2P
+	if (wpa_s->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+	    wpa_s->global->p2p != NULL) {
+		wpa_s->p2p_cb_on_scan_complete = 0;
+		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+				"stopped scan processing");
+			return -1;
+		}
+	}
+#endif /* CONFIG_P2P */
+
 	scan_res = wpa_supplicant_get_scan_results(wpa_s,
 						   data ? &data->scan_info :
 						   NULL, 1);
@@ -980,7 +1091,8 @@
 		return 0;
 	}
 
-	if (bgscan_notify_scan(wpa_s, scan_res) == 1) {
+	if (!wpas_driver_bss_selection(wpa_s) &&
+	    bgscan_notify_scan(wpa_s, scan_res) == 1) {
 		wpa_scan_results_free(scan_res);
 		return 0;
 	}
@@ -992,16 +1104,15 @@
 		skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid,
 						    scan_res);
 		wpa_scan_results_free(scan_res);
-		if (skip)
+		if (skip) {
+			wpa_supplicant_rsn_preauth_scan_results(wpa_s);
 			return 0;
-#ifdef ANDROID_BRCM_P2P_PATCH
+		}
+
 		if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "Connect Failed");
+			wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
 			return -1;
 		}
-#else
-		wpa_supplicant_connect(wpa_s, selected, ssid);
-#endif
 		wpa_supplicant_rsn_preauth_scan_results(wpa_s);
 	} else {
 		wpa_scan_results_free(scan_res);
@@ -1022,10 +1133,14 @@
 				 */
 				timeout_sec = 0;
 				timeout_usec = 250000;
+				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+							    timeout_usec);
+				return 0;
 			}
 #endif /* CONFIG_P2P */
-			wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
-						    timeout_usec);
+			if (wpa_supplicant_req_sched_scan(wpa_s))
+				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+							    timeout_usec);
 		}
 	}
 	return 0;
@@ -1270,11 +1385,8 @@
 		return;
 
 	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
-	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) ||
-	    (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
-	     os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0)) {
+	if (wpa_drv_get_bssid(wpa_s, bssid) >= 0 &&
+	    os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
 			MACSTR, MAC2STR(bssid));
 		random_add_randomness(bssid, ETH_ALEN);
@@ -1427,12 +1539,22 @@
 }
 
 
+static int disconnect_reason_recoverable(u16 reason_code)
+{
+	return reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY ||
+		reason_code == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA ||
+		reason_code == WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+}
+
+
 static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
 					  u16 reason_code)
 {
 	const u8 *bssid;
 	int authenticating;
 	u8 prev_pending_bssid[ETH_ALEN];
+	struct wpa_bss *fast_reconnect = NULL;
+	struct wpa_ssid *fast_reconnect_ssid = NULL;
 
 	authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
 	os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
@@ -1455,13 +1577,29 @@
 	}
 	if (!wpa_s->auto_reconnect_disabled ||
 	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Auto connect enabled: try to "
-			"reconnect (wps=%d)",
-			wpa_s->key_mgmt == WPA_KEY_MGMT_WPS);
-		if (wpa_s->wpa_state >= WPA_ASSOCIATING)
+		wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to "
+			"reconnect (wps=%d wpa_state=%d)",
+			wpa_s->key_mgmt == WPA_KEY_MGMT_WPS,
+			wpa_s->wpa_state);
+		if (wpa_s->wpa_state == WPA_COMPLETED &&
+		    wpa_s->current_ssid &&
+		    wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+		    disconnect_reason_recoverable(reason_code)) {
+			/*
+			 * It looks like the AP has dropped association with
+			 * us, but could allow us to get back in. Try to
+			 * reconnect to the same BSS without full scan to save
+			 * time for some common cases.
+			 */
+			fast_reconnect = wpa_s->current_bss;
+			fast_reconnect_ssid = wpa_s->current_ssid;
+		} else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
 			wpa_supplicant_req_scan(wpa_s, 0, 500000);
+		else
+			wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
+				"immediate scan");
 	} else {
-		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Auto connect disabled: do not "
+		wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not "
 			"try to re-connect");
 		wpa_s->reassociate = 0;
 		wpa_s->disconnected = 1;
@@ -1469,7 +1607,8 @@
 	bssid = wpa_s->bssid;
 	if (is_zero_ether_addr(bssid))
 		bssid = wpa_s->pending_bssid;
-	wpas_connection_failed(wpa_s, bssid);
+	if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+		wpas_connection_failed(wpa_s, bssid);
 	wpa_sm_notify_disassoc(wpa_s->wpa);
 	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
 		" reason=%d",
@@ -1483,12 +1622,22 @@
 
 	if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
 		sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid);
+
+	if (fast_reconnect) {
+#ifndef CONFIG_NO_SCAN_PROCESSING
+		wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
+		if (wpa_supplicant_connect(wpa_s, fast_reconnect,
+					   fast_reconnect_ssid) < 0) {
+			/* Recover through full scan */
+			wpa_supplicant_req_scan(wpa_s, 0, 100000);
+		}
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+	}
 }
 
 
 #ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
-static void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx,
-						    void *sock_ctx)
+void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 
@@ -1532,6 +1681,9 @@
 
 		/* initialize countermeasures */
 		wpa_s->countermeasures = 1;
+
+		wpa_blacklist_add(wpa_s, wpa_s->bssid);
+
 		wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
 
 		/*
@@ -1667,9 +1819,8 @@
 		wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
 		break;
 	case TDLS_REQUEST_TEARDOWN:
-		/* request from driver to add FTIE */
-		wpa_tdls_recv_teardown_notify(wpa_s->wpa, data->tdls.peer,
-					      data->tdls.reason_code);
+		wpa_tdls_send_teardown(wpa_s->wpa, data->tdls.peer,
+				       data->tdls.reason_code);
 		break;
 	}
 }
@@ -1796,6 +1947,50 @@
 }
 
 
+static void wnm_action_rx(struct wpa_supplicant *wpa_s, struct rx_action *rx)
+{
+	u8 action, mode;
+	const u8 *pos, *end;
+
+	if (rx->data == NULL || rx->len == 0)
+		return;
+
+	pos = rx->data;
+	end = pos + rx->len;
+	action = *pos++;
+
+	wpa_printf(MSG_DEBUG, "WNM: RX action %u from " MACSTR,
+		   action, MAC2STR(rx->sa));
+	switch (action) {
+	case WNM_BSS_TRANS_MGMT_REQ:
+		if (pos + 5 > end)
+			break;
+		wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
+			   "Request: dialog_token=%u request_mode=0x%x "
+			   "disassoc_timer=%u validity_interval=%u",
+			   pos[0], pos[1], WPA_GET_LE16(pos + 2), pos[4]);
+		mode = pos[1];
+		pos += 5;
+		if (mode & 0x08)
+			pos += 12; /* BSS Termination Duration */
+		if (mode & 0x10) {
+			char url[256];
+			if (pos + 1 > end || pos + 1 + pos[0] > end) {
+				wpa_printf(MSG_DEBUG, "WNM: Invalid BSS "
+					   "Transition Management Request "
+					   "(URL)");
+				break;
+			}
+			os_memcpy(url, pos + 1, pos[0]);
+			url[pos[0]] = '\0';
+			wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation "
+				"Imminent - session_info_url=%s", url);
+		}
+		break;
+	}
+}
+
+
 void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
@@ -1804,14 +1999,33 @@
 
 	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
 	    event != EVENT_INTERFACE_ENABLED &&
-	    event != EVENT_INTERFACE_STATUS) {
-		wpa_dbg(wpa_s, MSG_DEBUG, "Ignore event %d while interface is "
-			"disabled", event);
+	    event != EVENT_INTERFACE_STATUS &&
+	    event != EVENT_SCHED_SCAN_STOPPED) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Ignore event %s (%d) while interface is disabled",
+			event_to_string(event), event);
 		return;
 	}
 
-	wpa_dbg(wpa_s, MSG_DEBUG, "Event %d received on interface %s",
-		event, wpa_s->ifname);
+#ifndef CONFIG_NO_STDOUT_DEBUG
+{
+	int level = MSG_DEBUG;
+
+	if (event == EVENT_RX_MGMT && data && data->rx_mgmt.frame &&
+	    data->rx_mgmt.frame_len >= 24) {
+		const struct ieee80211_hdr *hdr;
+		u16 fc;
+		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+		fc = le_to_host16(hdr->frame_control);
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+			level = MSG_EXCESSIVE;
+	}
+
+	wpa_dbg(wpa_s, level, "Event %s (%d) received",
+		event_to_string(event), event);
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
 
 	switch (event) {
 	case EVENT_AUTH:
@@ -1835,6 +2049,11 @@
 					       data->disassoc_info.addr);
 			break;
 		}
+		if (wpa_s->ap_iface) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in "
+				"AP mode");
+			break;
+		}
 #endif /* CONFIG_AP */
 		if (data) {
 			reason_code = data->disassoc_info.reason_code;
@@ -1884,13 +2103,13 @@
 					       data->deauth_info.addr);
 			break;
 		}
+		if (wpa_s->ap_iface) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in "
+				"AP mode");
+			break;
+		}
 #endif /* CONFIG_AP */
 		wpa_supplicant_event_disassoc(wpa_s, reason_code);
-
-#if defined(ANDROID_BRCM_P2P_PATCH) && defined(CONFIG_P2P)
-		wpas_p2p_group_remove_notif(wpa_s, reason_code);
-#endif
-
 		break;
 	case EVENT_MICHAEL_MIC_FAILURE:
 		wpa_supplicant_event_michael_mic_failure(wpa_s, data);
@@ -1950,27 +2169,28 @@
 		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
 			sme_event_assoc_timed_out(wpa_s, data);
 		break;
-#ifdef CONFIG_AP
 	case EVENT_TX_STATUS:
 		wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS dst=" MACSTR
 			" type=%d stype=%d",
 			MAC2STR(data->tx_status.dst),
 			data->tx_status.type, data->tx_status.stype);
+#ifdef CONFIG_AP
 		if (wpa_s->ap_iface == NULL) {
-#ifdef CONFIG_P2P
+#ifdef CONFIG_OFFCHANNEL
 			if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
 			    data->tx_status.stype == WLAN_FC_STYPE_ACTION)
-				wpas_send_action_tx_status(
+				offchannel_send_action_tx_status(
 					wpa_s, data->tx_status.dst,
 					data->tx_status.data,
 					data->tx_status.data_len,
 					data->tx_status.ack ?
-					P2P_SEND_ACTION_SUCCESS :
-					P2P_SEND_ACTION_NO_ACK);
-#endif /* CONFIG_P2P */
+					OFFCHANNEL_SEND_ACTION_SUCCESS :
+					OFFCHANNEL_SEND_ACTION_NO_ACK);
+#endif /* CONFIG_OFFCHANNEL */
 			break;
 		}
-#ifdef CONFIG_P2P
+#endif /* CONFIG_AP */
+#ifdef CONFIG_OFFCHANNEL
 		wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst="
 			MACSTR, MAC2STR(wpa_s->parent->pending_action_dst));
 		/*
@@ -1981,16 +2201,17 @@
 		    data->tx_status.stype == WLAN_FC_STYPE_ACTION &&
 		    os_memcmp(wpa_s->parent->pending_action_dst,
 			      data->tx_status.dst, ETH_ALEN) == 0) {
-			wpas_send_action_tx_status(
+			offchannel_send_action_tx_status(
 				wpa_s->parent, data->tx_status.dst,
 				data->tx_status.data,
 				data->tx_status.data_len,
 				data->tx_status.ack ?
-				P2P_SEND_ACTION_SUCCESS :
-				P2P_SEND_ACTION_NO_ACK);
+				OFFCHANNEL_SEND_ACTION_SUCCESS :
+				OFFCHANNEL_SEND_ACTION_NO_ACK);
 			break;
 		}
-#endif /* CONFIG_P2P */
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_AP
 		switch (data->tx_status.type) {
 		case WLAN_FC_TYPE_MGMT:
 			ap_mgmt_tx_cb(wpa_s, data->tx_status.data,
@@ -2005,12 +2226,23 @@
 				     data->tx_status.ack);
 			break;
 		}
+#endif /* CONFIG_AP */
+		break;
+#ifdef CONFIG_AP
+	case EVENT_EAPOL_TX_STATUS:
+		ap_eapol_tx_status(wpa_s, data->eapol_tx_status.dst,
+				   data->eapol_tx_status.data,
+				   data->eapol_tx_status.data_len,
+				   data->eapol_tx_status.ack);
+		break;
+	case EVENT_DRIVER_CLIENT_POLL_OK:
+		ap_client_poll_ok(wpa_s, data->client_poll.addr);
 		break;
 	case EVENT_RX_FROM_UNKNOWN:
 		if (wpa_s->ap_iface == NULL)
 			break;
-		ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.frame,
-				       data->rx_from_unknown.len);
+		ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
+				       data->rx_from_unknown.wds);
 		break;
 	case EVENT_RX_MGMT:
 		if (wpa_s->ap_iface == NULL) {
@@ -2028,26 +2260,8 @@
 				size_t ie_len = data->rx_mgmt.frame_len -
 					(mgmt->u.probe_req.variable -
 					 data->rx_mgmt.frame);
-			#ifdef ANDROID_BRCM_P2P_PATCH
-				wpa_printf(MSG_DEBUG, "Non-AP: Probe request frame ");
-			{
-				/* If we are Go or client, we need not reply the probe reqest on eth0 interface */
-				struct wpa_supplicant* ifs;
-				int ignore = 0;
-				for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
-					if ( (ifs->p2p_group_interface == P2P_GROUP_INTERFACE_GO ) ||(ifs->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT )) {
-						wpa_printf(MSG_DEBUG, "Non-AP: NEERAJKG Ignoring Probe request");
-						ignore = 1;
-						break;
-					}
-				}
-				if(ignore)
-					break;
-				else
-					wpa_printf(MSG_DEBUG, "Non-AP: Couln't Ignore Probe request %d", wpa_s->p2p_group_interface);
-			}
-			#endif
-				wpas_p2p_probe_req_rx(wpa_s, src, ie, ie_len);
+				wpas_p2p_probe_req_rx(wpa_s, src, mgmt->da,
+						      mgmt->bssid, ie, ie_len);
 				break;
 			}
 #endif /* CONFIG_P2P */
@@ -2081,6 +2295,28 @@
 		}
 #endif /* CONFIG_SME */
 #endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_GAS
+		if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
+		    gas_query_rx(wpa_s->gas, data->rx_action.da,
+				 data->rx_action.sa, data->rx_action.bssid,
+				 data->rx_action.data, data->rx_action.len,
+				 data->rx_action.freq) == 0)
+			break;
+#endif /* CONFIG_GAS */
+		if (data->rx_action.category == WLAN_ACTION_WNM) {
+			wnm_action_rx(wpa_s, &data->rx_action);
+			break;
+		}
+#ifdef CONFIG_TDLS
+		if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
+		    data->rx_action.len >= 4 &&
+		    data->rx_action.data[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "TDLS: Received Discovery "
+				"Response from " MACSTR,
+				MAC2STR(data->rx_action.sa));
+			break;
+		}
+#endif /* CONFIG_TDLS */
 #ifdef CONFIG_P2P
 		wpas_p2p_rx_action(wpa_s, data->rx_action.da,
 				   data->rx_action.sa,
@@ -2098,6 +2334,8 @@
 		if (wpa_s->ap_iface) {
 			hostapd_probe_req_rx(wpa_s->ap_iface->bss[0],
 					     data->rx_probe_req.sa,
+					     data->rx_probe_req.da,
+					     data->rx_probe_req.bssid,
 					     data->rx_probe_req.ie,
 					     data->rx_probe_req.ie_len);
 			break;
@@ -2105,20 +2343,35 @@
 #endif /* CONFIG_AP */
 #ifdef CONFIG_P2P
 		wpas_p2p_probe_req_rx(wpa_s, data->rx_probe_req.sa,
+				      data->rx_probe_req.da,
+				      data->rx_probe_req.bssid,
 				      data->rx_probe_req.ie,
 				      data->rx_probe_req.ie_len);
 #endif /* CONFIG_P2P */
 		break;
-#ifdef CONFIG_P2P
 	case EVENT_REMAIN_ON_CHANNEL:
+#ifdef CONFIG_OFFCHANNEL
+		offchannel_remain_on_channel_cb(
+			wpa_s, data->remain_on_channel.freq,
+			data->remain_on_channel.duration);
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_P2P
 		wpas_p2p_remain_on_channel_cb(
 			wpa_s, data->remain_on_channel.freq,
 			data->remain_on_channel.duration);
+#endif /* CONFIG_P2P */
 		break;
 	case EVENT_CANCEL_REMAIN_ON_CHANNEL:
+#ifdef CONFIG_OFFCHANNEL
+		offchannel_cancel_remain_on_channel_cb(
+			wpa_s, data->remain_on_channel.freq);
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_P2P
 		wpas_p2p_cancel_remain_on_channel_cb(
 			wpa_s, data->remain_on_channel.freq);
+#endif /* CONFIG_P2P */
 		break;
+#ifdef CONFIG_P2P
 	case EVENT_P2P_DEV_FOUND: {
 		struct p2p_peer_info peer_info;
 
@@ -2161,7 +2414,8 @@
 				   data->p2p_prov_disc_req.dev_name,
 				   data->p2p_prov_disc_req.supp_config_methods,
 				   data->p2p_prov_disc_req.dev_capab,
-				   data->p2p_prov_disc_req.group_capab);
+				   data->p2p_prov_disc_req.group_capab,
+				   NULL, 0);
 		break;
 	case EVENT_P2P_PROV_DISC_RESPONSE:
 		wpas_prov_disc_resp(wpa_s, data->p2p_prov_disc_resp.peer,
@@ -2182,18 +2436,6 @@
 				 data->p2p_sd_resp.tlvs_len);
 		break;
 #endif /* CONFIG_P2P */
-#ifdef CONFIG_CLIENT_MLME
-	case EVENT_MLME_RX: {
-		struct ieee80211_rx_status rx_status;
-		os_memset(&rx_status, 0, sizeof(rx_status));
-		rx_status.freq = data->mlme_rx.freq;
-		rx_status.channel = data->mlme_rx.channel;
-		rx_status.ssi = data->mlme_rx.ssi;
-		ieee80211_sta_rx(wpa_s, data->mlme_rx.buf, data->mlme_rx.len,
-				 &rx_status);
-		break;
-	}
-#endif /* CONFIG_CLIENT_MLME */
 	case EVENT_EAPOL_RX:
 		wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
 					data->eapol_rx.data,
@@ -2209,6 +2451,7 @@
 	case EVENT_INTERFACE_ENABLED:
 		wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
 		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+			wpa_supplicant_update_mac_addr(wpa_s);
 #ifdef CONFIG_AP
 			if (!wpa_s->ap_iface) {
 				wpa_supplicant_set_state(wpa_s,
@@ -2268,12 +2511,44 @@
 			hostapd_event_sta_low_ack(wpa_s->ap_iface->bss[0],
 						  data->low_ack.addr);
 #endif /* CONFIG_AP */
+#ifdef CONFIG_TDLS
+		if (data)
+			wpa_tdls_disable_link(wpa_s->wpa, data->low_ack.addr);
+#endif /* CONFIG_TDLS */
 		break;
 	case EVENT_IBSS_PEER_LOST:
 #ifdef CONFIG_IBSS_RSN
 		ibss_rsn_stop(wpa_s->ibss_rsn, data->ibss_peer_lost.peer);
 #endif /* CONFIG_IBSS_RSN */
 		break;
+	case EVENT_DRIVER_GTK_REKEY:
+		if (os_memcmp(data->driver_gtk_rekey.bssid,
+			      wpa_s->bssid, ETH_ALEN))
+			break;
+		if (!wpa_s->wpa)
+			break;
+		wpa_sm_update_replay_ctr(wpa_s->wpa,
+					 data->driver_gtk_rekey.replay_ctr);
+		break;
+	case EVENT_SCHED_SCAN_STOPPED:
+		wpa_s->sched_scanning = 0;
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+			break;
+
+		/*
+		 * If we timed out, start a new sched scan to continue
+		 * searching for more SSIDs.
+		 */
+		if (wpa_s->sched_scan_timed_out)
+			wpa_supplicant_req_sched_scan(wpa_s);
+		break;
+	case EVENT_WPS_BUTTON_PUSHED:
+#ifdef CONFIG_WPS
+		wpas_wps_start_pbc(wpa_s, NULL, 0);
+#endif /* CONFIG_WPS */
+		break;
 	default:
 		wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
 		break;
diff --git a/wpa_supplicant/examples/udhcpd-p2p.conf b/wpa_supplicant/examples/udhcpd-p2p.conf
index b94f94f..df59094 100644
--- a/wpa_supplicant/examples/udhcpd-p2p.conf
+++ b/wpa_supplicant/examples/udhcpd-p2p.conf
@@ -62,12 +62,12 @@
 # The location of the pid file
 pidfile	/var/run/udhcpd-wlan2.pid	#default: /var/run/udhcpd.pid
 
-# Everytime udhcpd writes a leases file, the below script will be called.
+# Every time udhcpd writes a leases file, the below script will be called.
 # Useful for writing the lease file to flash every few hours.
 
 #notify_file				#default: (no script)
 
-#notify_file	dumpleases 	# <--- usefull for debugging
+#notify_file	dumpleases 	# <--- useful for debugging
 
 # The following are bootp specific options, setable by udhcpd.
 
diff --git a/wpa_supplicant/examples/wps-ap-cli b/wpa_supplicant/examples/wps-ap-cli
new file mode 100755
index 0000000..7c6b0aa
--- /dev/null
+++ b/wpa_supplicant/examples/wps-ap-cli
@@ -0,0 +1,78 @@
+#!/bin/sh
+
+CLI=wpa_cli
+
+pbc()
+{
+	echo "Starting PBC mode"
+	echo "Push button on the station within two minutes"
+	if ! $CLI wps_pbc | grep -q OK; then
+		echo "Failed to enable PBC mode"
+	fi
+}
+
+enter_pin()
+{
+	echo "Enter a PIN from a station to be enrolled to the network."
+	read -p "Enrollee PIN: " 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
+		case "$resp" in
+			y*)
+				cpin=`echo "$pin" | sed "s/[^1234567890]//g"`
+				;;
+			*)
+				return 1
+				;;
+		esac
+	fi
+	if [ "$cpin" = "FAIL" ]; then
+		echo "Invalid PIN: $pin"
+		return 1
+	fi
+	echo "Enabling Enrollee PIN: $cpin"
+	$CLI wps_pin any "$cpin"
+}
+
+show_config()
+{
+	$CLI status wps
+}
+
+main_menu()
+{
+	echo "WPS AP"
+	echo "------"
+	echo "1: Push button (activate PBC)"
+	echo "2: Enter Enrollee PIN"
+	echo "3: Show current configuration"
+	echo "0: Exit wps-ap-cli"
+
+	read -p "Command: " cmd
+
+	case "$cmd" in
+		1)
+			pbc
+			;;
+		2)
+			enter_pin
+			;;
+		3)
+			show_config
+			;;
+		0)
+			exit 0
+			;;
+		*)
+			echo "Unknown command: $cmd"
+			;;
+	esac
+
+	echo
+	main_menu
+}
+
+
+main_menu
diff --git a/wpa_supplicant/gas_query.c b/wpa_supplicant/gas_query.c
new file mode 100644
index 0000000..3b736da
--- /dev/null
+++ b/wpa_supplicant/gas_query.c
@@ -0,0 +1,481 @@
+/*
+ * Generic advertisement service (GAS) query
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "offchannel.h"
+#include "gas_query.h"
+
+
+#define GAS_QUERY_TIMEOUT 5
+
+
+struct gas_query_pending {
+	struct dl_list list;
+	u8 addr[ETH_ALEN];
+	u8 dialog_token;
+	u8 next_frag_id;
+	unsigned int wait_comeback:1;
+	unsigned int offchannel_tx_started:1;
+	int freq;
+	u16 status_code;
+	struct wpabuf *adv_proto;
+	struct wpabuf *resp;
+	void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+		   enum gas_query_result result,
+		   const struct wpabuf *adv_proto,
+		   const struct wpabuf *resp, u16 status_code);
+	void *ctx;
+};
+
+struct gas_query {
+	struct wpa_supplicant *wpa_s;
+	struct dl_list pending; /* struct gas_query_pending */
+};
+
+
+static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx);
+static void gas_query_timeout(void *eloop_data, void *user_ctx);
+
+
+struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
+{
+	struct gas_query *gas;
+
+	gas = os_zalloc(sizeof(*gas));
+	if (gas == NULL)
+		return NULL;
+
+	gas->wpa_s = wpa_s;
+	dl_list_init(&gas->pending);
+
+	return gas;
+}
+
+
+static void gas_query_done(struct gas_query *gas,
+			   struct gas_query_pending *query,
+			   enum gas_query_result result)
+{
+	if (query->offchannel_tx_started)
+		offchannel_send_action_done(gas->wpa_s);
+	eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+	eloop_cancel_timeout(gas_query_timeout, gas, query);
+	dl_list_del(&query->list);
+	query->cb(query->ctx, query->addr, query->dialog_token, result,
+		  query->adv_proto, query->resp, query->status_code);
+	wpabuf_free(query->adv_proto);
+	wpabuf_free(query->resp);
+	os_free(query);
+}
+
+
+void gas_query_deinit(struct gas_query *gas)
+{
+	struct gas_query_pending *query, *next;
+
+	if (gas == NULL)
+		return;
+
+	dl_list_for_each_safe(query, next, &gas->pending,
+			      struct gas_query_pending, list)
+		gas_query_done(gas, query, GAS_QUERY_DELETED_AT_DEINIT);
+
+	os_free(gas);
+}
+
+
+static struct gas_query_pending *
+gas_query_get_pending(struct gas_query *gas, const u8 *addr, u8 dialog_token)
+{
+	struct gas_query_pending *q;
+	dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
+		if (os_memcmp(q->addr, addr, ETH_ALEN) == 0 &&
+		    q->dialog_token == dialog_token)
+			return q;
+	}
+	return NULL;
+}
+
+
+static int gas_query_append(struct gas_query_pending *query, const u8 *data,
+			    size_t len)
+{
+	if (wpabuf_resize(&query->resp, len) < 0) {
+		wpa_printf(MSG_DEBUG, "GAS: No memory to store the response");
+		return -1;
+	}
+	wpabuf_put_data(query->resp, data, len);
+	return 0;
+}
+
+
+static int gas_query_tx(struct gas_query *gas, struct gas_query_pending *query,
+			struct wpabuf *req)
+{
+	int res;
+	wpa_printf(MSG_DEBUG, "GAS: Send action frame to " MACSTR " len=%u "
+		   "freq=%d", MAC2STR(query->addr),
+		   (unsigned int) wpabuf_len(req), query->freq);
+	res = offchannel_send_action(gas->wpa_s, query->freq, query->addr,
+				     gas->wpa_s->own_addr, query->addr,
+				     wpabuf_head(req), wpabuf_len(req), 1000,
+				     NULL, 0);
+	if (res == 0)
+		query->offchannel_tx_started = 1;
+	return res;
+}
+
+
+static void gas_query_tx_comeback_req(struct gas_query *gas,
+				      struct gas_query_pending *query)
+{
+	struct wpabuf *req;
+
+	req = gas_build_comeback_req(query->dialog_token);
+	if (req == NULL) {
+		gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+		return;
+	}
+
+	if (gas_query_tx(gas, query, req) < 0) {
+		wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+			   MACSTR, MAC2STR(query->addr));
+		gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+	}
+
+	wpabuf_free(req);
+}
+
+
+static void gas_query_tx_comeback_timeout(void *eloop_data, void *user_ctx)
+{
+	struct gas_query *gas = eloop_data;
+	struct gas_query_pending *query = user_ctx;
+
+	wpa_printf(MSG_DEBUG, "GAS: Comeback timeout for request to " MACSTR,
+		   MAC2STR(query->addr));
+	gas_query_tx_comeback_req(gas, query);
+}
+
+
+static void gas_query_tx_comeback_req_delay(struct gas_query *gas,
+					    struct gas_query_pending *query,
+					    u16 comeback_delay)
+{
+	unsigned int secs, usecs;
+
+	secs = (comeback_delay * 1024) / 1000000;
+	usecs = comeback_delay * 1024 - secs * 1000000;
+	wpa_printf(MSG_DEBUG, "GAS: Send comeback request to " MACSTR
+		   " in %u secs %u usecs", MAC2STR(query->addr), secs, usecs);
+	eloop_cancel_timeout(gas_query_tx_comeback_timeout, gas, query);
+	eloop_register_timeout(secs, usecs, gas_query_tx_comeback_timeout,
+			       gas, query);
+}
+
+
+static void gas_query_rx_initial(struct gas_query *gas,
+				 struct gas_query_pending *query,
+				 const u8 *adv_proto, const u8 *resp,
+				 size_t len, u16 comeback_delay)
+{
+	wpa_printf(MSG_DEBUG, "GAS: Received initial response from "
+		   MACSTR " (dialog_token=%u comeback_delay=%u)",
+		   MAC2STR(query->addr), query->dialog_token, comeback_delay);
+
+	query->adv_proto = wpabuf_alloc_copy(adv_proto, 2 + adv_proto[1]);
+	if (query->adv_proto == NULL) {
+		gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+		return;
+	}
+
+	if (comeback_delay) {
+		query->wait_comeback = 1;
+		gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
+		return;
+	}
+
+	/* Query was completed without comeback mechanism */
+	if (gas_query_append(query, resp, len) < 0) {
+		gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+		return;
+	}
+
+	gas_query_done(gas, query, GAS_QUERY_SUCCESS);
+}
+
+
+static void gas_query_rx_comeback(struct gas_query *gas,
+				  struct gas_query_pending *query,
+				  const u8 *adv_proto, const u8 *resp,
+				  size_t len, u8 frag_id, u8 more_frags,
+				  u16 comeback_delay)
+{
+	wpa_printf(MSG_DEBUG, "GAS: Received comeback response from "
+		   MACSTR " (dialog_token=%u frag_id=%u more_frags=%u "
+		   "comeback_delay=%u)",
+		   MAC2STR(query->addr), query->dialog_token, frag_id,
+		   more_frags, comeback_delay);
+
+	if ((size_t) 2 + adv_proto[1] != wpabuf_len(query->adv_proto) ||
+	    os_memcmp(adv_proto, wpabuf_head(query->adv_proto),
+		      wpabuf_len(query->adv_proto)) != 0) {
+		wpa_printf(MSG_DEBUG, "GAS: Advertisement Protocol changed "
+			   "between initial and comeback response from "
+			   MACSTR, MAC2STR(query->addr));
+		gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
+		return;
+	}
+
+	if (comeback_delay) {
+		if (frag_id) {
+			wpa_printf(MSG_DEBUG, "GAS: Invalid comeback response "
+				   "with non-zero frag_id and comeback_delay "
+				   "from " MACSTR, MAC2STR(query->addr));
+			gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
+			return;
+		}
+		gas_query_tx_comeback_req_delay(gas, query, comeback_delay);
+		return;
+	}
+
+	if (frag_id != query->next_frag_id) {
+		wpa_printf(MSG_DEBUG, "GAS: Unexpected frag_id in response "
+			   "from " MACSTR, MAC2STR(query->addr));
+		gas_query_done(gas, query, GAS_QUERY_PEER_ERROR);
+		return;
+	}
+	query->next_frag_id++;
+
+	if (gas_query_append(query, resp, len) < 0) {
+		gas_query_done(gas, query, GAS_QUERY_INTERNAL_ERROR);
+		return;
+	}
+
+	if (more_frags) {
+		gas_query_tx_comeback_req(gas, query);
+		return;
+	}
+
+	gas_query_done(gas, query, GAS_QUERY_SUCCESS);
+}
+
+
+int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
+		 const u8 *bssid, const u8 *data, size_t len, int freq)
+{
+	struct gas_query_pending *query;
+	u8 action, dialog_token, frag_id = 0, more_frags = 0;
+	u16 comeback_delay, resp_len;
+	const u8 *pos, *adv_proto;
+
+	if (gas == NULL || len < 4)
+		return -1;
+
+	pos = data;
+	action = *pos++;
+	dialog_token = *pos++;
+
+	if (action != WLAN_PA_GAS_INITIAL_RESP &&
+	    action != WLAN_PA_GAS_COMEBACK_RESP)
+		return -1; /* Not a GAS response */
+
+	query = gas_query_get_pending(gas, sa, dialog_token);
+	if (query == NULL) {
+		wpa_printf(MSG_DEBUG, "GAS: No pending query found for " MACSTR
+			   " dialog token %u", MAC2STR(sa), dialog_token);
+		return -1;
+	}
+
+	if (query->wait_comeback && action == WLAN_PA_GAS_INITIAL_RESP) {
+		wpa_printf(MSG_DEBUG, "GAS: Unexpected initial response from "
+			   MACSTR " dialog token %u when waiting for comeback "
+			   "response", MAC2STR(sa), dialog_token);
+		return 0;
+	}
+
+	if (!query->wait_comeback && action == WLAN_PA_GAS_COMEBACK_RESP) {
+		wpa_printf(MSG_DEBUG, "GAS: Unexpected comeback response from "
+			   MACSTR " dialog token %u when waiting for initial "
+			   "response", MAC2STR(sa), dialog_token);
+		return 0;
+	}
+
+	query->status_code = WPA_GET_LE16(pos);
+	pos += 2;
+
+	if (query->status_code != WLAN_STATUS_SUCCESS) {
+		wpa_printf(MSG_DEBUG, "GAS: Query to " MACSTR " dialog token "
+			   "%u failed - status code %u",
+			   MAC2STR(sa), dialog_token, query->status_code);
+		gas_query_done(gas, query, GAS_QUERY_FAILURE);
+		return 0;
+	}
+
+	if (action == WLAN_PA_GAS_COMEBACK_RESP) {
+		if (pos + 1 > data + len)
+			return 0;
+		frag_id = *pos & 0x7f;
+		more_frags = (*pos & 0x80) >> 7;
+		pos++;
+	}
+
+	/* Comeback Delay */
+	if (pos + 2 > data + len)
+		return 0;
+	comeback_delay = WPA_GET_LE16(pos);
+	pos += 2;
+
+	/* Advertisement Protocol element */
+	if (pos + 2 > data + len || pos + 2 + pos[1] > data + len) {
+		wpa_printf(MSG_DEBUG, "GAS: No room for Advertisement "
+			   "Protocol element in the response from " MACSTR,
+			   MAC2STR(sa));
+		return 0;
+	}
+
+	if (*pos != WLAN_EID_ADV_PROTO) {
+		wpa_printf(MSG_DEBUG, "GAS: Unexpected Advertisement "
+			   "Protocol element ID %u in response from " MACSTR,
+			   *pos, MAC2STR(sa));
+		return 0;
+	}
+
+	adv_proto = pos;
+	pos += 2 + pos[1];
+
+	/* Query Response Length */
+	if (pos + 2 > data + len) {
+		wpa_printf(MSG_DEBUG, "GAS: No room for GAS Response Length");
+		return 0;
+	}
+	resp_len = WPA_GET_LE16(pos);
+	pos += 2;
+
+	if (pos + resp_len > data + len) {
+		wpa_printf(MSG_DEBUG, "GAS: Truncated Query Response in "
+			   "response from " MACSTR, MAC2STR(sa));
+		return 0;
+	}
+
+	if (pos + resp_len < data + len) {
+		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));
+	}
+
+	if (action == WLAN_PA_GAS_COMEBACK_RESP)
+		gas_query_rx_comeback(gas, query, adv_proto, pos, resp_len,
+				      frag_id, more_frags, comeback_delay);
+	else
+		gas_query_rx_initial(gas, query, adv_proto, pos, resp_len,
+				     comeback_delay);
+
+	return 0;
+}
+
+
+static void gas_query_timeout(void *eloop_data, void *user_ctx)
+{
+	struct gas_query *gas = eloop_data;
+	struct gas_query_pending *query = user_ctx;
+
+	wpa_printf(MSG_DEBUG, "GAS: No response received for query to " MACSTR,
+		   MAC2STR(query->addr));
+	gas_query_done(gas, query, GAS_QUERY_TIMEOUT);
+}
+
+
+static int gas_query_dialog_token_available(struct gas_query *gas,
+					    const u8 *dst, u8 dialog_token)
+{
+	struct gas_query_pending *q;
+	dl_list_for_each(q, &gas->pending, struct gas_query_pending, list) {
+		if (os_memcmp(dst, q->addr, ETH_ALEN) == 0 &&
+		    dialog_token == q->dialog_token)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
+		  struct wpabuf *req,
+		  void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+			     enum gas_query_result result,
+			     const struct wpabuf *adv_proto,
+			     const struct wpabuf *resp, u16 status_code),
+		  void *ctx)
+{
+	struct gas_query_pending *query;
+	int dialog_token;
+
+	if (wpabuf_len(req) < 3)
+		return -1;
+
+	for (dialog_token = 0; dialog_token < 256; dialog_token++) {
+		if (gas_query_dialog_token_available(gas, dst, dialog_token))
+			break;
+	}
+	if (dialog_token == 256)
+		return -1; /* Too many pending queries */
+
+	query = os_zalloc(sizeof(*query));
+	if (query == NULL)
+		return -1;
+
+	os_memcpy(query->addr, dst, ETH_ALEN);
+	query->dialog_token = dialog_token;
+	query->freq = freq;
+	query->cb = cb;
+	query->ctx = ctx;
+	dl_list_add(&gas->pending, &query->list);
+
+	*(wpabuf_mhead_u8(req) + 2) = dialog_token;
+
+	wpa_printf(MSG_DEBUG, "GAS: Starting request for " MACSTR
+		   " dialog_token %u", MAC2STR(dst), dialog_token);
+	if (gas_query_tx(gas, query, req) < 0) {
+		wpa_printf(MSG_DEBUG, "GAS: Failed to send Action frame to "
+			   MACSTR, MAC2STR(query->addr));
+		os_free(query);
+		return -1;
+	}
+
+	eloop_register_timeout(GAS_QUERY_TIMEOUT, 0, gas_query_timeout,
+			       gas, query);
+
+	return dialog_token;
+}
+
+
+void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token)
+{
+	struct gas_query_pending *query;
+
+	query = gas_query_get_pending(gas, dst, dialog_token);
+	if (query)
+		gas_query_done(gas, query, GAS_QUERY_CANCELLED);
+
+}
diff --git a/wpa_supplicant/gas_query.h b/wpa_supplicant/gas_query.h
new file mode 100644
index 0000000..64c3825
--- /dev/null
+++ b/wpa_supplicant/gas_query.h
@@ -0,0 +1,61 @@
+/*
+ * Generic advertisement service (GAS) query
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef GAS_QUERY_H
+#define GAS_QUERY_H
+
+struct gas_query;
+
+#ifdef CONFIG_GAS
+
+struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s);
+void gas_query_deinit(struct gas_query *gas);
+int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
+		 const u8 *bssid, const u8 *data, size_t len, int freq);
+
+enum gas_query_result {
+	GAS_QUERY_SUCCESS,
+	GAS_QUERY_FAILURE,
+	GAS_QUERY_TIMEOUT,
+	GAS_QUERY_PEER_ERROR,
+	GAS_QUERY_INTERNAL_ERROR,
+	GAS_QUERY_CANCELLED,
+	GAS_QUERY_DELETED_AT_DEINIT
+};
+
+int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
+		  struct wpabuf *req,
+		  void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+			     enum gas_query_result result,
+			     const struct wpabuf *adv_proto,
+			     const struct wpabuf *resp, u16 status_code),
+		  void *ctx);
+void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token);
+
+#else /* CONFIG_GAS */
+
+static inline struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
+{
+	return (void *) 1;
+}
+
+static inline void gas_query_deinit(struct gas_query *gas)
+{
+}
+
+#endif /* CONFIG_GAS */
+
+
+#endif /* GAS_QUERY_H */
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 0d7d568..d4fa39d 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -168,8 +168,8 @@
 }
 
 
-int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
-		       const u8 *psk)
+static int ibss_rsn_supp_init(struct ibss_rsn_peer *peer, const u8 *own_addr,
+			      const u8 *psk)
 {
 	struct wpa_sm_ctx *ctx = os_zalloc(sizeof(*ctx));
 	if (ctx == NULL)
@@ -339,6 +339,8 @@
 		return -1;
 	}
 
+	wpa_init_keys(ibss_rsn->auth_group);
+
 	return 0;
 }
 
diff --git a/wpa_supplicant/interworking.c b/wpa_supplicant/interworking.c
new file mode 100644
index 0000000..d42aa40
--- /dev/null
+++ b/wpa_supplicant/interworking.c
@@ -0,0 +1,1138 @@
+/*
+ * Interworking (IEEE 802.11u)
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "common/wpa_ctrl.h"
+#include "drivers/driver.h"
+#include "eap_common/eap_defs.h"
+#include "eap_peer/eap_methods.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "bss.h"
+#include "scan.h"
+#include "notify.h"
+#include "gas_query.h"
+#include "interworking.h"
+
+
+#if defined(EAP_SIM) | defined(EAP_SIM_DYNAMIC)
+#define INTERWORKING_3GPP
+#else
+#if defined(EAP_AKA) | defined(EAP_AKA_DYNAMIC)
+#define INTERWORKING_3GPP
+#else
+#if defined(EAP_AKA_PRIME) | defined(EAP_AKA_PRIME_DYNAMIC)
+#define INTERWORKING_3GPP
+#endif
+#endif
+#endif
+
+static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s);
+
+
+static struct wpabuf * anqp_build_req(u16 info_ids[], size_t num_ids,
+				      struct wpabuf *extra)
+{
+	struct wpabuf *buf;
+	size_t i;
+	u8 *len_pos;
+
+	buf = gas_anqp_build_initial_req(0, 4 + num_ids * 2 +
+					 (extra ? wpabuf_len(extra) : 0));
+	if (buf == NULL)
+		return NULL;
+
+	len_pos = gas_anqp_add_element(buf, ANQP_QUERY_LIST);
+	for (i = 0; i < num_ids; i++)
+		wpabuf_put_le16(buf, info_ids[i]);
+	gas_anqp_set_element_len(buf, len_pos);
+	if (extra)
+		wpabuf_put_buf(buf, extra);
+
+	gas_anqp_set_len(buf);
+
+	return buf;
+}
+
+
+static void interworking_anqp_resp_cb(void *ctx, const u8 *dst,
+				      u8 dialog_token,
+				      enum gas_query_result result,
+				      const struct wpabuf *adv_proto,
+				      const struct wpabuf *resp,
+				      u16 status_code)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	anqp_resp_cb(wpa_s, dst, dialog_token, result, adv_proto, resp,
+		     status_code);
+	interworking_next_anqp_fetch(wpa_s);
+}
+
+
+static int interworking_anqp_send_req(struct wpa_supplicant *wpa_s,
+				      struct wpa_bss *bss)
+{
+	struct wpabuf *buf;
+	int ret = 0;
+	int res;
+	u16 info_ids[] = {
+		ANQP_CAPABILITY_LIST,
+		ANQP_VENUE_NAME,
+		ANQP_NETWORK_AUTH_TYPE,
+		ANQP_ROAMING_CONSORTIUM,
+		ANQP_IP_ADDR_TYPE_AVAILABILITY,
+		ANQP_NAI_REALM,
+		ANQP_3GPP_CELLULAR_NETWORK,
+		ANQP_DOMAIN_NAME
+	};
+	struct wpabuf *extra = NULL;
+
+	wpa_printf(MSG_DEBUG, "Interworking: ANQP Query Request to " MACSTR,
+		   MAC2STR(bss->bssid));
+
+	buf = anqp_build_req(info_ids, sizeof(info_ids) / sizeof(info_ids[0]),
+			     extra);
+	wpabuf_free(extra);
+	if (buf == NULL)
+		return -1;
+
+	res = gas_query_req(wpa_s->gas, bss->bssid, bss->freq, buf,
+			    interworking_anqp_resp_cb, wpa_s);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		ret = -1;
+	} else
+		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
+			   "%u", res);
+
+	wpabuf_free(buf);
+	return ret;
+}
+
+
+struct nai_realm_eap {
+	u8 method;
+	u8 inner_method;
+	enum nai_realm_eap_auth_inner_non_eap inner_non_eap;
+	u8 cred_type;
+	u8 tunneled_cred_type;
+};
+
+struct nai_realm {
+	u8 encoding;
+	char *realm;
+	u8 eap_count;
+	struct nai_realm_eap *eap;
+};
+
+
+static void nai_realm_free(struct nai_realm *realms, u16 count)
+{
+	u16 i;
+
+	if (realms == NULL)
+		return;
+	for (i = 0; i < count; i++) {
+		os_free(realms[i].eap);
+		os_free(realms[i].realm);
+	}
+	os_free(realms);
+}
+
+
+static const u8 * nai_realm_parse_eap(struct nai_realm_eap *e, const u8 *pos,
+				      const u8 *end)
+{
+	u8 elen, auth_count, a;
+	const u8 *e_end;
+
+	if (pos + 3 > end) {
+		wpa_printf(MSG_DEBUG, "No room for EAP Method fixed fields");
+		return NULL;
+	}
+
+	elen = *pos++;
+	if (pos + elen > end || elen < 2) {
+		wpa_printf(MSG_DEBUG, "No room for EAP Method subfield");
+		return NULL;
+	}
+	e_end = pos + elen;
+	e->method = *pos++;
+	auth_count = *pos++;
+	wpa_printf(MSG_DEBUG, "EAP Method: len=%u method=%u auth_count=%u",
+		   elen, e->method, auth_count);
+
+	for (a = 0; a < auth_count; a++) {
+		u8 id, len;
+
+		if (pos + 2 > end || pos + 2 + pos[1] > end) {
+			wpa_printf(MSG_DEBUG, "No room for Authentication "
+				   "Parameter subfield");
+			return NULL;
+		}
+
+		id = *pos++;
+		len = *pos++;
+
+		switch (id) {
+		case NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH:
+			if (len < 1)
+				break;
+			e->inner_non_eap = *pos;
+			if (e->method != EAP_TYPE_TTLS)
+				break;
+			switch (*pos) {
+			case NAI_REALM_INNER_NON_EAP_PAP:
+				wpa_printf(MSG_DEBUG, "EAP-TTLS/PAP");
+				break;
+			case NAI_REALM_INNER_NON_EAP_CHAP:
+				wpa_printf(MSG_DEBUG, "EAP-TTLS/CHAP");
+				break;
+			case NAI_REALM_INNER_NON_EAP_MSCHAP:
+				wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAP");
+				break;
+			case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
+				wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2");
+				break;
+			}
+			break;
+		case NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD:
+			if (len < 1)
+				break;
+			e->inner_method = *pos;
+			wpa_printf(MSG_DEBUG, "Inner EAP method: %u",
+				   e->inner_method);
+			break;
+		case NAI_REALM_EAP_AUTH_CRED_TYPE:
+			if (len < 1)
+				break;
+			e->cred_type = *pos;
+			wpa_printf(MSG_DEBUG, "Credential Type: %u",
+				   e->cred_type);
+			break;
+		case NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE:
+			if (len < 1)
+				break;
+			e->tunneled_cred_type = *pos;
+			wpa_printf(MSG_DEBUG, "Tunneled EAP Method Credential "
+				   "Type: %u", e->tunneled_cred_type);
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "Unsupported Authentication "
+				   "Parameter: id=%u len=%u", id, len);
+			wpa_hexdump(MSG_DEBUG, "Authentication Parameter "
+				    "Value", pos, len);
+			break;
+		}
+
+		pos += len;
+	}
+
+	return e_end;
+}
+
+
+static const u8 * nai_realm_parse_realm(struct nai_realm *r, const u8 *pos,
+					const u8 *end)
+{
+	u16 len;
+	const u8 *f_end;
+	u8 realm_len, e;
+
+	if (end - pos < 4) {
+		wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
+			   "fixed fields");
+		return NULL;
+	}
+
+	len = WPA_GET_LE16(pos); /* NAI Realm Data field Length */
+	pos += 2;
+	if (pos + len > end || len < 3) {
+		wpa_printf(MSG_DEBUG, "No room for NAI Realm Data "
+			   "(len=%u; left=%u)",
+			   len, (unsigned int) (end - pos));
+		return NULL;
+	}
+	f_end = pos + len;
+
+	r->encoding = *pos++;
+	realm_len = *pos++;
+	if (pos + realm_len > f_end) {
+		wpa_printf(MSG_DEBUG, "No room for NAI Realm "
+			   "(len=%u; left=%u)",
+			   realm_len, (unsigned int) (f_end - pos));
+		return NULL;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "NAI Realm", pos, realm_len);
+	r->realm = os_malloc(realm_len + 1);
+	if (r->realm == NULL)
+		return NULL;
+	os_memcpy(r->realm, pos, realm_len);
+	r->realm[realm_len] = '\0';
+	pos += realm_len;
+
+	if (pos + 1 > f_end) {
+		wpa_printf(MSG_DEBUG, "No room for EAP Method Count");
+		return NULL;
+	}
+	r->eap_count = *pos++;
+	wpa_printf(MSG_DEBUG, "EAP Count: %u", r->eap_count);
+	if (pos + r->eap_count * 3 > f_end) {
+		wpa_printf(MSG_DEBUG, "No room for EAP Methods");
+		return NULL;
+	}
+	r->eap = os_zalloc(r->eap_count * sizeof(struct nai_realm_eap));
+	if (r->eap == NULL)
+		return NULL;
+
+	for (e = 0; e < r->eap_count; e++) {
+		pos = nai_realm_parse_eap(&r->eap[e], pos, f_end);
+		if (pos == NULL)
+			return NULL;
+	}
+
+	return f_end;
+}
+
+
+static struct nai_realm * nai_realm_parse(struct wpabuf *anqp, u16 *count)
+{
+	struct nai_realm *realm;
+	const u8 *pos, *end;
+	u16 i, num;
+
+	if (anqp == NULL || wpabuf_len(anqp) < 2)
+		return NULL;
+
+	pos = wpabuf_head_u8(anqp);
+	end = pos + wpabuf_len(anqp);
+	num = WPA_GET_LE16(pos);
+	wpa_printf(MSG_DEBUG, "NAI Realm Count: %u", num);
+	pos += 2;
+
+	if (num * 5 > end - pos) {
+		wpa_printf(MSG_DEBUG, "Invalid NAI Realm Count %u - not "
+			   "enough data (%u octets) for that many realms",
+			   num, (unsigned int) (end - pos));
+		return NULL;
+	}
+
+	realm = os_zalloc(num * sizeof(struct nai_realm));
+	if (realm == NULL)
+		return NULL;
+
+	for (i = 0; i < num; i++) {
+		pos = nai_realm_parse_realm(&realm[i], pos, end);
+		if (pos == NULL) {
+			nai_realm_free(realm, num);
+			return NULL;
+		}
+	}
+
+	*count = num;
+	return realm;
+}
+
+
+static int nai_realm_match(struct nai_realm *realm, const char *home_realm)
+{
+	char *tmp, *pos, *end;
+	int match = 0;
+
+	if (realm->realm == NULL || home_realm == NULL)
+		return 0;
+
+	if (os_strchr(realm->realm, ';') == NULL)
+		return os_strcasecmp(realm->realm, home_realm) == 0;
+
+	tmp = os_strdup(realm->realm);
+	if (tmp == NULL)
+		return 0;
+
+	pos = tmp;
+	while (*pos) {
+		end = os_strchr(pos, ';');
+		if (end)
+			*end = '\0';
+		if (os_strcasecmp(pos, home_realm) == 0) {
+			match = 1;
+			break;
+		}
+		if (end == NULL)
+			break;
+		pos = end + 1;
+	}
+
+	os_free(tmp);
+
+	return match;
+}
+
+
+static int nai_realm_cred_username(struct nai_realm_eap *eap)
+{
+	if (eap_get_name(EAP_VENDOR_IETF, eap->method) == NULL)
+		return 0; /* method not supported */
+
+	if (eap->method != EAP_TYPE_TTLS && eap->method != EAP_TYPE_PEAP) {
+		/* Only tunneled methods with username/password supported */
+		return 0;
+	}
+
+	if (eap->method == EAP_TYPE_PEAP &&
+	    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+		return 0;
+
+	if (eap->method == EAP_TYPE_TTLS) {
+		if (eap->inner_method == 0 && eap->inner_non_eap == 0)
+			return 0;
+		if (eap->inner_method &&
+		    eap_get_name(EAP_VENDOR_IETF, eap->inner_method) == NULL)
+			return 0;
+		if (eap->inner_non_eap &&
+		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_PAP &&
+		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_CHAP &&
+		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAP &&
+		    eap->inner_non_eap != NAI_REALM_INNER_NON_EAP_MSCHAPV2)
+			return 0;
+	}
+
+	if (eap->inner_method &&
+	    eap->inner_method != EAP_TYPE_GTC &&
+	    eap->inner_method != EAP_TYPE_MSCHAPV2)
+		return 0;
+
+	return 1;
+}
+
+
+static struct nai_realm_eap * nai_realm_find_eap(struct wpa_supplicant *wpa_s,
+						 struct nai_realm *realm)
+{
+	u8 e;
+
+	if (wpa_s->conf->home_username == NULL ||
+	    wpa_s->conf->home_username[0] == '\0' ||
+	    wpa_s->conf->home_password == NULL ||
+	    wpa_s->conf->home_password[0] == '\0')
+		return NULL;
+
+	for (e = 0; e < realm->eap_count; e++) {
+		struct nai_realm_eap *eap = &realm->eap[e];
+		if (nai_realm_cred_username(eap))
+			return eap;
+	}
+
+	return NULL;
+}
+
+
+#ifdef INTERWORKING_3GPP
+
+static int plmn_id_match(struct wpabuf *anqp, const char *imsi)
+{
+	const char *sep;
+	u8 plmn[3];
+	const u8 *pos, *end;
+	u8 udhl;
+
+	sep = os_strchr(imsi, '-');
+	if (sep == NULL || (sep - imsi != 5 && sep - imsi != 6))
+		return 0;
+
+	/* See Annex A of 3GPP TS 24.234 v8.1.0 for description */
+	plmn[0] = (imsi[0] - '0') | ((imsi[1] - '0') << 4);
+	plmn[1] = imsi[2] - '0';
+	if (sep - imsi == 6)
+		plmn[1] |= (imsi[5] - '0') << 4;
+	else
+		plmn[1] |= 0xf0;
+	plmn[2] = (imsi[3] - '0') | ((imsi[4] - '0') << 4);
+
+	if (anqp == NULL)
+		return 0;
+	pos = wpabuf_head_u8(anqp);
+	end = pos + wpabuf_len(anqp);
+	if (pos + 2 > end)
+		return 0;
+	if (*pos != 0) {
+		wpa_printf(MSG_DEBUG, "Unsupported GUD version 0x%x", *pos);
+		return 0;
+	}
+	pos++;
+	udhl = *pos++;
+	if (pos + udhl > end) {
+		wpa_printf(MSG_DEBUG, "Invalid UDHL");
+		return 0;
+	}
+	end = pos + udhl;
+
+	while (pos + 2 <= end) {
+		u8 iei, len;
+		const u8 *l_end;
+		iei = *pos++;
+		len = *pos++ & 0x7f;
+		if (pos + len > end)
+			break;
+		l_end = pos + len;
+
+		if (iei == 0 && len > 0) {
+			/* PLMN List */
+			u8 num, i;
+			num = *pos++;
+			for (i = 0; i < num; i++) {
+				if (pos + 3 > end)
+					break;
+				if (os_memcmp(pos, plmn, 3) == 0)
+					return 1; /* Found matching PLMN */
+			}
+		}
+
+		pos = l_end;
+	}
+
+	return 0;
+}
+
+
+static int set_root_nai(struct wpa_ssid *ssid, const char *imsi, char prefix)
+{
+	const char *sep, *msin;
+	char nai[100], *end, *pos;
+	size_t msin_len, plmn_len;
+
+	/*
+	 * TS 23.003, Clause 14 (3GPP to WLAN Interworking)
+	 * Root NAI:
+	 * <aka:0|sim:1><IMSI>@wlan.mnc<MNC>.mcc<MCC>.3gppnetwork.org
+	 * <MNC> is zero-padded to three digits in case two-digit MNC is used
+	 */
+
+	if (imsi == NULL || os_strlen(imsi) > 16) {
+		wpa_printf(MSG_DEBUG, "No valid IMSI available");
+		return -1;
+	}
+	sep = os_strchr(imsi, '-');
+	if (sep == NULL)
+		return -1;
+	plmn_len = sep - imsi;
+	if (plmn_len != 5 && plmn_len != 6)
+		return -1;
+	msin = sep + 1;
+	msin_len = os_strlen(msin);
+
+	pos = nai;
+	end = pos + sizeof(nai);
+	*pos++ = prefix;
+	os_memcpy(pos, imsi, plmn_len);
+	pos += plmn_len;
+	os_memcpy(pos, msin, msin_len);
+	pos += msin_len;
+	pos += os_snprintf(pos, end - pos, "@wlan.mnc");
+	if (plmn_len == 5) {
+		*pos++ = '0';
+		*pos++ = imsi[3];
+		*pos++ = imsi[4];
+	} else {
+		*pos++ = imsi[3];
+		*pos++ = imsi[4];
+		*pos++ = imsi[5];
+	}
+	pos += os_snprintf(pos, end - pos, ".mcc%c%c%c.3gppnetwork.org",
+			   imsi[0], imsi[1], imsi[2]);
+
+	return wpa_config_set_quoted(ssid, "identity", nai);
+}
+
+#endif /* INTERWORKING_3GPP */
+
+
+static int interworking_connect_3gpp(struct wpa_supplicant *wpa_s,
+				     struct wpa_bss *bss)
+{
+#ifdef INTERWORKING_3GPP
+	struct wpa_ssid *ssid;
+	const u8 *ie;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
+	if (ie == NULL)
+		return -1;
+	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR " (3GPP)",
+		   MAC2STR(bss->bssid));
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL)
+		return -1;
+
+	wpas_notify_network_added(wpa_s, ssid);
+	wpa_config_set_network_defaults(ssid);
+	ssid->temporary = 1;
+	ssid->ssid = os_zalloc(ie[1] + 1);
+	if (ssid->ssid == NULL)
+		goto fail;
+	os_memcpy(ssid->ssid, ie + 2, ie[1]);
+	ssid->ssid_len = ie[1];
+
+	/* TODO: figure out whether to use EAP-SIM, EAP-AKA, or EAP-AKA' */
+	if (wpa_config_set(ssid, "eap", "SIM", 0) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-SIM not supported");
+		goto fail;
+	}
+	if (set_root_nai(ssid, wpa_s->conf->home_imsi, '1') < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to set Root NAI");
+		goto fail;
+	}
+
+	if (wpa_s->conf->home_milenage && wpa_s->conf->home_milenage[0]) {
+		if (wpa_config_set_quoted(ssid, "password",
+					  wpa_s->conf->home_milenage) < 0)
+			goto fail;
+	} else {
+		/* TODO: PIN */
+		if (wpa_config_set_quoted(ssid, "pcsc", "") < 0)
+			goto fail;
+	}
+
+	if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
+	    wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
+	    < 0)
+		goto fail;
+
+	wpa_supplicant_select_network(wpa_s, ssid);
+
+	return 0;
+
+fail:
+	wpas_notify_network_removed(wpa_s, ssid);
+	wpa_config_remove_network(wpa_s->conf, ssid->id);
+#endif /* INTERWORKING_3GPP */
+	return -1;
+}
+
+
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wpa_ssid *ssid;
+	struct nai_realm *realm;
+	struct nai_realm_eap *eap = NULL;
+	u16 count, i;
+	char buf[100];
+	const u8 *ie;
+
+	if (bss == NULL)
+		return -1;
+	ie = wpa_bss_get_ie(bss, WLAN_EID_SSID);
+	if (ie == NULL || ie[1] == 0) {
+		wpa_printf(MSG_DEBUG, "Interworking: No SSID known for "
+			   MACSTR, MAC2STR(bss->bssid));
+		return -1;
+	}
+
+	realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+	if (realm == NULL) {
+		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
+			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
+		count = 0;
+	}
+
+	for (i = 0; i < count; i++) {
+		if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
+			continue;
+		eap = nai_realm_find_eap(wpa_s, &realm[i]);
+		if (eap)
+			break;
+	}
+
+	if (!eap) {
+		if (interworking_connect_3gpp(wpa_s, bss) == 0) {
+			if (realm)
+				nai_realm_free(realm, count);
+			return 0;
+		}
+
+		wpa_printf(MSG_DEBUG, "Interworking: No matching credentials "
+			   "and EAP method found for " MACSTR,
+			   MAC2STR(bss->bssid));
+		nai_realm_free(realm, count);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "Interworking: Connect with " MACSTR,
+		   MAC2STR(bss->bssid));
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL) {
+		nai_realm_free(realm, count);
+		return -1;
+	}
+	wpas_notify_network_added(wpa_s, ssid);
+	wpa_config_set_network_defaults(ssid);
+	ssid->temporary = 1;
+	ssid->ssid = os_zalloc(ie[1] + 1);
+	if (ssid->ssid == NULL)
+		goto fail;
+	os_memcpy(ssid->ssid, ie + 2, ie[1]);
+	ssid->ssid_len = ie[1];
+
+	if (wpa_config_set(ssid, "eap", eap_get_name(EAP_VENDOR_IETF,
+						     eap->method), 0) < 0)
+		goto fail;
+
+	if (wpa_s->conf->home_username && wpa_s->conf->home_username[0] &&
+	    wpa_config_set_quoted(ssid, "identity",
+				  wpa_s->conf->home_username) < 0)
+		goto fail;
+
+	if (wpa_s->conf->home_password && wpa_s->conf->home_password[0] &&
+	    wpa_config_set_quoted(ssid, "password", wpa_s->conf->home_password)
+	    < 0)
+		goto fail;
+
+	switch (eap->method) {
+	case EAP_TYPE_TTLS:
+		if (eap->inner_method) {
+			os_snprintf(buf, sizeof(buf), "\"autheap=%s\"",
+				    eap_get_name(EAP_VENDOR_IETF,
+						 eap->inner_method));
+			if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
+				goto fail;
+			break;
+		}
+		switch (eap->inner_non_eap) {
+		case NAI_REALM_INNER_NON_EAP_PAP:
+			if (wpa_config_set(ssid, "phase2", "\"auth=PAP\"", 0) <
+			    0)
+				goto fail;
+			break;
+		case NAI_REALM_INNER_NON_EAP_CHAP:
+			if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
+			    < 0)
+				goto fail;
+			break;
+		case NAI_REALM_INNER_NON_EAP_MSCHAP:
+			if (wpa_config_set(ssid, "phase2", "\"auth=CHAP\"", 0)
+			    < 0)
+				goto fail;
+			break;
+		case NAI_REALM_INNER_NON_EAP_MSCHAPV2:
+			if (wpa_config_set(ssid, "phase2", "\"auth=MSCHAPV2\"",
+					   0) < 0)
+				goto fail;
+			break;
+		}
+		break;
+	case EAP_TYPE_PEAP:
+		os_snprintf(buf, sizeof(buf), "\"auth=%s\"",
+			    eap_get_name(EAP_VENDOR_IETF, eap->inner_method));
+		if (wpa_config_set(ssid, "phase2", buf, 0) < 0)
+			goto fail;
+		break;
+	}
+
+	if (wpa_s->conf->home_ca_cert && wpa_s->conf->home_ca_cert[0] &&
+	    wpa_config_set_quoted(ssid, "ca_cert", wpa_s->conf->home_ca_cert) <
+	    0)
+		goto fail;
+
+	nai_realm_free(realm, count);
+
+	wpa_supplicant_select_network(wpa_s, ssid);
+
+	return 0;
+
+fail:
+	wpas_notify_network_removed(wpa_s, ssid);
+	wpa_config_remove_network(wpa_s->conf, ssid->id);
+	nai_realm_free(realm, count);
+	return -1;
+}
+
+
+static int interworking_credentials_available_3gpp(
+	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	int ret = 0;
+
+#ifdef INTERWORKING_3GPP
+	if (bss->anqp_3gpp == NULL)
+		return ret;
+
+	if (wpa_s->conf->home_imsi == NULL || !wpa_s->conf->home_imsi[0] ||
+	    wpa_s->conf->home_milenage == NULL ||
+	    !wpa_s->conf->home_milenage[0])
+		return ret;
+
+	wpa_printf(MSG_DEBUG, "Interworking: Parsing 3GPP info from " MACSTR,
+		   MAC2STR(bss->bssid));
+	ret = plmn_id_match(bss->anqp_3gpp, wpa_s->conf->home_imsi);
+	wpa_printf(MSG_DEBUG, "PLMN match %sfound", ret ? "" : "not ");
+#endif /* INTERWORKING_3GPP */
+	return ret;
+}
+
+
+static int interworking_credentials_available_realm(
+	struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct nai_realm *realm;
+	u16 count, i;
+	int found = 0;
+
+	if (bss->anqp_nai_realm == NULL)
+		return 0;
+
+	if (wpa_s->conf->home_realm == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "Interworking: Parsing NAI Realm list from "
+		   MACSTR, MAC2STR(bss->bssid));
+	realm = nai_realm_parse(bss->anqp_nai_realm, &count);
+	if (realm == NULL) {
+		wpa_printf(MSG_DEBUG, "Interworking: Could not parse NAI "
+			   "Realm list from " MACSTR, MAC2STR(bss->bssid));
+		return 0;
+	}
+
+	for (i = 0; i < count; i++) {
+		if (!nai_realm_match(&realm[i], wpa_s->conf->home_realm))
+			continue;
+		if (nai_realm_find_eap(wpa_s, &realm[i])) {
+			found++;
+			break;
+		}
+	}
+
+	nai_realm_free(realm, count);
+
+	return found;
+}
+
+
+static int interworking_credentials_available(struct wpa_supplicant *wpa_s,
+					      struct wpa_bss *bss)
+{
+	return interworking_credentials_available_realm(wpa_s, bss) ||
+		interworking_credentials_available_3gpp(wpa_s, bss);
+}
+
+
+static void interworking_select_network(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss, *selected = NULL;
+	unsigned int count = 0;
+
+	wpa_s->network_select = 0;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (!interworking_credentials_available(wpa_s, bss))
+			continue;
+		count++;
+		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_AP MACSTR,
+			MAC2STR(bss->bssid));
+		if (selected == NULL && wpa_s->auto_select)
+			selected = bss;
+	}
+
+	if (count == 0) {
+		wpa_msg(wpa_s, MSG_INFO, INTERWORKING_NO_MATCH "No network "
+			"with matching credentials found");
+	}
+
+	if (selected)
+		interworking_connect(wpa_s, selected);
+}
+
+
+static void interworking_next_anqp_fetch(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+	int found = 0;
+	const u8 *ie;
+
+	if (!wpa_s->fetch_anqp_in_progress)
+		return;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (!(bss->caps & IEEE80211_CAP_ESS))
+			continue;
+		ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_CAPAB);
+		if (ie == NULL || ie[1] < 4 || !(ie[5] & 0x80))
+			continue; /* AP does not support Interworking */
+
+		if (!(bss->flags & WPA_BSS_ANQP_FETCH_TRIED)) {
+			found++;
+			bss->flags |= WPA_BSS_ANQP_FETCH_TRIED;
+			wpa_msg(wpa_s, MSG_INFO, "Starting ANQP fetch for "
+				MACSTR, MAC2STR(bss->bssid));
+			interworking_anqp_send_req(wpa_s, bss);
+			break;
+		}
+	}
+
+	if (found == 0) {
+		wpa_msg(wpa_s, MSG_INFO, "ANQP fetch completed");
+		wpa_s->fetch_anqp_in_progress = 0;
+		if (wpa_s->network_select)
+			interworking_select_network(wpa_s);
+	}
+}
+
+
+static void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list)
+		bss->flags &= ~WPA_BSS_ANQP_FETCH_TRIED;
+
+	wpa_s->fetch_anqp_in_progress = 1;
+	interworking_next_anqp_fetch(wpa_s);
+}
+
+
+int interworking_fetch_anqp(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->fetch_anqp_in_progress || wpa_s->network_select)
+		return 0;
+
+	wpa_s->network_select = 0;
+
+	interworking_start_fetch_anqp(wpa_s);
+
+	return 0;
+}
+
+
+void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->fetch_anqp_in_progress)
+		return;
+
+	wpa_s->fetch_anqp_in_progress = 0;
+}
+
+
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+		  u16 info_ids[], size_t num_ids)
+{
+	struct wpabuf *buf;
+	int ret = 0;
+	int freq;
+	struct wpa_bss *bss;
+	int res;
+
+	freq = wpa_s->assoc_freq;
+	bss = wpa_bss_get_bssid(wpa_s, dst);
+	if (bss)
+		freq = bss->freq;
+	if (freq <= 0)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "ANQP: Query Request to " MACSTR " for %u id(s)",
+		   MAC2STR(dst), (unsigned int) num_ids);
+
+	buf = anqp_build_req(info_ids, num_ids, NULL);
+	if (buf == NULL)
+		return -1;
+
+	res = gas_query_req(wpa_s->gas, dst, freq, buf, anqp_resp_cb, wpa_s);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "ANQP: Failed to send Query Request");
+		ret = -1;
+	} else
+		wpa_printf(MSG_DEBUG, "ANQP: Query started with dialog token "
+			   "%u", res);
+
+	wpabuf_free(buf);
+	return ret;
+}
+
+
+static void interworking_parse_rx_anqp_resp(struct wpa_supplicant *wpa_s,
+					    const u8 *sa, u16 info_id,
+					    const u8 *data, size_t slen)
+{
+	const u8 *pos = data;
+	struct wpa_bss *bss = wpa_bss_get_bssid(wpa_s, sa);
+
+	switch (info_id) {
+	case ANQP_CAPABILITY_LIST:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" ANQP Capability list", MAC2STR(sa));
+		break;
+	case ANQP_VENUE_NAME:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" Venue Name", MAC2STR(sa));
+		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Venue Name", pos, slen);
+		if (bss) {
+			wpabuf_free(bss->anqp_venue_name);
+			bss->anqp_venue_name = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_NETWORK_AUTH_TYPE:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" Network Authentication Type information",
+			MAC2STR(sa));
+		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Network Authentication "
+				  "Type", pos, slen);
+		if (bss) {
+			wpabuf_free(bss->anqp_network_auth_type);
+			bss->anqp_network_auth_type =
+				wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_ROAMING_CONSORTIUM:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" Roaming Consortium list", MAC2STR(sa));
+		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: Roaming Consortium",
+				  pos, slen);
+		if (bss) {
+			wpabuf_free(bss->anqp_roaming_consortium);
+			bss->anqp_roaming_consortium =
+				wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" IP Address Type Availability information",
+			MAC2STR(sa));
+		wpa_hexdump(MSG_MSGDUMP, "ANQP: IP Address Availability",
+			    pos, slen);
+		if (bss) {
+			wpabuf_free(bss->anqp_ip_addr_type_availability);
+			bss->anqp_ip_addr_type_availability =
+				wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_NAI_REALM:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" NAI Realm list", MAC2STR(sa));
+		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: NAI Realm", pos, slen);
+		if (bss) {
+			wpabuf_free(bss->anqp_nai_realm);
+			bss->anqp_nai_realm = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_3GPP_CELLULAR_NETWORK:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" 3GPP Cellular Network information", MAC2STR(sa));
+		wpa_hexdump_ascii(MSG_DEBUG, "ANQP: 3GPP Cellular Network",
+				  pos, slen);
+		if (bss) {
+			wpabuf_free(bss->anqp_3gpp);
+			bss->anqp_3gpp = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_DOMAIN_NAME:
+		wpa_msg(wpa_s, MSG_INFO, "RX-ANQP " MACSTR
+			" Domain Name list", MAC2STR(sa));
+		wpa_hexdump_ascii(MSG_MSGDUMP, "ANQP: Domain Name", pos, slen);
+		if (bss) {
+			wpabuf_free(bss->anqp_domain_name);
+			bss->anqp_domain_name = wpabuf_alloc_copy(pos, slen);
+		}
+		break;
+	case ANQP_VENDOR_SPECIFIC:
+		if (slen < 3)
+			return;
+
+		switch (WPA_GET_BE24(pos)) {
+		default:
+			wpa_printf(MSG_DEBUG, "Interworking: Unsupported "
+				   "vendor-specific ANQP OUI %06x",
+				   WPA_GET_BE24(pos));
+			return;
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "Interworking: Unsupported ANQP Info ID "
+			   "%u", info_id);
+		break;
+	}
+}
+
+
+void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
+		  enum gas_query_result result,
+		  const struct wpabuf *adv_proto,
+		  const struct wpabuf *resp, u16 status_code)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	const u8 *pos;
+	const u8 *end;
+	u16 info_id;
+	u16 slen;
+
+	if (result != GAS_QUERY_SUCCESS)
+		return;
+
+	pos = wpabuf_head(adv_proto);
+	if (wpabuf_len(adv_proto) < 4 || pos[0] != WLAN_EID_ADV_PROTO ||
+	    pos[1] < 2 || pos[3] != ACCESS_NETWORK_QUERY_PROTOCOL) {
+		wpa_printf(MSG_DEBUG, "ANQP: Unexpected Advertisement "
+			   "Protocol in response");
+		return;
+	}
+
+	pos = wpabuf_head(resp);
+	end = pos + wpabuf_len(resp);
+
+	while (pos < end) {
+		if (pos + 4 > end) {
+			wpa_printf(MSG_DEBUG, "ANQP: Invalid element");
+			break;
+		}
+		info_id = WPA_GET_LE16(pos);
+		pos += 2;
+		slen = WPA_GET_LE16(pos);
+		pos += 2;
+		if (pos + slen > end) {
+			wpa_printf(MSG_DEBUG, "ANQP: Invalid element length "
+				   "for Info ID %u", info_id);
+			break;
+		}
+		interworking_parse_rx_anqp_resp(wpa_s, dst, info_id, pos,
+						slen);
+		pos += slen;
+	}
+}
+
+
+static void interworking_scan_res_handler(struct wpa_supplicant *wpa_s,
+					  struct wpa_scan_results *scan_res)
+{
+	wpa_printf(MSG_DEBUG, "Interworking: Scan results available - start "
+		   "ANQP fetch");
+	interworking_start_fetch_anqp(wpa_s);
+}
+
+
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select)
+{
+	interworking_stop_fetch_anqp(wpa_s);
+	wpa_s->network_select = 1;
+	wpa_s->auto_select = !!auto_select;
+	wpa_printf(MSG_DEBUG, "Interworking: Start scan for network "
+		   "selection");
+	wpa_s->scan_res_handler = interworking_scan_res_handler;
+	wpa_s->scan_req = 2;
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+	return 0;
+}
diff --git a/wpa_supplicant/interworking.h b/wpa_supplicant/interworking.h
new file mode 100644
index 0000000..247df30
--- /dev/null
+++ b/wpa_supplicant/interworking.h
@@ -0,0 +1,31 @@
+/*
+ * Interworking (IEEE 802.11u)
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef INTERWORKING_H
+#define INTERWORKING_H
+
+enum gas_query_result;
+
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+		  u16 info_ids[], size_t num_ids);
+void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
+		  enum gas_query_result result,
+		  const struct wpabuf *adv_proto,
+		  const struct wpabuf *resp, u16 status_code);
+int interworking_fetch_anqp(struct wpa_supplicant *wpa_s);
+void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s);
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+
+#endif /* INTERWORKING_H */
diff --git a/wpa_supplicant/mlme.c b/wpa_supplicant/mlme.c
deleted file mode 100644
index 49713f5..0000000
--- a/wpa_supplicant/mlme.c
+++ /dev/null
@@ -1,3181 +0,0 @@
-/*
- * WPA Supplicant - Client mode MLME
- * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004, Instant802 Networks, Inc.
- * Copyright (c) 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#include "includes.h"
-
-#include "common.h"
-#include "eloop.h"
-#include "config_ssid.h"
-#include "wpa_supplicant_i.h"
-#include "notify.h"
-#include "driver_i.h"
-#include "rsn_supp/wpa.h"
-#include "common/ieee802_11_defs.h"
-#include "common/ieee802_11_common.h"
-#include "mlme.h"
-
-
-/* Timeouts and intervals in milliseconds */
-#define IEEE80211_AUTH_TIMEOUT (200)
-#define IEEE80211_AUTH_MAX_TRIES 3
-#define IEEE80211_ASSOC_TIMEOUT (200)
-#define IEEE80211_ASSOC_MAX_TRIES 3
-#define IEEE80211_MONITORING_INTERVAL (2000)
-#define IEEE80211_PROBE_INTERVAL (60000)
-#define IEEE80211_RETRY_AUTH_INTERVAL (1000)
-#define IEEE80211_SCAN_INTERVAL (2000)
-#define IEEE80211_SCAN_INTERVAL_SLOW (15000)
-#define IEEE80211_IBSS_JOIN_TIMEOUT (20000)
-
-#define IEEE80211_PROBE_DELAY (33)
-#define IEEE80211_CHANNEL_TIME (33)
-#define IEEE80211_PASSIVE_CHANNEL_TIME (200)
-#define IEEE80211_SCAN_RESULT_EXPIRE (10000)
-#define IEEE80211_IBSS_MERGE_INTERVAL (30000)
-#define IEEE80211_IBSS_INACTIVITY_LIMIT (60000)
-
-#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
-
-
-#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
-
-
-struct ieee80211_sta_bss {
-	struct ieee80211_sta_bss *next;
-	struct ieee80211_sta_bss *hnext;
-
-	u8 bssid[ETH_ALEN];
-	u8 ssid[MAX_SSID_LEN];
-	size_t ssid_len;
-	u16 capability; /* host byte order */
-	int hw_mode;
-	int channel;
-	int freq;
-	int rssi;
-	u8 *ie;
-	size_t ie_len;
-	u8 *wpa_ie;
-	size_t wpa_ie_len;
-	u8 *rsn_ie;
-	size_t rsn_ie_len;
-	u8 *wmm_ie;
-	size_t wmm_ie_len;
-	u8 *mdie;
-	size_t mdie_len;
-#define IEEE80211_MAX_SUPP_RATES 32
-	u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
-	size_t supp_rates_len;
-	int beacon_int;
-	u64 timestamp;
-
-	int probe_resp;
-	struct os_time last_update;
-};
-
-
-static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s,
-				     const u8 *dst,
-				     const u8 *ssid, size_t ssid_len);
-static struct ieee80211_sta_bss *
-ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid);
-static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s);
-static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s);
-static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx);
-static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx);
-static void ieee80211_build_tspec(struct wpabuf *buf);
-static int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s,
-					  const u8 *ies, size_t ies_len);
-
-
-static int ieee80211_sta_set_channel(struct wpa_supplicant *wpa_s,
-				     enum hostapd_hw_mode phymode, int chan,
-				     int freq)
-{
-	size_t i;
-	struct hostapd_hw_modes *mode;
-
-	for (i = 0; i < wpa_s->mlme.num_modes; i++) {
-		mode = &wpa_s->mlme.modes[i];
-		if (mode->mode == phymode) {
-			wpa_s->mlme.curr_rates = mode->rates;
-			wpa_s->mlme.num_curr_rates = mode->num_rates;
-			break;
-		}
-	}
-
-	return wpa_drv_set_channel(wpa_s, phymode, chan, freq);
-}
-
-
-static int ecw2cw(int ecw)
-{
-	int cw = 1;
-	while (ecw > 0) {
-		cw <<= 1;
-		ecw--;
-	}
-	return cw - 1;
-}
-
-
-static void ieee80211_sta_wmm_params(struct wpa_supplicant *wpa_s,
-				     const u8 *wmm_param, size_t wmm_param_len)
-{
-	size_t left;
-	int count;
-	const u8 *pos;
-	u8 wmm_acm;
-
-	if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
-		return;
-	count = wmm_param[6] & 0x0f;
-	if (count == wpa_s->mlme.wmm_last_param_set)
-		return;
-	wpa_s->mlme.wmm_last_param_set = count;
-
-	pos = wmm_param + 8;
-	left = wmm_param_len - 8;
-
-	wmm_acm = 0;
-	for (; left >= 4; left -= 4, pos += 4) {
-		int aci = (pos[0] >> 5) & 0x03;
-		int acm = (pos[0] >> 4) & 0x01;
-		int aifs, cw_max, cw_min, burst_time;
-
-		switch (aci) {
-		case 1: /* AC_BK */
-			if (acm)
-				wmm_acm |= BIT(1) | BIT(2); /* BK/- */
-			break;
-		case 2: /* AC_VI */
-			if (acm)
-				wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
-			break;
-		case 3: /* AC_VO */
-			if (acm)
-				wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
-			break;
-		case 0: /* AC_BE */
-		default:
-			if (acm)
-				wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
-			break;
-		}
-
-		aifs = pos[0] & 0x0f;
-		cw_max = ecw2cw((pos[1] & 0xf0) >> 4);
-		cw_min = ecw2cw(pos[1] & 0x0f);
-		/* TXOP is in units of 32 usec; burst_time in 0.1 ms */
-		burst_time = (pos[2] | (pos[3] << 8)) * 32 / 100;
-		wpa_printf(MSG_DEBUG, "MLME: WMM aci=%d acm=%d aifs=%d "
-			   "cWmin=%d cWmax=%d burst=%d",
-			   aci, acm, aifs, cw_min, cw_max, burst_time);
-		/* TODO: driver configuration */
-	}
-}
-
-
-static void ieee80211_set_associated(struct wpa_supplicant *wpa_s, int assoc)
-{
-	if (wpa_s->mlme.associated == assoc && !assoc)
-		return;
-
-	wpa_s->mlme.associated = assoc;
-
-	if (assoc) {
-		union wpa_event_data data;
-		os_memset(&data, 0, sizeof(data));
-		wpa_s->mlme.prev_bssid_set = 1;
-		os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN);
-		data.assoc_info.req_ies = wpa_s->mlme.assocreq_ies;
-		data.assoc_info.req_ies_len = wpa_s->mlme.assocreq_ies_len;
-		data.assoc_info.resp_ies = wpa_s->mlme.assocresp_ies;
-		data.assoc_info.resp_ies_len = wpa_s->mlme.assocresp_ies_len;
-		data.assoc_info.freq = wpa_s->mlme.freq;
-		wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
-	} else {
-		wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL);
-	}
-	os_get_time(&wpa_s->mlme.last_probe);
-}
-
-
-static int ieee80211_sta_tx(struct wpa_supplicant *wpa_s, const u8 *buf,
-			    size_t len)
-{
-	return wpa_drv_send_mlme(wpa_s, buf, len);
-}
-
-
-static void ieee80211_send_auth(struct wpa_supplicant *wpa_s,
-				int transaction, const u8 *extra,
-				size_t extra_len, int encrypt)
-{
-	u8 *buf;
-	size_t len;
-	struct ieee80211_mgmt *mgmt;
-
-	buf = os_malloc(sizeof(*mgmt) + 6 + extra_len);
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-			   "auth frame");
-		return;
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	len = 24 + 6;
-	os_memset(mgmt, 0, 24 + 6);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_AUTH);
-	if (encrypt)
-		mgmt->frame_control |= host_to_le16(WLAN_FC_ISWEP);
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->u.auth.auth_alg = host_to_le16(wpa_s->mlme.auth_alg);
-	mgmt->u.auth.auth_transaction = host_to_le16(transaction);
-	wpa_s->mlme.auth_transaction = transaction + 1;
-	mgmt->u.auth.status_code = host_to_le16(0);
-	if (extra) {
-		os_memcpy(buf + len, extra, extra_len);
-		len += extra_len;
-	}
-
-	ieee80211_sta_tx(wpa_s, buf, len);
-	os_free(buf);
-}
-
-
-static void ieee80211_reschedule_timer(struct wpa_supplicant *wpa_s, int ms)
-{
-	eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL);
-	eloop_register_timeout(ms / 1000, 1000 * (ms % 1000),
-			       ieee80211_sta_timer, wpa_s, NULL);
-}
-
-
-static void ieee80211_authenticate(struct wpa_supplicant *wpa_s)
-{
-	u8 *extra;
-	size_t extra_len;
-
-	wpa_s->mlme.auth_tries++;
-	if (wpa_s->mlme.auth_tries > IEEE80211_AUTH_MAX_TRIES) {
-		wpa_printf(MSG_DEBUG, "MLME: authentication with AP " MACSTR
-			   " timed out", MAC2STR(wpa_s->bssid));
-		return;
-	}
-
-	wpa_s->mlme.state = IEEE80211_AUTHENTICATE;
-	wpa_printf(MSG_DEBUG, "MLME: authenticate with AP " MACSTR,
-		   MAC2STR(wpa_s->bssid));
-
-	extra = NULL;
-	extra_len = 0;
-
-#ifdef CONFIG_IEEE80211R
-	if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X ||
-	     wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) &&
-	    wpa_s->mlme.ft_ies) {
-		struct ieee80211_sta_bss *bss;
-		struct rsn_mdie *mdie = NULL;
-		bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-		if (bss && bss->mdie_len >= 2 + sizeof(*mdie))
-			mdie = (struct rsn_mdie *) (bss->mdie + 2);
-		if (mdie &&
-		    os_memcmp(mdie->mobility_domain, wpa_s->mlme.current_md,
-			      MOBILITY_DOMAIN_ID_LEN) == 0) {
-			wpa_printf(MSG_DEBUG, "MLME: Trying to use FT "
-				   "over-the-air");
-			wpa_s->mlme.auth_alg = WLAN_AUTH_FT;
-			extra = wpa_s->mlme.ft_ies;
-			extra_len = wpa_s->mlme.ft_ies_len;
-		}
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	ieee80211_send_auth(wpa_s, 1, extra, extra_len, 0);
-
-	ieee80211_reschedule_timer(wpa_s, IEEE80211_AUTH_TIMEOUT);
-}
-
-
-static void ieee80211_send_assoc(struct wpa_supplicant *wpa_s)
-{
-	struct ieee80211_mgmt *mgmt;
-	u8 *pos, *ies, *buf;
-	int i, len;
-	u16 capab;
-	struct ieee80211_sta_bss *bss;
-	int wmm = 0;
-	size_t blen, buflen;
-
-	if (wpa_s->mlme.curr_rates == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: curr_rates not set for assoc");
-		return;
-	}
-
-	buflen = sizeof(*mgmt) + 200 + wpa_s->mlme.extra_ie_len +
-		wpa_s->mlme.ssid_len;
-#ifdef CONFIG_IEEE80211R
-	if (wpa_s->mlme.ft_ies)
-		buflen += wpa_s->mlme.ft_ies_len;
-#endif /* CONFIG_IEEE80211R */
-	buf = os_malloc(buflen);
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-			   "assoc frame");
-		return;
-	}
-	blen = 0;
-
-	capab = wpa_s->mlme.capab;
-	if (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G) {
-		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME |
-			WLAN_CAPABILITY_SHORT_PREAMBLE;
-	}
-	bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-	if (bss) {
-		if (bss->capability & WLAN_CAPABILITY_PRIVACY)
-			capab |= WLAN_CAPABILITY_PRIVACY;
-		if (bss->wmm_ie) {
-			wmm = 1;
-		}
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	blen += 24;
-	os_memset(mgmt, 0, 24);
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-
-	if (wpa_s->mlme.prev_bssid_set) {
-		blen += 10;
-		mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-						   WLAN_FC_STYPE_REASSOC_REQ);
-		mgmt->u.reassoc_req.capab_info = host_to_le16(capab);
-		mgmt->u.reassoc_req.listen_interval = host_to_le16(1);
-		os_memcpy(mgmt->u.reassoc_req.current_ap,
-			  wpa_s->mlme.prev_bssid,
-			  ETH_ALEN);
-	} else {
-		blen += 4;
-		mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-						   WLAN_FC_STYPE_ASSOC_REQ);
-		mgmt->u.assoc_req.capab_info = host_to_le16(capab);
-		mgmt->u.assoc_req.listen_interval = host_to_le16(1);
-	}
-
-	/* SSID */
-	ies = pos = buf + blen;
-	blen += 2 + wpa_s->mlme.ssid_len;
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = wpa_s->mlme.ssid_len;
-	os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
-
-	len = wpa_s->mlme.num_curr_rates;
-	if (len > 8)
-		len = 8;
-	pos = buf + blen;
-	blen += len + 2;
-	*pos++ = WLAN_EID_SUPP_RATES;
-	*pos++ = len;
-	for (i = 0; i < len; i++)
-		*pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5);
-
-	if (wpa_s->mlme.num_curr_rates > len) {
-		pos = buf + blen;
-		blen += wpa_s->mlme.num_curr_rates - len + 2;
-		*pos++ = WLAN_EID_EXT_SUPP_RATES;
-		*pos++ = wpa_s->mlme.num_curr_rates - len;
-		for (i = len; i < wpa_s->mlme.num_curr_rates; i++)
-			*pos++ = (u8) (wpa_s->mlme.curr_rates[i] / 5);
-	}
-
-	if (wpa_s->mlme.extra_ie && wpa_s->mlme.auth_alg != WLAN_AUTH_FT) {
-		pos = buf + blen;
-		blen += wpa_s->mlme.extra_ie_len;
-		os_memcpy(pos, wpa_s->mlme.extra_ie, wpa_s->mlme.extra_ie_len);
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X ||
-	     wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) &&
-	    wpa_s->mlme.auth_alg != WLAN_AUTH_FT &&
-	    bss && bss->mdie &&
-	    bss->mdie_len >= 2 + sizeof(struct rsn_mdie) &&
-	    bss->mdie[1] >= sizeof(struct rsn_mdie)) {
-		pos = buf + blen;
-		blen += 2 + sizeof(struct rsn_mdie);
-		*pos++ = WLAN_EID_MOBILITY_DOMAIN;
-		*pos++ = sizeof(struct rsn_mdie);
-		os_memcpy(pos, bss->mdie + 2, MOBILITY_DOMAIN_ID_LEN);
-		pos += MOBILITY_DOMAIN_ID_LEN;
-		*pos++ = 0; /* FIX: copy from the target AP's MDIE */
-	}
-
-	if ((wpa_s->mlme.key_mgmt == KEY_MGMT_FT_802_1X ||
-	     wpa_s->mlme.key_mgmt == KEY_MGMT_FT_PSK) &&
-	    wpa_s->mlme.auth_alg == WLAN_AUTH_FT && wpa_s->mlme.ft_ies) {
-		pos = buf + blen;
-		os_memcpy(pos, wpa_s->mlme.ft_ies, wpa_s->mlme.ft_ies_len);
-		pos += wpa_s->mlme.ft_ies_len;
-		blen += wpa_s->mlme.ft_ies_len;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	if (wmm && wpa_s->mlme.wmm_enabled) {
-		pos = buf + blen;
-		blen += 9;
-		*pos++ = WLAN_EID_VENDOR_SPECIFIC;
-		*pos++ = 7; /* len */
-		*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
-		*pos++ = 0x50;
-		*pos++ = 0xf2;
-		*pos++ = 2; /* WMM */
-		*pos++ = 0; /* WMM info */
-		*pos++ = 1; /* WMM ver */
-		*pos++ = 0;
-	}
-
-	os_free(wpa_s->mlme.assocreq_ies);
-	wpa_s->mlme.assocreq_ies_len = (buf + blen) - ies;
-	wpa_s->mlme.assocreq_ies = os_malloc(wpa_s->mlme.assocreq_ies_len);
-	if (wpa_s->mlme.assocreq_ies) {
-		os_memcpy(wpa_s->mlme.assocreq_ies, ies,
-			  wpa_s->mlme.assocreq_ies_len);
-	}
-
-	ieee80211_sta_tx(wpa_s, buf, blen);
-	os_free(buf);
-}
-
-
-static void ieee80211_send_deauth(struct wpa_supplicant *wpa_s, u16 reason)
-{
-	u8 *buf;
-	size_t len;
-	struct ieee80211_mgmt *mgmt;
-
-	buf = os_zalloc(sizeof(*mgmt));
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-			   "deauth frame");
-		return;
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	len = 24;
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_DEAUTH);
-	len += 2;
-	mgmt->u.deauth.reason_code = host_to_le16(reason);
-
-	ieee80211_sta_tx(wpa_s, buf, len);
-	os_free(buf);
-}
-
-
-static void ieee80211_send_disassoc(struct wpa_supplicant *wpa_s, u16 reason)
-{
-	u8 *buf;
-	size_t len;
-	struct ieee80211_mgmt *mgmt;
-
-	buf = os_zalloc(sizeof(*mgmt));
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-			   "disassoc frame");
-		return;
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	len = 24;
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_DISASSOC);
-	len += 2;
-	mgmt->u.disassoc.reason_code = host_to_le16(reason);
-
-	ieee80211_sta_tx(wpa_s, buf, len);
-	os_free(buf);
-}
-
-
-static int ieee80211_privacy_mismatch(struct wpa_supplicant *wpa_s)
-{
-	struct ieee80211_sta_bss *bss;
-	int res = 0;
-
-	if (wpa_s->mlme.mixed_cell ||
-	    wpa_s->mlme.key_mgmt != KEY_MGMT_NONE)
-		return 0;
-
-	bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-	if (bss == NULL)
-		return 0;
-
-	if (ieee80211_sta_wep_configured(wpa_s) !=
-	    !!(bss->capability & WLAN_CAPABILITY_PRIVACY))
-		res = 1;
-
-	return res;
-}
-
-
-static void ieee80211_associate(struct wpa_supplicant *wpa_s)
-{
-	wpa_s->mlme.assoc_tries++;
-	if (wpa_s->mlme.assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
-		wpa_printf(MSG_DEBUG, "MLME: association with AP " MACSTR
-			   " timed out", MAC2STR(wpa_s->bssid));
-		return;
-	}
-
-	wpa_s->mlme.state = IEEE80211_ASSOCIATE;
-	wpa_printf(MSG_DEBUG, "MLME: associate with AP " MACSTR,
-		   MAC2STR(wpa_s->bssid));
-	if (ieee80211_privacy_mismatch(wpa_s)) {
-		wpa_printf(MSG_DEBUG, "MLME: mismatch in privacy "
-			   "configuration and mixed-cell disabled - abort "
-			   "association");
-		return;
-	}
-
-	ieee80211_send_assoc(wpa_s);
-
-	ieee80211_reschedule_timer(wpa_s, IEEE80211_ASSOC_TIMEOUT);
-}
-
-
-static void ieee80211_associated(struct wpa_supplicant *wpa_s)
-{
-	int disassoc;
-
-	/* TODO: start monitoring current AP signal quality and number of
-	 * missed beacons. Scan other channels every now and then and search
-	 * for better APs. */
-	/* TODO: remove expired BSSes */
-
-	wpa_s->mlme.state = IEEE80211_ASSOCIATED;
-
-#if 0 /* FIX */
-	sta = sta_info_get(local, wpa_s->bssid);
-	if (sta == NULL) {
-		wpa_printf(MSG_DEBUG "MLME: No STA entry for own AP " MACSTR,
-			   MAC2STR(wpa_s->bssid));
-		disassoc = 1;
-	} else {
-		disassoc = 0;
-		if (time_after(jiffies,
-			       sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
-			if (wpa_s->mlme.probereq_poll) {
-				wpa_printf(MSG_DEBUG "MLME: No ProbeResp from "
-					   "current AP " MACSTR " - assume "
-					   "out of range",
-					   MAC2STR(wpa_s->bssid));
-				disassoc = 1;
-			} else {
-				ieee80211_send_probe_req(
-					wpa_s->bssid,
-					wpa_s->mlme.scan_ssid,
-					wpa_s->mlme.scan_ssid_len);
-				wpa_s->mlme.probereq_poll = 1;
-			}
-		} else {
-			wpa_s->mlme.probereq_poll = 0;
-			if (time_after(jiffies, wpa_s->mlme.last_probe +
-				       IEEE80211_PROBE_INTERVAL)) {
-				wpa_s->mlme.last_probe = jiffies;
-				ieee80211_send_probe_req(wpa_s->bssid,
-							 wpa_s->mlme.ssid,
-							 wpa_s->mlme.ssid_len);
-			}
-		}
-		sta_info_release(local, sta);
-	}
-#else
-	disassoc = 0;
-#endif
-	if (disassoc) {
-		wpa_supplicant_event(wpa_s, EVENT_DISASSOC, NULL);
-		ieee80211_reschedule_timer(wpa_s,
-					   IEEE80211_MONITORING_INTERVAL +
-					   30000);
-	} else {
-		ieee80211_reschedule_timer(wpa_s,
-					   IEEE80211_MONITORING_INTERVAL);
-	}
-}
-
-
-static void ieee80211_send_probe_req(struct wpa_supplicant *wpa_s,
-				     const u8 *dst,
-				     const u8 *ssid, size_t ssid_len)
-{
-	u8 *buf;
-	size_t len;
-	struct ieee80211_mgmt *mgmt;
-	u8 *pos, *supp_rates;
-	u8 *esupp_rates = NULL;
-	int i;
-
-	buf = os_malloc(sizeof(*mgmt) + 200 + wpa_s->mlme.extra_probe_ie_len);
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to allocate buffer for "
-			   "probe request");
-		return;
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	len = 24;
-	os_memset(mgmt, 0, 24);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_PROBE_REQ);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	if (dst) {
-		os_memcpy(mgmt->da, dst, ETH_ALEN);
-		os_memcpy(mgmt->bssid, dst, ETH_ALEN);
-	} else {
-		os_memset(mgmt->da, 0xff, ETH_ALEN);
-		os_memset(mgmt->bssid, 0xff, ETH_ALEN);
-	}
-	pos = buf + len;
-	len += 2 + ssid_len;
-	*pos++ = WLAN_EID_SSID;
-	*pos++ = ssid_len;
-	os_memcpy(pos, ssid, ssid_len);
-
-	supp_rates = buf + len;
-	len += 2;
-	supp_rates[0] = WLAN_EID_SUPP_RATES;
-	supp_rates[1] = 0;
-	for (i = 0; i < wpa_s->mlme.num_curr_rates; i++) {
-		if (esupp_rates) {
-			pos = buf + len;
-			len++;
-			esupp_rates[1]++;
-		} else if (supp_rates[1] == 8) {
-			esupp_rates = pos;
-			esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
-			esupp_rates[1] = 1;
-			pos = &esupp_rates[2];
-			len += 3;
-		} else {
-			pos = buf + len;
-			len++;
-			supp_rates[1]++;
-		}
-		*pos++ = wpa_s->mlme.curr_rates[i] / 5;
-	}
-
-	if (wpa_s->mlme.extra_probe_ie) {
-		os_memcpy(pos, wpa_s->mlme.extra_probe_ie,
-			  wpa_s->mlme.extra_probe_ie_len);
-		len += wpa_s->mlme.extra_probe_ie_len;
-	}
-
-	ieee80211_sta_tx(wpa_s, buf, len);
-	os_free(buf);
-}
-
-
-static int ieee80211_sta_wep_configured(struct wpa_supplicant *wpa_s)
-{
-#if 0 /* FIX */
-	if (sdata == NULL || sdata->default_key == NULL ||
-	    sdata->default_key->alg != ALG_WEP)
-		return 0;
-	return 1;
-#else
-	return 0;
-#endif
-}
-
-
-static void ieee80211_auth_completed(struct wpa_supplicant *wpa_s)
-{
-	wpa_printf(MSG_DEBUG, "MLME: authenticated");
-	wpa_s->mlme.authenticated = 1;
-	ieee80211_associate(wpa_s);
-}
-
-
-static void ieee80211_auth_challenge(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len,
-				     struct ieee80211_rx_status *rx_status)
-{
-	u8 *pos;
-	struct ieee802_11_elems elems;
-
-	wpa_printf(MSG_DEBUG, "MLME: replying to auth challenge");
-	pos = mgmt->u.auth.variable;
-	if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0)
-	    == ParseFailed) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to parse Auth(challenge)");
-		return;
-	}
-	if (elems.challenge == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: no challenge IE in shared key "
-			   "auth frame");
-		return;
-	}
-	ieee80211_send_auth(wpa_s, 3, elems.challenge - 2,
-			    elems.challenge_len + 2, 1);
-}
-
-
-static void ieee80211_rx_mgmt_auth(struct wpa_supplicant *wpa_s,
-				   struct ieee80211_mgmt *mgmt,
-				   size_t len,
-				   struct ieee80211_rx_status *rx_status)
-{
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-	u16 auth_alg, auth_transaction, status_code;
-	int adhoc;
-
-	adhoc = ssid && ssid->mode == WPAS_MODE_IBSS;
-
-	if (wpa_s->mlme.state != IEEE80211_AUTHENTICATE && !adhoc) {
-		wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
-			   "from " MACSTR ", but not in authenticate state - "
-			   "ignored", MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (len < 24 + 6) {
-		wpa_printf(MSG_DEBUG, "MLME: too short (%lu) authentication "
-			   "frame received from " MACSTR " - ignored",
-			   (unsigned long) len, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (!adhoc && os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
-			   "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
-			   ") - ignored",
-			   MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-		return;
-	}
-
-	if (adhoc && os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: authentication frame received "
-			   "from unknown BSSID (SA=" MACSTR " BSSID=" MACSTR
-			   ") - ignored",
-			   MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-		return;
-	}
-
-	auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
-	auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
-	status_code = le_to_host16(mgmt->u.auth.status_code);
-
-	wpa_printf(MSG_DEBUG, "MLME: RX authentication from " MACSTR
-		   " (alg=%d transaction=%d status=%d)",
-		   MAC2STR(mgmt->sa), auth_alg, auth_transaction, status_code);
-
-	if (adhoc) {
-		/* IEEE 802.11 standard does not require authentication in IBSS
-		 * networks and most implementations do not seem to use it.
-		 * However, try to reply to authentication attempts if someone
-		 * has actually implemented this.
-		 * TODO: Could implement shared key authentication. */
-		if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1) {
-			wpa_printf(MSG_DEBUG, "MLME: unexpected IBSS "
-				   "authentication frame (alg=%d "
-				   "transaction=%d)",
-				   auth_alg, auth_transaction);
-			return;
-		}
-		ieee80211_send_auth(wpa_s, 2, NULL, 0, 0);
-	}
-
-	if (auth_alg != wpa_s->mlme.auth_alg ||
-	    auth_transaction != wpa_s->mlme.auth_transaction) {
-		wpa_printf(MSG_DEBUG, "MLME: unexpected authentication frame "
-			   "(alg=%d transaction=%d)",
-			   auth_alg, auth_transaction);
-		return;
-	}
-
-	if (status_code != WLAN_STATUS_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "MLME: AP denied authentication "
-			   "(auth_alg=%d code=%d)", wpa_s->mlme.auth_alg,
-			   status_code);
-		if (status_code == WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG) {
-			const int num_algs = 3;
-			u8 algs[num_algs];
-			int i, pos;
-			algs[0] = algs[1] = algs[2] = 0xff;
-			if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN)
-				algs[0] = WLAN_AUTH_OPEN;
-			if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED)
-				algs[1] = WLAN_AUTH_SHARED_KEY;
-			if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP)
-				algs[2] = WLAN_AUTH_LEAP;
-			if (wpa_s->mlme.auth_alg == WLAN_AUTH_OPEN)
-				pos = 0;
-			else if (wpa_s->mlme.auth_alg == WLAN_AUTH_SHARED_KEY)
-				pos = 1;
-			else
-				pos = 2;
-			for (i = 0; i < num_algs; i++) {
-				pos++;
-				if (pos >= num_algs)
-					pos = 0;
-				if (algs[pos] == wpa_s->mlme.auth_alg ||
-				    algs[pos] == 0xff)
-					continue;
-				if (algs[pos] == WLAN_AUTH_SHARED_KEY &&
-				    !ieee80211_sta_wep_configured(wpa_s))
-					continue;
-				wpa_s->mlme.auth_alg = algs[pos];
-				wpa_printf(MSG_DEBUG, "MLME: set auth_alg=%d "
-					   "for next try",
-					   wpa_s->mlme.auth_alg);
-				break;
-			}
-		}
-		return;
-	}
-
-	switch (wpa_s->mlme.auth_alg) {
-	case WLAN_AUTH_OPEN:
-	case WLAN_AUTH_LEAP:
-		ieee80211_auth_completed(wpa_s);
-		break;
-	case WLAN_AUTH_SHARED_KEY:
-		if (wpa_s->mlme.auth_transaction == 4)
-			ieee80211_auth_completed(wpa_s);
-		else
-			ieee80211_auth_challenge(wpa_s, mgmt, len,
-						 rx_status);
-		break;
-#ifdef CONFIG_IEEE80211R
-	case WLAN_AUTH_FT:
-	{
-		union wpa_event_data data;
-		struct wpabuf *ric = NULL;
-		os_memset(&data, 0, sizeof(data));
-		data.ft_ies.ies = mgmt->u.auth.variable;
-		data.ft_ies.ies_len = len -
-			(mgmt->u.auth.variable - (u8 *) mgmt);
-		os_memcpy(data.ft_ies.target_ap, wpa_s->bssid, ETH_ALEN);
-		if (os_strcmp(wpa_s->driver->name, "test") == 0 &&
-		    wpa_s->mlme.wmm_enabled) {
-			ric = wpabuf_alloc(200);
-			if (ric) {
-				/* Build simple RIC-Request: RDIE | TSPEC */
-
-				/* RIC Data (RDIE) */
-				wpabuf_put_u8(ric, WLAN_EID_RIC_DATA);
-				wpabuf_put_u8(ric, 4);
-				wpabuf_put_u8(ric, 0); /* RDIE Identifier */
-				wpabuf_put_u8(ric, 1); /* Resource Descriptor
-							* Count */
-				wpabuf_put_le16(ric, 0); /* Status Code */
-
-				/* WMM TSPEC */
-				ieee80211_build_tspec(ric);
-
-				data.ft_ies.ric_ies = wpabuf_head(ric);
-				data.ft_ies.ric_ies_len = wpabuf_len(ric);
-			}
-		}
-
-		wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data);
-		wpabuf_free(ric);
-		ieee80211_auth_completed(wpa_s);
-		break;
-	}
-#endif /* CONFIG_IEEE80211R */
-	}
-}
-
-
-static void ieee80211_rx_mgmt_deauth(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len,
-				     struct ieee80211_rx_status *rx_status)
-{
-	u16 reason_code;
-
-	if (len < 24 + 2) {
-		wpa_printf(MSG_DEBUG, "MLME: too short (%lu) deauthentication "
-			   "frame received from " MACSTR " - ignored",
-			   (unsigned long) len, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: deauthentication frame received "
-			   "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
-			   ") - ignored",
-			   MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-		return;
-	}
-
-	reason_code = le_to_host16(mgmt->u.deauth.reason_code);
-
-	wpa_printf(MSG_DEBUG, "MLME: RX deauthentication from " MACSTR
-		   " (reason=%d)", MAC2STR(mgmt->sa), reason_code);
-
-	if (wpa_s->mlme.authenticated)
-		wpa_printf(MSG_DEBUG, "MLME: deauthenticated");
-
-	if (wpa_s->mlme.state == IEEE80211_AUTHENTICATE ||
-	    wpa_s->mlme.state == IEEE80211_ASSOCIATE ||
-	    wpa_s->mlme.state == IEEE80211_ASSOCIATED) {
-		wpa_s->mlme.state = IEEE80211_AUTHENTICATE;
-		ieee80211_reschedule_timer(wpa_s,
-					   IEEE80211_RETRY_AUTH_INTERVAL);
-	}
-
-	ieee80211_set_associated(wpa_s, 0);
-	wpa_s->mlme.authenticated = 0;
-}
-
-
-static void ieee80211_rx_mgmt_disassoc(struct wpa_supplicant *wpa_s,
-				       struct ieee80211_mgmt *mgmt,
-				       size_t len,
-				       struct ieee80211_rx_status *rx_status)
-{
-	u16 reason_code;
-
-	if (len < 24 + 2) {
-		wpa_printf(MSG_DEBUG, "MLME: too short (%lu) disassociation "
-			   "frame received from " MACSTR " - ignored",
-			   (unsigned long) len, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: disassociation frame received "
-			   "from unknown AP (SA=" MACSTR " BSSID=" MACSTR
-			   ") - ignored",
-			   MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-		return;
-	}
-
-	reason_code = le_to_host16(mgmt->u.disassoc.reason_code);
-
-	wpa_printf(MSG_DEBUG, "MLME: RX disassociation from " MACSTR
-		   " (reason=%d)", MAC2STR(mgmt->sa), reason_code);
-
-	if (wpa_s->mlme.associated)
-		wpa_printf(MSG_DEBUG, "MLME: disassociated");
-
-	if (wpa_s->mlme.state == IEEE80211_ASSOCIATED) {
-		wpa_s->mlme.state = IEEE80211_ASSOCIATE;
-		ieee80211_reschedule_timer(wpa_s,
-					   IEEE80211_RETRY_AUTH_INTERVAL);
-	}
-
-	ieee80211_set_associated(wpa_s, 0);
-}
-
-
-static void ieee80211_build_tspec(struct wpabuf *buf)
-{
-	struct wmm_tspec_element *tspec;
-	int tid, up;
-
-	tspec = wpabuf_put(buf, sizeof(*tspec));
-	tspec->eid = WLAN_EID_VENDOR_SPECIFIC;
-	tspec->length = sizeof(*tspec) - 2;
-	tspec->oui[0] = 0x00;
-	tspec->oui[1] = 0x50;
-	tspec->oui[2] = 0xf2;
-	tspec->oui_type = 2;
-	tspec->oui_subtype = 2;
-	tspec->version = 1;
-
-	tid = 1;
-	up = 6; /* Voice */
-	tspec->ts_info[0] = (tid << 1) |
-		(WMM_TSPEC_DIRECTION_BI_DIRECTIONAL << 5) |
-		BIT(7);
-	tspec->ts_info[1] = up << 3;
-	tspec->nominal_msdu_size = host_to_le16(1530);
-	tspec->mean_data_rate = host_to_le32(128000); /* bits per second */
-	tspec->minimum_phy_rate = host_to_le32(6000000);
-	tspec->surplus_bandwidth_allowance = host_to_le16(0x3000); /* 150% */
-}
-
-
-static void ieee80211_tx_addts(struct wpa_supplicant *wpa_s)
-{
-	struct wpabuf *buf;
-	struct ieee80211_mgmt *mgmt;
-	size_t alen;
-
-	wpa_printf(MSG_DEBUG, "MLME: Send ADDTS Request for Voice TSPEC");
-	mgmt = NULL;
-	alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
-
-	buf = wpabuf_alloc(alen + sizeof(struct wmm_tspec_element));
-	if (buf == NULL)
-		return;
-
-	mgmt = wpabuf_put(buf, alen);
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_ACTION);
-	mgmt->u.action.category = WLAN_ACTION_WMM;
-	mgmt->u.action.u.wmm_action.action_code = WMM_ACTION_CODE_ADDTS_REQ;
-	mgmt->u.action.u.wmm_action.dialog_token = 1;
-	mgmt->u.action.u.wmm_action.status_code = 0;
-
-	ieee80211_build_tspec(buf);
-
-	ieee80211_sta_tx(wpa_s, wpabuf_head(buf), wpabuf_len(buf));
-	wpabuf_free(buf);
-}
-
-
-static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
-					 struct ieee80211_mgmt *mgmt,
-					 size_t len,
-					 struct ieee80211_rx_status *rx_status,
-					 int reassoc)
-{
-	u8 rates[32];
-	size_t rates_len;
-	u16 capab_info, status_code, aid;
-	struct ieee802_11_elems elems;
-	u8 *pos;
-
-	/* AssocResp and ReassocResp have identical structure, so process both
-	 * of them in this function. */
-
-	if (wpa_s->mlme.state != IEEE80211_ASSOCIATE) {
-		wpa_printf(MSG_DEBUG, "MLME: association frame received from "
-			   MACSTR ", but not in associate state - ignored",
-			   MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (len < 24 + 6) {
-		wpa_printf(MSG_DEBUG, "MLME: too short (%lu) association "
-			   "frame received from " MACSTR " - ignored",
-			   (unsigned long) len, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (os_memcmp(wpa_s->bssid, mgmt->sa, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: association frame received from "
-			   "unknown AP (SA=" MACSTR " BSSID=" MACSTR ") - "
-			   "ignored", MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid));
-		return;
-	}
-
-	capab_info = le_to_host16(mgmt->u.assoc_resp.capab_info);
-	status_code = le_to_host16(mgmt->u.assoc_resp.status_code);
-	aid = le_to_host16(mgmt->u.assoc_resp.aid);
-	if ((aid & (BIT(15) | BIT(14))) != (BIT(15) | BIT(14)))
-		wpa_printf(MSG_DEBUG, "MLME: invalid aid value %d; bits 15:14 "
-			   "not set", aid);
-	aid &= ~(BIT(15) | BIT(14));
-
-	wpa_printf(MSG_DEBUG, "MLME: RX %sssocResp from " MACSTR
-		   " (capab=0x%x status=%d aid=%d)",
-		   reassoc ? "Rea" : "A", MAC2STR(mgmt->sa),
-		   capab_info, status_code, aid);
-
-	pos = mgmt->u.assoc_resp.variable;
-	if (ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems, 0)
-	    == ParseFailed) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to parse AssocResp");
-		return;
-	}
-
-	if (status_code != WLAN_STATUS_SUCCESS) {
-		wpa_printf(MSG_DEBUG, "MLME: AP denied association (code=%d)",
-			   status_code);
-#ifdef CONFIG_IEEE80211W
-		if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY &&
-		    elems.timeout_int && elems.timeout_int_len == 5 &&
-		    elems.timeout_int[0] == WLAN_TIMEOUT_ASSOC_COMEBACK) {
-			u32 tu, ms;
-			tu = WPA_GET_LE32(elems.timeout_int + 1);
-			ms = tu * 1024 / 1000;
-			wpa_printf(MSG_DEBUG, "MLME: AP rejected association "
-				   "temporarily; comeback duration %u TU "
-				   "(%u ms)", tu, ms);
-			if (ms > IEEE80211_ASSOC_TIMEOUT) {
-				wpa_printf(MSG_DEBUG, "MLME: Update timer "
-					   "based on comeback duration");
-				ieee80211_reschedule_timer(wpa_s, ms);
-			}
-		}
-#endif /* CONFIG_IEEE80211W */
-		return;
-	}
-
-	if (elems.supp_rates == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: no SuppRates element in "
-			   "AssocResp");
-		return;
-	}
-
-	if (wpa_s->mlme.auth_alg == WLAN_AUTH_FT) {
-		if (!reassoc) {
-			wpa_printf(MSG_DEBUG, "MLME: AP tried to use "
-				   "association, not reassociation, response "
-				   "with FT");
-			return;
-		}
-		if (wpa_ft_validate_reassoc_resp(
-			    wpa_s->wpa, pos, len - (pos - (u8 *) mgmt),
-			    mgmt->sa) < 0) {
-			wpa_printf(MSG_DEBUG, "MLME: FT validation of Reassoc"
-				   "Resp failed");
-			return;
-		}
-	} else if (wpa_sm_set_ft_params(wpa_s->wpa, pos,
-					len - (pos - (u8 *) mgmt)) < 0)
-		return;
-
-	wpa_printf(MSG_DEBUG, "MLME: associated");
-	wpa_s->mlme.aid = aid;
-	wpa_s->mlme.ap_capab = capab_info;
-
-	os_free(wpa_s->mlme.assocresp_ies);
-	wpa_s->mlme.assocresp_ies_len = len - (pos - (u8 *) mgmt);
-	wpa_s->mlme.assocresp_ies = os_malloc(wpa_s->mlme.assocresp_ies_len);
-	if (wpa_s->mlme.assocresp_ies) {
-		os_memcpy(wpa_s->mlme.assocresp_ies, pos,
-			  wpa_s->mlme.assocresp_ies_len);
-	}
-
-	ieee80211_set_associated(wpa_s, 1);
-
-	rates_len = elems.supp_rates_len;
-	if (rates_len > sizeof(rates))
-		rates_len = sizeof(rates);
-	os_memcpy(rates, elems.supp_rates, rates_len);
-	if (elems.ext_supp_rates) {
-		size_t _len = elems.ext_supp_rates_len;
-		if (_len > sizeof(rates) - rates_len)
-			_len = sizeof(rates) - rates_len;
-		os_memcpy(rates + rates_len, elems.ext_supp_rates, _len);
-		rates_len += _len;
-	}
-
-	if (wpa_drv_set_bssid(wpa_s, wpa_s->bssid) < 0) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to set BSSID for the "
-			   "netstack");
-	}
-	if (wpa_drv_set_ssid(wpa_s, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) <
-	    0) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to set SSID for the "
-			   "netstack");
-	}
-
-	/* Remove STA entry before adding a new one just in case to avoid
-	 * problems with existing configuration (e.g., keys). */
-	wpa_drv_mlme_remove_sta(wpa_s, wpa_s->bssid);
-	if (wpa_drv_mlme_add_sta(wpa_s, wpa_s->bssid, rates, rates_len) < 0) {
-		wpa_printf(MSG_DEBUG, "MLME: failed to add STA entry to the "
-			   "netstack");
-	}
-
-	if (elems.wmm && wpa_s->mlme.wmm_enabled)
-		ieee80211_sta_wmm_params(wpa_s, elems.wmm, elems.wmm_len);
-
-	ieee80211_associated(wpa_s);
-
-	if (wpa_s->mlme.auth_alg != WLAN_AUTH_FT &&
-	    os_strcmp(wpa_s->driver->name, "test") == 0 &&
-	    elems.wmm && wpa_s->mlme.wmm_enabled) {
-		/* Test WMM-AC - send ADDTS for WMM TSPEC */
-		ieee80211_tx_addts(wpa_s);
-	}
-}
-
-
-/* Caller must hold local->sta_bss_lock */
-static void __ieee80211_bss_hash_add(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_sta_bss *bss)
-{
-	bss->hnext = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)];
-	wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)] = bss;
-}
-
-
-/* Caller must hold local->sta_bss_lock */
-static void __ieee80211_bss_hash_del(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_sta_bss *bss)
-{
-	struct ieee80211_sta_bss *b, *prev = NULL;
-	b = wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)];
-	while (b) {
-		if (b == bss) {
-			if (prev == NULL) {
-				wpa_s->mlme.sta_bss_hash[STA_HASH(bss->bssid)]
-					= bss->hnext;
-			} else {
-				prev->hnext = bss->hnext;
-			}
-			break;
-		}
-		prev = b;
-		b = b->hnext;
-	}
-}
-
-
-static struct ieee80211_sta_bss *
-ieee80211_bss_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
-	struct ieee80211_sta_bss *bss;
-
-	bss = os_zalloc(sizeof(*bss));
-	if (bss == NULL)
-		return NULL;
-	os_memcpy(bss->bssid, bssid, ETH_ALEN);
-
-	/* TODO: order by RSSI? */
-	bss->next = wpa_s->mlme.sta_bss_list;
-	wpa_s->mlme.sta_bss_list = bss;
-	__ieee80211_bss_hash_add(wpa_s, bss);
-	return bss;
-}
-
-
-static struct ieee80211_sta_bss *
-ieee80211_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid)
-{
-	struct ieee80211_sta_bss *bss;
-
-	bss = wpa_s->mlme.sta_bss_hash[STA_HASH(bssid)];
-	while (bss) {
-		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
-			break;
-		bss = bss->hnext;
-	}
-	return bss;
-}
-
-
-static void ieee80211_bss_free(struct wpa_supplicant *wpa_s,
-			       struct ieee80211_sta_bss *bss)
-{
-	__ieee80211_bss_hash_del(wpa_s, bss);
-	os_free(bss->ie);
-	os_free(bss->wpa_ie);
-	os_free(bss->rsn_ie);
-	os_free(bss->wmm_ie);
-	os_free(bss->mdie);
-	os_free(bss);
-}
-
-
-static void ieee80211_bss_list_deinit(struct wpa_supplicant *wpa_s)
-{
-	struct ieee80211_sta_bss *bss, *prev;
-
-	bss = wpa_s->mlme.sta_bss_list;
-	wpa_s->mlme.sta_bss_list = NULL;
-	while (bss) {
-		prev = bss;
-		bss = bss->next;
-		ieee80211_bss_free(wpa_s, prev);
-	}
-}
-
-
-static void ieee80211_bss_info(struct wpa_supplicant *wpa_s,
-			       struct ieee80211_mgmt *mgmt,
-			       size_t len,
-			       struct ieee80211_rx_status *rx_status,
-			       int beacon)
-{
-	struct ieee802_11_elems elems;
-	size_t baselen;
-	int channel, invalid = 0, clen;
-	struct ieee80211_sta_bss *bss;
-	u64 timestamp;
-	u8 *pos, *ie_pos;
-	size_t ie_len;
-
-	if (!beacon && os_memcmp(mgmt->da, wpa_s->own_addr, ETH_ALEN))
-		return; /* ignore ProbeResp to foreign address */
-
-#if 0
-	wpa_printf(MSG_MSGDUMP, "MLME: RX %s from " MACSTR " to " MACSTR,
-		   beacon ? "Beacon" : "Probe Response",
-		   MAC2STR(mgmt->sa), MAC2STR(mgmt->da));
-#endif
-
-	baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
-	if (baselen > len)
-		return;
-
-	pos = mgmt->u.beacon.timestamp;
-	timestamp = WPA_GET_LE64(pos);
-
-#if 0 /* FIX */
-	if (local->conf.mode == IW_MODE_ADHOC && beacon &&
-	    os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0) {
-#ifdef IEEE80211_IBSS_DEBUG
-		static unsigned long last_tsf_debug = 0;
-		u64 tsf;
-		if (local->hw->get_tsf)
-			tsf = local->hw->get_tsf(local->mdev);
-		else
-			tsf = -1LLU;
-		if (time_after(jiffies, last_tsf_debug + 5 * HZ)) {
-			wpa_printf(MSG_DEBUG, "RX beacon SA=" MACSTR " BSSID="
-				   MACSTR " TSF=0x%llx BCN=0x%llx diff=%lld "
-				   "@%ld",
-				   MAC2STR(mgmt->sa), MAC2STR(mgmt->bssid),
-				   tsf, timestamp, tsf - timestamp, jiffies);
-			last_tsf_debug = jiffies;
-		}
-#endif /* IEEE80211_IBSS_DEBUG */
-	}
-#endif
-
-	ie_pos = mgmt->u.beacon.variable;
-	ie_len = len - baselen;
-	if (ieee802_11_parse_elems(ie_pos, ie_len, &elems, 0) == ParseFailed)
-		invalid = 1;
-
-#if 0 /* FIX */
-	if (local->conf.mode == IW_MODE_ADHOC && elems.supp_rates &&
-	    os_memcmp(mgmt->bssid, local->bssid, ETH_ALEN) == 0 &&
-	    (sta = sta_info_get(local, mgmt->sa))) {
-		struct ieee80211_rate *rates;
-		size_t num_rates;
-		u32 supp_rates, prev_rates;
-		int i, j, oper_mode;
-
-		rates = local->curr_rates;
-		num_rates = local->num_curr_rates;
-		oper_mode = wpa_s->mlme.sta_scanning ?
-			local->scan_oper_phymode : local->conf.phymode;
-		for (i = 0; i < local->hw->num_modes; i++) {
-			struct ieee80211_hw_modes *mode = &local->hw->modes[i];
-			if (oper_mode == mode->mode) {
-				rates = mode->rates;
-				num_rates = mode->num_rates;
-				break;
-			}
-		}
-
-		supp_rates = 0;
-		for (i = 0; i < elems.supp_rates_len +
-			     elems.ext_supp_rates_len; i++) {
-			u8 rate = 0;
-			int own_rate;
-			if (i < elems.supp_rates_len)
-				rate = elems.supp_rates[i];
-			else if (elems.ext_supp_rates)
-				rate = elems.ext_supp_rates
-					[i - elems.supp_rates_len];
-			own_rate = 5 * (rate & 0x7f);
-			if (oper_mode == MODE_ATHEROS_TURBO)
-				own_rate *= 2;
-			for (j = 0; j < num_rates; j++)
-				if (rates[j].rate == own_rate)
-					supp_rates |= BIT(j);
-		}
-
-		prev_rates = sta->supp_rates;
-		sta->supp_rates &= supp_rates;
-		if (sta->supp_rates == 0) {
-			/* No matching rates - this should not really happen.
-			 * Make sure that at least one rate is marked
-			 * supported to avoid issues with TX rate ctrl. */
-			sta->supp_rates = wpa_s->mlme.supp_rates_bits;
-		}
-		if (sta->supp_rates != prev_rates) {
-			wpa_printf(MSG_DEBUG, "MLME: updated supp_rates set "
-				   "for " MACSTR " based on beacon info "
-				   "(0x%x & 0x%x -> 0x%x)",
-				   MAC2STR(sta->addr), prev_rates,
-				   supp_rates, sta->supp_rates);
-		}
-		sta_info_release(local, sta);
-	}
-#endif
-
-	if (elems.ssid == NULL)
-		return;
-
-	if (elems.ds_params && elems.ds_params_len == 1)
-		channel = elems.ds_params[0];
-	else
-		channel = rx_status->channel;
-
-	bss = ieee80211_bss_get(wpa_s, mgmt->bssid);
-	if (bss == NULL) {
-		bss = ieee80211_bss_add(wpa_s, mgmt->bssid);
-		if (bss == NULL)
-			return;
-	} else {
-#if 0
-		/* TODO: order by RSSI? */
-		spin_lock_bh(&local->sta_bss_lock);
-		list_move_tail(&bss->list, &local->sta_bss_list);
-		spin_unlock_bh(&local->sta_bss_lock);
-#endif
-	}
-
-	if (bss->probe_resp && beacon) {
-		/* Do not allow beacon to override data from Probe Response. */
-		return;
-	}
-
-	bss->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
-	bss->capability = le_to_host16(mgmt->u.beacon.capab_info);
-
-	if (bss->ie == NULL || bss->ie_len < ie_len) {
-		os_free(bss->ie);
-		bss->ie = os_malloc(ie_len);
-	}
-	if (bss->ie) {
-		os_memcpy(bss->ie, ie_pos, ie_len);
-		bss->ie_len = ie_len;
-	}
-
-	if (elems.ssid && elems.ssid_len <= MAX_SSID_LEN) {
-		os_memcpy(bss->ssid, elems.ssid, elems.ssid_len);
-		bss->ssid_len = elems.ssid_len;
-	}
-
-	bss->supp_rates_len = 0;
-	if (elems.supp_rates) {
-		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
-		if (clen > elems.supp_rates_len)
-			clen = elems.supp_rates_len;
-		os_memcpy(&bss->supp_rates[bss->supp_rates_len],
-			  elems.supp_rates, clen);
-		bss->supp_rates_len += clen;
-	}
-	if (elems.ext_supp_rates) {
-		clen = IEEE80211_MAX_SUPP_RATES - bss->supp_rates_len;
-		if (clen > elems.ext_supp_rates_len)
-			clen = elems.ext_supp_rates_len;
-		os_memcpy(&bss->supp_rates[bss->supp_rates_len],
-			  elems.ext_supp_rates, clen);
-		bss->supp_rates_len += clen;
-	}
-
-	if (elems.wpa_ie &&
-	    (bss->wpa_ie == NULL || bss->wpa_ie_len != elems.wpa_ie_len ||
-	     os_memcmp(bss->wpa_ie, elems.wpa_ie, elems.wpa_ie_len))) {
-		os_free(bss->wpa_ie);
-		bss->wpa_ie = os_malloc(elems.wpa_ie_len + 2);
-		if (bss->wpa_ie) {
-			os_memcpy(bss->wpa_ie, elems.wpa_ie - 2,
-				  elems.wpa_ie_len + 2);
-			bss->wpa_ie_len = elems.wpa_ie_len + 2;
-		} else
-			bss->wpa_ie_len = 0;
-	} else if (!elems.wpa_ie && bss->wpa_ie) {
-		os_free(bss->wpa_ie);
-		bss->wpa_ie = NULL;
-		bss->wpa_ie_len = 0;
-	}
-
-	if (elems.rsn_ie &&
-	    (bss->rsn_ie == NULL || bss->rsn_ie_len != elems.rsn_ie_len ||
-	     os_memcmp(bss->rsn_ie, elems.rsn_ie, elems.rsn_ie_len))) {
-		os_free(bss->rsn_ie);
-		bss->rsn_ie = os_malloc(elems.rsn_ie_len + 2);
-		if (bss->rsn_ie) {
-			os_memcpy(bss->rsn_ie, elems.rsn_ie - 2,
-				  elems.rsn_ie_len + 2);
-			bss->rsn_ie_len = elems.rsn_ie_len + 2;
-		} else
-			bss->rsn_ie_len = 0;
-	} else if (!elems.rsn_ie && bss->rsn_ie) {
-		os_free(bss->rsn_ie);
-		bss->rsn_ie = NULL;
-		bss->rsn_ie_len = 0;
-	}
-
-	if (elems.wmm &&
-	    (bss->wmm_ie == NULL || bss->wmm_ie_len != elems.wmm_len ||
-	     os_memcmp(bss->wmm_ie, elems.wmm, elems.wmm_len))) {
-		os_free(bss->wmm_ie);
-		bss->wmm_ie = os_malloc(elems.wmm_len + 2);
-		if (bss->wmm_ie) {
-			os_memcpy(bss->wmm_ie, elems.wmm - 2,
-				  elems.wmm_len + 2);
-			bss->wmm_ie_len = elems.wmm_len + 2;
-		} else
-			bss->wmm_ie_len = 0;
-	} else if (!elems.wmm && bss->wmm_ie) {
-		os_free(bss->wmm_ie);
-		bss->wmm_ie = NULL;
-		bss->wmm_ie_len = 0;
-	}
-
-#ifdef CONFIG_IEEE80211R
-	if (elems.mdie &&
-	    (bss->mdie == NULL || bss->mdie_len != elems.mdie_len ||
-	     os_memcmp(bss->mdie, elems.mdie, elems.mdie_len))) {
-		os_free(bss->mdie);
-		bss->mdie = os_malloc(elems.mdie_len + 2);
-		if (bss->mdie) {
-			os_memcpy(bss->mdie, elems.mdie - 2,
-				  elems.mdie_len + 2);
-			bss->mdie_len = elems.mdie_len + 2;
-		} else
-			bss->mdie_len = 0;
-	} else if (!elems.mdie && bss->mdie) {
-		os_free(bss->mdie);
-		bss->mdie = NULL;
-		bss->mdie_len = 0;
-	}
-#endif /* CONFIG_IEEE80211R */
-
-	bss->hw_mode = wpa_s->mlme.phymode;
-	bss->channel = channel;
-	bss->freq = wpa_s->mlme.freq;
-	if (channel != wpa_s->mlme.channel &&
-	    (wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211G ||
-	     wpa_s->mlme.phymode == HOSTAPD_MODE_IEEE80211B) &&
-	    channel >= 1 && channel <= 14) {
-		static const int freq_list[] = {
-			2412, 2417, 2422, 2427, 2432, 2437, 2442,
-			2447, 2452, 2457, 2462, 2467, 2472, 2484
-		};
-		/* IEEE 802.11g/b mode can receive packets from neighboring
-		 * channels, so map the channel into frequency. */
-		bss->freq = freq_list[channel - 1];
-	}
-	bss->timestamp = timestamp;
-	os_get_time(&bss->last_update);
-	bss->rssi = rx_status->ssi;
-	if (!beacon)
-		bss->probe_resp++;
-}
-
-
-static void ieee80211_rx_mgmt_probe_resp(struct wpa_supplicant *wpa_s,
-					 struct ieee80211_mgmt *mgmt,
-					 size_t len,
-					 struct ieee80211_rx_status *rx_status)
-{
-	ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 0);
-}
-
-
-static void ieee80211_rx_mgmt_beacon(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len,
-				     struct ieee80211_rx_status *rx_status)
-{
-	int use_protection;
-	size_t baselen;
-	struct ieee802_11_elems elems;
-
-	ieee80211_bss_info(wpa_s, mgmt, len, rx_status, 1);
-
-	if (!wpa_s->mlme.associated ||
-	    os_memcmp(wpa_s->bssid, mgmt->bssid, ETH_ALEN) != 0)
-		return;
-
-	/* Process beacon from the current BSS */
-	baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
-	if (baselen > len)
-		return;
-
-	if (ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen,
-				   &elems, 0) == ParseFailed)
-		return;
-
-	use_protection = 0;
-	if (elems.erp_info && elems.erp_info_len >= 1) {
-		use_protection =
-			(elems.erp_info[0] & ERP_INFO_USE_PROTECTION) != 0;
-	}
-
-	if (use_protection != !!wpa_s->mlme.use_protection) {
-		wpa_printf(MSG_DEBUG, "MLME: CTS protection %s (BSSID=" MACSTR
-			   ")",
-			   use_protection ? "enabled" : "disabled",
-			   MAC2STR(wpa_s->bssid));
-		wpa_s->mlme.use_protection = use_protection ? 1 : 0;
-		wpa_s->mlme.cts_protect_erp_frames = use_protection;
-	}
-
-	if (elems.wmm && wpa_s->mlme.wmm_enabled) {
-		ieee80211_sta_wmm_params(wpa_s, elems.wmm,
-					 elems.wmm_len);
-	}
-}
-
-
-static void ieee80211_rx_mgmt_probe_req(struct wpa_supplicant *wpa_s,
-					struct ieee80211_mgmt *mgmt,
-					size_t len,
-					struct ieee80211_rx_status *rx_status)
-{
-	int tx_last_beacon, adhoc;
-#if 0 /* FIX */
-	struct ieee80211_mgmt *resp;
-#endif
-	u8 *pos, *end;
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-
-	adhoc = ssid && ssid->mode == WPAS_MODE_IBSS;
-
-	if (!adhoc || wpa_s->mlme.state != IEEE80211_IBSS_JOINED ||
-	    len < 24 + 2 || wpa_s->mlme.probe_resp == NULL)
-		return;
-
-#if 0 /* FIX */
-	if (local->hw->tx_last_beacon)
-		tx_last_beacon = local->hw->tx_last_beacon(local->mdev);
-	else
-#endif
-		tx_last_beacon = 1;
-
-#ifdef IEEE80211_IBSS_DEBUG
-	wpa_printf(MSG_DEBUG, "MLME: RX ProbeReq SA=" MACSTR " DA=" MACSTR
-		   " BSSID=" MACSTR " (tx_last_beacon=%d)",
-		   MAC2STR(mgmt->sa), MAC2STR(mgmt->da),
-		   MAC2STR(mgmt->bssid), tx_last_beacon);
-#endif /* IEEE80211_IBSS_DEBUG */
-
-	if (!tx_last_beacon)
-		return;
-
-	if (os_memcmp(mgmt->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
-	    os_memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
-		return;
-
-	end = ((u8 *) mgmt) + len;
-	pos = mgmt->u.probe_req.variable;
-	if (pos[0] != WLAN_EID_SSID ||
-	    pos + 2 + pos[1] > end) {
-		wpa_printf(MSG_DEBUG, "MLME: Invalid SSID IE in ProbeReq from "
-			   MACSTR, MAC2STR(mgmt->sa));
-		return;
-	}
-	if (pos[1] != 0 &&
-	    (pos[1] != wpa_s->mlme.ssid_len ||
-	     os_memcmp(pos + 2, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len) != 0))
-	{
-		/* Ignore ProbeReq for foreign SSID */
-		return;
-	}
-
-#if 0 /* FIX */
-	/* Reply with ProbeResp */
-	skb = skb_copy(wpa_s->mlme.probe_resp, GFP_ATOMIC);
-	if (skb == NULL)
-		return;
-
-	resp = (struct ieee80211_mgmt *) skb->data;
-	os_memcpy(resp->da, mgmt->sa, ETH_ALEN);
-#ifdef IEEE80211_IBSS_DEBUG
-	wpa_printf(MSG_DEBUG, "MLME: Sending ProbeResp to " MACSTR,
-		   MAC2STR(resp->da));
-#endif /* IEEE80211_IBSS_DEBUG */
-	ieee80211_sta_tx(wpa_s, skb, 0, 1);
-#endif
-}
-
-
-#ifdef CONFIG_IEEE80211R
-static void ieee80211_rx_mgmt_ft_action(struct wpa_supplicant *wpa_s,
-					struct ieee80211_mgmt *mgmt,
-					size_t len,
-					struct ieee80211_rx_status *rx_status)
-{
-	union wpa_event_data data;
-	u16 status;
-	u8 *sta_addr, *target_ap_addr;
-
-	if (len < 24 + 1 + sizeof(mgmt->u.action.u.ft_action_resp)) {
-		wpa_printf(MSG_DEBUG, "MLME: Too short FT Action frame");
-		return;
-	}
-
-	/*
-	 * Only FT Action Response is needed for now since reservation
-	 * protocol is not supported.
-	 */
-	if (mgmt->u.action.u.ft_action_resp.action != 2) {
-		wpa_printf(MSG_DEBUG, "MLME: Unexpected FT Action %d",
-			   mgmt->u.action.u.ft_action_resp.action);
-		return;
-	}
-
-	status = le_to_host16(mgmt->u.action.u.ft_action_resp.status_code);
-	sta_addr = mgmt->u.action.u.ft_action_resp.sta_addr;
-	target_ap_addr = mgmt->u.action.u.ft_action_resp.target_ap_addr;
-	wpa_printf(MSG_DEBUG, "MLME: Received FT Action Response: STA " MACSTR
-		   " TargetAP " MACSTR " Status Code %d",
-		   MAC2STR(sta_addr), MAC2STR(target_ap_addr), status);
-	if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: Foreign STA Address " MACSTR
-			   " in FT Action Response", MAC2STR(sta_addr));
-		return;
-	}
-
-	if (status) {
-		wpa_printf(MSG_DEBUG, "MLME: FT Action Response indicates "
-			   "failure (status code %d)", status);
-		/* TODO: report error to FT code(?) */
-		return;
-	}
-
-	os_memset(&data, 0, sizeof(data));
-	data.ft_ies.ies = mgmt->u.action.u.ft_action_resp.variable;
-	data.ft_ies.ies_len = len - (mgmt->u.action.u.ft_action_resp.variable -
-				     (u8 *) mgmt);
-	data.ft_ies.ft_action = 1;
-	os_memcpy(data.ft_ies.target_ap, target_ap_addr, ETH_ALEN);
-	wpa_supplicant_event(wpa_s, EVENT_FT_RESPONSE, &data);
-	/* TODO: should only re-associate, if EVENT_FT_RESPONSE was processed
-	 * successfully */
-	wpa_s->mlme.prev_bssid_set = 1;
-	wpa_s->mlme.auth_alg = WLAN_AUTH_FT;
-	os_memcpy(wpa_s->mlme.prev_bssid, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(wpa_s->bssid, target_ap_addr, ETH_ALEN);
-	ieee80211_associate(wpa_s);
-}
-#endif /* CONFIG_IEEE80211R */
-
-
-#ifdef CONFIG_IEEE80211W
-
-/* MLME-SAQuery.response */
-static int ieee80211_sta_send_sa_query_resp(struct wpa_supplicant *wpa_s,
-					    const u8 *addr, const u8 *trans_id)
-{
-	struct ieee80211_mgmt *mgmt;
-	int res;
-	size_t len;
-
-	mgmt = os_zalloc(sizeof(*mgmt));
-	if (mgmt == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
-			   "SA Query action frame");
-		return -1;
-	}
-
-	len = 24;
-	os_memcpy(mgmt->da, addr, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_ACTION);
-	mgmt->u.action.category = WLAN_ACTION_SA_QUERY;
-	mgmt->u.action.u.sa_query_resp.action = WLAN_SA_QUERY_RESPONSE;
-	os_memcpy(mgmt->u.action.u.sa_query_resp.trans_id, trans_id,
-		  WLAN_SA_QUERY_TR_ID_LEN);
-	len += 1 + sizeof(mgmt->u.action.u.sa_query_resp);
-
-	res = ieee80211_sta_tx(wpa_s, (u8 *) mgmt, len);
-	os_free(mgmt);
-
-	return res;
-}
-
-
-static void ieee80211_rx_mgmt_sa_query_action(
-	struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-	struct ieee80211_rx_status *rx_status)
-{
-	if (len < 24 + 1 + sizeof(mgmt->u.action.u.sa_query_req)) {
-		wpa_printf(MSG_DEBUG, "MLME: Too short SA Query Action frame");
-		return;
-	}
-
-	if (mgmt->u.action.u.sa_query_req.action != WLAN_SA_QUERY_REQUEST) {
-		wpa_printf(MSG_DEBUG, "MLME: Unexpected SA Query Action %d",
-			   mgmt->u.action.u.sa_query_req.action);
-		return;
-	}
-
-	if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "MLME: Ignore SA Query from unknown "
-			   "source " MACSTR, MAC2STR(mgmt->sa));
-		return;
-	}
-
-	if (wpa_s->mlme.state == IEEE80211_ASSOCIATE) {
-		wpa_printf(MSG_DEBUG, "MLME: Ignore SA query request during "
-			   "association process");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "MLME: Replying to SA Query request");
-	ieee80211_sta_send_sa_query_resp(wpa_s, mgmt->sa, mgmt->u.action.u.
-					 sa_query_req.trans_id);
-}
-
-#endif /* CONFIG_IEEE80211W */
-
-
-static void dump_tspec(struct wmm_tspec_element *tspec)
-{
-	int up, psb, dir, tid;
-	u16 val;
-
-	up = (tspec->ts_info[1] >> 3) & 0x07;
-	psb = (tspec->ts_info[1] >> 2) & 0x01;
-	dir = (tspec->ts_info[0] >> 5) & 0x03;
-	tid = (tspec->ts_info[0] >> 1) & 0x0f;
-	wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d",
-		   up, psb, dir, tid);
-	val = le_to_host16(tspec->nominal_msdu_size);
-	wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s",
-		   val & 0x7fff, val & 0x8000 ? " (fixed)" : "");
-	wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps",
-		   le_to_host32(tspec->mean_data_rate));
-	wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps",
-		   le_to_host32(tspec->minimum_phy_rate));
-	val = le_to_host16(tspec->surplus_bandwidth_allowance);
-	wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u",
-		   val >> 13, 10000 * (val & 0x1fff) / 0x2000);
-	val = le_to_host16(tspec->medium_time);
-	wpa_printf(MSG_DEBUG, "WMM: Medium Time: %u (= %u usec/sec)",
-		   val, 32 * val);
-}
-
-
-static int is_wmm_tspec(const u8 *ie, size_t len)
-{
-	const struct wmm_tspec_element *tspec;
-
-	if (len < sizeof(*tspec))
-		return 0;
-
-	tspec = (const struct wmm_tspec_element *) ie;
-	if (tspec->eid != WLAN_EID_VENDOR_SPECIFIC ||
-	    tspec->length < sizeof(*tspec) - 2 ||
-	    tspec->oui[0] != 0x00 || tspec->oui[1] != 0x50 ||
-	    tspec->oui[2] != 0xf2 || tspec->oui_type != 2 ||
-	    tspec->oui_subtype != 2 || tspec->version != 1)
-		return 0;
-
-	return 1;
-}
-
-
-static void ieee80211_rx_addts_resp(
-	struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-	size_t var_len)
-{
-	struct wmm_tspec_element *tspec;
-
-	wpa_printf(MSG_DEBUG, "WMM: Received ADDTS Response");
-	wpa_hexdump(MSG_MSGDUMP, "WMM: ADDTS Response IE(s)",
-		    mgmt->u.action.u.wmm_action.variable, var_len);
-	if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len))
-		return;
-	tspec = (struct wmm_tspec_element *)
-		mgmt->u.action.u.wmm_action.variable;
-	dump_tspec(tspec);
-}
-
-
-static void ieee80211_rx_delts(
-	struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-	size_t var_len)
-{
-	struct wmm_tspec_element *tspec;
-
-	wpa_printf(MSG_DEBUG, "WMM: Received DELTS");
-	wpa_hexdump(MSG_MSGDUMP, "WMM: DELTS IE(s)",
-		    mgmt->u.action.u.wmm_action.variable, var_len);
-	if (!is_wmm_tspec(mgmt->u.action.u.wmm_action.variable, var_len))
-		return;
-	tspec = (struct wmm_tspec_element *)
-		mgmt->u.action.u.wmm_action.variable;
-	dump_tspec(tspec);
-}
-
-
-static void ieee80211_rx_mgmt_wmm_action(
-	struct wpa_supplicant *wpa_s, struct ieee80211_mgmt *mgmt, size_t len,
-	struct ieee80211_rx_status *rx_status)
-{
-	size_t alen;
-
-	alen = mgmt->u.action.u.wmm_action.variable - (u8 *) mgmt;
-	if (len < alen) {
-		wpa_printf(MSG_DEBUG, "WMM: Received Action frame too short");
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "WMM: Received Action frame: Action Code %d, "
-		   "Dialog Token %d, Status Code %d",
-		   mgmt->u.action.u.wmm_action.action_code,
-		   mgmt->u.action.u.wmm_action.dialog_token,
-		   mgmt->u.action.u.wmm_action.status_code);
-
-	switch (mgmt->u.action.u.wmm_action.action_code) {
-	case WMM_ACTION_CODE_ADDTS_RESP:
-		ieee80211_rx_addts_resp(wpa_s, mgmt, len, len - alen);
-		break;
-	case WMM_ACTION_CODE_DELTS:
-		ieee80211_rx_delts(wpa_s, mgmt, len, len - alen);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "WMM: Unsupported Action Code %d",
-			   mgmt->u.action.u.wmm_action.action_code);
-		break;
-	}
-}
-
-
-static void ieee80211_rx_mgmt_action(struct wpa_supplicant *wpa_s,
-				     struct ieee80211_mgmt *mgmt,
-				     size_t len,
-				     struct ieee80211_rx_status *rx_status)
-{
-	wpa_printf(MSG_DEBUG, "MLME: received Action frame");
-
-	if (len < 25)
-		return;
-
-	switch (mgmt->u.action.category) {
-#ifdef CONFIG_IEEE80211R
-	case WLAN_ACTION_FT:
-		ieee80211_rx_mgmt_ft_action(wpa_s, mgmt, len, rx_status);
-		break;
-#endif /* CONFIG_IEEE80211R */
-#ifdef CONFIG_IEEE80211W
-	case WLAN_ACTION_SA_QUERY:
-		ieee80211_rx_mgmt_sa_query_action(wpa_s, mgmt, len, rx_status);
-		break;
-#endif /* CONFIG_IEEE80211W */
-	case WLAN_ACTION_WMM:
-		ieee80211_rx_mgmt_wmm_action(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_ACTION_PUBLIC:
-		if (wpa_s->mlme.public_action_cb) {
-			wpa_s->mlme.public_action_cb(
-				wpa_s->mlme.public_action_cb_ctx,
-				(u8 *) mgmt, len, rx_status->freq);
-			return;
-		}
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "MLME: unknown Action Category %d",
-			   mgmt->u.action.category);
-		break;
-	}
-}
-
-
-static void ieee80211_sta_rx_mgmt(struct wpa_supplicant *wpa_s,
-				  const u8 *buf, size_t len,
-				  struct ieee80211_rx_status *rx_status)
-{
-	struct ieee80211_mgmt *mgmt;
-	u16 fc;
-
-	if (len < 24)
-		return;
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	fc = le_to_host16(mgmt->frame_control);
-
-	switch (WLAN_FC_GET_STYPE(fc)) {
-	case WLAN_FC_STYPE_PROBE_REQ:
-		ieee80211_rx_mgmt_probe_req(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_PROBE_RESP:
-		ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_BEACON:
-		ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_AUTH:
-		ieee80211_rx_mgmt_auth(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_ASSOC_RESP:
-		ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 0);
-		break;
-	case WLAN_FC_STYPE_REASSOC_RESP:
-		ieee80211_rx_mgmt_assoc_resp(wpa_s, mgmt, len, rx_status, 1);
-		break;
-	case WLAN_FC_STYPE_DEAUTH:
-		ieee80211_rx_mgmt_deauth(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_DISASSOC:
-		ieee80211_rx_mgmt_disassoc(wpa_s, mgmt, len, rx_status);
-		break;
-	case WLAN_FC_STYPE_ACTION:
-		ieee80211_rx_mgmt_action(wpa_s, mgmt, len, rx_status);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "MLME: received unknown management "
-			   "frame - stype=%d", WLAN_FC_GET_STYPE(fc));
-		break;
-	}
-}
-
-
-static void ieee80211_sta_rx_scan(struct wpa_supplicant *wpa_s,
-				  const u8 *buf, size_t len,
-				  struct ieee80211_rx_status *rx_status)
-{
-	struct ieee80211_mgmt *mgmt;
-	u16 fc;
-
-	if (len < 24)
-		return;
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	fc = le_to_host16(mgmt->frame_control);
-
-	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT) {
-		if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_PROBE_RESP) {
-			ieee80211_rx_mgmt_probe_resp(wpa_s, mgmt,
-						     len, rx_status);
-		} else if (WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON) {
-			ieee80211_rx_mgmt_beacon(wpa_s, mgmt, len, rx_status);
-		}
-	}
-}
-
-
-static int ieee80211_sta_active_ibss(struct wpa_supplicant *wpa_s)
-{
-	int active = 0;
-
-#if 0 /* FIX */
-	list_for_each(ptr, &local->sta_list) {
-		sta = list_entry(ptr, struct sta_info, list);
-		if (sta->dev == dev &&
-		    time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
-			       jiffies)) {
-			active++;
-			break;
-		}
-	}
-#endif
-
-	return active;
-}
-
-
-static void ieee80211_sta_expire(struct wpa_supplicant *wpa_s)
-{
-#if 0 /* FIX */
-	list_for_each_safe(ptr, n, &local->sta_list) {
-		sta = list_entry(ptr, struct sta_info, list);
-		if (time_after(jiffies, sta->last_rx +
-			       IEEE80211_IBSS_INACTIVITY_LIMIT)) {
-			wpa_printf(MSG_DEBUG, "MLME: expiring inactive STA "
-				   MACSTR, MAC2STR(sta->addr));
-			sta_info_free(local, sta, 1);
-		}
-	}
-#endif
-}
-
-
-static void ieee80211_sta_merge_ibss(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_driver_scan_params params;
-
-	ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL);
-
-	ieee80211_sta_expire(wpa_s);
-	if (ieee80211_sta_active_ibss(wpa_s))
-		return;
-
-	wpa_printf(MSG_DEBUG, "MLME: No active IBSS STAs - trying to scan for "
-		   "other IBSS networks with same SSID (merge)");
-	os_memset(&params, 0, sizeof(params));
-	params.ssids[0].ssid = wpa_s->mlme.ssid;
-	params.ssids[0].ssid_len = wpa_s->mlme.ssid_len;
-	params.num_ssids = wpa_s->mlme.ssid_len ? 1 : 0;
-	ieee80211_sta_req_scan(wpa_s, &params);
-}
-
-
-static void ieee80211_sta_timer(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-
-	switch (wpa_s->mlme.state) {
-	case IEEE80211_DISABLED:
-		break;
-	case IEEE80211_AUTHENTICATE:
-		ieee80211_authenticate(wpa_s);
-		break;
-	case IEEE80211_ASSOCIATE:
-		ieee80211_associate(wpa_s);
-		break;
-	case IEEE80211_ASSOCIATED:
-		ieee80211_associated(wpa_s);
-		break;
-	case IEEE80211_IBSS_SEARCH:
-		ieee80211_sta_find_ibss(wpa_s);
-		break;
-	case IEEE80211_IBSS_JOINED:
-		ieee80211_sta_merge_ibss(wpa_s);
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "ieee80211_sta_timer: Unknown state %d",
-			   wpa_s->mlme.state);
-		break;
-	}
-
-	if (ieee80211_privacy_mismatch(wpa_s)) {
-		wpa_printf(MSG_DEBUG, "MLME: privacy configuration mismatch "
-			   "and mixed-cell disabled - disassociate");
-
-		ieee80211_send_disassoc(wpa_s, WLAN_REASON_UNSPECIFIED);
-		ieee80211_set_associated(wpa_s, 0);
-	}
-}
-
-
-static void ieee80211_sta_new_auth(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-	if (ssid && ssid->mode != WPAS_MODE_INFRA)
-		return;
-
-#if 0 /* FIX */
-	if (local->hw->reset_tsf) {
-		/* Reset own TSF to allow time synchronization work. */
-		local->hw->reset_tsf(local->mdev);
-	}
-#endif
-
-	wpa_s->mlme.wmm_last_param_set = -1; /* allow any WMM update */
-
-
-	if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_OPEN)
-		wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN;
-	else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_SHARED)
-		wpa_s->mlme.auth_alg = WLAN_AUTH_SHARED_KEY;
-	else if (wpa_s->mlme.auth_algs & WPA_AUTH_ALG_LEAP)
-		wpa_s->mlme.auth_alg = WLAN_AUTH_LEAP;
-	else
-		wpa_s->mlme.auth_alg = WLAN_AUTH_OPEN;
-	wpa_printf(MSG_DEBUG, "MLME: Initial auth_alg=%d",
-		   wpa_s->mlme.auth_alg);
-	wpa_s->mlme.auth_transaction = -1;
-	wpa_s->mlme.auth_tries = wpa_s->mlme.assoc_tries = 0;
-	ieee80211_authenticate(wpa_s);
-}
-
-
-static int ieee80211_ibss_allowed(struct wpa_supplicant *wpa_s)
-{
-#if 0 /* FIX */
-	int m, c;
-
-	for (m = 0; m < local->hw->num_modes; m++) {
-		struct ieee80211_hw_modes *mode = &local->hw->modes[m];
-		if (mode->mode != local->conf.phymode)
-			continue;
-		for (c = 0; c < mode->num_channels; c++) {
-			struct ieee80211_channel *chan = &mode->channels[c];
-			if (chan->flag & IEEE80211_CHAN_W_SCAN &&
-			    chan->chan == local->conf.channel) {
-				if (chan->flag & IEEE80211_CHAN_W_IBSS)
-					return 1;
-				break;
-			}
-		}
-	}
-#endif
-
-	return 0;
-}
-
-
-static int ieee80211_sta_join_ibss(struct wpa_supplicant *wpa_s,
-				   struct ieee80211_sta_bss *bss)
-{
-	int res = 0, rates, done = 0, bssid_changed;
-	struct ieee80211_mgmt *mgmt;
-#if 0 /* FIX */
-	struct ieee80211_tx_control control;
-	struct ieee80211_rate *rate;
-	struct rate_control_extra extra;
-#endif
-	u8 *pos, *buf;
-	size_t len;
-
-	/* Remove possible STA entries from other IBSS networks. */
-#if 0 /* FIX */
-	sta_info_flush(local, NULL);
-
-	if (local->hw->reset_tsf) {
-		/* Reset own TSF to allow time synchronization work. */
-		local->hw->reset_tsf(local->mdev);
-	}
-#endif
-	bssid_changed = os_memcmp(wpa_s->bssid, bss->bssid, ETH_ALEN);
-	os_memcpy(wpa_s->bssid, bss->bssid, ETH_ALEN);
-	if (bssid_changed)
-		wpas_notify_bssid_changed(wpa_s);
-
-#if 0 /* FIX */
-	local->conf.beacon_int = bss->beacon_int >= 10 ? bss->beacon_int : 10;
-
-	sdata->drop_unencrypted = bss->capability &
-		host_to_le16(WLAN_CAPABILITY_PRIVACY) ? 1 : 0;
-#endif
-
-#if 0 /* FIX */
-	os_memset(&rq, 0, sizeof(rq));
-	rq.m = bss->freq * 100000;
-	rq.e = 1;
-	res = ieee80211_ioctl_siwfreq(wpa_s, NULL, &rq, NULL);
-#endif
-
-	if (!ieee80211_ibss_allowed(wpa_s)) {
-#if 0 /* FIX */
-		wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed on channel %d "
-			   "(%d MHz)", local->conf.channel,
-			   local->conf.freq);
-#endif
-		return -1;
-	}
-
-	/* Set beacon template based on scan results */
-	buf = os_malloc(400);
-	len = 0;
-	do {
-		if (buf == NULL)
-			break;
-
-		mgmt = (struct ieee80211_mgmt *) buf;
-		len += 24 + sizeof(mgmt->u.beacon);
-		os_memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
-		mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-						   WLAN_FC_STYPE_BEACON);
-		os_memset(mgmt->da, 0xff, ETH_ALEN);
-		os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-		os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-#if 0 /* FIX */
-		mgmt->u.beacon.beacon_int =
-			host_to_le16(local->conf.beacon_int);
-#endif
-		mgmt->u.beacon.capab_info = host_to_le16(bss->capability);
-
-		pos = buf + len;
-		len += 2 + wpa_s->mlme.ssid_len;
-		*pos++ = WLAN_EID_SSID;
-		*pos++ = wpa_s->mlme.ssid_len;
-		os_memcpy(pos, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
-
-		rates = bss->supp_rates_len;
-		if (rates > 8)
-			rates = 8;
-		pos = buf + len;
-		len += 2 + rates;
-		*pos++ = WLAN_EID_SUPP_RATES;
-		*pos++ = rates;
-		os_memcpy(pos, bss->supp_rates, rates);
-
-		pos = buf + len;
-		len += 2 + 1;
-		*pos++ = WLAN_EID_DS_PARAMS;
-		*pos++ = 1;
-		*pos++ = bss->channel;
-
-		pos = buf + len;
-		len += 2 + 2;
-		*pos++ = WLAN_EID_IBSS_PARAMS;
-		*pos++ = 2;
-		/* FIX: set ATIM window based on scan results */
-		*pos++ = 0;
-		*pos++ = 0;
-
-		if (bss->supp_rates_len > 8) {
-			rates = bss->supp_rates_len - 8;
-			pos = buf + len;
-			len += 2 + rates;
-			*pos++ = WLAN_EID_EXT_SUPP_RATES;
-			*pos++ = rates;
-			os_memcpy(pos, &bss->supp_rates[8], rates);
-		}
-
-#if 0 /* FIX */
-		os_memset(&control, 0, sizeof(control));
-		control.pkt_type = PKT_PROBE_RESP;
-		os_memset(&extra, 0, sizeof(extra));
-		extra.endidx = local->num_curr_rates;
-		rate = rate_control_get_rate(wpa_s, skb, &extra);
-		if (rate == NULL) {
-			wpa_printf(MSG_DEBUG, "MLME: Failed to determine TX "
-				   "rate for IBSS beacon");
-			break;
-		}
-		control.tx_rate = (wpa_s->mlme.short_preamble &&
-				   (rate->flags & IEEE80211_RATE_PREAMBLE2)) ?
-			rate->val2 : rate->val;
-		control.antenna_sel = local->conf.antenna_sel;
-		control.power_level = local->conf.power_level;
-		control.no_ack = 1;
-		control.retry_limit = 1;
-		control.rts_cts_duration = 0;
-#endif
-
-#if 0 /* FIX */
-		wpa_s->mlme.probe_resp = skb_copy(skb, GFP_ATOMIC);
-		if (wpa_s->mlme.probe_resp) {
-			mgmt = (struct ieee80211_mgmt *)
-				wpa_s->mlme.probe_resp->data;
-			mgmt->frame_control =
-				IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					     WLAN_FC_STYPE_PROBE_RESP);
-		} else {
-			wpa_printf(MSG_DEBUG, "MLME: Could not allocate "
-				   "ProbeResp template for IBSS");
-		}
-
-		if (local->hw->beacon_update &&
-		    local->hw->beacon_update(wpa_s, skb, &control) == 0) {
-			wpa_printf(MSG_DEBUG, "MLME: Configured IBSS beacon "
-				   "template based on scan results");
-			skb = NULL;
-		}
-
-		rates = 0;
-		for (i = 0; i < bss->supp_rates_len; i++) {
-			int rate = (bss->supp_rates[i] & 0x7f) * 5;
-			if (local->conf.phymode == MODE_ATHEROS_TURBO)
-				rate *= 2;
-			for (j = 0; j < local->num_curr_rates; j++)
-				if (local->curr_rates[j] == rate)
-					rates |= BIT(j);
-		}
-		wpa_s->mlme.supp_rates_bits = rates;
-#endif
-		done = 1;
-	} while (0);
-
-	os_free(buf);
-	if (!done) {
-		wpa_printf(MSG_DEBUG, "MLME: Failed to configure IBSS beacon "
-			   "template");
-	}
-
-	wpa_s->mlme.state = IEEE80211_IBSS_JOINED;
-	ieee80211_reschedule_timer(wpa_s, IEEE80211_IBSS_MERGE_INTERVAL);
-
-	return res;
-}
-
-
-#if 0 /* FIX */
-static int ieee80211_sta_create_ibss(struct wpa_supplicant *wpa_s)
-{
-	struct ieee80211_sta_bss *bss;
-	u8 bssid[ETH_ALEN], *pos;
-	int i;
-
-#if 0
-	/* Easier testing, use fixed BSSID. */
-	os_memset(bssid, 0xfe, ETH_ALEN);
-#else
-	/* Generate random, not broadcast, locally administered BSSID. Mix in
-	 * own MAC address to make sure that devices that do not have proper
-	 * random number generator get different BSSID. */
-	os_get_random(bssid, ETH_ALEN);
-	for (i = 0; i < ETH_ALEN; i++)
-		bssid[i] ^= wpa_s->own_addr[i];
-	bssid[0] &= ~0x01;
-	bssid[0] |= 0x02;
-#endif
-
-	wpa_printf(MSG_DEBUG, "MLME: Creating new IBSS network, BSSID "
-		   MACSTR "", MAC2STR(bssid));
-
-	bss = ieee80211_bss_add(wpa_s, bssid);
-	if (bss == NULL)
-		return -ENOMEM;
-
-#if 0 /* FIX */
-	if (local->conf.beacon_int == 0)
-		local->conf.beacon_int = 100;
-	bss->beacon_int = local->conf.beacon_int;
-	bss->hw_mode = local->conf.phymode;
-	bss->channel = local->conf.channel;
-	bss->freq = local->conf.freq;
-#endif
-	os_get_time(&bss->last_update);
-	bss->capability = host_to_le16(WLAN_CAPABILITY_IBSS);
-#if 0 /* FIX */
-	if (sdata->default_key) {
-		bss->capability |= host_to_le16(WLAN_CAPABILITY_PRIVACY);
-	} else
-		sdata->drop_unencrypted = 0;
-	bss->supp_rates_len = local->num_curr_rates;
-#endif
-	pos = bss->supp_rates;
-#if 0 /* FIX */
-	for (i = 0; i < local->num_curr_rates; i++) {
-		int rate = local->curr_rates[i];
-		if (local->conf.phymode == MODE_ATHEROS_TURBO)
-			rate /= 2;
-		*pos++ = (u8) (rate / 5);
-	}
-#endif
-
-	return ieee80211_sta_join_ibss(wpa_s, bss);
-}
-#endif
-
-
-static int ieee80211_sta_find_ibss(struct wpa_supplicant *wpa_s)
-{
-	struct ieee80211_sta_bss *bss;
-	int found = 0;
-	u8 bssid[ETH_ALEN];
-	int active_ibss;
-	struct os_time now;
-
-	if (wpa_s->mlme.ssid_len == 0)
-		return -EINVAL;
-
-	active_ibss = ieee80211_sta_active_ibss(wpa_s);
-#ifdef IEEE80211_IBSS_DEBUG
-	wpa_printf(MSG_DEBUG, "MLME: sta_find_ibss (active_ibss=%d)",
-		   active_ibss);
-#endif /* IEEE80211_IBSS_DEBUG */
-	for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) {
-		if (wpa_s->mlme.ssid_len != bss->ssid_len ||
-		    os_memcmp(wpa_s->mlme.ssid, bss->ssid, bss->ssid_len) != 0
-		    || !(bss->capability & WLAN_CAPABILITY_IBSS))
-			continue;
-#ifdef IEEE80211_IBSS_DEBUG
-		wpa_printf(MSG_DEBUG, "   bssid=" MACSTR " found",
-			   MAC2STR(bss->bssid));
-#endif /* IEEE80211_IBSS_DEBUG */
-		os_memcpy(bssid, bss->bssid, ETH_ALEN);
-		found = 1;
-		if (active_ibss ||
-		    os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0)
-			break;
-	}
-
-#ifdef IEEE80211_IBSS_DEBUG
-	wpa_printf(MSG_DEBUG, "   sta_find_ibss: selected " MACSTR " current "
-		   MACSTR, MAC2STR(bssid), MAC2STR(wpa_s->bssid));
-#endif /* IEEE80211_IBSS_DEBUG */
-	if (found && os_memcmp(wpa_s->bssid, bssid, ETH_ALEN) != 0 &&
-	    (bss = ieee80211_bss_get(wpa_s, bssid))) {
-		wpa_printf(MSG_DEBUG, "MLME: Selected IBSS BSSID " MACSTR
-			   " based on configured SSID",
-			   MAC2STR(bssid));
-		return ieee80211_sta_join_ibss(wpa_s, bss);
-	}
-#ifdef IEEE80211_IBSS_DEBUG
-	wpa_printf(MSG_DEBUG, "   did not try to join ibss");
-#endif /* IEEE80211_IBSS_DEBUG */
-
-	/* Selected IBSS not found in current scan results - try to scan */
-	os_get_time(&now);
-#if 0 /* FIX */
-	if (wpa_s->mlme.state == IEEE80211_IBSS_JOINED &&
-	    !ieee80211_sta_active_ibss(wpa_s)) {
-		ieee80211_reschedule_timer(wpa_s,
-					   IEEE80211_IBSS_MERGE_INTERVAL);
-	} else if (time_after(jiffies, wpa_s->mlme.last_scan_completed +
-			      IEEE80211_SCAN_INTERVAL)) {
-		wpa_printf(MSG_DEBUG, "MLME: Trigger new scan to find an IBSS "
-			   "to join");
-		return ieee80211_sta_req_scan(wpa_s->mlme.ssid,
-					      wpa_s->mlme.ssid_len);
-	} else if (wpa_s->mlme.state != IEEE80211_IBSS_JOINED) {
-		int interval = IEEE80211_SCAN_INTERVAL;
-
-		if (time_after(jiffies, wpa_s->mlme.ibss_join_req +
-			       IEEE80211_IBSS_JOIN_TIMEOUT)) {
-			if (wpa_s->mlme.create_ibss &&
-			    ieee80211_ibss_allowed(wpa_s))
-				return ieee80211_sta_create_ibss(wpa_s);
-			if (wpa_s->mlme.create_ibss) {
-				wpa_printf(MSG_DEBUG, "MLME: IBSS not allowed "
-					   "on the configured channel %d "
-					   "(%d MHz)",
-					   local->conf.channel,
-					   local->conf.freq);
-			}
-
-			/* No IBSS found - decrease scan interval and continue
-			 * scanning. */
-			interval = IEEE80211_SCAN_INTERVAL_SLOW;
-		}
-
-		wpa_s->mlme.state = IEEE80211_IBSS_SEARCH;
-		ieee80211_reschedule_timer(wpa_s, interval);
-		return 0;
-	}
-#endif
-
-	return 0;
-}
-
-
-int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid,
-			   size_t *len)
-{
-	os_memcpy(ssid, wpa_s->mlme.ssid, wpa_s->mlme.ssid_len);
-	*len = wpa_s->mlme.ssid_len;
-	return 0;
-}
-
-
-int ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
-			    struct wpa_driver_associate_params *params)
-{
-	struct ieee80211_sta_bss *bss;
-	int bssid_changed;
-
-	wpa_s->mlme.bssid_set = 0;
-	wpa_s->mlme.freq = params->freq;
-	if (params->bssid) {
-		bssid_changed = os_memcmp(wpa_s->bssid, params->bssid,
-					  ETH_ALEN);
-		os_memcpy(wpa_s->bssid, params->bssid, ETH_ALEN);
-		if (bssid_changed)
-			wpas_notify_bssid_changed(wpa_s);
-
-		if (!is_zero_ether_addr(params->bssid))
-			wpa_s->mlme.bssid_set = 1;
-		bss = ieee80211_bss_get(wpa_s, wpa_s->bssid);
-		if (bss) {
-			wpa_s->mlme.phymode = bss->hw_mode;
-			wpa_s->mlme.channel = bss->channel;
-			wpa_s->mlme.freq = bss->freq;
-		}
-	}
-
-#if 0 /* FIX */
-	/* TODO: This should always be done for IBSS, even if IEEE80211_QOS is
-	 * not defined. */
-	if (local->hw->conf_tx) {
-		struct ieee80211_tx_queue_params qparam;
-		int i;
-
-		os_memset(&qparam, 0, sizeof(qparam));
-		/* TODO: are these ok defaults for all hw_modes? */
-		qparam.aifs = 2;
-		qparam.cw_min =
-			local->conf.phymode == MODE_IEEE80211B ? 31 : 15;
-		qparam.cw_max = 1023;
-		qparam.burst_time = 0;
-		for (i = IEEE80211_TX_QUEUE_DATA0; i < NUM_TX_DATA_QUEUES; i++)
-		{
-			local->hw->conf_tx(wpa_s, i + IEEE80211_TX_QUEUE_DATA0,
-					   &qparam);
-		}
-		/* IBSS uses different parameters for Beacon sending */
-		qparam.cw_min++;
-		qparam.cw_min *= 2;
-		qparam.cw_min--;
-		local->hw->conf_tx(wpa_s, IEEE80211_TX_QUEUE_BEACON, &qparam);
-	}
-#endif
-
-	if (wpa_s->mlme.ssid_len != params->ssid_len ||
-	    os_memcmp(wpa_s->mlme.ssid, params->ssid, params->ssid_len) != 0)
-		wpa_s->mlme.prev_bssid_set = 0;
-	os_memcpy(wpa_s->mlme.ssid, params->ssid, params->ssid_len);
-	os_memset(wpa_s->mlme.ssid + params->ssid_len, 0,
-		  MAX_SSID_LEN - params->ssid_len);
-	wpa_s->mlme.ssid_len = params->ssid_len;
-	wpa_s->mlme.ssid_set = 1;
-
-	os_free(wpa_s->mlme.extra_ie);
-	if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
-		wpa_s->mlme.extra_ie = NULL;
-		wpa_s->mlme.extra_ie_len = 0;
-	} else {
-		wpa_s->mlme.extra_ie = os_malloc(params->wpa_ie_len);
-		if (wpa_s->mlme.extra_ie == NULL) {
-			wpa_s->mlme.extra_ie_len = 0;
-			return -1;
-		}
-		os_memcpy(wpa_s->mlme.extra_ie, params->wpa_ie,
-			  params->wpa_ie_len);
-		wpa_s->mlme.extra_ie_len = params->wpa_ie_len;
-	}
-
-	wpa_s->mlme.key_mgmt = params->key_mgmt_suite;
-
-	ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode,
-				  wpa_s->mlme.channel, wpa_s->mlme.freq);
-
-	if (params->mode == WPAS_MODE_IBSS && !wpa_s->mlme.bssid_set) {
-		os_get_time(&wpa_s->mlme.ibss_join_req);
-		wpa_s->mlme.state = IEEE80211_IBSS_SEARCH;
-		return ieee80211_sta_find_ibss(wpa_s);
-	}
-
-	if (wpa_s->mlme.bssid_set)
-		ieee80211_sta_new_auth(wpa_s);
-
-	return 0;
-}
-
-
-static void ieee80211_sta_save_oper_chan(struct wpa_supplicant *wpa_s)
-{
-	wpa_s->mlme.scan_oper_channel = wpa_s->mlme.channel;
-	wpa_s->mlme.scan_oper_freq = wpa_s->mlme.freq;
-	wpa_s->mlme.scan_oper_phymode = wpa_s->mlme.phymode;
-}
-
-
-static int ieee80211_sta_restore_oper_chan(struct wpa_supplicant *wpa_s)
-{
-	wpa_s->mlme.channel = wpa_s->mlme.scan_oper_channel;
-	wpa_s->mlme.freq = wpa_s->mlme.scan_oper_freq;
-	wpa_s->mlme.phymode = wpa_s->mlme.scan_oper_phymode;
-	if (wpa_s->mlme.freq == 0)
-		return 0;
-	return ieee80211_sta_set_channel(wpa_s, wpa_s->mlme.phymode,
-					 wpa_s->mlme.channel,
-					 wpa_s->mlme.freq);
-}
-
-
-static int ieee80211_active_scan(struct wpa_supplicant *wpa_s)
-{
-	size_t m;
-	int c;
-
-	for (m = 0; m < wpa_s->mlme.num_modes; m++) {
-		struct hostapd_hw_modes *mode = &wpa_s->mlme.modes[m];
-		if ((int) mode->mode != (int) wpa_s->mlme.phymode)
-			continue;
-		for (c = 0; c < mode->num_channels; c++) {
-			struct hostapd_channel_data *chan = &mode->channels[c];
-			if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
-			    chan->chan == wpa_s->mlme.channel) {
-				if (!(chan->flag & HOSTAPD_CHAN_PASSIVE_SCAN))
-					return 1;
-				break;
-			}
-		}
-	}
-
-	return 0;
-}
-
-
-static void ieee80211_sta_scan_timer(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	struct hostapd_hw_modes *mode;
-	struct hostapd_channel_data *chan;
-	int skip = 0;
-	int timeout = 0;
-	struct wpa_ssid *ssid = wpa_s->current_ssid;
-	int adhoc;
-
-	if (!wpa_s->mlme.sta_scanning || wpa_s->mlme.modes == NULL)
-		return;
-
-	adhoc = ssid && ssid->mode == 1;
-
-	switch (wpa_s->mlme.scan_state) {
-	case SCAN_SET_CHANNEL:
-		mode = &wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx];
-		if (wpa_s->mlme.scan_hw_mode_idx >=
-		    (int) wpa_s->mlme.num_modes ||
-		    (wpa_s->mlme.scan_hw_mode_idx + 1 ==
-		     (int) wpa_s->mlme.num_modes
-		     && wpa_s->mlme.scan_channel_idx >= mode->num_channels)) {
-			if (ieee80211_sta_restore_oper_chan(wpa_s)) {
-				wpa_printf(MSG_DEBUG, "MLME: failed to "
-					   "restore operational channel after "
-					   "scan");
-			}
-			wpa_printf(MSG_DEBUG, "MLME: scan completed");
-			wpa_s->mlme.sta_scanning = 0;
-			os_get_time(&wpa_s->mlme.last_scan_completed);
-			wpa_supplicant_event(wpa_s, EVENT_SCAN_RESULTS, NULL);
-			if (adhoc) {
-				if (!wpa_s->mlme.bssid_set ||
-				    (wpa_s->mlme.state ==
-				     IEEE80211_IBSS_JOINED &&
-				     !ieee80211_sta_active_ibss(wpa_s)))
-					ieee80211_sta_find_ibss(wpa_s);
-			}
-			return;
-		}
-		skip = !(wpa_s->mlme.hw_modes & (1 << mode->mode));
-		chan = &mode->channels[wpa_s->mlme.scan_channel_idx];
-		if ((chan->flag & HOSTAPD_CHAN_DISABLED) ||
-		    (adhoc && (chan->flag & HOSTAPD_CHAN_NO_IBSS)) ||
-		    (wpa_s->mlme.hw_modes & (1 << HOSTAPD_MODE_IEEE80211G) &&
-		     mode->mode == HOSTAPD_MODE_IEEE80211B &&
-		     wpa_s->mlme.scan_skip_11b))
-			skip = 1;
-		if (!skip && wpa_s->mlme.scan_freqs) {
-			int i, found = 0;
-			for (i = 0; wpa_s->mlme.scan_freqs[i]; i++) {
-				if (wpa_s->mlme.scan_freqs[i] == chan->freq) {
-					found = 1;
-					break;
-				}
-			}
-			if (!found)
-				skip = 1;
-		}
-
-		if (!skip) {
-			wpa_printf(MSG_MSGDUMP,
-				   "MLME: scan channel %d (%d MHz)",
-				   chan->chan, chan->freq);
-
-			wpa_s->mlme.channel = chan->chan;
-			wpa_s->mlme.freq = chan->freq;
-			wpa_s->mlme.phymode = mode->mode;
-			if (ieee80211_sta_set_channel(wpa_s, mode->mode,
-						      chan->chan, chan->freq))
-			{
-				wpa_printf(MSG_DEBUG, "MLME: failed to set "
-					   "channel %d (%d MHz) for scan",
-					   chan->chan, chan->freq);
-				skip = 1;
-			}
-		}
-
-		wpa_s->mlme.scan_channel_idx++;
-		if (wpa_s->mlme.scan_channel_idx >=
-		    wpa_s->mlme.modes[wpa_s->mlme.scan_hw_mode_idx].
-		    num_channels) {
-			wpa_s->mlme.scan_hw_mode_idx++;
-			wpa_s->mlme.scan_channel_idx = 0;
-		}
-
-		if (skip) {
-			timeout = 0;
-			break;
-		}
-
-		timeout = IEEE80211_PROBE_DELAY;
-		wpa_s->mlme.scan_state = SCAN_SEND_PROBE;
-		break;
-	case SCAN_SEND_PROBE:
-		if (ieee80211_active_scan(wpa_s)) {
-			ieee80211_send_probe_req(wpa_s, NULL,
-						 wpa_s->mlme.scan_ssid,
-						 wpa_s->mlme.scan_ssid_len);
-			timeout = IEEE80211_CHANNEL_TIME;
-		} else {
-			timeout = IEEE80211_PASSIVE_CHANNEL_TIME;
-		}
-		wpa_s->mlme.scan_state = SCAN_SET_CHANNEL;
-		break;
-	}
-
-	eloop_register_timeout(timeout / 1000, 1000 * (timeout % 1000),
-			       ieee80211_sta_scan_timer, wpa_s, NULL);
-}
-
-
-int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s,
-			   struct wpa_driver_scan_params *params)
-{
-	const u8 *ssid = params->ssids[0].ssid;
-	size_t ssid_len = params->ssids[0].ssid_len;
-
-	if (ssid_len > MAX_SSID_LEN)
-		return -1;
-
-	/* MLME-SCAN.request (page 118)  page 144 (11.1.3.1)
-	 * BSSType: INFRASTRUCTURE, INDEPENDENT, ANY_BSS
-	 * BSSID: MACAddress
-	 * SSID
-	 * ScanType: ACTIVE, PASSIVE
-	 * ProbeDelay: delay (in microseconds) to be used prior to transmitting
-	 *    a Probe frame during active scanning
-	 * ChannelList
-	 * MinChannelTime (>= ProbeDelay), in TU
-	 * MaxChannelTime: (>= MinChannelTime), in TU
-	 */
-
-	 /* MLME-SCAN.confirm
-	  * BSSDescriptionSet
-	  * ResultCode: SUCCESS, INVALID_PARAMETERS
-	 */
-
-	/* TODO: if assoc, move to power save mode for the duration of the
-	 * scan */
-
-	if (wpa_s->mlme.sta_scanning)
-		return -1;
-
-	wpa_printf(MSG_DEBUG, "MLME: starting scan");
-
-	ieee80211_sta_set_probe_req_ie(wpa_s, params->extra_ies,
-				       params->extra_ies_len);
-
-	os_free(wpa_s->mlme.scan_freqs);
-	if (params->freqs) {
-		int i;
-		for (i = 0; params->freqs[i]; i++)
-			;
-		wpa_s->mlme.scan_freqs = os_malloc((i + 1) * sizeof(int));
-		if (wpa_s->mlme.scan_freqs)
-			os_memcpy(wpa_s->mlme.scan_freqs, params->freqs,
-				  (i + 1) * sizeof(int));
-	} else
-		wpa_s->mlme.scan_freqs = NULL;
-
-	ieee80211_sta_save_oper_chan(wpa_s);
-
-	wpa_s->mlme.sta_scanning = 1;
-	/* TODO: stop TX queue? */
-
-	if (ssid) {
-		wpa_s->mlme.scan_ssid_len = ssid_len;
-		os_memcpy(wpa_s->mlme.scan_ssid, ssid, ssid_len);
-	} else
-		wpa_s->mlme.scan_ssid_len = 0;
-	wpa_s->mlme.scan_skip_11b = 1; /* FIX: clear this is 11g is not
-					* supported */
-	wpa_s->mlme.scan_state = SCAN_SET_CHANNEL;
-	wpa_s->mlme.scan_hw_mode_idx = 0;
-	wpa_s->mlme.scan_channel_idx = 0;
-	eloop_register_timeout(0, 1, ieee80211_sta_scan_timer, wpa_s, NULL);
-
-	return 0;
-}
-
-
-struct wpa_scan_results *
-ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s)
-{
-	size_t ap_num = 0;
-	struct wpa_scan_results *res;
-	struct wpa_scan_res *r;
-	struct ieee80211_sta_bss *bss;
-
-	res = os_zalloc(sizeof(*res));
-	for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next)
-		ap_num++;
-	res->res = os_zalloc(ap_num * sizeof(struct wpa_scan_res *));
-	if (res->res == NULL) {
-		os_free(res);
-		return NULL;
-	}
-
-	for (bss = wpa_s->mlme.sta_bss_list; bss; bss = bss->next) {
-		r = os_zalloc(sizeof(*r) + bss->ie_len);
-		if (r == NULL)
-			break;
-		os_memcpy(r->bssid, bss->bssid, ETH_ALEN);
-		r->freq = bss->freq;
-		r->beacon_int = bss->beacon_int;
-		r->caps = bss->capability;
-		r->level = bss->rssi;
-		r->tsf = bss->timestamp;
-		if (bss->ie) {
-			r->ie_len = bss->ie_len;
-			os_memcpy(r + 1, bss->ie, bss->ie_len);
-		}
-
-		res->res[res->num++] = r;
-	}
-
-	return res;
-}
-
-
-#if 0 /* FIX */
-struct sta_info * ieee80211_ibss_add_sta(struct wpa_supplicant *wpa_s,
-					 struct sk_buff *skb, u8 *bssid,
-					 u8 *addr)
-{
-	struct ieee80211_local *local = dev->priv;
-	struct list_head *ptr;
-	struct sta_info *sta;
-	struct wpa_supplicant *sta_dev = NULL;
-
-	/* TODO: Could consider removing the least recently used entry and
-	 * allow new one to be added. */
-	if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
-		if (net_ratelimit()) {
-			wpa_printf(MSG_DEBUG, "MLME: No room for a new IBSS "
-				   "STA entry " MACSTR, MAC2STR(addr));
-		}
-		return NULL;
-	}
-
-	spin_lock_bh(&local->sub_if_lock);
-	list_for_each(ptr, &local->sub_if_list) {
-		sdata = list_entry(ptr, struct ieee80211_sub_if_data, list);
-		if (sdata->type == IEEE80211_SUB_IF_TYPE_STA &&
-		    os_memcmp(bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
-			sta_dev = sdata->dev;
-			break;
-		}
-	}
-	spin_unlock_bh(&local->sub_if_lock);
-
-	if (sta_dev == NULL)
-		return NULL;
-
-	wpa_printf(MSG_DEBUG, "MLME: Adding new IBSS station " MACSTR
-		   " (dev=%s)", MAC2STR(addr), sta_dev->name);
-
-	sta = sta_info_add(wpa_s, addr);
-	if (sta == NULL) {
-		return NULL;
-	}
-
-	sta->dev = sta_dev;
-	sta->supp_rates = wpa_s->mlme.supp_rates_bits;
-
-	rate_control_rate_init(local, sta);
-
-	return sta; /* caller will call sta_info_release() */
-}
-#endif
-
-
-int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason)
-{
-	wpa_printf(MSG_DEBUG, "MLME: deauthenticate(reason=%d)", reason);
-
-	ieee80211_send_deauth(wpa_s, reason);
-	ieee80211_set_associated(wpa_s, 0);
-	return 0;
-}
-
-
-int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason)
-{
-	wpa_printf(MSG_DEBUG, "MLME: disassociate(reason=%d)", reason);
-
-	if (!wpa_s->mlme.associated)
-		return -1;
-
-	ieee80211_send_disassoc(wpa_s, reason);
-	ieee80211_set_associated(wpa_s, 0);
-	return 0;
-}
-
-
-void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
-		      struct ieee80211_rx_status *rx_status)
-{
-	struct ieee80211_mgmt *mgmt;
-	u16 fc;
-	const u8 *pos;
-
-	/* wpa_hexdump(MSG_MSGDUMP, "MLME: Received frame", buf, len); */
-
-	if (wpa_s->mlme.sta_scanning) {
-		ieee80211_sta_rx_scan(wpa_s, buf, len, rx_status);
-		return;
-	}
-
-	if (len < 24)
-		return;
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	fc = le_to_host16(mgmt->frame_control);
-
-	if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT)
-		ieee80211_sta_rx_mgmt(wpa_s, buf, len, rx_status);
-	else if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_DATA) {
-		if ((fc & (WLAN_FC_TODS | WLAN_FC_FROMDS)) !=
-		    WLAN_FC_FROMDS)
-			return;
-		/* mgmt->sa is actually BSSID for FromDS data frames */
-		if (os_memcmp(mgmt->sa, wpa_s->bssid, ETH_ALEN) != 0)
-			return;
-		/* Skip IEEE 802.11 and LLC headers */
-		pos = buf + 24 + 6;
-		if (WPA_GET_BE16(pos) != ETH_P_EAPOL)
-			return;
-		pos += 2;
-		/* mgmt->bssid is actually BSSID for SA data frames */
-		wpa_supplicant_rx_eapol(wpa_s, mgmt->bssid,
-					pos, buf + len - pos);
-	}
-}
-
-
-int ieee80211_sta_init(struct wpa_supplicant *wpa_s)
-{
-	u16 num_modes, flags;
-
-	wpa_s->mlme.modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes,
-							&flags);
-	if (wpa_s->mlme.modes == NULL) {
-		wpa_printf(MSG_ERROR, "MLME: Failed to read supported "
-			   "channels and rates from the driver");
-		return -1;
-	}
-
-	wpa_s->mlme.num_modes = num_modes;
-
-	wpa_s->mlme.hw_modes = 1 << HOSTAPD_MODE_IEEE80211A;
-	wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211B;
-	wpa_s->mlme.hw_modes |= 1 << HOSTAPD_MODE_IEEE80211G;
-
-	wpa_s->mlme.wmm_enabled = 1;
-
-	return 0;
-}
-
-
-void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s)
-{
-	eloop_cancel_timeout(ieee80211_sta_timer, wpa_s, NULL);
-	eloop_cancel_timeout(ieee80211_sta_scan_timer, wpa_s, NULL);
-	os_free(wpa_s->mlme.extra_ie);
-	wpa_s->mlme.extra_ie = NULL;
-	os_free(wpa_s->mlme.extra_probe_ie);
-	wpa_s->mlme.extra_probe_ie = NULL;
-	os_free(wpa_s->mlme.assocreq_ies);
-	wpa_s->mlme.assocreq_ies = NULL;
-	os_free(wpa_s->mlme.assocresp_ies);
-	wpa_s->mlme.assocresp_ies = NULL;
-	ieee80211_bss_list_deinit(wpa_s);
-	ieee80211_sta_free_hw_features(wpa_s->mlme.modes,
-				       wpa_s->mlme.num_modes);
-#ifdef CONFIG_IEEE80211R
-	os_free(wpa_s->mlme.ft_ies);
-	wpa_s->mlme.ft_ies = NULL;
-	wpa_s->mlme.ft_ies_len = 0;
-#endif /* CONFIG_IEEE80211R */
-
-	os_free(wpa_s->mlme.scan_freqs);
-	wpa_s->mlme.scan_freqs = NULL;
-}
-
-
-#ifdef CONFIG_IEEE80211R
-
-int ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-				const u8 *ies, size_t ies_len)
-{
-	if (md == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: Clear FT mobility domain");
-		os_memset(wpa_s->mlme.current_md, 0, MOBILITY_DOMAIN_ID_LEN);
-	} else {
-		wpa_printf(MSG_DEBUG, "MLME: Update FT IEs for MD " MACSTR,
-			   MAC2STR(md));
-		os_memcpy(wpa_s->mlme.current_md, md, MOBILITY_DOMAIN_ID_LEN);
-	}
-
-	wpa_hexdump(MSG_DEBUG, "MLME: FT IEs", ies, ies_len);
-	os_free(wpa_s->mlme.ft_ies);
-	wpa_s->mlme.ft_ies = os_malloc(ies_len);
-	if (wpa_s->mlme.ft_ies == NULL)
-		return -1;
-	os_memcpy(wpa_s->mlme.ft_ies, ies, ies_len);
-	wpa_s->mlme.ft_ies_len = ies_len;
-
-	return 0;
-}
-
-
-int ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action,
-				 const u8 *target_ap,
-				 const u8 *ies, size_t ies_len)
-{
-	u8 *buf;
-	size_t len;
-	struct ieee80211_mgmt *mgmt;
-	int res;
-
-	/*
-	 * Action frame payload:
-	 * Category[1] = 6 (Fast BSS Transition)
-	 * Action[1] = 1 (Fast BSS Transition Request)
-	 * STA Address
-	 * Target AP Address
-	 * FT IEs
-	 */
-
-	buf = os_zalloc(sizeof(*mgmt) + ies_len);
-	if (buf == NULL) {
-		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
-			   "FT action frame");
-		return -1;
-	}
-
-	mgmt = (struct ieee80211_mgmt *) buf;
-	len = 24;
-	os_memcpy(mgmt->da, wpa_s->bssid, ETH_ALEN);
-	os_memcpy(mgmt->sa, wpa_s->own_addr, ETH_ALEN);
-	os_memcpy(mgmt->bssid, wpa_s->bssid, ETH_ALEN);
-	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
-					   WLAN_FC_STYPE_ACTION);
-	mgmt->u.action.category = WLAN_ACTION_FT;
-	mgmt->u.action.u.ft_action_req.action = action;
-	os_memcpy(mgmt->u.action.u.ft_action_req.sta_addr, wpa_s->own_addr,
-		  ETH_ALEN);
-	os_memcpy(mgmt->u.action.u.ft_action_req.target_ap_addr, target_ap,
-		  ETH_ALEN);
-	os_memcpy(mgmt->u.action.u.ft_action_req.variable, ies, ies_len);
-	len += 1 + sizeof(mgmt->u.action.u.ft_action_req) + ies_len;
-
-	wpa_printf(MSG_DEBUG, "MLME: Send FT Action Frame: Action=%d "
-		   "Target AP=" MACSTR " body_len=%lu",
-		   action, MAC2STR(target_ap), (unsigned long) ies_len);
-
-	res = ieee80211_sta_tx(wpa_s, buf, len);
-	os_free(buf);
-
-	return res;
-}
-
-#endif /* CONFIG_IEEE80211R */
-
-
-static int ieee80211_sta_set_probe_req_ie(struct wpa_supplicant *wpa_s,
-					  const u8 *ies, size_t ies_len)
-{
-	os_free(wpa_s->mlme.extra_probe_ie);
-	wpa_s->mlme.extra_probe_ie = NULL;
-	wpa_s->mlme.extra_probe_ie_len = 0;
-
-	if (ies == NULL)
-		return 0;
-
-	wpa_s->mlme.extra_probe_ie = os_malloc(ies_len);
-	if (wpa_s->mlme.extra_probe_ie == NULL)
-		return -1;
-
-	os_memcpy(wpa_s->mlme.extra_probe_ie, ies, ies_len);
-	wpa_s->mlme.extra_probe_ie_len = ies_len;
-
-	return 0;
-}
diff --git a/wpa_supplicant/mlme.h b/wpa_supplicant/mlme.h
deleted file mode 100644
index fe3c6e4..0000000
--- a/wpa_supplicant/mlme.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * WPA Supplicant - Client mode MLME
- * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2004, Instant802 Networks, Inc.
- * Copyright (c) 2005-2006, Devicescape Software, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Alternatively, this software may be distributed under the terms of BSD
- * license.
- *
- * See README and COPYING for more details.
- */
-
-#ifndef MLME_H
-#define MLME_H
-
-struct wpa_supplicant;
-
-struct ieee80211_rx_status {
-	int freq;
-        int channel;
-        int ssi;
-};
-
-#ifdef CONFIG_CLIENT_MLME
-
-int ieee80211_sta_init(struct wpa_supplicant *wpa_s);
-void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s);
-int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s,
-			   struct wpa_driver_scan_params *params);
-int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s, u16 reason);
-int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s, u16 reason);
-int ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
-			    struct wpa_driver_associate_params *params);
-int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid,
-			   size_t *len);
-void ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
-		      struct ieee80211_rx_status *rx_status);
-struct wpa_scan_results *
-ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s);
-int ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-				const u8 *ies, size_t ies_len);
-int ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action,
-				 const u8 *target_ap,
-				 const u8 *ies, size_t ies_len);
-
-#else /* CONFIG_CLIENT_MLME */
-
-static inline int ieee80211_sta_init(struct wpa_supplicant *wpa_s)
-{
-	return 0;
-}
-
-static inline void ieee80211_sta_deinit(struct wpa_supplicant *wpa_s)
-{
-}
-
-static inline int ieee80211_sta_req_scan(struct wpa_supplicant *wpa_s,
-					 struct wpa_driver_scan_params *params)
-{
-	return -1;
-}
-
-static inline int ieee80211_sta_deauthenticate(struct wpa_supplicant *wpa_s,
-					       u16 reason)
-{
-	return -1;
-}
-
-static inline int ieee80211_sta_disassociate(struct wpa_supplicant *wpa_s,
-					     u16 reason)
-{
-	return -1;
-}
-
-static inline int
-ieee80211_sta_associate(struct wpa_supplicant *wpa_s,
-			struct wpa_driver_associate_params *params)
-{
-	return -1;
-}
-
-static inline int ieee80211_sta_get_ssid(struct wpa_supplicant *wpa_s,
-					 u8 *ssid, size_t *len)
-{
-	return -1;
-}
-
-static inline void
-ieee80211_sta_rx(struct wpa_supplicant *wpa_s, const u8 *buf, size_t len,
-		 struct ieee80211_rx_status *rx_status)
-{
-}
-
-static inline struct wpa_scan_results *
-ieee80211_sta_get_scan_results(struct wpa_supplicant *wpa_s)
-{
-	return NULL;
-}
-
-static inline int
-ieee80211_sta_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
-			    const u8 *ies, size_t ies_len)
-{
-	return -1;
-}
-
-static inline int
-ieee80211_sta_send_ft_action(struct wpa_supplicant *wpa_s, u8 action,
-			     const u8 *target_ap,
-			     const u8 *ies, size_t ies_len)
-{
-	return -1;
-}
-
-#endif /* CONFIG_CLIENT_MLME */
-
-#endif /* MLME_H */
diff --git a/wpa_supplicant/notify.c b/wpa_supplicant/notify.c
index 0d2f542..6e9b5a9 100644
--- a/wpa_supplicant/notify.c
+++ b/wpa_supplicant/notify.c
@@ -22,6 +22,7 @@
 #include "dbus/dbus_common.h"
 #include "dbus/dbus_old.h"
 #include "dbus/dbus_new.h"
+#include "rsn_supp/wpa.h"
 #include "driver_i.h"
 #include "scan.h"
 #include "p2p_supplicant.h"
@@ -140,6 +141,15 @@
 }
 
 
+void wpas_notify_network_request(struct wpa_supplicant *wpa_s,
+				 struct wpa_ssid *ssid,
+				 enum wpa_ctrl_req_type rtype,
+				 const char *default_txt)
+{
+	wpas_dbus_signal_network_request(wpa_s, ssid, rtype, default_txt);
+}
+
+
 void wpas_notify_scanning(struct wpa_supplicant *wpa_s)
 {
 	/* notify the old DBus API */
@@ -238,8 +248,13 @@
 void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
 				 struct wpa_ssid *ssid)
 {
+	if (wpa_s->wpa)
+		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
 	if (wpa_s->global->p2p_group_formation != wpa_s)
 		wpas_dbus_unregister_network(wpa_s, ssid->id);
+#ifdef CONFIG_P2P
+	wpas_p2p_network_removed(wpa_s, ssid);
+#endif /* CONFIG_P2P */
 }
 
 
@@ -431,9 +446,10 @@
 }
 
 
-void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s, int status)
+void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s,
+				      struct p2p_go_neg_results *res)
 {
-	wpas_dbus_signal_p2p_go_neg_resp(wpa_s, status);
+	wpas_dbus_signal_p2p_go_neg_resp(wpa_s, res);
 }
 
 
@@ -509,9 +525,12 @@
 
 
 static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
-					  const u8 *sta)
+					  const u8 *sta,
+					  const u8 *p2p_dev_addr)
 {
 #ifdef CONFIG_P2P
+	wpas_p2p_notify_ap_sta_authorized(wpa_s, p2p_dev_addr);
+
 	/*
 	 * Register a group member object corresponding to this peer and
 	 * emit a PeerJoined signal. This will check if it really is a
@@ -548,10 +567,11 @@
 
 
 void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
-				const u8 *mac_addr, int authorized)
+				const u8 *mac_addr, int authorized,
+				const u8 *p2p_dev_addr)
 {
 	if (authorized)
-		wpas_notify_ap_sta_authorized(wpa_s, mac_addr);
+		wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr);
 	else
 		wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr);
 }
diff --git a/wpa_supplicant/notify.h b/wpa_supplicant/notify.h
index 98cbcb1..236a31e 100644
--- a/wpa_supplicant/notify.h
+++ b/wpa_supplicant/notify.h
@@ -36,6 +36,10 @@
 					 struct wpa_ssid *ssid);
 void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
 				  struct wpa_ssid *ssid);
+void wpas_notify_network_request(struct wpa_supplicant *wpa_s,
+				 struct wpa_ssid *ssid,
+				 enum wpa_ctrl_req_type rtype,
+				 const char *default_txt);
 void wpas_notify_scanning(struct wpa_supplicant *wpa_s);
 void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success);
 void wpas_notify_scan_results(struct wpa_supplicant *wpa_s);
@@ -82,7 +86,8 @@
 void wpas_notify_resume(struct wpa_global *global);
 
 void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
-				const u8 *mac_addr, int authorized);
+				const u8 *mac_addr, int authorized,
+				const u8 *p2p_dev_addr);
 void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
 				  const u8 *dev_addr, int new_device);
 void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s,
@@ -93,7 +98,7 @@
 void wpas_notify_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
 				const u8 *src, u16 dev_passwd_id);
 void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s,
-				      int status);
+				      struct p2p_go_neg_results *res);
 void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s,
 				       int status, const u8 *bssid);
 void wpas_notify_p2p_sd_request(struct wpa_supplicant *wpa_s,
diff --git a/wpa_supplicant/offchannel.c b/wpa_supplicant/offchannel.c
new file mode 100644
index 0000000..790f14a
--- /dev/null
+++ b/wpa_supplicant/offchannel.c
@@ -0,0 +1,314 @@
+/*
+ * wpa_supplicant - Off-channel Action frame TX/RX
+ * Copyright (c) 2009-2010, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "utils/eloop.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "offchannel.h"
+
+
+
+static struct wpa_supplicant *
+wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
+{
+	struct wpa_supplicant *iface;
+
+	if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
+		return wpa_s;
+
+	/*
+	 * Try to find a group interface that matches with the source address.
+	 */
+	iface = wpa_s->global->ifaces;
+	while (iface) {
+		if (os_memcmp(wpa_s->pending_action_src,
+			      iface->own_addr, ETH_ALEN) == 0)
+			break;
+		iface = iface->next;
+	}
+	if (iface) {
+		wpa_printf(MSG_DEBUG, "P2P: Use group interface %s "
+			   "instead of interface %s for Action TX",
+			   iface->ifname, wpa_s->ifname);
+		return iface;
+	}
+
+	return wpa_s;
+}
+
+
+static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct wpa_supplicant *iface;
+	int res;
+	int without_roc;
+
+	without_roc = wpa_s->pending_action_without_roc;
+	wpa_s->pending_action_without_roc = 0;
+	wpa_printf(MSG_DEBUG, "Off-channel: Send Action callback "
+		   "(without_roc=%d pending_action_tx=%p)",
+		   without_roc, wpa_s->pending_action_tx);
+
+	if (wpa_s->pending_action_tx == NULL)
+		return;
+
+	/*
+	 * This call is likely going to be on the P2P device instance if the
+	 * driver uses a separate interface for that purpose. However, some
+	 * Action frames are actually sent within a P2P Group and when that is
+	 * the case, we need to follow power saving (e.g., GO buffering the
+	 * frame for a client in PS mode or a client following the advertised
+	 * NoA from its GO). To make that easier for the driver, select the
+	 * correct group interface here.
+	 */
+	iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
+
+	if (wpa_s->off_channel_freq != wpa_s->pending_action_freq &&
+	    wpa_s->pending_action_freq != 0 &&
+	    wpa_s->pending_action_freq != iface->assoc_freq) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Pending Action frame TX "
+			   "waiting for another freq=%u (off_channel_freq=%u "
+			   "assoc_freq=%u)",
+			   wpa_s->pending_action_freq,
+			   wpa_s->off_channel_freq,
+			   iface->assoc_freq);
+		if (without_roc && wpa_s->off_channel_freq == 0) {
+			/*
+			 * We may get here if wpas_send_action() found us to be
+			 * on the correct channel, but remain-on-channel cancel
+			 * event was received before getting here.
+			 */
+			wpa_printf(MSG_DEBUG, "Off-channel: Schedule "
+				   "remain-on-channel to send Action frame");
+			if (wpa_drv_remain_on_channel(
+				    wpa_s, wpa_s->pending_action_freq, 200) <
+			    0) {
+				wpa_printf(MSG_DEBUG, "Off-channel: Failed to "
+					   "request driver to remain on "
+					   "channel (%u MHz) for Action Frame "
+					   "TX", wpa_s->pending_action_freq);
+			} else {
+				wpa_s->off_channel_freq = 0;
+				wpa_s->roc_waiting_drv_freq =
+					wpa_s->pending_action_freq;
+			}
+		}
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "Off-channel: Sending pending Action frame to "
+		   MACSTR " using interface %s",
+		   MAC2STR(wpa_s->pending_action_dst), iface->ifname);
+	res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
+				  wpa_s->pending_action_dst,
+				  wpa_s->pending_action_src,
+				  wpa_s->pending_action_bssid,
+				  wpabuf_head(wpa_s->pending_action_tx),
+				  wpabuf_len(wpa_s->pending_action_tx),
+				  wpa_s->pending_action_no_cck);
+	if (res) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Failed to send the "
+			   "pending Action frame");
+		/*
+		 * Use fake TX status event to allow state machines to
+		 * continue.
+		 */
+		offchannel_send_action_tx_status(
+			wpa_s, wpa_s->pending_action_dst,
+			wpabuf_head(wpa_s->pending_action_tx),
+			wpabuf_len(wpa_s->pending_action_tx),
+			OFFCHANNEL_SEND_ACTION_FAILED);
+	}
+}
+
+
+void offchannel_send_action_tx_status(
+	struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
+	size_t data_len, enum offchannel_send_action_result result)
+{
+	if (wpa_s->pending_action_tx == NULL) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
+			   "no pending operation");
+		return;
+	}
+
+	if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Ignore Action TX status - "
+			   "unknown destination address");
+		return;
+	}
+
+	wpabuf_free(wpa_s->pending_action_tx);
+	wpa_s->pending_action_tx = NULL;
+
+	wpa_printf(MSG_DEBUG, "Off-channel: TX status result=%d cb=%p",
+		   result, wpa_s->pending_action_tx_status_cb);
+
+	if (wpa_s->pending_action_tx_status_cb) {
+		wpa_s->pending_action_tx_status_cb(
+			wpa_s, wpa_s->pending_action_freq,
+			wpa_s->pending_action_dst, wpa_s->pending_action_src,
+			wpa_s->pending_action_bssid,
+			data, data_len, result);
+	}
+}
+
+
+int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
+			   const u8 *dst, const u8 *src, const u8 *bssid,
+			   const u8 *buf, size_t len, unsigned int wait_time,
+			   void (*tx_cb)(struct wpa_supplicant *wpa_s,
+					 unsigned int freq, const u8 *dst,
+					 const u8 *src, const u8 *bssid,
+					 const u8 *data, size_t data_len,
+					 enum offchannel_send_action_result
+					 result),
+			   int no_cck)
+{
+	wpa_printf(MSG_DEBUG, "Off-channel: Send action frame: freq=%d dst="
+		   MACSTR " src=" MACSTR " bssid=" MACSTR " len=%d",
+		   freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
+		   (int) len);
+
+	wpa_s->pending_action_tx_status_cb = tx_cb;
+
+	if (wpa_s->pending_action_tx) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Dropped pending Action "
+			   "frame TX to " MACSTR,
+			   MAC2STR(wpa_s->pending_action_dst));
+		wpabuf_free(wpa_s->pending_action_tx);
+	}
+	wpa_s->pending_action_tx = wpabuf_alloc(len);
+	if (wpa_s->pending_action_tx == NULL) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Failed to allocate Action "
+			   "frame TX buffer (len=%llu)",
+			   (unsigned long long) len);
+		return -1;
+	}
+	wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
+	os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
+	os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
+	os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
+	wpa_s->pending_action_freq = freq;
+	wpa_s->pending_action_no_cck = no_cck;
+
+	if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
+		struct wpa_supplicant *iface;
+
+		iface = wpas_get_tx_interface(wpa_s,
+					      wpa_s->pending_action_src);
+		wpa_s->action_tx_wait_time = wait_time;
+
+		return wpa_drv_send_action(
+			iface, wpa_s->pending_action_freq,
+			wait_time, wpa_s->pending_action_dst,
+			wpa_s->pending_action_src, wpa_s->pending_action_bssid,
+			wpabuf_head(wpa_s->pending_action_tx),
+			wpabuf_len(wpa_s->pending_action_tx),
+			wpa_s->pending_action_no_cck);
+	}
+
+	if (freq) {
+		struct wpa_supplicant *tx_iface;
+		tx_iface = wpas_get_tx_interface(wpa_s, src);
+		if (tx_iface->assoc_freq == freq) {
+			wpa_printf(MSG_DEBUG, "Off-channel: Already on "
+				   "requested channel (TX interface operating "
+				   "channel)");
+			freq = 0;
+		}
+	}
+
+	if (wpa_s->off_channel_freq == freq || freq == 0) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Already on requested "
+			   "channel; send Action frame immediately");
+		/* TODO: Would there ever be need to extend the current
+		 * duration on the channel? */
+		wpa_s->pending_action_without_roc = 1;
+		eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
+		eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
+		return 0;
+	}
+	wpa_s->pending_action_without_roc = 0;
+
+	if (wpa_s->roc_waiting_drv_freq == freq) {
+		wpa_printf(MSG_DEBUG, "Off-channel: Already waiting for "
+			   "driver to get to frequency %u MHz; continue "
+			   "waiting to send the Action frame", freq);
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "Off-channel: Schedule Action frame to be "
+		   "transmitted once the driver gets to the requested "
+		   "channel");
+	if (wait_time > wpa_s->max_remain_on_chan)
+		wait_time = wpa_s->max_remain_on_chan;
+	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 "
+			   "Frame TX", freq);
+		return -1;
+	}
+	wpa_s->off_channel_freq = 0;
+	wpa_s->roc_waiting_drv_freq = freq;
+
+	return 0;
+}
+
+
+void offchannel_send_action_done(struct wpa_supplicant *wpa_s)
+{
+	wpa_printf(MSG_DEBUG, "Off-channel: Action frame sequence done "
+		   "notification");
+	wpabuf_free(wpa_s->pending_action_tx);
+	wpa_s->pending_action_tx = NULL;
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX &&
+	    wpa_s->action_tx_wait_time)
+		wpa_drv_send_action_cancel_wait(wpa_s);
+
+	if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
+		wpa_drv_cancel_remain_on_channel(wpa_s);
+		wpa_s->off_channel_freq = 0;
+		wpa_s->roc_waiting_drv_freq = 0;
+	}
+}
+
+
+void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				     unsigned int freq, unsigned int duration)
+{
+	wpa_s->roc_waiting_drv_freq = 0;
+	wpa_s->off_channel_freq = freq;
+	wpas_send_action_cb(wpa_s, NULL);
+}
+
+
+void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+					    unsigned int freq)
+{
+	wpa_s->off_channel_freq = 0;
+}
+
+
+void offchannel_deinit(struct wpa_supplicant *wpa_s)
+{
+	wpabuf_free(wpa_s->pending_action_tx);
+	wpa_s->pending_action_tx = NULL;
+	eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
+}
diff --git a/wpa_supplicant/offchannel.h b/wpa_supplicant/offchannel.h
new file mode 100644
index 0000000..60e0d03
--- /dev/null
+++ b/wpa_supplicant/offchannel.h
@@ -0,0 +1,39 @@
+/*
+ * wpa_supplicant - Off-channel Action frame TX/RX
+ * Copyright (c) 2009-2010, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef OFFCHANNEL_H
+#define OFFCHANNEL_H
+
+int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
+			   const u8 *dst, const u8 *src, const u8 *bssid,
+			   const u8 *buf, size_t len, unsigned int wait_time,
+			   void (*tx_cb)(struct wpa_supplicant *wpa_s,
+					 unsigned int freq, const u8 *dst,
+					 const u8 *src, const u8 *bssid,
+					 const u8 *data, size_t data_len,
+					 enum offchannel_send_action_result
+					 result),
+			   int no_cck);
+void offchannel_send_action_done(struct wpa_supplicant *wpa_s);
+void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				     unsigned int freq, unsigned int duration);
+void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+					    unsigned int freq);
+void offchannel_deinit(struct wpa_supplicant *wpa_s);
+void offchannel_send_action_tx_status(
+	struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
+	size_t data_len, enum offchannel_send_action_result result);
+
+#endif /* OFFCHANNEL_H */
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index f4c5a53..613d37c 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -22,6 +22,7 @@
 #include "wps/wps_i.h"
 #include "p2p/p2p.h"
 #include "ap/hostapd.h"
+#include "ap/ap_config.h"
 #include "ap/p2p_hostapd.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "rsn_supp/wpa.h"
@@ -30,10 +31,10 @@
 #include "ap.h"
 #include "config_ssid.h"
 #include "config.h"
-#include "mlme.h"
 #include "notify.h"
 #include "scan.h"
 #include "bss.h"
+#include "offchannel.h"
 #include "wps_supplicant.h"
 #include "p2p_supplicant.h"
 
@@ -44,6 +45,14 @@
  */
 #define P2P_MAX_JOIN_SCAN_ATTEMPTS 10
 
+#ifndef P2P_MAX_CLIENT_IDLE
+/*
+ * How many seconds to try to reconnect to the GO when connection in P2P client
+ * role has been lost.
+ */
+#define P2P_MAX_CLIENT_IDLE 10
+#endif /* P2P_MAX_CLIENT_IDLE */
+
 
 static void wpas_p2p_long_listen_timeout(void *eloop_ctx, void *timeout_ctx);
 static struct wpa_supplicant *
@@ -58,6 +67,36 @@
 static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s);
 
+#ifdef ANDROID_P2P
+void wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s, int freq)
+{
+	struct wpa_supplicant *iface = NULL;
+	struct p2p_data *p2p = wpa_s->global->p2p;
+
+	for (iface = wpa_s->global->ifaces; iface; iface = iface->next) {
+		if((iface->p2p_group_interface) && (iface->current_ssid) &&
+			(iface->current_ssid->frequency != freq)) {
+
+			if (iface->p2p_group_interface == P2P_GROUP_INTERFACE_GO) {
+					/* Try to see whether we can move the GO. If it
+					 * is not possible, remove the GO interface
+					 */
+					if(wpa_drv_go_switch_channel(iface, freq) == 0) {
+							wpa_printf(MSG_ERROR, "P2P: GO Moved to freq(%d)", freq);
+							iface->current_ssid->frequency = freq;
+							//p2p->op_channel = freq;
+							continue;
+					}
+			}
+
+			/* If GO cannot be moved or if the conflicting interface is a
+			 * P2P Client, remove the interface */
+			wpas_p2p_disconnect(iface);
+		}
+	}
+}
+#endif
+
 
 static void wpas_p2p_scan_res_handler(struct wpa_supplicant *wpa_s,
 				      struct wpa_scan_results *scan_res)
@@ -92,6 +131,8 @@
 	int ret;
 	struct wpabuf *wps_ie, *ies;
 	int social_channels[] = { 2412, 2437, 2462, 0, 0 };
+	size_t ielen;
+	int was_in_p2p_scan;
 
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
@@ -110,7 +151,8 @@
 	if (wps_ie == NULL)
 		return -1;
 
-	ies = wpabuf_alloc(wpabuf_len(wps_ie) + 100);
+	ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+	ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
 	if (ies == NULL) {
 		wpabuf_free(wps_ie);
 		return -1;
@@ -120,6 +162,7 @@
 
 	p2p_scan_ie(wpa_s->global->p2p, ies);
 
+	params.p2p_probe = 1;
 	params.extra_ies = wpabuf_head(ies);
 	params.extra_ies_len = wpabuf_len(ies);
 
@@ -140,39 +183,24 @@
 		break;
 	}
 
+	was_in_p2p_scan = wpa_s->scan_res_handler == wpas_p2p_scan_res_handler;
 	wpa_s->scan_res_handler = wpas_p2p_scan_res_handler;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		ret = ieee80211_sta_req_scan(wpa_s, &params);
-	else
-		ret = wpa_drv_scan(wpa_s, &params);
+	ret = wpa_drv_scan(wpa_s, &params);
 
 	wpabuf_free(ies);
 
+	if (ret) {
+		wpa_s->scan_res_handler = NULL;
+		if (wpa_s->scanning || was_in_p2p_scan) {
+			wpa_s->p2p_cb_on_scan_complete = 1;
+			ret = 1;
+		}
+	}
+
 	return ret;
 }
 
 
-#ifdef CONFIG_CLIENT_MLME
-static void p2p_rx_action_mlme(void *ctx, const u8 *buf, size_t len, int freq)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-	const struct ieee80211_mgmt *mgmt;
-	size_t hdr_len;
-
-	if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
-		return;
-	mgmt = (const struct ieee80211_mgmt *) buf;
-	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
-	if (hdr_len > len)
-		return;
-	p2p_rx_action(wpa_s->global->p2p, mgmt->da, mgmt->sa, mgmt->bssid,
-		      mgmt->u.action.category,
-		      &mgmt->u.action.u.vs_public_action.action,
-		      len - hdr_len, freq);
-}
-#endif /* CONFIG_CLIENT_MLME */
-
-
 static enum wpa_driver_if_type wpas_p2p_if_type(int p2p_group_interface)
 {
 	switch (p2p_group_interface) {
@@ -467,6 +495,52 @@
 }
 
 
+static void wpas_p2p_add_persistent_group_client(struct wpa_supplicant *wpa_s,
+						 const u8 *addr)
+{
+	struct wpa_ssid *ssid, *s;
+	u8 *n;
+	size_t i;
+
+	ssid = wpa_s->current_ssid;
+	if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
+	    !ssid->p2p_persistent_group)
+		return;
+
+	for (s = wpa_s->parent->conf->ssid; s; s = s->next) {
+		if (s->disabled != 2 || s->mode != WPAS_MODE_P2P_GO)
+			continue;
+
+		if (s->ssid_len == ssid->ssid_len &&
+		    os_memcmp(s->ssid, ssid->ssid, s->ssid_len) == 0)
+			break;
+	}
+
+	if (s == NULL)
+		return;
+
+	for (i = 0; s->p2p_client_list && i < s->num_p2p_clients; i++) {
+		if (os_memcmp(s->p2p_client_list + i * ETH_ALEN, addr,
+			      ETH_ALEN) == 0)
+			return; /* already in list */
+	}
+
+	n = os_realloc(s->p2p_client_list,
+		       (s->num_p2p_clients + 1) * ETH_ALEN);
+	if (n == NULL)
+		return;
+	os_memcpy(n + s->num_p2p_clients * ETH_ALEN, addr, ETH_ALEN);
+	s->p2p_client_list = n;
+	s->num_p2p_clients++;
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+	if (wpa_s->parent->conf->update_config &&
+	    wpa_config_write(wpa_s->parent->confname, wpa_s->parent->conf))
+		wpa_printf(MSG_DEBUG, "P2P: Failed to update configuration");
+#endif /* CONFIG_NO_CONFIG_WRITE */
+}
+
+
 static void wpas_group_formation_completed(struct wpa_supplicant *wpa_s,
 					   int success)
 {
@@ -509,15 +583,8 @@
 		client = ssid->mode == WPAS_MODE_INFRA;
 		if (ssid->mode == WPAS_MODE_P2P_GO) {
 			persistent = ssid->p2p_persistent_group;
-#ifndef ANDROID_BRCM_P2P_PATCH
-			os_memcpy(go_dev_addr, wpa_s->parent->own_addr,
-				  ETH_ALEN);
-#else
-			/* P2P_ADDR: Use p2p_dev_addr instead of own mac addr */
 			os_memcpy(go_dev_addr, wpa_s->global->p2p_dev_addr,
 				  ETH_ALEN);
-
-#endif
 		} else
 			persistent = wpas_p2p_persistent_group(wpa_s,
 							       go_dev_addr,
@@ -564,162 +631,45 @@
 	if (persistent)
 		network_id = wpas_p2p_store_persistent_group(wpa_s->parent,
 							     ssid, go_dev_addr);
-	if (network_id < 0)
+	if (network_id < 0 && ssid)
 		network_id = ssid->id;
 	if (!client)
 		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
 }
 
 
-static struct wpa_supplicant *
-wpas_get_tx_interface(struct wpa_supplicant *wpa_s, const u8 *src)
+static void wpas_p2p_send_action_tx_status(struct wpa_supplicant *wpa_s,
+					   unsigned int freq,
+					   const u8 *dst, const u8 *src,
+					   const u8 *bssid,
+					   const u8 *data, size_t data_len,
+					   enum offchannel_send_action_result
+					   result)
 {
-	struct wpa_supplicant *iface;
+	enum p2p_send_action_result res = P2P_SEND_ACTION_SUCCESS;
 
-	if (os_memcmp(src, wpa_s->own_addr, ETH_ALEN) == 0)
-		return wpa_s;
-
-	/*
-	 * Try to find a group interface that matches with the source address.
-	 */
-	iface = wpa_s->global->ifaces;
-	while (iface) {
-		if (os_memcmp(wpa_s->pending_action_src,
-			      iface->own_addr, ETH_ALEN) == 0)
-			break;
-		iface = iface->next;
-	}
-	if (iface) {
-		wpa_printf(MSG_DEBUG, "P2P: Use group interface %s "
-			   "instead of interface %s for Action TX",
-			   iface->ifname, wpa_s->ifname);
-		return iface;
-	}
-
-	return wpa_s;
-}
-
-
-static void wpas_send_action_cb(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	struct wpa_supplicant *iface;
-	int res;
-	int without_roc;
-
-	without_roc = wpa_s->pending_action_without_roc;
-	wpa_s->pending_action_without_roc = 0;
-	wpa_printf(MSG_DEBUG, "P2P: Send Action callback (without_roc=%d "
-		   "pending_action_tx=%p)",
-		   without_roc, wpa_s->pending_action_tx);
-
-	if (wpa_s->pending_action_tx == NULL)
-		return;
-
-	/*
-	 * This call is likely going to be on the P2P device instance if the
-	 * driver uses a separate interface for that purpose. However, some
-	 * Action frames are actually sent within a P2P Group and when that is
-	 * the case, we need to follow power saving (e.g., GO buffering the
-	 * frame for a client in PS mode or a client following the advertised
-	 * NoA from its GO). To make that easier for the driver, select the
-	 * correct group interface here.
-	 */
-	iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
-
-	if (wpa_s->off_channel_freq != wpa_s->pending_action_freq &&
-	    wpa_s->pending_action_freq != 0 &&
-	    wpa_s->pending_action_freq != iface->assoc_freq) {
-		wpa_printf(MSG_DEBUG, "P2P: Pending Action frame TX "
-			   "waiting for another freq=%u (off_channel_freq=%u "
-			   "assoc_freq=%u)",
-			   wpa_s->pending_action_freq,
-			   wpa_s->off_channel_freq,
-			   iface->assoc_freq);
-		if (without_roc && wpa_s->off_channel_freq == 0) {
-			/*
-			 * We may get here if wpas_send_action() found us to be
-			 * on the correct channel, but remain-on-channel cancel
-			 * event was received before getting here.
-			 */
-			wpa_printf(MSG_DEBUG, "P2P: Schedule "
-				   "remain-on-channel to send Action frame");
-			if (wpa_drv_remain_on_channel(
-				    wpa_s, wpa_s->pending_action_freq, 200) <
-			    0) {
-				wpa_printf(MSG_DEBUG, "P2P: Failed to request "
-					   "driver to remain on channel (%u "
-					   "MHz) for Action Frame TX",
-					   wpa_s->pending_action_freq);
-			} else {
-				wpa_s->off_channel_freq = 0;
-				wpa_s->roc_waiting_drv_freq =
-					wpa_s->pending_action_freq;
-			}
-		}
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "P2P: Sending pending Action frame to "
-		   MACSTR " using interface %s",
-		   MAC2STR(wpa_s->pending_action_dst), iface->ifname);
-	res = wpa_drv_send_action(iface, wpa_s->pending_action_freq, 0,
-				  wpa_s->pending_action_dst,
-				  wpa_s->pending_action_src,
-				  wpa_s->pending_action_bssid,
-				  wpabuf_head(wpa_s->pending_action_tx),
-				  wpabuf_len(wpa_s->pending_action_tx));
-	if (res) {
-		wpa_printf(MSG_DEBUG, "P2P: Failed to send the pending "
-			   "Action frame");
-		/*
-		 * Use fake TX status event to allow P2P state machine to
-		 * continue.
-		 */
-		wpas_send_action_tx_status(
-			wpa_s, wpa_s->pending_action_dst,
-			wpabuf_head(wpa_s->pending_action_tx),
-			wpabuf_len(wpa_s->pending_action_tx),
-			P2P_SEND_ACTION_FAILED);
-	}
-}
-
-
-void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
-				const u8 *data, size_t data_len,
-				enum p2p_send_action_result result)
-{
 	if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
 		return;
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
 		return;
 
-	if (wpa_s->pending_action_tx == NULL) {
-		wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - no "
-			   "pending operation");
-		return;
+	switch (result) {
+	case OFFCHANNEL_SEND_ACTION_SUCCESS:
+		res = P2P_SEND_ACTION_SUCCESS;
+		break;
+	case OFFCHANNEL_SEND_ACTION_NO_ACK:
+		res = P2P_SEND_ACTION_NO_ACK;
+		break;
+	case OFFCHANNEL_SEND_ACTION_FAILED:
+		res = P2P_SEND_ACTION_FAILED;
+		break;
 	}
 
-	if (os_memcmp(dst, wpa_s->pending_action_dst, ETH_ALEN) != 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Ignore Action TX status - unknown "
-			   "destination address");
-		return;
-	}
-
-	wpabuf_free(wpa_s->pending_action_tx);
-	wpa_s->pending_action_tx = NULL;
-
-	p2p_send_action_cb(wpa_s->global->p2p, wpa_s->pending_action_freq,
-			   wpa_s->pending_action_dst,
-			   wpa_s->pending_action_src,
-			   wpa_s->pending_action_bssid,
-			   result);
+	p2p_send_action_cb(wpa_s->global->p2p, freq, dst, src, bssid, res);
 
 	if (wpa_s->pending_pd_before_join &&
-	    (os_memcmp(wpa_s->pending_action_dst, wpa_s->pending_join_dev_addr,
-		       ETH_ALEN) == 0 ||
-	     os_memcmp(wpa_s->pending_action_dst,
-		       wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
+	    (os_memcmp(dst, wpa_s->pending_join_dev_addr, ETH_ALEN) == 0 ||
+	     os_memcmp(dst, wpa_s->pending_join_iface_addr, ETH_ALEN) == 0)) {
 		wpa_s->pending_pd_before_join = 0;
 		wpa_printf(MSG_DEBUG, "P2P: Starting pending "
 			   "join-existing-group operation");
@@ -733,104 +683,16 @@
 			    size_t len, unsigned int wait_time)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-
-	wpa_printf(MSG_DEBUG, "P2P: Send action frame: freq=%d dst=" MACSTR
-		   " src=" MACSTR " bssid=" MACSTR " len=%d",
-		   freq, MAC2STR(dst), MAC2STR(src), MAC2STR(bssid),
-		   (int) len);
-
-	if (wpa_s->pending_action_tx) {
-		wpa_printf(MSG_DEBUG, "P2P: Dropped pending Action frame TX "
-			   "to " MACSTR, MAC2STR(wpa_s->pending_action_dst));
-		wpabuf_free(wpa_s->pending_action_tx);
-	}
-	wpa_s->pending_action_tx = wpabuf_alloc(len);
-	if (wpa_s->pending_action_tx == NULL) {
-		wpa_printf(MSG_DEBUG, "P2P: Failed to allocate Action frame "
-			   "TX buffer (len=%llu)", (unsigned long long) len);
-		return -1;
-	}
-	wpabuf_put_data(wpa_s->pending_action_tx, buf, len);
-	os_memcpy(wpa_s->pending_action_src, src, ETH_ALEN);
-	os_memcpy(wpa_s->pending_action_dst, dst, ETH_ALEN);
-	os_memcpy(wpa_s->pending_action_bssid, bssid, ETH_ALEN);
-	wpa_s->pending_action_freq = freq;
-
-	if (freq != 0 && wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
-		struct wpa_supplicant *iface;
-
-		iface = wpas_get_tx_interface(wpa_s, wpa_s->pending_action_src);
-		wpa_s->action_tx_wait_time = wait_time;
-
-		return wpa_drv_send_action(iface, wpa_s->pending_action_freq,
-					wait_time, wpa_s->pending_action_dst,
-					wpa_s->pending_action_src,
-					wpa_s->pending_action_bssid,
-					wpabuf_head(wpa_s->pending_action_tx),
-					wpabuf_len(wpa_s->pending_action_tx));
-	}
-
-	if (freq) {
-		struct wpa_supplicant *tx_iface;
-		tx_iface = wpas_get_tx_interface(wpa_s, src);
-		if (tx_iface->assoc_freq == freq) {
-			wpa_printf(MSG_DEBUG, "P2P: Already on requested "
-				   "channel (TX interface operating channel)");
-			freq = 0;
-		}
-	}
-
-	if (wpa_s->off_channel_freq == freq || freq == 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Already on requested channel; "
-			   "send Action frame immediately");
-		/* TODO: Would there ever be need to extend the current
-		 * duration on the channel? */
-		wpa_s->pending_action_without_roc = 1;
-		eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
-		eloop_register_timeout(0, 0, wpas_send_action_cb, wpa_s, NULL);
-		return 0;
-	}
-	wpa_s->pending_action_without_roc = 0;
-
-	if (wpa_s->roc_waiting_drv_freq == freq) {
-		wpa_printf(MSG_DEBUG, "P2P: Already waiting for driver to get "
-			   "to frequency %u MHz; continue waiting to send the "
-			   "Action frame", freq);
-		return 0;
-	}
-
-	wpa_printf(MSG_DEBUG, "P2P: Schedule Action frame to be transmitted "
-		   "once the driver gets to the requested channel");
-	if (wait_time > wpa_s->max_remain_on_chan)
-		wait_time = wpa_s->max_remain_on_chan;
-	if (wpa_drv_remain_on_channel(wpa_s, freq, wait_time) < 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Failed to request driver "
-			   "to remain on channel (%u MHz) for Action "
-			   "Frame TX", freq);
-		return -1;
-	}
-	wpa_s->off_channel_freq = 0;
-	wpa_s->roc_waiting_drv_freq = freq;
-
-	return 0;
+	return offchannel_send_action(wpa_s, freq, dst, src, bssid, buf, len,
+				      wait_time,
+				      wpas_p2p_send_action_tx_status, 1);
 }
 
 
 static void wpas_send_action_done(void *ctx)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-	wpa_printf(MSG_DEBUG, "P2P: Action frame sequence done notification");
-	wpabuf_free(wpa_s->pending_action_tx);
-	wpa_s->pending_action_tx = NULL;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_OFFCHANNEL_TX) {
-		if (wpa_s->action_tx_wait_time)
-			wpa_drv_send_action_cancel_wait(wpa_s);
-		wpa_s->off_channel_freq = 0;
-	} else if (wpa_s->off_channel_freq || wpa_s->roc_waiting_drv_freq) {
-		wpa_drv_cancel_remain_on_channel(wpa_s);
-		wpa_s->off_channel_freq = 0;
-		wpa_s->roc_waiting_drv_freq = 0;
-	}
+	offchannel_send_action_done(wpa_s);
 }
 
 
@@ -887,22 +749,13 @@
 			wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
 			ssid->frequency,
 			params->passphrase ? params->passphrase : "",
-#ifndef ANDROID_BRCM_P2P_PATCH
-			MAC2STR(wpa_s->parent->own_addr),
-#else
-			/* P2P_ADDR: use p2p_dev_addr instead of own addr */
 			MAC2STR(wpa_s->global->p2p_dev_addr),
-#endif
 			params->persistent_group ? " [PERSISTENT]" : "");
+
 		if (params->persistent_group)
 			network_id = wpas_p2p_store_persistent_group(
 				wpa_s->parent, ssid,
-#ifndef ANDROID_BRCM_P2P_PATCH
-				wpa_s->parent->own_addr);
-#else
-				/* P2P_ADDR: Use p2p device address */
 				wpa_s->global->p2p_dev_addr);
-#endif
 		if (network_id < 0)
 			network_id = ssid->id;
 		wpas_notify_p2p_group_started(wpa_s, ssid, network_id, 0);
@@ -920,7 +773,7 @@
 	}
 	if (params->wps_method == WPS_PBC)
 		wpa_supplicant_ap_wps_pbc(wpa_s, params->peer_interface_addr,
-					  NULL);
+					  params->peer_device_addr);
 	else if (wpa_s->p2p_pin[0])
 		wpa_supplicant_ap_wps_pin(wpa_s, params->peer_interface_addr,
 					  wpa_s->p2p_pin, NULL, 0);
@@ -942,6 +795,8 @@
 	if (ssid == NULL)
 		return;
 
+	wpa_s->show_group_started = 0;
+
 	wpa_config_set_network_defaults(ssid);
 	ssid->temporary = 1;
 	ssid->p2p_group = 1;
@@ -995,6 +850,7 @@
 
 	d->p2p_group_idle = s->p2p_group_idle;
 	d->p2p_intra_bss = s->p2p_intra_bss;
+	d->persistent_reconnect = s->persistent_reconnect;
 }
 
 
@@ -1017,16 +873,7 @@
 
 	os_snprintf(ifname, sizeof(ifname), "p2p-%s-%d", wpa_s->ifname,
 		    wpa_s->p2p_group_idx);
-
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/**
-	 * Monitor interface name is derived from p2p interface name
-	 * We need to reset p2p interface name early to take care of extra character in monitor interface name
-	 */
-	if (os_strlen(ifname) + os_strlen(WPA_MONITOR_IFNAME_PREFIX)  >= IFNAMSIZ &&
-#else
-	if (os_strlen(ifname) >= IFNAMSIZ  &&
-#endif
+	if (os_strlen(ifname) >= IFNAMSIZ &&
 	    os_strlen(wpa_s->ifname) < IFNAMSIZ) {
 		/* Try to avoid going over the IFNAMSIZ length limit */
 		os_snprintf(ifname, sizeof(ifname), "p2p-%d",
@@ -1147,13 +994,13 @@
 	if (res->status) {
 		wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_FAILURE "status=%d",
 			res->status);
-		wpas_notify_p2p_go_neg_completed(wpa_s, res->status);
+		wpas_notify_p2p_go_neg_completed(wpa_s, res);
 		wpas_p2p_remove_pending_group_interface(wpa_s);
 		return;
 	}
 
 	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
-	wpas_notify_p2p_go_neg_completed(wpa_s, P2P_SC_SUCCESS);
+	wpas_notify_p2p_go_neg_completed(wpa_s, res);
 
 	if (wpa_s->create_p2p_iface) {
 		struct wpa_supplicant *group_wpa_s =
@@ -1209,6 +1056,7 @@
 		    const struct p2p_peer_info *info,
 		    int new_device)
 {
+#ifndef CONFIG_NO_STDOUT_DEBUG
 	struct wpa_supplicant *wpa_s = ctx;
 	char devtype[WPS_DEV_TYPE_BUFSIZE];
 
@@ -1221,6 +1069,7 @@
 				     sizeof(devtype)),
 		info->device_name, info->config_methods,
 		info->dev_capab, info->group_capab);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
 
 	wpas_notify_p2p_device_found(ctx, info->p2p_device_addr, new_device);
 }
@@ -1229,10 +1078,10 @@
 static void wpas_dev_lost(void *ctx, const u8 *dev_addr)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-#ifdef ANDROID_BRCM_P2P_PATCH
+
 	wpa_msg(wpa_s, MSG_INFO, P2P_EVENT_DEVICE_LOST
 		"p2p_dev_addr=" MACSTR, MAC2STR(dev_addr));
-#endif
+
 	wpas_notify_p2p_device_lost(wpa_s, dev_addr);
 }
 
@@ -1284,7 +1133,7 @@
 static int wpas_send_probe_resp(void *ctx, const struct wpabuf *buf)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-	return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf));
+	return wpa_drv_send_mlme(wpa_s, wpabuf_head(buf), wpabuf_len(buf), 1);
 }
 
 
@@ -1579,8 +1428,11 @@
 		os_free(buf);
 	}
 
-	if (wpa_s->p2p_sd_over_ctrl_iface)
+	if (wpa_s->p2p_sd_over_ctrl_iface) {
+		wpas_notify_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+					   update_indic, tlvs, tlvs_len);
 		return; /* to be processed by an external program */
+	}
 
 	resp = wpabuf_alloc(10000);
 	if (resp == NULL)
@@ -1727,26 +1579,26 @@
 }
 
 
-void * wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
-			   const struct wpabuf *tlvs)
+u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+			const struct wpabuf *tlvs)
 {
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return (void *) wpa_drv_p2p_sd_request(wpa_s, dst, tlvs);
+		return wpa_drv_p2p_sd_request(wpa_s, dst, tlvs);
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
-		return NULL;
-	return p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
+		return 0;
+	return (uintptr_t) p2p_sd_request(wpa_s->global->p2p, dst, tlvs);
 }
 
 
-void * wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
-				u8 version, const char *query)
+u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
+			     u8 version, const char *query)
 {
 	struct wpabuf *tlvs;
-	void *ret;
+	u64 ret;
 
 	tlvs = wpabuf_alloc(2 + 1 + 1 + 1 + os_strlen(query));
 	if (tlvs == NULL)
-		return NULL;
+		return 0;
 	wpabuf_put_le16(tlvs, 1 + 1 + 1 + os_strlen(query));
 	wpabuf_put_u8(tlvs, P2P_SERV_UPNP); /* Service Protocol Type */
 	wpabuf_put_u8(tlvs, 1); /* Service Transaction ID */
@@ -1758,13 +1610,14 @@
 }
 
 
-int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, void *req)
+int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req)
 {
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
-		return wpa_drv_p2p_sd_cancel_request(wpa_s, (u64) req);
+		return wpa_drv_p2p_sd_cancel_request(wpa_s, req);
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
-	return p2p_sd_cancel_request(wpa_s->global->p2p, req);
+	return p2p_sd_cancel_request(wpa_s->global->p2p,
+				     (void *) (uintptr_t) req);
 }
 
 
@@ -1925,13 +1778,28 @@
 void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
 			const u8 *dev_addr, const u8 *pri_dev_type,
 			const char *dev_name, u16 supp_config_methods,
-			u8 dev_capab, u8 group_capab)
+			u8 dev_capab, u8 group_capab, const u8 *group_id,
+			size_t group_id_len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	char devtype[WPS_DEV_TYPE_BUFSIZE];
-	char params[200];
+	char params[300];
 	u8 empty_dev_type[8];
 	unsigned int generated_pin = 0;
+	struct wpa_supplicant *group = NULL;
+
+	if (group_id) {
+		for (group = wpa_s->global->ifaces; group; group = group->next)
+		{
+			struct wpa_ssid *s = group->current_ssid;
+			if (s != NULL &&
+			    s->mode == WPAS_MODE_P2P_GO &&
+			    group_id_len - ETH_ALEN == s->ssid_len &&
+			    os_memcmp(group_id + ETH_ALEN, s->ssid,
+				      s->ssid_len) == 0)
+				break;
+		}
+	}
 
 	if (pri_dev_type == NULL) {
 		os_memset(empty_dev_type, 0, sizeof(empty_dev_type));
@@ -1939,14 +1807,19 @@
 	}
 	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",
+		    "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);
+		    dev_name, supp_config_methods, dev_capab, group_capab,
+		    group ? " group=" : "",
+		    group ? group->ifname : "");
 	params[sizeof(params) - 1] = '\0';
-
+#ifdef ANDROID_P2P
+	if ((config_methods & WPS_CONFIG_DISPLAY) && (wpa_s->p2p_pin[0] == '\0')) {
+#else
 	if (config_methods & WPS_CONFIG_DISPLAY) {
+#endif
 		generated_pin = wps_generate_pin();
 		wpas_prov_disc_local_display(wpa_s, peer, params,
 					     generated_pin);
@@ -1969,7 +1842,11 @@
 
 	if (config_methods & WPS_CONFIG_DISPLAY)
 		wpas_prov_disc_local_keypad(wpa_s, peer, "");
+#ifdef ANDROID_P2P
+	else if ((config_methods & WPS_CONFIG_KEYPAD) && (wpa_s->p2p_pin[0] == '\0')) {
+#else
 	else if (config_methods & WPS_CONFIG_KEYPAD) {
+#endif
 		generated_pin = wps_generate_pin();
 		wpas_prov_disc_local_display(wpa_s, peer, "", generated_pin);
 	} else if (config_methods & WPS_CONFIG_PUSHBUTTON)
@@ -1991,8 +1868,8 @@
 }
 
 
-void wpas_prov_disc_fail(void *ctx, const u8 *peer,
-			 enum p2p_prov_disc_status status)
+static void wpas_prov_disc_fail(void *ctx, const u8 *peer,
+				enum p2p_prov_disc_status status)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 
@@ -2281,8 +2158,7 @@
 static int wpas_p2p_setup_channels(struct wpa_supplicant *wpa_s,
 				   struct p2p_channels *chan)
 {
-	struct hostapd_hw_modes *modes, *mode;
-	u16 num_modes, flags;
+	struct hostapd_hw_modes *mode;
 	int cla, op;
 	struct p2p_oper_class_map op_class[] = {
 		{ HOSTAPD_MODE_IEEE80211G, 81, 1, 13, 1, BW20 },
@@ -2300,8 +2176,7 @@
 		{ -1, 0, 0, 0, 0, BW20 }
 	};
 
-	modes = wpa_drv_get_hw_feature_data(wpa_s, &num_modes, &flags);
-	if (modes == NULL) {
+	if (wpa_s->hw.modes == NULL) {
 		wpa_printf(MSG_DEBUG, "P2P: Driver did not support fetching "
 			   "of all supported channels; assume dualband "
 			   "support");
@@ -2315,7 +2190,7 @@
 		u8 ch;
 		struct p2p_reg_class *reg = NULL;
 
-		mode = get_mode(modes, num_modes, o->mode);
+		mode = get_mode(wpa_s->hw.modes, wpa_s->hw.num_modes, o->mode);
 		if (mode == NULL)
 			continue;
 		for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
@@ -2348,8 +2223,6 @@
 
 	chan->reg_classes = cla;
 
-	ieee80211_sta_free_hw_features(modes, num_modes);
-
 	return 0;
 }
 
@@ -2381,25 +2254,10 @@
 	struct p2p_config p2p;
 	unsigned int r;
 	int i;
-#ifdef ANDROID_BRCM_P2P_PATCH
-	char buf[200];
-#endif
 
 	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
 		return 0;
 
-#ifdef CONFIG_CLIENT_MLME
-	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)) {
-		wpa_s->mlme.public_action_cb = p2p_rx_action_mlme;
-		wpa_s->mlme.public_action_cb_ctx = wpa_s;
-	}
-#endif /* CONFIG_CLIENT_MLME */
-
-	if (wpa_drv_disable_11b_rates(wpa_s, 1) < 0) {
-		wpa_printf(MSG_DEBUG, "P2P: Failed to disable 11b rates");
-		/* Continue anyway; this is not really a fatal error */
-	}
-
 	if (global->p2p)
 		return 0;
 
@@ -2445,20 +2303,8 @@
 	p2p.invitation_result = wpas_invitation_result;
 	p2p.get_noa = wpas_get_noa;
 
-#ifdef ANDROID_BRCM_P2P_PATCH
-	/* P2P_ADDR: Using p2p_dev_addr to hold the actual p2p device address incase if
-	 * we are not using the primary interface for p2p operations.
-	 */
-	wpa_drv_driver_cmd(wpa_s,  "P2P_DEV_ADDR", buf, sizeof(buf));	
-	os_memcpy(p2p.p2p_dev_addr, buf, ETH_ALEN);
-	os_memcpy(wpa_s->global->p2p_dev_addr, buf, ETH_ALEN);
-	os_memcpy(p2p.dev_addr, buf, ETH_ALEN);
-	wpa_printf(MSG_DEBUG, "P2P: Device address ("MACSTR")", MAC2STR(p2p.p2p_dev_addr));
-#else
 	os_memcpy(wpa_s->global->p2p_dev_addr, wpa_s->own_addr, ETH_ALEN);
-#endif
-
-	os_memcpy(p2p.dev_addr, wpa_s->own_addr, ETH_ALEN);
+	os_memcpy(p2p.dev_addr, wpa_s->global->p2p_dev_addr, ETH_ALEN);
 	p2p.dev_name = wpa_s->conf->device_name;
 	p2p.manufacturer = wpa_s->conf->manufacturer;
 	p2p.model_name = wpa_s->conf->model_name;
@@ -2564,11 +2410,16 @@
 {
 	if (wpa_s->driver && wpa_s->drv_priv)
 		wpa_drv_probe_req_report(wpa_s, 0);
+
+	if (wpa_s->go_params) {
+		/* Clear any stored provisioning info */
+		p2p_clear_provisioning_info(
+			wpa_s->global->p2p,
+			wpa_s->go_params->peer_interface_addr);
+	}
+
 	os_free(wpa_s->go_params);
 	wpa_s->go_params = NULL;
-	wpabuf_free(wpa_s->pending_action_tx);
-	wpa_s->pending_action_tx = NULL;
-	eloop_cancel_timeout(wpas_send_action_cb, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
 	wpa_s->p2p_long_listen = 0;
@@ -2656,6 +2507,9 @@
 				 int go_intent, const u8 *own_interface_addr,
 				 unsigned int force_freq, int persistent_group)
 {
+	if (persistent_group && wpa_s->conf->persistent_reconnect)
+		persistent_group = 2;
+
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
 		return wpa_drv_p2p_connect(wpa_s, peer_addr, wps_method,
 					   go_intent, own_interface_addr,
@@ -2674,6 +2528,9 @@
 				int go_intent, const u8 *own_interface_addr,
 				unsigned int force_freq, int persistent_group)
 {
+	if (persistent_group && wpa_s->conf->persistent_reconnect)
+		persistent_group = 2;
+
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT)
 		return -1;
 
@@ -2756,7 +2613,6 @@
 		wpa_s->pending_pd_before_join = 1;
 
 		switch (wpa_s->pending_join_wps_method) {
-		case WPS_PIN_LABEL:
 		case WPS_PIN_DISPLAY:
 			method = WPS_CONFIG_KEYPAD;
 			break;
@@ -2771,9 +2627,24 @@
 			break;
 		}
 
+		if ((p2p_get_provisioning_info(wpa_s->global->p2p,
+					       wpa_s->pending_join_dev_addr) ==
+		     method)) {
+			/*
+			 * We have already performed provision discovery for
+			 * joining the group. Proceed directly to join
+			 * operation without duplicated provision discovery. */
+			wpa_printf(MSG_DEBUG, "P2P: Provision discovery "
+				   "with " MACSTR " already done - proceed to "
+				   "join",
+				   MAC2STR(wpa_s->pending_join_dev_addr));
+			wpa_s->pending_pd_before_join = 0;
+			goto start;
+		}
+
 		if (p2p_prov_disc_req(wpa_s->global->p2p,
-				      wpa_s->pending_join_dev_addr, method, 1)
-		    < 0) {
+				      wpa_s->pending_join_dev_addr, method, 1,
+				      freq) < 0) {
 			wpa_printf(MSG_DEBUG, "P2P: Failed to send Provision "
 				   "Discovery Request before joining an "
 				   "existing group");
@@ -2806,6 +2677,7 @@
 	int ret;
 	struct wpa_driver_scan_params params;
 	struct wpabuf *wps_ie, *ies;
+	size_t ielen;
 
 	os_memset(&params, 0, sizeof(params));
 
@@ -2822,7 +2694,8 @@
 		return;
 	}
 
-	ies = wpabuf_alloc(wpabuf_len(wps_ie) + 100);
+	ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+	ies = wpabuf_alloc(wpabuf_len(wps_ie) + ielen);
 	if (ies == NULL) {
 		wpabuf_free(wps_ie);
 		wpas_p2p_scan_res_join(wpa_s, NULL);
@@ -2833,6 +2706,7 @@
 
 	p2p_scan_ie(wpa_s->global->p2p, ies);
 
+	params.p2p_probe = 1;
 	params.extra_ies = wpabuf_head(ies);
 	params.extra_ies_len = wpabuf_len(ies);
 
@@ -2841,10 +2715,7 @@
 	 * the new scan results become available.
 	 */
 	wpa_s->scan_res_handler = wpas_p2p_scan_res_join;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		ret = ieee80211_sta_req_scan(wpa_s, &params);
-	else
-		ret = wpa_drv_scan(wpa_s, &params);
+	ret = wpa_drv_scan(wpa_s, &params);
 
 	wpabuf_free(ies);
 
@@ -2938,6 +2809,7 @@
 	u8 bssid[ETH_ALEN];
 	int ret = 0;
 	enum wpa_driver_if_type iftype;
+	const u8 *if_addr;
 
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
@@ -3033,46 +2905,34 @@
 
 	wpa_s->create_p2p_iface = wpas_p2p_create_iface(wpa_s);
 
-	if (!wpa_s->create_p2p_iface) {
-		if (auth) {
-			if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
-						 go_intent, wpa_s->own_addr,
-						 force_freq, persistent_group)
-			    < 0)
-				return -1;
-			return ret;
-		}
-		if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
-					  go_intent, wpa_s->own_addr,
-					  force_freq, persistent_group) < 0)
+	if (wpa_s->create_p2p_iface) {
+		/* Prepare to add a new interface for the group */
+		iftype = WPA_IF_P2P_GROUP;
+		if (go_intent == 15)
+			iftype = WPA_IF_P2P_GO;
+		if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
+			wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
+				   "interface for the group");
 			return -1;
-		return ret;
-	}
+		}
 
-	/* Prepare to add a new interface for the group */
-	iftype = WPA_IF_P2P_GROUP;
-	if (join)
-		iftype = WPA_IF_P2P_CLIENT;
-	else if (go_intent == 15)
-		iftype = WPA_IF_P2P_GO;
-	if (wpas_p2p_add_group_interface(wpa_s, iftype) < 0) {
-		wpa_printf(MSG_ERROR, "P2P: Failed to allocate a new "
-			   "interface for the group");
-		return -1;
-	}
+		if_addr = wpa_s->pending_interface_addr;
+	} else
+		if_addr = wpa_s->own_addr;
 
 	if (auth) {
 		if (wpas_p2p_auth_go_neg(wpa_s, peer_addr, wps_method,
-					 go_intent,
-					 wpa_s->pending_interface_addr,
+					 go_intent, if_addr,
 					 force_freq, persistent_group) < 0)
 			return -1;
 		return ret;
 	}
-	if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method, go_intent,
-				  wpa_s->pending_interface_addr,
-				  force_freq, persistent_group) < 0) {
-		wpas_p2p_remove_pending_group_interface(wpa_s);
+
+	if (wpas_p2p_start_go_neg(wpa_s, peer_addr, wps_method,
+				  go_intent, if_addr, force_freq,
+				  persistent_group) < 0) {
+		if (wpa_s->create_p2p_iface)
+			wpas_p2p_remove_pending_group_interface(wpa_s);
 		return -1;
 	}
 	return ret;
@@ -3093,9 +2953,6 @@
 {
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
-	wpa_s->roc_waiting_drv_freq = 0;
-	wpa_s->off_channel_freq = freq;
-	wpas_send_action_cb(wpa_s, NULL);
 	if (wpa_s->off_channel_freq == wpa_s->pending_listen_freq) {
 		p2p_listen_cb(wpa_s->global->p2p, wpa_s->pending_listen_freq,
 			      wpa_s->pending_listen_duration);
@@ -3133,7 +2990,6 @@
 	wpa_printf(MSG_DEBUG, "P2P: Cancel remain-on-channel callback "
 		   "(p2p_long_listen=%d ms pending_action_tx=%p)",
 		   wpa_s->p2p_long_listen, wpa_s->pending_action_tx);
-	wpa_s->off_channel_freq = 0;
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return;
 	if (p2p_listen_end(wpa_s->global->p2p, freq) > 0)
@@ -3186,9 +3042,9 @@
 }
 
 
-static void wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
-				    struct p2p_go_neg_results *params,
-				    int freq)
+static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
+				   struct p2p_go_neg_results *params,
+				   int freq)
 {
 	u8 bssid[ETH_ALEN];
 	int res;
@@ -3249,7 +3105,16 @@
 		wpa_printf(MSG_DEBUG, "P2P: Force GO on the channel we are "
 			   "already using on a shared interface");
 		params->freq = res;
+	} else if (res > 0 && freq != res &&
+		   !(wpa_s->drv_flags &
+		     WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+		wpa_printf(MSG_DEBUG, "P2P: Cannot start P2P group on %u MHz "
+			   "while connected on another channel (%u MHz)",
+			   freq, res);
+		return -1;
 	}
+
+	return 0;
 }
 
 
@@ -3294,11 +3159,9 @@
 	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
 		return -1;
 
-#ifdef ANDROID_BRCM_P2P_PATCH
 	/* Make sure we are not running find during connection establishment */
-	wpa_printf(MSG_DEBUG, "P2P: Stopping P2P FIND, if any");
+	wpa_printf(MSG_DEBUG, "P2P: Stop any on-going P2P FIND");
 	wpas_p2p_stop_find(wpa_s);
-#endif
 
 	if (freq == 2) {
 		wpa_printf(MSG_DEBUG, "P2P: Request to start GO on 2.4 GHz "
@@ -3346,7 +3209,8 @@
 		return -1;
 	}
 
-	wpas_p2p_init_go_params(wpa_s, &params, freq);
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq))
+		return -1;
 	p2p_go_params(wpa_s->global->p2p, &params);
 	params.persistent_group = persistent_group;
 
@@ -3429,7 +3293,8 @@
 	if (ssid->mode != WPAS_MODE_P2P_GO)
 		return -1;
 
-	wpas_p2p_init_go_params(wpa_s, &params, freq);
+	if (wpas_p2p_init_go_params(wpa_s, &params, freq))
+		return -1;
 
 	params.role_go = 1;
 	if (ssid->passphrase == NULL ||
@@ -3460,6 +3325,11 @@
 	struct wpa_supplicant *wpa_s = ctx;
 	if (wpa_s->ap_iface) {
 		struct hostapd_data *hapd = wpa_s->ap_iface->bss[0];
+		if (!(hapd->conf->p2p & P2P_GROUP_OWNER)) {
+			wpabuf_free(beacon_ies);
+			wpabuf_free(proberesp_ies);
+			return;
+		}
 		if (beacon_ies) {
 			wpabuf_free(hapd->p2p_beacon_ie);
 			hapd->p2p_beacon_ie = beacon_ies;
@@ -3503,7 +3373,10 @@
 	if (cfg == NULL)
 		return NULL;
 
-	cfg->persistent_group = persistent_group;
+	if (persistent_group && wpa_s->conf->persistent_reconnect)
+		cfg->persistent_group = 2;
+	else if (persistent_group)
+		cfg->persistent_group = 1;
 	os_memcpy(cfg->interface_addr, wpa_s->own_addr, ETH_ALEN);
 	if (wpa_s->max_stations &&
 	    wpa_s->max_stations < wpa_s->conf->max_num_sta)
@@ -3533,6 +3406,9 @@
 		return;
 	}
 
+	/* Clear any stored provisioning info */
+	p2p_clear_provisioning_info(wpa_s->global->p2p, peer_addr);
+
 	eloop_cancel_timeout(wpas_p2p_group_formation_timeout, wpa_s->parent,
 			     NULL);
 	if (wpa_s->global->p2p)
@@ -3551,35 +3427,44 @@
 			   "provisioning not in progress");
 		return;
 	}
+
+	if (wpa_s->go_params) {
+		p2p_clear_provisioning_info(
+			wpa_s->global->p2p,
+			wpa_s->go_params->peer_interface_addr);
+	}
+
 	wpas_notify_p2p_wps_failed(wpa_s, fail);
 }
 
 
 int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
-		       const char *config_method)
+		       const char *config_method, int join)
 {
 	u16 config_methods;
 
-	if (os_strcmp(config_method, "display") == 0)
+	if (os_strncmp(config_method, "display", 7) == 0)
 		config_methods = WPS_CONFIG_DISPLAY;
-	else if (os_strcmp(config_method, "keypad") == 0)
+	else if (os_strncmp(config_method, "keypad", 6) == 0)
 		config_methods = WPS_CONFIG_KEYPAD;
-	else if (os_strcmp(config_method, "pbc") == 0 ||
-		 os_strcmp(config_method, "pushbutton") == 0)
+	else if (os_strncmp(config_method, "pbc", 3) == 0 ||
+		 os_strncmp(config_method, "pushbutton", 10) == 0)
 		config_methods = WPS_CONFIG_PUSHBUTTON;
-	else
+	else {
+		wpa_printf(MSG_DEBUG, "P2P: Unknown config method");
 		return -1;
+	}
 
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
 		return wpa_drv_p2p_prov_disc_req(wpa_s, peer_addr,
-						 config_methods);
+						 config_methods, join);
 	}
 
 	if (wpa_s->global->p2p == NULL || wpa_s->global->p2p_disabled)
 		return -1;
 
 	return p2p_prov_disc_req(wpa_s->global->p2p, peer_addr,
-				 config_methods, 0);
+				 config_methods, join, 0);
 }
 
 
@@ -3626,6 +3511,7 @@
 	wpa_s->p2p_long_listen = 0;
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_p2p_join_scan, wpa_s, NULL);
+	wpa_s->p2p_cb_on_scan_complete = 0;
 
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_MGMT) {
 		wpa_drv_p2p_stop_find(wpa_s);
@@ -3666,6 +3552,14 @@
 	eloop_cancel_timeout(wpas_p2p_long_listen_timeout, wpa_s, NULL);
 	wpa_s->p2p_long_listen = 0;
 
+	/*
+	 * Stop previous find/listen operation to avoid trying to request a new
+	 * remain-on-channel operation while the driver is still running the
+	 * previous one.
+	 */
+	if (wpa_s->global->p2p)
+		p2p_stop_find(wpa_s->global->p2p);
+
 	res = wpas_p2p_listen_start(wpa_s, timeout * 1000);
 	if (res == 0 && timeout * 1000 > wpa_s->max_remain_on_chan) {
 		wpa_s->p2p_long_listen = timeout * 1000;
@@ -3692,9 +3586,6 @@
 		return -1;
 
 	p2p_ie = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
-#ifdef ANDROID_BRCM_P2P_PATCH
-	if (p2p_ie == NULL) return -1;
-#endif
 	ret = p2p_assoc_req_ie(wpa_s->global->p2p, bss->bssid, buf, len,
 			       p2p_group, p2p_ie);
 	wpabuf_free(p2p_ie);
@@ -3704,6 +3595,7 @@
 
 
 int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
+			  const u8 *dst, const u8 *bssid,
 			  const u8 *ie, size_t ie_len)
 {
 	if (wpa_s->global->p2p_disabled)
@@ -3711,7 +3603,8 @@
 	if (wpa_s->global->p2p == NULL)
 		return 0;
 
-	return p2p_probe_req_rx(wpa_s->global->p2p, addr, ie, ie_len);
+	return p2p_probe_req_rx(wpa_s->global->p2p, addr, dst, bssid,
+				ie, ie_len);
 }
 
 
@@ -3744,6 +3637,11 @@
 {
 	p2p_group_deinit(wpa_s->p2p_group);
 	wpa_s->p2p_group = NULL;
+
+	wpa_s->ap_configured_cb = NULL;
+	wpa_s->ap_configured_cb_ctx = NULL;
+	wpa_s->ap_configured_cb_data = NULL;
+	wpa_s->connect_without_scan = NULL;
 }
 
 
@@ -3767,7 +3665,7 @@
 {
 	enum p2p_invite_role role;
 	u8 *bssid = NULL;
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
 	int go;
 #endif
 
@@ -3779,7 +3677,7 @@
 			return -1;
 		}
 
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
 	wpa_printf(MSG_DEBUG, "P2P: Check to see if already runnig persistent wpa_s %p grp ssid %s ssid_len %d", wpa_s, ssid->ssid, ssid->ssid_len);
 	if(wpas_get_p2p_group(wpa_s, ssid->ssid, ssid->ssid_len, &go)) {
 		wpa_printf(MSG_DEBUG, "P2P: We are already running persistent group");
@@ -3802,7 +3700,7 @@
 			bssid = wpa_s->pending_interface_addr;
 		} else
 			bssid = wpa_s->own_addr;
-#ifdef ANDROID_BRCM_P2P_PATCH
+#ifdef ANDROID_P2P
 	}
 #endif
 	} else {
@@ -3853,7 +3751,7 @@
 		role = P2P_INVITE_ROLE_ACTIVE_GO;
 		bssid = wpa_s->own_addr;
 		if (go_dev_addr == NULL)
-			go_dev_addr = wpa_s->parent->own_addr;
+			go_dev_addr = wpa_s->global->p2p_dev_addr;
 	} else {
 		role = P2P_INVITE_ROLE_CLIENT;
 		if (wpa_s->wpa_state < WPA_ASSOCIATED) {
@@ -3889,6 +3787,7 @@
 	u8 go_dev_addr[ETH_ALEN];
 	int network_id = -1;
 	int persistent;
+	int freq;
 
 	if (!wpa_s->show_group_started || !ssid)
 		return;
@@ -3906,28 +3805,22 @@
 	if (wpa_s->global->p2p_group_formation == wpa_s)
 		wpa_s->global->p2p_group_formation = NULL;
 
+	freq = wpa_s->current_bss ? wpa_s->current_bss->freq :
+		(int) wpa_s->assoc_freq;
 	if (ssid->passphrase == NULL && ssid->psk_set) {
 		char psk[65];
 		wpa_snprintf_hex(psk, sizeof(psk), ssid->psk, 32);
 		wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
 			"%s client ssid=\"%s\" freq=%d psk=%s go_dev_addr="
 			MACSTR "%s",
-		#ifdef ANDROID_BRCM_P2P_PATCH
-			wpa_s->ifname, ssid_txt, wpa_s->current_bss->freq, psk,
-		#else
-			wpa_s->ifname, ssid_txt, ssid->frequency, psk,
-		#endif
+			wpa_s->ifname, ssid_txt, freq, psk,
 			MAC2STR(go_dev_addr),
 			persistent ? " [PERSISTENT]" : "");
 	} else {
 		wpa_msg(wpa_s->parent, MSG_INFO, P2P_EVENT_GROUP_STARTED
 			"%s client ssid=\"%s\" freq=%d passphrase=\"%s\" "
 			"go_dev_addr=" MACSTR "%s",
-		#ifdef ANDROID_BRCM_P2P_PATCH
-			wpa_s->ifname, ssid_txt, wpa_s->current_bss->freq,
-		#else
-			wpa_s->ifname, ssid_txt, ssid->frequency,
-		#endif
+			wpa_s->ifname, ssid_txt, freq,
 			ssid->passphrase ? ssid->passphrase : "",
 			MAC2STR(go_dev_addr),
 			persistent ? " [PERSISTENT]" : "");
@@ -3974,11 +3867,19 @@
 }
 
 
+static int wpas_p2p_is_client(struct wpa_supplicant *wpa_s)
+{
+	return wpa_s->current_ssid != NULL &&
+		wpa_s->current_ssid->p2p_group &&
+		wpa_s->current_ssid->mode == WPAS_MODE_INFRA;
+}
+
+
 static void wpas_p2p_group_idle_timeout(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 
-	if (wpa_s->conf->p2p_group_idle == 0) {
+	if (wpa_s->conf->p2p_group_idle == 0 && !wpas_p2p_is_client(wpa_s)) {
 		wpa_printf(MSG_DEBUG, "P2P: Ignore group idle timeout - "
 			   "disabled");
 		return;
@@ -3993,17 +3894,24 @@
 
 static void wpas_p2p_set_group_idle_timeout(struct wpa_supplicant *wpa_s)
 {
-	eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
-	if (wpa_s->conf->p2p_group_idle == 0)
-		return;
+	unsigned int timeout;
 
+	eloop_cancel_timeout(wpas_p2p_group_idle_timeout, wpa_s, NULL);
 	if (wpa_s->current_ssid == NULL || !wpa_s->current_ssid->p2p_group)
 		return;
 
+	timeout = wpa_s->conf->p2p_group_idle;
+	if (wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+	    (timeout == 0 || timeout > P2P_MAX_CLIENT_IDLE))
+	    timeout = P2P_MAX_CLIENT_IDLE;
+
+	if (timeout == 0)
+		return;
+
 	wpa_printf(MSG_DEBUG, "P2P: Set P2P group idle timeout to %u seconds",
-		   wpa_s->conf->p2p_group_idle);
-	eloop_register_timeout(wpa_s->conf->p2p_group_idle, 0,
-			       wpas_p2p_group_idle_timeout, wpa_s, NULL);
+		   timeout);
+	eloop_register_timeout(timeout, 0, wpas_p2p_group_idle_timeout,
+			       wpa_s, NULL);
 }
 
 
@@ -4018,23 +3926,6 @@
 	p2p_deauth_notif(wpa_s->global->p2p, bssid, reason_code, ie, ie_len);
 }
 
-#ifdef ANDROID_BRCM_P2P_PATCH
-void wpas_p2p_group_remove_notif(struct wpa_supplicant *wpa_s, u16 reason_code)
-{
-	if(wpa_s->global->p2p_disabled)
-		return;
-
-	/* If we are running a P2P Client and we received a Deauth/Disassoc from the Go, then remove 
-	   the virutal interface on which the client is running. */
-	if((wpa_s != wpa_s->parent) && (wpa_s->p2p_group_interface == P2P_GROUP_INTERFACE_CLIENT) && (wpa_s->key_mgmt != WPA_KEY_MGMT_WPS)) {
-
-		wpa_printf(MSG_DEBUG, "P2P: [EVENT_DEAUTH] Removing P2P_CLIENT virtual intf.");
-		wpa_supplicant_cancel_scan(wpa_s);
-		wpa_s->removal_reason = P2P_GROUP_REMOVAL_UNAVAILABLE;
-		wpas_p2p_group_delete(wpa_s);
-	}
-}
-#endif
 
 void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			     u16 reason_code, const u8 *ie, size_t ie_len)
@@ -4168,49 +4059,10 @@
 {
 	if (!wpa_s->ap_iface)
 		return -1;
-
-#ifdef ANDROID_BRCM_P2P_PATCH
-#define NOA_BUF_LEN 50
-	/* Now get the NOA descriptor from the driver */
-	hostapd_p2p_set_noa(wpa_s->ap_iface->bss[0], count, start,
-						   duration);
-	if(count > 0) {
-		u8 noa[NOA_BUF_LEN];
-		int noa_len = 0;
-		wpa_printf(MSG_DEBUG, "P2P: Get NOA attribute from driver");
-		noa_len = wpa_drv_get_noa(wpa_s, noa, NOA_BUF_LEN);
-		if (noa_len) {
-			wpa_printf(MSG_DEBUG, "P2P: Now Update NOA attributes in Beacons/ProbeRsps noa_len %d", noa_len);
-			return p2p_group_notif_noa(wpa_s->p2p_group, noa, noa_len);
-		}
-		else
-			return 0;
-	}
-	else
-		return 0;
-#else
 	return hostapd_p2p_set_noa(wpa_s->ap_iface->bss[0], count, start,
 				   duration);
-#endif
 }
 
-#ifdef ANDROID_BRCM_P2P_PATCH
-int wpas_drv_set_p2p_powersave(struct wpa_supplicant *wpa_s, int legacy_ps, int opp_ps, int ctwindow)
-{
-#define NOA_BUF_LEN 50
-	u8 noa[NOA_BUF_LEN];
-	int noa_len = 0;
-	wpa_drv_set_p2p_powersave(wpa_s, legacy_ps, opp_ps, ctwindow);
-	wpa_printf(MSG_DEBUG, "P2P: Get NOA attribute from driver");
-	noa_len = wpa_drv_get_noa(wpa_s, noa, NOA_BUF_LEN);
-	if (noa_len) {
-		wpa_printf(MSG_DEBUG, "P2P: Now Update NOA attributes in Beacons/ProbeRsps noa_len %d", noa_len);
-		return p2p_group_notif_noa(wpa_s->p2p_group, noa, noa_len);
-	}
-	else
-		return 0;
-}
-#endif
 
 int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled)
 {
@@ -4305,7 +4157,9 @@
 void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s)
 {
 	wpas_p2p_disable_cross_connect(wpa_s);
-	if (!wpa_s->ap_iface)
+	if (!wpa_s->ap_iface &&
+	    !eloop_is_timeout_registered(wpas_p2p_group_idle_timeout,
+					 wpa_s, NULL))
 		wpas_p2p_set_group_idle_timeout(wpa_s);
 }
 
@@ -4496,3 +4350,60 @@
 
 	return 0;
 }
+
+
+int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->global->p2p_disabled || wpa_s->global->p2p == NULL)
+		return 0;
+
+	return p2p_in_progress(wpa_s->global->p2p);
+}
+
+
+void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid)
+
+{
+	if (wpa_s->p2p_in_provisioning && ssid->p2p_group &&
+	    eloop_cancel_timeout(wpas_p2p_group_formation_timeout,
+				 wpa_s->parent, NULL) > 0) {
+		wpa_printf(MSG_DEBUG, "P2P: Canceled group formation due to "
+			   "P2P group network getting removed");
+		wpas_p2p_group_formation_timeout(wpa_s->parent, NULL);
+	}
+}
+
+
+struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
+					  const u8 *addr)
+{
+	struct wpa_ssid *s;
+	size_t i;
+
+	for (s = wpa_s->conf->ssid; s; s = s->next) {
+		if (s->disabled != 2)
+			continue;
+		if (os_memcmp(s->bssid, addr, ETH_ALEN) == 0)
+			return s; /* peer is GO in the persistent group */
+		if (s->mode != WPAS_MODE_P2P_GO || s->p2p_client_list == NULL)
+			continue;
+		for (i = 0; i < s->num_p2p_clients; i++) {
+			if (os_memcmp(s->p2p_client_list + i * ETH_ALEN,
+				      addr, ETH_ALEN) == 0)
+				return s; /* peer is P2P client in persistent
+					   * group */
+		}
+	}
+
+	return NULL;
+}
+
+
+void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
+				       const u8 *addr)
+{
+	if (addr == NULL)
+		return;
+	wpas_p2p_add_persistent_group_client(wpa_s, addr);
+}
diff --git a/wpa_supplicant/p2p_supplicant.h b/wpa_supplicant/p2p_supplicant.h
index 5be9ba2..6fe1e1d 100644
--- a/wpa_supplicant/p2p_supplicant.h
+++ b/wpa_supplicant/p2p_supplicant.h
@@ -31,6 +31,10 @@
 				   unsigned int freq, unsigned int duration);
 void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
 					  unsigned int freq);
+#ifdef ANDROID_P2P
+void wpas_p2p_handle_frequency_conflicts(struct wpa_supplicant *wpa_s,
+                                          int freq);
+#endif
 int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
 int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
 		       int freq);
@@ -43,7 +47,7 @@
 void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
 			  int registrar);
 int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
-		       const char *config_method);
+		       const char *config_method, int join);
 void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
 				const u8 *data, size_t data_len,
 				enum p2p_send_action_result result);
@@ -58,6 +62,7 @@
 int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
 			  u8 *buf, size_t len, int p2p_group);
 int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
+			  const u8 *dst, const u8 *bssid,
 			  const u8 *ie, size_t ie_len);
 void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
 			const u8 *sa, const u8 *bssid,
@@ -72,17 +77,18 @@
 void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
 			const u8 *dev_addr, const u8 *pri_dev_type,
 			const char *dev_name, u16 supp_config_methods,
-			u8 dev_capab, u8 group_capab);
+			u8 dev_capab, u8 group_capab, const u8 *group_id,
+			size_t group_id_len);
 void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods);
 void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
 		     u16 update_indic, const u8 *tlvs, size_t tlvs_len);
 void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
 		      const u8 *tlvs, size_t tlvs_len);
-void * wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
-			   const struct wpabuf *tlvs);
-void * wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
-				u8 version, const char *query);
-int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, void *req);
+u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+			const struct wpabuf *tlvs);
+u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
+			     u8 version, const char *query);
+int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req);
 void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
 			  const u8 *dst, u8 dialog_token,
 			  const struct wpabuf *resp_tlvs);
@@ -108,12 +114,6 @@
 			unsigned int interval);
 void wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			   u16 reason_code, const u8 *ie, size_t ie_len);
-#ifdef ANDROID_BRCM_P2P_PATCH
-void wpas_p2p_group_remove_notif(struct wpa_supplicant *wpa_s,
-				u16 reason_code);
-int wpas_drv_set_p2p_powersave(struct wpa_supplicant *wpa_s, int legacy_ps,
-				int opp_ps, int ctwindow);
-#endif /* ANDROID_BRCM_P2P_PATCH */
 void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
 			     u16 reason_code, const u8 *ie, size_t ie_len);
 void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
@@ -132,5 +132,12 @@
 int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s);
 void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
 			 struct wps_event_fail *fail);
+int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s);
+void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid);
+struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
+					  const u8 *addr);
+void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
+				       const u8 *addr);
 
 #endif /* P2P_SUPPLICANT_H */
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index bb64e9a..e453cfc 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -20,7 +20,6 @@
 #include "config.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
-#include "mlme.h"
 #include "wps_supplicant.h"
 #include "p2p_supplicant.h"
 #include "p2p/p2p.h"
@@ -52,13 +51,13 @@
 
 
 #ifdef CONFIG_WPS
-static int wpas_wps_in_use(struct wpa_config *conf,
+static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
 			   enum wps_request_type *req_type)
 {
 	struct wpa_ssid *ssid;
 	int wps = 0;
 
-	for (ssid = conf->ssid; ssid; ssid = ssid->next) {
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
 		if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
 			continue;
 
@@ -71,6 +70,14 @@
 			return 2;
 	}
 
+#ifdef CONFIG_P2P
+	wpa_s->wps->dev.p2p = 1;
+	if (!wps) {
+		wps = 1;
+		*req_type = WPS_REQ_ENROLLEE_INFO;
+	}
+#endif /* CONFIG_P2P */
+
 	return wps;
 }
 #endif /* CONFIG_WPS */
@@ -192,16 +199,71 @@
 
 	wpa_supplicant_notify_scanning(wpa_s, 1);
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		ret = ieee80211_sta_req_scan(wpa_s, params);
-	else
-		ret = wpa_drv_scan(wpa_s, params);
-
+	ret = wpa_drv_scan(wpa_s, params);
 	if (ret) {
 		wpa_supplicant_notify_scanning(wpa_s, 0);
 		wpas_notify_scan_done(wpa_s, 0);
-	} else
+	} else {
 		wpa_s->scan_runs++;
+		wpa_s->normal_scans++;
+	}
+
+	return ret;
+}
+
+
+static void
+wpa_supplicant_delayed_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Starting delayed sched scan");
+
+	if (wpa_supplicant_req_sched_scan(wpa_s))
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+static void
+wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Sched scan timeout - stopping it");
+
+	wpa_s->sched_scan_timed_out = 1;
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+}
+
+
+static int
+wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+				struct wpa_driver_scan_params *params,
+				int interval)
+{
+	int ret;
+
+	wpa_supplicant_notify_scanning(wpa_s, 1);
+	ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
+	if (ret)
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+	else
+		wpa_s->sched_scanning = 1;
+
+	return ret;
+}
+
+
+static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	int ret;
+
+	ret = wpa_drv_stop_sched_scan(wpa_s);
+	if (ret) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "stopping sched_scan failed!");
+		/* TODO: what to do if stopping fails? */
+		return -1;
+	}
 
 	return ret;
 }
@@ -240,16 +302,128 @@
 }
 
 
+static void wpa_supplicant_optimize_freqs(
+	struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params)
+{
+#ifdef CONFIG_P2P
+	if (params->freqs == NULL && wpa_s->p2p_in_provisioning &&
+	    wpa_s->go_params) {
+		/* Optimize provisioning state scan based on GO information */
+		if (wpa_s->p2p_in_provisioning < 5 &&
+		    wpa_s->go_params->freq > 0) {
+			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));
+			if (params->freqs)
+				params->freqs[0] = wpa_s->go_params->freq;
+		} else if (wpa_s->p2p_in_provisioning < 8 &&
+			   wpa_s->go_params->freq_list[0]) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common "
+				"channels");
+			int_array_concat(&params->freqs,
+					 wpa_s->go_params->freq_list);
+			if (params->freqs)
+				int_array_sort_unique(params->freqs);
+		}
+		wpa_s->p2p_in_provisioning++;
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS
+	if (params->freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
+		/*
+		 * Optimize post-provisioning scan based on channel used
+		 * during provisioning.
+		 */
+		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));
+		if (params->freqs)
+			params->freqs[0] = wpa_s->wps_freq;
+		wpa_s->after_wps--;
+	}
+
+#endif /* CONFIG_WPS */
+}
+
+
+#ifdef CONFIG_INTERWORKING
+static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
+					   struct wpabuf *buf)
+{
+	if (wpa_s->conf->interworking == 0)
+		return;
+
+	wpabuf_put_u8(buf, WLAN_EID_EXT_CAPAB);
+	wpabuf_put_u8(buf, 4);
+	wpabuf_put_u8(buf, 0x00);
+	wpabuf_put_u8(buf, 0x00);
+	wpabuf_put_u8(buf, 0x00);
+	wpabuf_put_u8(buf, 0x80); /* Bit 31 - Interworking */
+
+	wpabuf_put_u8(buf, WLAN_EID_INTERWORKING);
+	wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 :
+		      1 + ETH_ALEN);
+	wpabuf_put_u8(buf, wpa_s->conf->access_network_type);
+	/* No Venue Info */
+	if (!is_zero_ether_addr(wpa_s->conf->hessid))
+		wpabuf_put_data(buf, wpa_s->conf->hessid, ETH_ALEN);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+static struct wpabuf *
+wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s,
+			 struct wpa_driver_scan_params *params)
+{
+	struct wpabuf *extra_ie = NULL;
+#ifdef CONFIG_WPS
+	int wps = 0;
+	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_INTERWORKING
+	if (wpa_s->conf->interworking &&
+	    wpabuf_resize(&extra_ie, 100) == 0)
+		wpas_add_interworking_elements(wpa_s, extra_ie);
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_WPS
+	wps = wpas_wps_in_use(wpa_s, &req_type);
+
+	if (wps) {
+		struct wpabuf *wps_ie;
+		wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
+						wpa_s->wps->uuid, req_type,
+						0, NULL);
+		if (wps_ie) {
+			if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0)
+				wpabuf_put_buf(extra_ie, wps_ie);
+			wpabuf_free(wps_ie);
+		}
+	}
+
+#ifdef CONFIG_P2P
+	if (wps) {
+		size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+		if (wpabuf_resize(&extra_ie, ielen) == 0)
+			wpas_p2p_scan_ie(wpa_s, extra_ie);
+	}
+#endif /* CONFIG_P2P */
+
+#endif /* CONFIG_WPS */
+
+	return extra_ie;
+}
+
+
 static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
 {
 	struct wpa_supplicant *wpa_s = eloop_ctx;
 	struct wpa_ssid *ssid;
 	int scan_req = 0, ret;
-	struct wpabuf *wps_ie = NULL;
-#ifdef CONFIG_WPS
-	int wps = 0;
-	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
-#endif /* CONFIG_WPS */
+	struct wpabuf *extra_ie;
 	struct wpa_driver_scan_params params;
 	size_t max_ssids;
 	enum wpa_states prev_state;
@@ -284,8 +458,21 @@
 		return;
 	}
 
-	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) ||
-	    wpa_s->conf->ap_scan == 2)
+#ifdef CONFIG_P2P
+	if (wpas_p2p_in_progress(wpa_s)) {
+		if (wpa_s->wpa_state == WPA_SCANNING) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
+				"while P2P operation is in progress");
+			wpa_supplicant_req_scan(wpa_s, 5, 0);
+		} else {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Do not request scan while "
+				"P2P operation is in progress");
+		}
+		return;
+	}
+#endif /* CONFIG_P2P */
+
+	if (wpa_s->conf->ap_scan == 2)
 		max_ssids = 1;
 	else {
 		max_ssids = wpa_s->max_scan_ssids;
@@ -293,10 +480,6 @@
 			max_ssids = WPAS_MAX_SCAN_SSIDS;
 	}
 
-#ifdef CONFIG_WPS
-	wps = wpas_wps_in_use(wpa_s->conf, &req_type);
-#endif /* CONFIG_WPS */
-
 	scan_req = wpa_s->scan_req;
 	wpa_s->scan_req = 0;
 
@@ -401,71 +584,8 @@
 			"SSID");
 	}
 
-#ifdef CONFIG_P2P
-	wpa_s->wps->dev.p2p = 1;
-	if (!wps) {
-		wps = 1;
-		req_type = WPS_REQ_ENROLLEE_INFO;
-	}
-
-	if (params.freqs == NULL && wpa_s->p2p_in_provisioning &&
-	    wpa_s->go_params) {
-		/* Optimize provisioning state scan based on GO information */
-		if (wpa_s->p2p_in_provisioning < 5 &&
-		    wpa_s->go_params->freq > 0) {
-			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));
-			if (params.freqs)
-				params.freqs[0] = wpa_s->go_params->freq;
-		} else if (wpa_s->p2p_in_provisioning < 8 &&
-			   wpa_s->go_params->freq_list[0]) {
-			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common "
-				"channels");
-			int_array_concat(&params.freqs,
-					 wpa_s->go_params->freq_list);
-			if (params.freqs)
-				int_array_sort_unique(params.freqs);
-		}
-		wpa_s->p2p_in_provisioning++;
-	}
-#endif /* CONFIG_P2P */
-
-#ifdef CONFIG_WPS
-	if (params.freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
-		/*
-		 * Optimize post-provisioning scan based on channel used
-		 * during provisioning.
-		 */
-		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));
-		if (params.freqs)
-			params.freqs[0] = wpa_s->wps_freq;
-		wpa_s->after_wps--;
-	}
-
-	if (wps) {
-		wps_ie = wps_build_probe_req_ie(wps == 2, &wpa_s->wps->dev,
-						wpa_s->wps->uuid, req_type,
-						0, NULL);
-		if (wps_ie) {
-			params.extra_ies = wpabuf_head(wps_ie);
-			params.extra_ies_len = wpabuf_len(wps_ie);
-		}
-	}
-#endif /* CONFIG_WPS */
-
-#ifdef CONFIG_P2P
-	if (wps_ie) {
-		if (wpabuf_resize(&wps_ie, 100) == 0) {
-			wpas_p2p_scan_ie(wpa_s, wps_ie);
-			params.extra_ies = wpabuf_head(wps_ie);
-			params.extra_ies_len = wpabuf_len(wps_ie);
-		}
-	}
-#endif /* CONFIG_P2P */
+	wpa_supplicant_optimize_freqs(wpa_s, &params);
+	extra_ie = wpa_supplicant_extra_ies(wpa_s, &params);
 
 	if (params.freqs == NULL && wpa_s->next_scan_freqs) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
@@ -477,10 +597,24 @@
 
 	params.filter_ssids = wpa_supplicant_build_filter_ssids(
 		wpa_s->conf, &params.num_filter_ssids);
+	if (extra_ie) {
+		params.extra_ies = wpabuf_head(extra_ie);
+		params.extra_ies_len = wpabuf_len(extra_ie);
+	}
+
+#ifdef CONFIG_P2P
+	if (wpa_s->p2p_in_provisioning) {
+		/*
+		 * The interface may not yet be in P2P mode, so we have to
+		 * explicitly request P2P probe to disable CCK rates.
+		 */
+		params.p2p_probe = 1;
+	}
+#endif /* CONFIG_P2P */
 
 	ret = wpa_supplicant_trigger_scan(wpa_s, &params);
 
-	wpabuf_free(wps_ie);
+	wpabuf_free(extra_ie);
 	os_free(params.freqs);
 	os_free(params.filter_ssids);
 
@@ -535,6 +669,215 @@
 
 
 /**
+ * wpa_supplicant_delayed_sched_scan - Request a delayed scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec: Number of seconds after which to scan
+ * @usec: Number of microseconds after which to scan
+ *
+ * This function is used to schedule periodic scans for neighboring
+ * access points after the specified time.
+ */
+int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
+				      int sec, int usec)
+{
+	if (!wpa_s->sched_scan_supported)
+		return -1;
+
+	eloop_register_timeout(sec, usec,
+			       wpa_supplicant_delayed_sched_scan_timeout,
+			       wpa_s, NULL);
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to schedule periodic scans for neighboring
+ * access points repeating the scan continuously.
+ */
+int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_driver_scan_params params;
+	enum wpa_states prev_state;
+	struct wpa_ssid *ssid;
+	struct wpabuf *wps_ie = NULL;
+	int ret;
+	unsigned int max_sched_scan_ssids;
+	int wildcard = 0;
+	int need_ssids;
+
+	if (!wpa_s->sched_scan_supported)
+		return -1;
+
+	if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
+		max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
+	else
+		max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
+	if (max_sched_scan_ssids < 1)
+		return -1;
+
+	if (wpa_s->sched_scanning) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning");
+		return 0;
+	}
+
+	need_ssids = 0;
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (!ssid->disabled && !ssid->scan_ssid) {
+			/* Use wildcard SSID to find this network */
+			wildcard = 1;
+		} else if (!ssid->disabled && ssid->ssid_len)
+			need_ssids++;
+	}
+	if (wildcard)
+		need_ssids++;
+
+	if (wpa_s->normal_scans < 3 &&
+	    (need_ssids <= wpa_s->max_scan_ssids ||
+	     wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) {
+		/*
+		 * When normal scan can speed up operations, use that for the
+		 * first operations before starting the sched_scan to allow
+		 * user space sleep more. We do this only if the normal scan
+		 * has functionality that is suitable for this or if the
+		 * sched_scan does not have better support for multiple SSIDs.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
+			"sched_scan for initial scans (normal_scans=%d)",
+			wpa_s->normal_scans);
+		return -1;
+	}
+
+	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 *
+					sizeof(struct wpa_driver_scan_filter));
+
+	prev_state = wpa_s->wpa_state;
+	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+	    wpa_s->wpa_state == WPA_INACTIVE)
+		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
+
+	/* Find the starting point from which to continue scanning */
+	ssid = wpa_s->conf->ssid;
+	if (wpa_s->prev_sched_ssid) {
+		while (ssid) {
+			if (ssid == wpa_s->prev_sched_ssid) {
+				ssid = ssid->next;
+				break;
+			}
+			ssid = ssid->next;
+		}
+	}
+
+	if (!ssid || !wpa_s->prev_sched_ssid) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
+
+		wpa_s->sched_scan_interval = 10;
+		wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
+		wpa_s->first_sched_scan = 1;
+		ssid = wpa_s->conf->ssid;
+		wpa_s->prev_sched_ssid = ssid;
+	}
+
+	if (wildcard) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan");
+		params.num_ssids++;
+	}
+
+	while (ssid) {
+		if (ssid->disabled)
+			goto next;
+
+		if (params.num_filter_ssids < wpa_s->max_match_sets &&
+		    params.filter_ssids && ssid->ssid && ssid->ssid_len) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s",
+				wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+			os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid,
+				  ssid->ssid, ssid->ssid_len);
+			params.filter_ssids[params.num_filter_ssids].ssid_len =
+				ssid->ssid_len;
+			params.num_filter_ssids++;
+		} else if (params.filter_ssids && ssid->ssid && ssid->ssid_len)
+		{
+			wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID "
+				"filter for sched_scan - drop filter");
+			os_free(params.filter_ssids);
+			params.filter_ssids = NULL;
+			params.num_filter_ssids = 0;
+		}
+
+		if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) {
+			if (params.num_ssids == max_sched_scan_ssids)
+				break; /* only room for broadcast SSID */
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"add to active scan ssid: %s",
+				wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+			params.ssids[params.num_ssids].ssid =
+				ssid->ssid;
+			params.ssids[params.num_ssids].ssid_len =
+				ssid->ssid_len;
+			params.num_ssids++;
+			if (params.num_ssids >= max_sched_scan_ssids) {
+				wpa_s->prev_sched_ssid = ssid;
+				break;
+			}
+		}
+
+	next:
+		wpa_s->prev_sched_ssid = ssid;
+		ssid = ssid->next;
+	}
+
+	if (params.num_filter_ssids == 0) {
+		os_free(params.filter_ssids);
+		params.filter_ssids = NULL;
+	}
+
+	if (wpa_s->wps)
+		wps_ie = wpa_supplicant_extra_ies(wpa_s, &params);
+
+	if (ssid || !wpa_s->first_sched_scan) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Starting sched scan: interval %d (no timeout)",
+			wpa_s->sched_scan_interval);
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Starting sched scan: interval %d timeout %d",
+			wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout);
+	}
+
+	ret = wpa_supplicant_start_sched_scan(wpa_s, &params,
+					      wpa_s->sched_scan_interval);
+	wpabuf_free(wps_ie);
+	os_free(params.filter_ssids);
+	if (ret) {
+		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
+		if (prev_state != wpa_s->wpa_state)
+			wpa_supplicant_set_state(wpa_s, prev_state);
+		return ret;
+	}
+
+	/* If we have more SSIDs to scan, add a timeout so we scan them too */
+	if (ssid || !wpa_s->first_sched_scan) {
+		wpa_s->sched_scan_timed_out = 0;
+		eloop_register_timeout(wpa_s->sched_scan_timeout, 0,
+				       wpa_supplicant_sched_scan_timeout,
+				       wpa_s, NULL);
+		wpa_s->first_sched_scan = 0;
+		wpa_s->sched_scan_timeout /= 2;
+		wpa_s->sched_scan_interval *= 2;
+	}
+
+	return 0;
+}
+
+
+/**
  * wpa_supplicant_cancel_scan - Cancel a scheduled scan request
  * @wpa_s: Pointer to wpa_supplicant data
  *
@@ -549,6 +892,23 @@
 }
 
 
+/**
+ * wpa_supplicant_cancel_sched_scan - Stop running scheduled scans
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to stop a periodic scheduled scan.
+ */
+void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->sched_scanning)
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan");
+	eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL);
+	wpa_supplicant_stop_sched_scan(wpa_s);
+}
+
+
 void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
 				    int scanning)
 {
@@ -686,15 +1046,28 @@
 }
 
 
+/*
+ * Channels with a great SNR can operate at full rate. What is a great SNR?
+ * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
+ * rule of thumb is that any SNR above 20 is good." This one
+ * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
+ * recommends 25 as a minimum SNR for 54 Mbps data rate. 30 is chosen here as a
+ * conservative value.
+ */
+#define GREAT_SNR 30
+
 /* Compare function for sorting scan results. Return >0 if @b is considered
  * better. */
 static int wpa_scan_result_compar(const void *a, const void *b)
 {
+#define IS_5GHZ(n) (n > 4000)
+#define MIN(a,b) a < b ? a : b
 	struct wpa_scan_res **_wa = (void *) a;
 	struct wpa_scan_res **_wb = (void *) b;
 	struct wpa_scan_res *wa = *_wa;
 	struct wpa_scan_res *wb = *_wb;
 	int wpa_a, wpa_b, maxrate_a, maxrate_b;
+	int snr_a, snr_b;
 
 	/* WPA/WPA2 support preferred */
 	wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
@@ -715,23 +1088,37 @@
 	    (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
 		return -1;
 
-	/* best/max rate preferred if signal level close enough XXX */
-	if ((wa->level && wb->level && abs(wb->level - wa->level) < 5) ||
+	if ((wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) &&
+	    !((wa->flags | wb->flags) & WPA_SCAN_NOISE_INVALID)) {
+		snr_a = MIN(wa->level - wa->noise, GREAT_SNR);
+		snr_b = MIN(wb->level - wb->noise, GREAT_SNR);
+	} else {
+		/* Not suitable information to calculate SNR, so use level */
+		snr_a = wa->level;
+		snr_b = wb->level;
+	}
+
+	/* best/max rate preferred if SNR close enough */
+        if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
 	    (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
 		maxrate_a = wpa_scan_get_max_rate(wa);
 		maxrate_b = wpa_scan_get_max_rate(wb);
 		if (maxrate_a != maxrate_b)
 			return maxrate_b - maxrate_a;
+		if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))
+			return IS_5GHZ(wa->freq) ? -1 : 1;
 	}
 
 	/* use freq for channel preference */
 
-	/* all things being equal, use signal level; if signal levels are
+	/* all things being equal, use SNR; if SNRs are
 	 * identical, use quality values since some drivers may only report
 	 * that value and leave the signal level zero */
-	if (wb->level == wa->level)
+	if (snr_b == snr_a)
 		return wb->qual - wa->qual;
-	return wb->level - wa->level;
+	return snr_b - snr_a;
+#undef MIN
+#undef IS_5GHZ
 }
 
 
@@ -783,6 +1170,37 @@
 #endif /* CONFIG_WPS */
 
 
+static void dump_scan_res(struct wpa_scan_results *scan_res)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	size_t i;
+
+	if (scan_res->res == NULL || scan_res->num == 0)
+		return;
+
+	wpa_printf(MSG_EXCESSIVE, "Sorted scan results");
+
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *r = scan_res->res[i];
+		if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID))
+		    == WPA_SCAN_LEVEL_DBM) {
+			int snr = r->level - r->noise;
+			wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
+				   "noise=%d level=%d snr=%d%s flags=0x%x",
+				   MAC2STR(r->bssid), r->freq, r->qual,
+				   r->noise, r->level, snr,
+				   snr >= GREAT_SNR ? "*" : "", r->flags);
+		} else {
+			wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
+				   "noise=%d level=%d flags=0x%x",
+				   MAC2STR(r->bssid), r->freq, r->qual,
+				   r->noise, r->level, r->flags);
+		}
+	}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
 /**
  * wpa_supplicant_get_scan_results - Get scan results
  * @wpa_s: Pointer to wpa_supplicant data
@@ -802,10 +1220,7 @@
 	size_t i;
 	int (*compar)(const void *, const void *) = wpa_scan_result_compar;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		scan_res = ieee80211_sta_get_scan_results(wpa_s);
-	else
-		scan_res = wpa_drv_get_scan_results2(wpa_s);
+	scan_res = wpa_drv_get_scan_results2(wpa_s);
 	if (scan_res == NULL) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
 		return NULL;
@@ -821,6 +1236,7 @@
 
 	qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),
 	      compar);
+	dump_scan_res(scan_res);
 
 	wpa_bss_update_start(wpa_s);
 	for (i = 0; i < scan_res->num; i++)
@@ -841,17 +1257,3 @@
 
 	return 0;
 }
-
-
-void wpa_scan_results_free(struct wpa_scan_results *res)
-{
-	size_t i;
-
-	if (res == NULL)
-		return;
-
-	for (i = 0; i < res->num; i++)
-		os_free(res->res[i]);
-	os_free(res->res);
-	os_free(res);
-}
diff --git a/wpa_supplicant/scan.h b/wpa_supplicant/scan.h
index 025b815..7fb84e6 100644
--- a/wpa_supplicant/scan.h
+++ b/wpa_supplicant/scan.h
@@ -17,7 +17,11 @@
 
 int wpa_supplicant_enabled_networks(struct wpa_config *conf);
 void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
+int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
+				      int sec, int usec);
+int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
 				    int scanning);
 struct wpa_driver_scan_params;
@@ -34,6 +38,5 @@
 					     u32 vendor_type);
 struct wpabuf * wpa_scan_get_vendor_ie_multi_beacon(
 	const struct wpa_scan_res *res, u32 vendor_type);
-void wpa_scan_results_free(struct wpa_scan_results *res);
 
 #endif /* SCAN_H */
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index 325ffc5..c5e47d1 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -29,7 +29,6 @@
 #include "wps_supplicant.h"
 #include "p2p_supplicant.h"
 #include "notify.h"
-#include "blacklist.h"
 #include "bss.h"
 #include "scan.h"
 #include "sme.h"
@@ -72,6 +71,7 @@
 	params.bssid = bss->bssid;
 	params.ssid = bss->ssid;
 	params.ssid_len = bss->ssid_len;
+	params.p2p = ssid->p2p_group;
 
 	if (wpa_s->sme.ssid_len != params.ssid_len ||
 	    os_memcmp(wpa_s->sme.ssid, params.ssid, params.ssid_len) != 0)
@@ -115,11 +115,7 @@
 
 	if ((wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
 	     wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
-	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
-			       WPA_KEY_MGMT_FT_IEEE8021X |
-			       WPA_KEY_MGMT_FT_PSK |
-			       WPA_KEY_MGMT_IEEE8021X_SHA256 |
-			       WPA_KEY_MGMT_PSK_SHA256))) {
+	    wpa_key_mgmt_wpa(ssid->key_mgmt)) {
 		int try_opportunistic;
 		try_opportunistic = ssid->proactive_key_caching &&
 			(ssid->proto & WPA_PROTO_RSN);
@@ -135,11 +131,7 @@
 				"key management and encryption suites");
 			return;
 		}
-	} else if (ssid->key_mgmt &
-		   (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
-		    WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
-		    WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
-		    WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+	} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
 		wpa_s->sme.assoc_req_ie_len = sizeof(wpa_s->sme.assoc_req_ie);
 		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
 					      wpa_s->sme.assoc_req_ie,
@@ -178,8 +170,7 @@
 		wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
 	}
 
-	if (md && ssid->key_mgmt & (WPA_KEY_MGMT_FT_PSK |
-				    WPA_KEY_MGMT_FT_IEEE8021X)) {
+	if (md && wpa_key_mgmt_ft(ssid->key_mgmt)) {
 		if (wpa_s->sme.assoc_req_ie_len + 5 <
 		    sizeof(wpa_s->sme.assoc_req_ie)) {
 			struct rsn_mdie *mdie;
@@ -226,17 +217,35 @@
 		u8 *pos;
 		size_t len;
 		int res;
-		int p2p_group;
-		p2p_group = wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE;
 		pos = wpa_s->sme.assoc_req_ie + wpa_s->sme.assoc_req_ie_len;
 		len = sizeof(wpa_s->sme.assoc_req_ie) -
 			wpa_s->sme.assoc_req_ie_len;
-		res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len, p2p_group);
+		res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
+					    ssid->p2p_group);
 		if (res >= 0)
 			wpa_s->sme.assoc_req_ie_len += res;
 	}
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_INTERWORKING
+	if (wpa_s->conf->interworking) {
+		u8 *pos = wpa_s->sme.assoc_req_ie;
+		if (wpa_s->sme.assoc_req_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+			pos += 2 + pos[1];
+		os_memmove(pos + 6, pos,
+			   wpa_s->sme.assoc_req_ie_len -
+			   (pos - wpa_s->sme.assoc_req_ie));
+		wpa_s->sme.assoc_req_ie_len += 6;
+		*pos++ = WLAN_EID_EXT_CAPAB;
+		*pos++ = 4;
+		*pos++ = 0x00;
+		*pos++ = 0x00;
+		*pos++ = 0x00;
+		*pos++ = 0x80; /* Bit 31 - Interworking */
+	}
+#endif /* CONFIG_INTERWORKING */
+
+	wpa_supplicant_cancel_sched_scan(wpa_s);
 	wpa_supplicant_cancel_scan(wpa_s);
 
 	wpa_msg(wpa_s, MSG_INFO, "SME: Trying to authenticate with " MACSTR
@@ -256,7 +265,8 @@
 	if (wpa_drv_authenticate(wpa_s, &params) < 0) {
 		wpa_msg(wpa_s, MSG_INFO, "SME: Authentication request to the "
 			"driver failed");
-		wpa_supplicant_req_scan(wpa_s, 1, 0);
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+		wpas_connection_failed(wpa_s, bss->bssid);
 		return;
 	}
 
@@ -392,16 +402,17 @@
 		wpa_dbg(wpa_s, MSG_DEBUG, "SME: Could not parse own IEs?!");
 		os_memset(&elems, 0, sizeof(elems));
 	}
-	if (elems.rsn_ie)
+	if (elems.rsn_ie) {
+		params.wpa_proto = WPA_PROTO_RSN;
 		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.rsn_ie - 2,
 					elems.rsn_ie_len + 2);
-	else if (elems.wpa_ie)
+	} else if (elems.wpa_ie) {
+		params.wpa_proto = WPA_PROTO_WPA;
 		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, elems.wpa_ie - 2,
 					elems.wpa_ie_len + 2);
-	else
+	} else
 		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
-	if (elems.p2p &&
-	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
+	if (wpa_s->current_ssid && wpa_s->current_ssid->p2p_group)
 		params.p2p = 1;
 
 	if (wpa_s->parent->set_sta_uapsd)
@@ -492,6 +503,7 @@
 			      union wpa_event_data *data)
 {
 	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Authentication timed out");
+	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
 	wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
 }
 
@@ -509,8 +521,7 @@
 			union wpa_event_data *data)
 {
 	wpa_dbg(wpa_s, MSG_DEBUG, "SME: Disassociation event received");
-	if (wpa_s->sme.prev_bssid_set &&
-	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)) {
+	if (wpa_s->sme.prev_bssid_set) {
 		/*
 		 * cfg80211/mac80211 can get into somewhat confused state if
 		 * the AP only disassociates us and leaves us in authenticated
@@ -628,7 +639,7 @@
 	os_memcpy(req + 2, trans_id, WLAN_SA_QUERY_TR_ID_LEN);
 	if (wpa_drv_send_action(wpa_s, wpa_s->assoc_freq, 0, wpa_s->bssid,
 				wpa_s->own_addr, wpa_s->bssid,
-				req, sizeof(req)) < 0)
+				req, sizeof(req), 0) < 0)
 		wpa_msg(wpa_s, MSG_INFO, "SME: Failed to send SA Query "
 			"Request");
 }
@@ -677,7 +688,7 @@
 }
 
 
-void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
+static void sme_stop_sa_query(struct wpa_supplicant *wpa_s)
 {
 	eloop_cancel_timeout(sme_sa_query_timer, wpa_s, NULL);
 	os_free(wpa_s->sme.sa_query_trans_id);
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index f09a6f0..a110171 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -24,6 +24,7 @@
 #include "utils/common.h"
 #include "utils/eloop.h"
 #include "utils/edit.h"
+#include "utils/list.h"
 #include "common/version.h"
 #ifdef ANDROID
 #include <cutils/properties.h>
@@ -103,6 +104,15 @@
 static int ping_interval = 5;
 static int interactive = 0;
 
+struct cli_txt_entry {
+	struct dl_list list;
+	char *txt;
+};
+
+static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
+
 
 static void print_help(void);
 static void wpa_cli_mon_receive(int sock, void *eloop_ctx, void *sock_ctx);
@@ -126,6 +136,164 @@
 }
 
 
+static void cli_txt_list_free(struct cli_txt_entry *e)
+{
+	dl_list_del(&e->list);
+	os_free(e->txt);
+	os_free(e);
+}
+
+
+static void cli_txt_list_flush(struct dl_list *list)
+{
+	struct cli_txt_entry *e;
+	while ((e = dl_list_first(list, struct cli_txt_entry, list)))
+		cli_txt_list_free(e);
+}
+
+
+static struct cli_txt_entry * cli_txt_list_get(struct dl_list *txt_list,
+					       const char *txt)
+{
+	struct cli_txt_entry *e;
+	dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+		if (os_strcmp(e->txt, txt) == 0)
+			return e;
+	}
+	return NULL;
+}
+
+
+static void cli_txt_list_del(struct dl_list *txt_list, const char *txt)
+{
+	struct cli_txt_entry *e;
+	e = cli_txt_list_get(txt_list, txt);
+	if (e)
+		cli_txt_list_free(e);
+}
+
+
+static void cli_txt_list_del_addr(struct dl_list *txt_list, const char *txt)
+{
+	u8 addr[ETH_ALEN];
+	char buf[18];
+	if (hwaddr_aton(txt, addr) < 0)
+		return;
+	os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+	cli_txt_list_del(txt_list, buf);
+}
+
+
+#ifdef CONFIG_P2P
+static void cli_txt_list_del_word(struct dl_list *txt_list, const char *txt)
+{
+	const char *end;
+	char *buf;
+	end = os_strchr(txt, ' ');
+	if (end == NULL)
+		end = txt + os_strlen(txt);
+	buf = os_malloc(end - txt + 1);
+	if (buf == NULL)
+		return;
+	os_memcpy(buf, txt, end - txt);
+	buf[end - txt] = '\0';
+	cli_txt_list_del(txt_list, buf);
+	os_free(buf);
+}
+#endif /* CONFIG_P2P */
+
+
+static int cli_txt_list_add(struct dl_list *txt_list, const char *txt)
+{
+	struct cli_txt_entry *e;
+	e = cli_txt_list_get(txt_list, txt);
+	if (e)
+		return 0;
+	e = os_zalloc(sizeof(*e));
+	if (e == NULL)
+		return -1;
+	e->txt = os_strdup(txt);
+	if (e->txt == NULL) {
+		os_free(e);
+		return -1;
+	}
+	dl_list_add(txt_list, &e->list);
+	return 0;
+}
+
+
+#ifdef CONFIG_P2P
+static int cli_txt_list_add_addr(struct dl_list *txt_list, const char *txt)
+{
+	u8 addr[ETH_ALEN];
+	char buf[18];
+	if (hwaddr_aton(txt, addr) < 0)
+		return -1;
+	os_snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+	return cli_txt_list_add(txt_list, buf);
+}
+
+
+static int cli_txt_list_add_word(struct dl_list *txt_list, const char *txt)
+{
+	const char *end;
+	char *buf;
+	int ret;
+	end = os_strchr(txt, ' ');
+	if (end == NULL)
+		end = txt + os_strlen(txt);
+	buf = os_malloc(end - txt + 1);
+	if (buf == NULL)
+		return -1;
+	os_memcpy(buf, txt, end - txt);
+	buf[end - txt] = '\0';
+	ret = cli_txt_list_add(txt_list, buf);
+	os_free(buf);
+	return ret;
+}
+#endif /* CONFIG_P2P */
+
+
+static char ** cli_txt_list_array(struct dl_list *txt_list)
+{
+	unsigned int i, count = dl_list_len(txt_list);
+	char **res;
+	struct cli_txt_entry *e;
+
+	res = os_zalloc((count + 1) * sizeof(char *));
+	if (res == NULL)
+		return NULL;
+
+	i = 0;
+	dl_list_for_each(e, txt_list, struct cli_txt_entry, list) {
+		res[i] = os_strdup(e->txt);
+		if (res[i] == NULL)
+			break;
+		i++;
+	}
+
+	return res;
+}
+
+
+static int get_cmd_arg_num(const char *str, int pos)
+{
+	int arg = 0, i;
+
+	for (i = 0; i <= pos; i++) {
+		if (str[i] != ' ') {
+			arg++;
+			while (i <= pos && str[i] != ' ')
+				i++;
+		}
+	}
+
+	if (arg > 0)
+		arg--;
+	return arg;
+}
+
+
 static int str_starts(const char *src, const char *match)
 {
 	return os_strncmp(src, match, os_strlen(match)) == 0;
@@ -286,8 +454,11 @@
 
 static int wpa_cli_cmd_status(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
-	int verbose = argc > 0 && os_strcmp(argv[0], "verbose") == 0;
-	return wpa_ctrl_command(ctrl, verbose ? "STATUS-VERBOSE" : "STATUS");
+	if (argc > 0 && os_strcmp(argv[0], "verbose") == 0)
+		return wpa_ctrl_command(ctrl, "STATUS-VERBOSE");
+	if (argc > 0 && os_strcmp(argv[0], "wps") == 0)
+		return wpa_ctrl_command(ctrl, "STATUS-WPS");
+	return wpa_ctrl_command(ctrl, "STATUS");
 }
 
 
@@ -381,13 +552,17 @@
 		return 0;
 	}
 
-	if (argc != 2) {
+	if (argc != 1 && argc != 2) {
 		printf("Invalid SET command: needs two arguments (variable "
 		       "name and value)\n");
 		return -1;
 	}
 
-	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
+	if (argc == 1)
+		res = os_snprintf(cmd, sizeof(cmd), "SET %s ", argv[0]);
+	else
+		res = os_snprintf(cmd, sizeof(cmd), "SET %s %s",
+				  argv[0], argv[1]);
 	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
 		printf("Too long SET command.\n");
 		return -1;
@@ -1499,6 +1674,21 @@
 }
 
 
+static char ** wpa_cli_complete_bss(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	char **res = NULL;
+
+	switch (arg) {
+	case 1:
+		res = cli_txt_list_array(&bsses);
+		break;
+	}
+
+	return res;
+}
+
+
 static int wpa_cli_cmd_get_capability(struct wpa_ctrl *ctrl, int argc,
 				      char *argv[])
 {
@@ -1792,6 +1982,21 @@
 }
 
 
+static char ** wpa_cli_complete_p2p_connect(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	char **res = NULL;
+
+	switch (arg) {
+	case 1:
+		res = cli_txt_list_array(&p2p_peers);
+		break;
+	}
+
+	return res;
+}
+
+
 static int wpa_cli_cmd_p2p_listen(struct wpa_ctrl *ctrl, int argc,
 				  char *argv[])
 {
@@ -1829,6 +2034,21 @@
 }
 
 
+static char ** wpa_cli_complete_p2p_group_remove(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	char **res = NULL;
+
+	switch (arg) {
+	case 1:
+		res = cli_txt_list_array(&p2p_groups);
+		break;
+	}
+
+	return res;
+}
+
+
 static int wpa_cli_cmd_p2p_group_add(struct wpa_ctrl *ctrl, int argc,
 					char *argv[])
 {
@@ -1857,15 +2077,19 @@
 	char cmd[128];
 	int res;
 
-	if (argc != 2) {
-		printf("Invalid P2P_PROV_DISC command: needs two arguments "
-		       "(address and config method\n"
-		       "(display, keypad, or pbc)\n");
+	if (argc != 2 && argc != 3) {
+		printf("Invalid P2P_PROV_DISC command: needs at least "
+		       "two arguments, address and config method\n"
+		       "(display, keypad, or pbc) and an optional join\n");
 		return -1;
 	}
 
-	res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s",
-			  argv[0], argv[1]);
+	if (argc == 3)
+		res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s %s",
+				  argv[0], argv[1], argv[2]);
+	else
+		res = os_snprintf(cmd, sizeof(cmd), "P2P_PROV_DISC %s %s",
+				  argv[0], argv[1]);
 	if (res < 0 || (size_t) res >= sizeof(cmd))
 		return -1;
 	cmd[sizeof(cmd) - 1] = '\0';
@@ -2099,6 +2323,21 @@
 }
 
 
+static char ** wpa_cli_complete_p2p_peer(const char *str, int pos)
+{
+	int arg = get_cmd_arg_num(str, pos);
+	char **res = NULL;
+
+	switch (arg) {
+	case 1:
+		res = cli_txt_list_array(&p2p_peers);
+		break;
+	}
+
+	return res;
+}
+
+
 static int wpa_ctrl_command_p2p_peer(struct wpa_ctrl *ctrl, char *cmd,
 				     char *addr, size_t addr_len,
 				     int discovered)
@@ -2144,13 +2383,13 @@
 
 	if (wpa_ctrl_command_p2p_peer(ctrl, "P2P_PEER FIRST",
 				      addr, sizeof(addr), discovered))
-		return 0;
+		return -1;
 	do {
 		os_snprintf(cmd, sizeof(cmd), "P2P_PEER NEXT-%s", addr);
 	} while (wpa_ctrl_command_p2p_peer(ctrl, cmd, addr, sizeof(addr),
 			 discovered) == 0);
 
-	return -1;
+	return 0;
 }
 
 
@@ -2267,6 +2506,80 @@
 #endif /* CONFIG_P2P */
 
 
+#ifdef CONFIG_INTERWORKING
+static int wpa_cli_cmd_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
+				  char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "FETCH_ANQP");
+}
+
+
+static int wpa_cli_cmd_stop_fetch_anqp(struct wpa_ctrl *ctrl, int argc,
+				       char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "STOP_FETCH_ANQP");
+}
+
+
+static int wpa_cli_cmd_interworking_select(struct wpa_ctrl *ctrl, int argc,
+					   char *argv[])
+{
+	char cmd[100];
+	int res;
+
+	if (argc == 0)
+		return wpa_ctrl_command(ctrl, "INTERWORKING_SELECT");
+
+	res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_SELECT %s", argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd))
+		return -1;
+	cmd[sizeof(cmd) - 1] = '\0';
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_interworking_connect(struct wpa_ctrl *ctrl, int argc,
+					    char *argv[])
+{
+	char cmd[100];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid INTERWORKING_CONNECT commands: needs one "
+		       "argument (BSSID)\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "INTERWORKING_CONNECT %s",
+			  argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd))
+		return -1;
+	cmd[sizeof(cmd) - 1] = '\0';
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int wpa_cli_cmd_anqp_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[100];
+	int res;
+
+	if (argc != 2) {
+		printf("Invalid ANQP_GET command: needs two arguments "
+		       "(addr and info id list)\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "ANQP_GET %s %s",
+			  argv[0], argv[1]);
+	if (res < 0 || (size_t) res >= sizeof(cmd))
+		return -1;
+	cmd[sizeof(cmd) - 1] = '\0';
+	return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
 static int wpa_cli_cmd_sta_autoconnect(struct wpa_ctrl *ctrl, int argc,
 				       char *argv[])
 {
@@ -2357,6 +2670,13 @@
 }
 
 
+static int wpa_cli_cmd_reauthenticate(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "REAUTHENTICATE");
+}
+
+
 static int wpa_cli_cmd_driver(struct wpa_ctrl *ctrl, int argc, char *argv[])
 {
 	char cmd[256];
@@ -2472,7 +2792,7 @@
 	  "blacklist = display the blacklist" },
 	{ "log_level", wpa_cli_cmd_log_level,
 	  cli_cmd_flag_none,
-	  "<level> [<timestamp>] = update the log level/timestamp of wpa_supplicant\n"
+	  "<level> [<timestamp>] = update the log level/timestamp\n"
 	  "log_level = display the current log level and log options" },
 	{ "list_networks", wpa_cli_cmd_list_networks,
 	  cli_cmd_flag_none,
@@ -2690,6 +3010,21 @@
 	{ "p2p_ext_listen", wpa_cli_cmd_p2p_ext_listen, cli_cmd_flag_none,
 	  "[<period> <interval>] = set extended listen timing" },
 #endif /* CONFIG_P2P */
+
+#ifdef CONFIG_INTERWORKING
+	{ "fetch_anqp", wpa_cli_cmd_fetch_anqp, cli_cmd_flag_none,
+	  "= fetch ANQP information for all APs" },
+	{ "stop_fetch_anqp", wpa_cli_cmd_stop_fetch_anqp, cli_cmd_flag_none,
+	  "= stop fetch_anqp operation" },
+	{ "interworking_select", wpa_cli_cmd_interworking_select,
+	  cli_cmd_flag_none,
+	  "[auto] = perform Interworking network selection" },
+	{ "interworking_connect", wpa_cli_cmd_interworking_connect,
+	  cli_cmd_flag_none,
+	  "<BSSID> = connect using Interworking credentials" },
+	{ "anqp_get", wpa_cli_cmd_anqp_get, cli_cmd_flag_none,
+	  "<addr> <info id>[,<info id>]... = request ANQP information" },
+#endif /* CONFIG_INTERWORKING */
 	{ "sta_autoconnect", wpa_cli_cmd_sta_autoconnect, cli_cmd_flag_none,
 	  "<0/1> = disable/enable automatic reconnection" },
 	{ "tdls_discover", wpa_cli_cmd_tdls_discover,
@@ -2704,6 +3039,8 @@
 	{ "signal_poll", wpa_cli_cmd_signal_poll,
 	  cli_cmd_flag_none,
 	  "= get signal parameters" },
+	{ "reauthenticate", wpa_cli_cmd_reauthenticate, cli_cmd_flag_none,
+	  "= trigger IEEE 802.1X/EAPOL reauthentication" },
 	{ "driver", wpa_cli_cmd_driver,
 	  cli_cmd_flag_none,
 	  "<command> = driver private commands" },
@@ -2784,6 +3121,17 @@
 {
 	int i;
 
+	if (os_strcasecmp(cmd, "bss") == 0)
+		return wpa_cli_complete_bss(str, pos);
+#ifdef CONFIG_P2P
+	if (os_strcasecmp(cmd, "p2p_connect") == 0)
+		return wpa_cli_complete_p2p_connect(str, pos);
+	if (os_strcasecmp(cmd, "p2p_peer") == 0)
+		return wpa_cli_complete_p2p_peer(str, pos);
+	if (os_strcasecmp(cmd, "p2p_group_remove") == 0)
+		return wpa_cli_complete_p2p_group_remove(str, pos);
+#endif /* CONFIG_P2P */
+
 	for (i = 0; wpa_cli_commands[i].cmd; i++) {
 		if (os_strcasecmp(wpa_cli_commands[i].cmd, cmd) == 0) {
 			edit_clear_line();
@@ -2961,19 +3309,20 @@
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
 	} else if (str_match(pos, P2P_EVENT_CROSS_CONNECT_DISABLE)) {
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
 	} else if (str_match(pos, WPS_EVENT_SUCCESS)) {
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
 	} else if (str_match(pos, WPS_EVENT_FAIL)) {
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, AP_STA_CONNECTED)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, AP_STA_DISCONNECTED)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
 	} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
 		printf("wpa_supplicant is terminating - stop monitoring\n");
 		wpa_cli_quit = 1;
 	}
-#ifdef ANDROID_BRCM_P2P_PATCH
-	else if (str_match(pos, P2P_EVENT_GO_NEG_FAILURE)) {
-		wpa_cli_exec(action_file, ctrl_ifname, pos);
-	}
-#endif
 }
 
 
@@ -2992,6 +3341,74 @@
 }
 
 
+static void cli_event(const char *str)
+{
+	const char *start, *s;
+
+	start = os_strchr(str, '>');
+	if (start == NULL)
+		return;
+
+	start++;
+
+	if (str_starts(start, WPA_EVENT_BSS_ADDED)) {
+		s = os_strchr(start, ' ');
+		if (s == NULL)
+			return;
+		s = os_strchr(s + 1, ' ');
+		if (s == NULL)
+			return;
+		cli_txt_list_add(&bsses, s + 1);
+		return;
+	}
+
+	if (str_starts(start, WPA_EVENT_BSS_REMOVED)) {
+		s = os_strchr(start, ' ');
+		if (s == NULL)
+			return;
+		s = os_strchr(s + 1, ' ');
+		if (s == NULL)
+			return;
+		cli_txt_list_del_addr(&bsses, s + 1);
+		return;
+	}
+
+#ifdef CONFIG_P2P
+	if (str_starts(start, P2P_EVENT_DEVICE_FOUND)) {
+		s = os_strstr(start, " p2p_dev_addr=");
+		if (s == NULL)
+			return;
+		cli_txt_list_add_addr(&p2p_peers, s + 14);
+		return;
+	}
+
+	if (str_starts(start, P2P_EVENT_DEVICE_LOST)) {
+		s = os_strstr(start, " p2p_dev_addr=");
+		if (s == NULL)
+			return;
+		cli_txt_list_del_addr(&p2p_peers, s + 14);
+		return;
+	}
+
+	if (str_starts(start, P2P_EVENT_GROUP_STARTED)) {
+		s = os_strchr(start, ' ');
+		if (s == NULL)
+			return;
+		cli_txt_list_add_word(&p2p_groups, s + 1);
+		return;
+	}
+
+	if (str_starts(start, P2P_EVENT_GROUP_REMOVED)) {
+		s = os_strchr(start, ' ');
+		if (s == NULL)
+			return;
+		cli_txt_list_del_word(&p2p_groups, s + 1);
+		return;
+	}
+#endif /* CONFIG_P2P */
+}
+
+
 static void wpa_cli_recv_pending(struct wpa_ctrl *ctrl, int action_monitor)
 {
 	if (ctrl_conn == NULL) {
@@ -3006,6 +3423,7 @@
 			if (action_monitor)
 				wpa_cli_action_process(buf);
 			else {
+				cli_event(buf);
 				if (wpa_cli_show_event(buf)) {
 					edit_clear_line();
 					printf("\r%s\n", buf);
@@ -3120,6 +3538,9 @@
 
 	eloop_run();
 
+	cli_txt_list_flush(&p2p_peers);
+	cli_txt_list_flush(&p2p_groups);
+	cli_txt_list_flush(&bsses);
 	edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
 	os_free(hfile);
 	eloop_cancel_timeout(wpa_cli_ping, NULL, NULL);
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
index 459aa8c..f75f02a 100644
--- a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
+++ b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
@@ -15,6 +15,7 @@
 #include <cstdio>
 
 #include "scanresults.h"
+#include "signalbar.h"
 #include "wpagui.h"
 #include "networkconfig.h"
 
@@ -33,6 +34,7 @@
 	wpagui = NULL;
 	scanResultsWidget->setItemsExpandable(FALSE);
 	scanResultsWidget->setRootIsDecorated(FALSE);
+	scanResultsWidget->setItemDelegate(new SignalBar(scanResultsWidget));
 }
 
 
@@ -91,7 +93,7 @@
 				bssid = (*it).mid(pos);
 			else if ((*it).startsWith("freq="))
 				freq = (*it).mid(pos);
-			else if ((*it).startsWith("qual="))
+			else if ((*it).startsWith("level="))
 				signal = (*it).mid(pos);
 			else if ((*it).startsWith("flags="))
 				flags = (*it).mid(pos);
diff --git a/wpa_supplicant/wpa_gui-qt4/signalbar.cpp b/wpa_supplicant/wpa_gui-qt4/signalbar.cpp
new file mode 100644
index 0000000..f2688d5
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/signalbar.cpp
@@ -0,0 +1,64 @@
+/*
+ * wpa_gui - SignalBar class
+ * Copyright (c) 2011, Kel Modderman <kel@otaku42.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <cstdio>
+#include <qapplication.h>
+
+#include "signalbar.h"
+
+
+SignalBar::SignalBar(QObject *parent)
+	: QStyledItemDelegate(parent)
+{
+}
+
+
+SignalBar::~SignalBar()
+{
+}
+
+
+void SignalBar::paint(QPainter *painter,
+		      const QStyleOptionViewItem &option,
+		      const QModelIndex &index) const
+{
+	QStyleOptionProgressBar opts;
+	int signal;
+
+	if (index.column() != 3) {
+		QStyledItemDelegate::paint(painter, option, index);
+		return;
+	}
+
+	if (index.data().toInt() > 0)
+		signal = 0 - (256 - index.data().toInt());
+	else
+		signal = index.data().toInt();
+
+	opts.minimum = -95;
+	opts.maximum = -35;
+	if (signal < opts.minimum)
+		opts.progress = opts.minimum;
+	else if (signal > opts.maximum)
+		opts.progress = opts.maximum;
+	else
+		opts.progress = signal;
+
+	opts.text = QString::number(signal) + " dBm";
+	opts.textVisible = true;
+	opts.rect = option.rect;
+
+	QApplication::style()->drawControl(QStyle::CE_ProgressBar,
+					   &opts, painter);
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/signalbar.h b/wpa_supplicant/wpa_gui-qt4/signalbar.h
new file mode 100644
index 0000000..3d5dec1
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/signalbar.h
@@ -0,0 +1,34 @@
+/*
+ * wpa_gui - SignalBar class
+ * Copyright (c) 2011, Kel Modderman <kel@otaku42.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef SIGNALBAR_H
+#define SIGNALBAR_H
+
+#include <QObject>
+#include <QStyledItemDelegate>
+
+class SignalBar : public QStyledItemDelegate
+{
+	Q_OBJECT
+
+public:
+	SignalBar(QObject *parent = 0);
+	~SignalBar();
+
+	virtual void paint(QPainter *painter,
+			   const QStyleOptionViewItem &option,
+			   const QModelIndex &index) const ;
+};
+
+#endif /* SIGNALBAR_H */
diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
index 85848d7..3c81929 100644
--- a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
+++ b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
@@ -34,6 +34,7 @@
 	wpagui.h \
 	eventhistory.h \
 	scanresults.h \
+	signalbar.h \
 	userdatarequest.h \
 	networkconfig.h \
 	addinterface.h \
@@ -44,6 +45,7 @@
 	wpagui.cpp \
 	eventhistory.cpp \
 	scanresults.cpp \
+	signalbar.cpp \
 	userdatarequest.cpp \
 	networkconfig.cpp \
 	addinterface.cpp \
diff --git a/wpa_supplicant/wpa_gui/.gitignore b/wpa_supplicant/wpa_gui/.gitignore
deleted file mode 100644
index 4df64a9..0000000
--- a/wpa_supplicant/wpa_gui/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-.moc
-.obj
-.ui
diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui b/wpa_supplicant/wpa_gui/eventhistory.ui
deleted file mode 100644
index 3735fb7..0000000
--- a/wpa_supplicant/wpa_gui/eventhistory.ui
+++ /dev/null
@@ -1,125 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>EventHistory</class>
-<widget class="QDialog">
-    <property name="name">
-        <cstring>EventHistory</cstring>
-    </property>
-    <property name="geometry">
-        <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>533</width>
-            <height>285</height>
-        </rect>
-    </property>
-    <property name="caption">
-        <string>Event history</string>
-    </property>
-    <vbox>
-        <property name="name">
-            <cstring>unnamed</cstring>
-        </property>
-        <widget class="QListView">
-            <column>
-                <property name="text">
-                    <string>Timestamp</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <column>
-                <property name="text">
-                    <string>Message</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <property name="name">
-                <cstring>eventListView</cstring>
-            </property>
-            <property name="sizePolicy">
-                <sizepolicy>
-                    <hsizetype>7</hsizetype>
-                    <vsizetype>7</vsizetype>
-                    <horstretch>0</horstretch>
-                    <verstretch>0</verstretch>
-                </sizepolicy>
-            </property>
-            <property name="resizePolicy">
-                <enum>Manual</enum>
-            </property>
-            <property name="selectionMode">
-                <enum>NoSelection</enum>
-            </property>
-            <property name="resizeMode">
-                <enum>LastColumn</enum>
-            </property>
-        </widget>
-        <widget class="QLayoutWidget">
-            <property name="name">
-                <cstring>layout30</cstring>
-            </property>
-            <hbox>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <spacer>
-                    <property name="name">
-                        <cstring>spacer3</cstring>
-                    </property>
-                    <property name="orientation">
-                        <enum>Horizontal</enum>
-                    </property>
-                    <property name="sizeType">
-                        <enum>Expanding</enum>
-                    </property>
-                    <property name="sizeHint">
-                        <size>
-                            <width>20</width>
-                            <height>20</height>
-                        </size>
-                    </property>
-                </spacer>
-                <widget class="QPushButton">
-                    <property name="name">
-                        <cstring>closeButton</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Close</string>
-                    </property>
-                </widget>
-            </hbox>
-        </widget>
-    </vbox>
-</widget>
-<connections>
-    <connection>
-        <sender>closeButton</sender>
-        <signal>clicked()</signal>
-        <receiver>EventHistory</receiver>
-        <slot>close()</slot>
-    </connection>
-</connections>
-<includes>
-    <include location="local" impldecl="in declaration">wpamsg.h</include>
-    <include location="local" impldecl="in implementation">eventhistory.ui.h</include>
-</includes>
-<slots>
-    <slot>addEvents( WpaMsgList msgs )</slot>
-    <slot>addEvent( WpaMsg msg )</slot>
-</slots>
-<functions>
-    <function access="private" specifier="non virtual">init()</function>
-    <function access="private" specifier="non virtual">destroy()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui.h b/wpa_supplicant/wpa_gui/eventhistory.ui.h
deleted file mode 100644
index cb2caab..0000000
--- a/wpa_supplicant/wpa_gui/eventhistory.ui.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-void EventHistory::init()
-{
-}
-
-
-void EventHistory::destroy()
-{
-}
-
-
-void EventHistory::addEvents(WpaMsgList msgs)
-{
-    WpaMsgList::iterator it;
-    for (it = msgs.begin(); it != msgs.end(); it++) {
-	addEvent(*it);
-    }
-}
-
-
-void EventHistory::addEvent(WpaMsg msg)
-{
-    Q3ListViewItem *item;
-    item = new Q3ListViewItem(eventListView,
-			     msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"),
-			     msg.getMsg());
-    if (item == NULL)
-	return;
-    eventListView->setSelected(item, false);
-}
diff --git a/wpa_supplicant/wpa_gui/main.cpp b/wpa_supplicant/wpa_gui/main.cpp
deleted file mode 100644
index a78473a..0000000
--- a/wpa_supplicant/wpa_gui/main.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
-#include <qapplication.h>
-#include "wpagui.h"
-
-int main( int argc, char ** argv )
-{
-    QApplication a( argc, argv );
-    WpaGui w;
-    int ret;
-
-#ifdef CONFIG_NATIVE_WINDOWS
-    WSADATA wsaData;
-    if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
-	printf("Could not find a usable WinSock.dll\n");
-	return -1;
-    }
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-    w.show();
-    a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
-    ret = a.exec();
-
-#ifdef CONFIG_NATIVE_WINDOWS
-    WSACleanup();
-#endif /* CONFIG_NATIVE_WINDOWS */
-
-    return ret;
-}
diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui b/wpa_supplicant/wpa_gui/networkconfig.ui
deleted file mode 100644
index 019ecf7..0000000
--- a/wpa_supplicant/wpa_gui/networkconfig.ui
+++ /dev/null
@@ -1,475 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>NetworkConfig</class>
-<widget class="QDialog">
-    <property name="name">
-        <cstring>NetworkConfig</cstring>
-    </property>
-    <property name="geometry">
-        <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>380</width>
-            <height>430</height>
-        </rect>
-    </property>
-    <property name="caption">
-        <string>NetworkConfig</string>
-    </property>
-    <grid>
-        <property name="name">
-            <cstring>unnamed</cstring>
-        </property>
-        <widget class="QPushButton" row="1" column="3">
-            <property name="name">
-                <cstring>cancelButton</cstring>
-            </property>
-            <property name="text">
-                <string>Cancel</string>
-            </property>
-        </widget>
-        <widget class="QFrame" row="0" column="0" rowspan="1" colspan="4">
-            <property name="name">
-                <cstring>frame9</cstring>
-            </property>
-            <property name="frameShape">
-                <enum>StyledPanel</enum>
-            </property>
-            <property name="frameShadow">
-                <enum>Raised</enum>
-            </property>
-            <grid>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <widget class="QLabel" row="0" column="0">
-                    <property name="name">
-                        <cstring>textLabel0</cstring>
-                    </property>
-                    <property name="text">
-                        <string>SSID</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="0" column="1">
-                    <property name="name">
-                        <cstring>ssidEdit</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                    <property name="toolTip" stdset="0">
-                        <string>Network name (Service Set IDentifier)</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="1" column="0">
-                    <property name="name">
-                        <cstring>textLabel1</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Network ID</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="1" column="1">
-                    <property name="name">
-                        <cstring>idstrEdit</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                    <property name="toolTip" stdset="0">
-                        <string>Network Identification String</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="2" column="0">
-                    <property name="name">
-                        <cstring>textLabel2</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Authentication</string>
-                    </property>
-                </widget>
-                <widget class="QComboBox" row="2" column="1">
-                    <item>
-                        <property name="text">
-                            <string>Plaintext or static WEP</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>IEEE 802.1X</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>WPA-Personal (PSK)</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>WPA-Enterprise (EAP)</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>WPA2-Personal (PSK)</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>WPA2-Enterprise (EAP)</string>
-                        </property>
-                    </item>
-                    <property name="name">
-                        <cstring>authSelect</cstring>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="3" column="0">
-                    <property name="name">
-                        <cstring>textLabel3</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Encryption</string>
-                    </property>
-                </widget>
-                <widget class="QComboBox" row="3" column="1">
-                    <item>
-                        <property name="text">
-                            <string>None</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>WEP</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>TKIP</string>
-                        </property>
-                    </item>
-                    <item>
-                        <property name="text">
-                            <string>CCMP</string>
-                        </property>
-                    </item>
-                    <property name="name">
-                        <cstring>encrSelect</cstring>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="4" column="0">
-                    <property name="name">
-                        <cstring>textLabel4</cstring>
-                    </property>
-                    <property name="text">
-                        <string>PSK</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="4" column="1">
-                    <property name="name">
-                        <cstring>pskEdit</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>false</bool>
-                    </property>
-                    <property name="echoMode">
-                        <enum>Password</enum>
-                    </property>
-                    <property name="toolTip" stdset="0">
-                        <string>WPA/WPA2 pre-shared key or passphrase</string>
-                    </property>
-                    <property name="whatsThis" stdset="0">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="5" column="0">
-                    <property name="name">
-                        <cstring>textLabel5</cstring>
-                    </property>
-                    <property name="text">
-                        <string>EAP method</string>
-                    </property>
-                </widget>
-                <widget class="QComboBox" row="5" column="1">
-                    <property name="name">
-                        <cstring>eapSelect</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>false</bool>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="6" column="0">
-                    <property name="name">
-                        <cstring>textLabel6</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Identity</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="6" column="1">
-                    <property name="name">
-                        <cstring>identityEdit</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>false</bool>
-                    </property>
-                    <property name="toolTip" stdset="0">
-                        <string>Username/Identity for EAP methods</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="7" column="0">
-                    <property name="name">
-                        <cstring>textLabel7</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Password</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="7" column="1">
-                    <property name="name">
-                        <cstring>passwordEdit</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>false</bool>
-                    </property>
-                    <property name="echoMode">
-                        <enum>Password</enum>
-                    </property>
-                    <property name="toolTip" stdset="0">
-                        <string>Password for EAP methods</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="8" column="0">
-                    <property name="name">
-                        <cstring>textLabel1_2</cstring>
-                    </property>
-                    <property name="text">
-                        <string>CA certificate</string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit" row="8" column="1">
-                    <property name="name">
-                        <cstring>cacertEdit</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>false</bool>
-                    </property>
-                </widget>
-                <widget class="QButtonGroup" row="9" column="0" rowspan="1" colspan="2">
-                    <property name="name">
-                        <cstring>buttonGroup1</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>true</bool>
-                    </property>
-                    <property name="title">
-                        <string>WEP keys</string>
-                    </property>
-                    <grid>
-                        <property name="name">
-                            <cstring>unnamed</cstring>
-                        </property>
-                        <widget class="QRadioButton" row="0" column="0">
-                            <property name="name">
-                                <cstring>wep0Radio</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                            <property name="text">
-                                <string>key 0</string>
-                            </property>
-                        </widget>
-                        <widget class="QRadioButton" row="1" column="0">
-                            <property name="name">
-                                <cstring>wep1Radio</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                            <property name="text">
-                                <string>key 1</string>
-                            </property>
-                        </widget>
-                        <widget class="QRadioButton" row="3" column="0">
-                            <property name="name">
-                                <cstring>wep3Radio</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                            <property name="text">
-                                <string>key 3</string>
-                            </property>
-                        </widget>
-                        <widget class="QRadioButton" row="2" column="0">
-                            <property name="name">
-                                <cstring>wep2Radio</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                            <property name="text">
-                                <string>key 2</string>
-                            </property>
-                        </widget>
-                        <widget class="QLineEdit" row="0" column="1">
-                            <property name="name">
-                                <cstring>wep0Edit</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                        </widget>
-                        <widget class="QLineEdit" row="1" column="1">
-                            <property name="name">
-                                <cstring>wep1Edit</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                        </widget>
-                        <widget class="QLineEdit" row="2" column="1">
-                            <property name="name">
-                                <cstring>wep2Edit</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                        </widget>
-                        <widget class="QLineEdit" row="3" column="1">
-                            <property name="name">
-                                <cstring>wep3Edit</cstring>
-                            </property>
-                            <property name="enabled">
-                                <bool>false</bool>
-                            </property>
-                        </widget>
-                    </grid>
-                </widget>
-            </grid>
-        </widget>
-        <spacer row="1" column="0">
-            <property name="name">
-                <cstring>spacer5</cstring>
-            </property>
-            <property name="orientation">
-                <enum>Horizontal</enum>
-            </property>
-            <property name="sizeType">
-                <enum>Expanding</enum>
-            </property>
-            <property name="sizeHint">
-                <size>
-                    <width>130</width>
-                    <height>20</height>
-                </size>
-            </property>
-        </spacer>
-        <widget class="QPushButton" row="1" column="1">
-            <property name="name">
-                <cstring>addButton</cstring>
-            </property>
-            <property name="text">
-                <string>Add</string>
-            </property>
-        </widget>
-        <widget class="QPushButton" row="1" column="2">
-            <property name="name">
-                <cstring>removeButton</cstring>
-            </property>
-            <property name="enabled">
-                <bool>false</bool>
-            </property>
-            <property name="text">
-                <string>Remove</string>
-            </property>
-        </widget>
-    </grid>
-</widget>
-<connections>
-    <connection>
-        <sender>authSelect</sender>
-        <signal>activated(int)</signal>
-        <receiver>NetworkConfig</receiver>
-        <slot>authChanged(int)</slot>
-    </connection>
-    <connection>
-        <sender>cancelButton</sender>
-        <signal>clicked()</signal>
-        <receiver>NetworkConfig</receiver>
-        <slot>close()</slot>
-    </connection>
-    <connection>
-        <sender>addButton</sender>
-        <signal>clicked()</signal>
-        <receiver>NetworkConfig</receiver>
-        <slot>addNetwork()</slot>
-    </connection>
-    <connection>
-        <sender>encrSelect</sender>
-        <signal>activated(const QString&amp;)</signal>
-        <receiver>NetworkConfig</receiver>
-        <slot>encrChanged(const QString&amp;)</slot>
-    </connection>
-    <connection>
-        <sender>removeButton</sender>
-        <signal>clicked()</signal>
-        <receiver>NetworkConfig</receiver>
-        <slot>removeNetwork()</slot>
-    </connection>
-</connections>
-<tabstops>
-    <tabstop>ssidEdit</tabstop>
-    <tabstop>idstrEdit</tabstop>
-    <tabstop>authSelect</tabstop>
-    <tabstop>encrSelect</tabstop>
-    <tabstop>pskEdit</tabstop>
-    <tabstop>eapSelect</tabstop>
-    <tabstop>identityEdit</tabstop>
-    <tabstop>passwordEdit</tabstop>
-    <tabstop>cacertEdit</tabstop>
-    <tabstop>wep0Radio</tabstop>
-    <tabstop>wep1Radio</tabstop>
-    <tabstop>wep2Radio</tabstop>
-    <tabstop>wep3Radio</tabstop>
-    <tabstop>wep0Edit</tabstop>
-    <tabstop>wep1Edit</tabstop>
-    <tabstop>wep2Edit</tabstop>
-    <tabstop>wep3Edit</tabstop>
-    <tabstop>addButton</tabstop>
-    <tabstop>removeButton</tabstop>
-    <tabstop>cancelButton</tabstop>
-</tabstops>
-<includes>
-    <include location="global" impldecl="in declaration">qlistview.h</include>
-    <include location="global" impldecl="in implementation">qmessagebox.h</include>
-    <include location="local" impldecl="in implementation">wpagui.h</include>
-    <include location="local" impldecl="in implementation">networkconfig.ui.h</include>
-</includes>
-<forwards>
-    <forward>class WpaGui;</forward>
-</forwards>
-<variables>
-    <variable access="private">WpaGui *wpagui;</variable>
-    <variable access="private">int edit_network_id;</variable>
-    <variable access="private">bool new_network;</variable>
-</variables>
-<slots>
-    <slot>authChanged( int sel )</slot>
-    <slot>addNetwork()</slot>
-    <slot>encrChanged( const QString &amp; sel )</slot>
-    <slot>writeWepKey( int network_id, QLineEdit * edit, int id )</slot>
-    <slot>removeNetwork()</slot>
-</slots>
-<functions>
-    <function access="private" specifier="non virtual">init()</function>
-    <function>paramsFromScanResults( QListViewItem * sel )</function>
-    <function>setWpaGui( WpaGui * _wpagui )</function>
-    <function returnType="int">setNetworkParam( int id, const char * field, const char * value, bool quote )</function>
-    <function access="private">wepEnabled( bool enabled )</function>
-    <function>paramsFromConfig( int network_id )</function>
-    <function>newNetwork()</function>
-    <function access="private">getEapCapa()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui.h b/wpa_supplicant/wpa_gui/networkconfig.ui.h
deleted file mode 100644
index 501d5d2..0000000
--- a/wpa_supplicant/wpa_gui/networkconfig.ui.h
+++ /dev/null
@@ -1,552 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-#include <stdlib.h>
-
-enum {
-    AUTH_NONE = 0,
-    AUTH_IEEE8021X = 1,
-    AUTH_WPA_PSK = 2,
-    AUTH_WPA_EAP = 3,
-    AUTH_WPA2_PSK = 4,
-    AUTH_WPA2_EAP = 5
-};
-
-#define WPA_GUI_KEY_DATA "[key is configured]"
-
-void NetworkConfig::init()
-{
-    wpagui = NULL;
-    new_network = false;
-}
-
-void NetworkConfig::paramsFromScanResults(Q3ListViewItem *sel)
-{
-    new_network = true;
-
-    /* SSID BSSID frequency signal flags */
-    setCaption(sel->text(0));
-    ssidEdit->setText(sel->text(0));
-    
-    QString flags = sel->text(4);
-    int auth, encr = 0;
-    if (flags.find("[WPA2-EAP") >= 0)
-	auth = AUTH_WPA2_EAP;
-    else if (flags.find("[WPA-EAP") >= 0)
-	auth = AUTH_WPA_EAP;
-    else if (flags.find("[WPA2-PSK") >= 0)
-	auth = AUTH_WPA2_PSK;
-    else if (flags.find("[WPA-PSK") >= 0)
-	auth = AUTH_WPA_PSK;
-    else
-	auth = AUTH_NONE;
-    
-    if (flags.find("-CCMP") >= 0)
-	encr = 1;
-    else if (flags.find("-TKIP") >= 0)
-	encr = 0;
-    else if (flags.find("WEP") >= 0)
-	encr = 1;
-    else
-	encr = 0;
- 
-    authSelect->setCurrentItem(auth);
-    authChanged(auth);
-    encrSelect->setCurrentItem(encr);
-
-    getEapCapa();
-}
-
-
-void NetworkConfig::authChanged(int sel)
-{
-    pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK);
-    bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP ||
-	       sel == AUTH_WPA2_EAP;
-    eapSelect->setEnabled(eap);
-    identityEdit->setEnabled(eap);
-    passwordEdit->setEnabled(eap);
-    cacertEdit->setEnabled(eap);
-   
-    while (encrSelect->count())
-	encrSelect->removeItem(0);
-    
-    if (sel == AUTH_NONE || sel == AUTH_IEEE8021X) {
-	encrSelect->insertItem("None");
-	encrSelect->insertItem("WEP");
-	encrSelect->setCurrentItem(sel == AUTH_NONE ? 0 : 1);
-    } else {
-	encrSelect->insertItem("TKIP");
-	encrSelect->insertItem("CCMP");
-	encrSelect->setCurrentItem((sel == AUTH_WPA2_PSK ||
-				    sel == AUTH_WPA2_EAP) ? 1 : 0);
-    }
-    
-    wepEnabled(sel == AUTH_IEEE8021X);
-}
-
-
-void NetworkConfig::addNetwork()
-{
-    char reply[10], cmd[256];
-    size_t reply_len;
-    int id;
-    int psklen = pskEdit->text().length();
-    int auth = authSelect->currentItem();
-
-    if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) {
-	if (psklen < 8 || psklen > 64) {
-	    QMessageBox::warning(this, "wpa_gui", "WPA-PSK requires a passphrase "
-				 "of 8 to 63 characters\n"
-				 "or 64 hex digit PSK");
-	    return;
-	}
-    }
-        
-    if (wpagui == NULL)
-	return;
-    
-    memset(reply, 0, sizeof(reply));
-    reply_len = sizeof(reply) - 1;
-    
-    if (new_network) {
-	wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len);
-	if (reply[0] == 'F') {
-	    QMessageBox::warning(this, "wpa_gui", "Failed to add network to wpa_supplicant\n"
-				 "configuration.");
-	    return;
-	}
-	id = atoi(reply);
-    } else {
-	id = edit_network_id;
-    }
-
-    setNetworkParam(id, "ssid", ssidEdit->text().ascii(), true);
-    
-    if (idstrEdit->isEnabled())
-	setNetworkParam(id, "id_str", idstrEdit->text().ascii(), true);
-
-    const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL;
-    switch (auth) {
-    case AUTH_NONE:
-	key_mgmt = "NONE";
-	break;
-    case AUTH_IEEE8021X:
-	key_mgmt = "IEEE8021X";
-	break;
-    case AUTH_WPA_PSK:
-	key_mgmt = "WPA-PSK";
-	proto = "WPA";
-	break;
-    case AUTH_WPA_EAP:
-	key_mgmt = "WPA-EAP";
-	proto = "WPA";
-	break;
-    case AUTH_WPA2_PSK:
-	key_mgmt = "WPA-PSK";
-	proto = "WPA2";
-	break;
-    case AUTH_WPA2_EAP:
-	key_mgmt = "WPA-EAP";
-	proto = "WPA2";
-	break;
-    }
-    
-    if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP ||
-	auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) {
-	int encr = encrSelect->currentItem();
-	if (encr == 0)
-	    pairwise = "TKIP";
-	else
-	    pairwise = "CCMP";
-    }
-    
-    if (proto)
-	setNetworkParam(id, "proto", proto, false);
-    if (key_mgmt)
-	setNetworkParam(id, "key_mgmt", key_mgmt, false);
-    if (pairwise) {
-	setNetworkParam(id, "pairwise", pairwise, false);
-	setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false);
-    }
-    if (pskEdit->isEnabled() &&
-	strcmp(pskEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
-	setNetworkParam(id, "psk", pskEdit->text().ascii(), psklen != 64);
-    if (eapSelect->isEnabled())
-	setNetworkParam(id, "eap", eapSelect->currentText().ascii(), false);
-    if (identityEdit->isEnabled())
-	setNetworkParam(id, "identity", identityEdit->text().ascii(), true);
-    if (passwordEdit->isEnabled() &&
-	strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
-	setNetworkParam(id, "password", passwordEdit->text().ascii(), true);
-    if (cacertEdit->isEnabled())
-	setNetworkParam(id, "ca_cert", cacertEdit->text().ascii(), true);
-    writeWepKey(id, wep0Edit, 0);
-    writeWepKey(id, wep1Edit, 1);
-    writeWepKey(id, wep2Edit, 2);
-    writeWepKey(id, wep3Edit, 3);
-  
-    if (wep0Radio->isEnabled() && wep0Radio->isChecked())
-	setNetworkParam(id, "wep_tx_keyidx", "0", false);
-    else if (wep1Radio->isEnabled() && wep1Radio->isChecked())
-	setNetworkParam(id, "wep_tx_keyidx", "1", false);
-    else if (wep2Radio->isEnabled() && wep2Radio->isChecked())
-	setNetworkParam(id, "wep_tx_keyidx", "2", false);
-    else if (wep3Radio->isEnabled() && wep3Radio->isChecked())
-	setNetworkParam(id, "wep_tx_keyidx", "3", false);
-
-    snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id);
-    reply_len = sizeof(reply);
-    wpagui->ctrlRequest(cmd, reply, &reply_len);
-    if (strncmp(reply, "OK", 2) != 0) {
-	QMessageBox::warning(this, "wpa_gui", "Failed to enable network in wpa_supplicant\n"
-			     "configuration.");
-	/* Network was added, so continue anyway */
-    }
-    wpagui->triggerUpdate();
-    wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
-
-    close();
-}
-
-
-void NetworkConfig::setWpaGui( WpaGui *_wpagui )
-{
-    wpagui = _wpagui;
-}
-
-
-int NetworkConfig::setNetworkParam(int id, const char *field, const char *value, bool quote)
-{
-    char reply[10], cmd[256];
-    size_t reply_len;
-    snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s",
-	     id, field, quote ? "\"" : "", value, quote ? "\"" : "");
-    reply_len = sizeof(reply);
-    wpagui->ctrlRequest(cmd, reply, &reply_len);
-    return strncmp(reply, "OK", 2) == 0 ? 0 : -1;
-}
-
-
-void NetworkConfig::encrChanged( const QString &sel )
-{
-    wepEnabled(sel.find("WEP") == 0);
-}
-
-
-void NetworkConfig::wepEnabled( bool enabled )
-{
-    wep0Edit->setEnabled(enabled);
-    wep1Edit->setEnabled(enabled);
-    wep2Edit->setEnabled(enabled);
-    wep3Edit->setEnabled(enabled);
-    wep0Radio->setEnabled(enabled);
-    wep1Radio->setEnabled(enabled);
-    wep2Radio->setEnabled(enabled);
-    wep3Radio->setEnabled(enabled);
-}
-
-
-void NetworkConfig::writeWepKey( int network_id, QLineEdit *edit, int id )
-{
-    char buf[10];
-    bool hex;
-    const char *txt, *pos;
-    size_t len;
-  
-    if (!edit->isEnabled() || edit->text().isEmpty())
-	return;
-    
-    /*
-        * Assume hex key if only hex characters are present and length matches
-       * with 40, 104, or 128-bit key
-       */
-    txt = edit->text().ascii();
-    if (strcmp(txt, WPA_GUI_KEY_DATA) == 0)
-	return;
-    len = strlen(txt);
-    if (len == 0)
-	return;
-    pos = txt;
-    hex = true;
-    while (*pos) {
-	if (!((*pos >= '0' && *pos <= '9') || (*pos >= 'a' && *pos <= 'f') ||
-	      (*pos >= 'A' && *pos <= 'F'))) {
-	    hex = false;
-	    break;
-	}
-	pos++;
-    }
-    if (hex && len != 10 && len != 26 && len != 32)
-	hex = false;
-    snprintf(buf, sizeof(buf), "wep_key%d", id);
-    setNetworkParam(network_id, buf, txt, !hex);
-}
-
-
-static int key_value_isset(const char *reply, size_t reply_len)
-{
-    return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0);
-}
-
-
-void NetworkConfig::paramsFromConfig( int network_id )
-{
-    int i, res;
-
-    edit_network_id = network_id;
-    getEapCapa();
-    
-    char reply[1024], cmd[256], *pos;
-    size_t reply_len;
-    
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
-	reply[0] == '"') {
-	reply[reply_len] = '\0';
-	pos = strchr(reply + 1, '"');
-	if (pos)
-	    *pos = '\0';
-	ssidEdit->setText(reply + 1);
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d id_str", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
-	reply[0] == '"') {
-	reply[reply_len] = '\0';
-	pos = strchr(reply + 1, '"');
-	if (pos)
-	    *pos = '\0';
-	idstrEdit->setText(reply + 1);
-    }
-    
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id);
-    reply_len = sizeof(reply) - 1;
-    int wpa = 0;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
-	reply[reply_len] = '\0';
-	if (strstr(reply, "RSN") || strstr(reply, "WPA2"))
-	    wpa = 2;
-	else if (strstr(reply, "WPA"))
-	    wpa = 1;
-    }
-
-    int auth = AUTH_NONE, encr = 0;
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
-	reply[reply_len] = '\0';
-	if (strstr(reply, "WPA-EAP"))
-	    auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP;
-	else if (strstr(reply, "WPA-PSK"))
-	    auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK;
-	else if (strstr(reply, "IEEE8021X")) {
-	    auth = AUTH_IEEE8021X;
-	    encr = 1;
-	}
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
-	reply[reply_len] = '\0';
-	if (strstr(reply, "CCMP") && auth != AUTH_NONE)
-	    encr = 1;
-	else if (strstr(reply, "TKIP"))
-	    encr = 0;
-	else if (strstr(reply, "WEP"))
-	    encr = 1;
-	else
-	    encr = 0;
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id);
-    reply_len = sizeof(reply) - 1;
-    res = wpagui->ctrlRequest(cmd, reply, &reply_len);
-    if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
-	reply[reply_len] = '\0';
-	pos = strchr(reply + 1, '"');
-	if (pos)
-	    *pos = '\0';
-	pskEdit->setText(reply + 1);
-    } else if (res >= 0 && key_value_isset(reply, reply_len)) {
-	pskEdit->setText(WPA_GUI_KEY_DATA);
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
-	reply[0] == '"') {
-	reply[reply_len] = '\0';
-	pos = strchr(reply + 1, '"');
-	if (pos)
-	    *pos = '\0';
-	identityEdit->setText(reply + 1);
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id);
-    reply_len = sizeof(reply) - 1;
-    res = wpagui->ctrlRequest(cmd, reply, &reply_len);
-    if (res >= 0 && reply_len >= 2 &&
-	reply[0] == '"') {
-	reply[reply_len] = '\0';
-	pos = strchr(reply + 1, '"');
-	if (pos)
-	    *pos = '\0';
-	passwordEdit->setText(reply + 1);
-    } else if (res >= 0 && key_value_isset(reply, reply_len)) {
-	passwordEdit->setText(WPA_GUI_KEY_DATA);
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
-	reply[0] == '"') {
-	reply[reply_len] = '\0';
-	pos = strchr(reply + 1, '"');
-	if (pos)
-	    *pos = '\0';
-	cacertEdit->setText(reply + 1);
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) {
-	reply[reply_len] = '\0';
-	for (i = 0; i < eapSelect->count(); i++) {
-	    if (eapSelect->text(i).compare(reply) == 0) {
-		eapSelect->setCurrentItem(i);
-		break;
-	    }
-	}
-    }
-
-    for (i = 0; i < 4; i++) {
-	QLineEdit *wepEdit;
-	switch (i) {
-	default:
-	case 0:
-	    wepEdit = wep0Edit;
-	    break;
-	case 1:
-	    wepEdit = wep1Edit;
-	    break;
-	case 2:
-	    wepEdit = wep2Edit;
-	    break;
-	case 3:
-	    wepEdit = wep3Edit;
-	    break;
-	}
-	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d", network_id, i);
-	reply_len = sizeof(reply) - 1;
-	res = wpagui->ctrlRequest(cmd, reply, &reply_len);
-	if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
-	    reply[reply_len] = '\0';
-	    pos = strchr(reply + 1, '"');
-	    if (pos)
-		*pos = '\0';
-	    if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
-		encr = 1;
-
-	    wepEdit->setText(reply + 1);
-	} else if (res >= 0 && key_value_isset(reply, reply_len)) {
-	    if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
-		encr = 1;
-	    wepEdit->setText(WPA_GUI_KEY_DATA);
-	}
-    }
-
-    snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id);
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) {
-	reply[reply_len] = '\0';
-	switch (atoi(reply)) {
-	case 0:
-	    wep0Radio->setChecked(true);
-	    break;
-	case 1:
-	    wep1Radio->setChecked(true);
-	    break;
-	case 2:
-	    wep2Radio->setChecked(true);
-	    break;
-	case 3:
-	    wep3Radio->setChecked(true);
-	    break;
-	}
-    }
-
-    authSelect->setCurrentItem(auth);
-    authChanged(auth);
-    encrSelect->setCurrentItem(encr);
-    if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
-	wepEnabled(encr == 1);
-
-    removeButton->setEnabled(true);
-    addButton->setText("Save");
-}
-
-
-void NetworkConfig::removeNetwork()
-{
-    char reply[10], cmd[256];
-    size_t reply_len;
-    
-    if (QMessageBox::information(this, "wpa_gui",
-				 "This will permanently remove the network\n"
-				 "from the configuration. Do you really want\n"
-				 "to remove this network?", "Yes", "No") != 0)
-	return;
-    
-    snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id);
-    reply_len = sizeof(reply);
-    wpagui->ctrlRequest(cmd, reply, &reply_len);
-    if (strncmp(reply, "OK", 2) != 0) {
-	QMessageBox::warning(this, "wpa_gui",
-			     "Failed to remove network from wpa_supplicant\n"
-			     "configuration.");
-    } else {
-	wpagui->triggerUpdate();
-	wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
-    }
-
-    close();
-}
-
-
-void NetworkConfig::newNetwork()
-{
-    new_network = true;
-    getEapCapa();
-}
-
-
-void NetworkConfig::getEapCapa()
-{
-    char reply[256];
-    size_t reply_len;
-    
-    if (wpagui == NULL)
-	return;
-
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0)
-	return;
-    reply[reply_len] = '\0';
-    
-    QString res(reply);
-    QStringList types = QStringList::split(QChar(' '), res);
-    eapSelect->insertStringList(types);
-}
diff --git a/wpa_supplicant/wpa_gui/scanresults.ui b/wpa_supplicant/wpa_gui/scanresults.ui
deleted file mode 100644
index dea305b..0000000
--- a/wpa_supplicant/wpa_gui/scanresults.ui
+++ /dev/null
@@ -1,179 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>ScanResults</class>
-<widget class="QDialog">
-    <property name="name">
-        <cstring>ScanResults</cstring>
-    </property>
-    <property name="geometry">
-        <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>452</width>
-            <height>225</height>
-        </rect>
-    </property>
-    <property name="caption">
-        <string>Scan results</string>
-    </property>
-    <vbox>
-        <property name="name">
-            <cstring>unnamed</cstring>
-        </property>
-        <widget class="QListView">
-            <column>
-                <property name="text">
-                    <string>SSID</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <column>
-                <property name="text">
-                    <string>BSSID</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <column>
-                <property name="text">
-                    <string>frequency</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <column>
-                <property name="text">
-                    <string>signal</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <column>
-                <property name="text">
-                    <string>flags</string>
-                </property>
-                <property name="clickable">
-                    <bool>true</bool>
-                </property>
-                <property name="resizable">
-                    <bool>true</bool>
-                </property>
-            </column>
-            <property name="name">
-                <cstring>scanResultsView</cstring>
-            </property>
-            <property name="frameShape">
-                <enum>StyledPanel</enum>
-            </property>
-            <property name="frameShadow">
-                <enum>Sunken</enum>
-            </property>
-        </widget>
-        <widget class="QLayoutWidget">
-            <property name="name">
-                <cstring>layout24</cstring>
-            </property>
-            <hbox>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <spacer>
-                    <property name="name">
-                        <cstring>spacer6</cstring>
-                    </property>
-                    <property name="orientation">
-                        <enum>Horizontal</enum>
-                    </property>
-                    <property name="sizeType">
-                        <enum>Expanding</enum>
-                    </property>
-                    <property name="sizeHint">
-                        <size>
-                            <width>50</width>
-                            <height>20</height>
-                        </size>
-                    </property>
-                </spacer>
-                <widget class="QPushButton">
-                    <property name="name">
-                        <cstring>scanButton</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Scan</string>
-                    </property>
-                </widget>
-                <widget class="QPushButton">
-                    <property name="name">
-                        <cstring>closeButton</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Close</string>
-                    </property>
-                </widget>
-            </hbox>
-        </widget>
-    </vbox>
-</widget>
-<connections>
-    <connection>
-        <sender>closeButton</sender>
-        <signal>clicked()</signal>
-        <receiver>ScanResults</receiver>
-        <slot>close()</slot>
-    </connection>
-    <connection>
-        <sender>scanButton</sender>
-        <signal>clicked()</signal>
-        <receiver>ScanResults</receiver>
-        <slot>scanRequest()</slot>
-    </connection>
-    <connection>
-        <sender>scanResultsView</sender>
-        <signal>doubleClicked(QListViewItem*)</signal>
-        <receiver>ScanResults</receiver>
-        <slot>bssSelected(QListViewItem*)</slot>
-    </connection>
-</connections>
-<includes>
-    <include location="local" impldecl="in implementation">common/wpa_ctrl.h</include>
-    <include location="local" impldecl="in implementation">wpagui.h</include>
-    <include location="local" impldecl="in implementation">networkconfig.h</include>
-    <include location="local" impldecl="in implementation">scanresults.ui.h</include>
-</includes>
-<forwards>
-    <forward>class WpaGui;</forward>
-</forwards>
-<variables>
-    <variable access="private">WpaGui *wpagui;</variable>
-    <variable access="private">QTimer *timer;</variable>
-</variables>
-<slots>
-    <slot>setWpaGui( WpaGui * _wpagui )</slot>
-    <slot>updateResults()</slot>
-    <slot>scanRequest()</slot>
-    <slot>getResults()</slot>
-    <slot>bssSelected( QListViewItem * sel )</slot>
-</slots>
-<functions>
-    <function access="private" specifier="non virtual">init()</function>
-    <function access="private" specifier="non virtual">destroy()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/scanresults.ui.h b/wpa_supplicant/wpa_gui/scanresults.ui.h
deleted file mode 100644
index 530d2e6..0000000
--- a/wpa_supplicant/wpa_gui/scanresults.ui.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-void ScanResults::init()
-{
-    wpagui = NULL;
-}
-
-
-void ScanResults::destroy()
-{
-    delete timer;
-}
-
-
-void ScanResults::setWpaGui(WpaGui *_wpagui)
-{
-    wpagui = _wpagui;
-    updateResults();
-    
-    timer = new QTimer(this);
-    connect(timer, SIGNAL(timeout()), SLOT(getResults()));
-    timer->start(10000, FALSE);
-}
-
-
-void ScanResults::updateResults()
-{
-    char reply[8192];
-    size_t reply_len;
-    
-    if (wpagui == NULL)
-	return;
-
-    reply_len = sizeof(reply) - 1;
-    if (wpagui->ctrlRequest("SCAN_RESULTS", reply, &reply_len) < 0)
-	return;
-    reply[reply_len] = '\0';
-
-    scanResultsView->clear();
-    
-    QString res(reply);
-    QStringList lines = QStringList::split(QChar('\n'), res);
-    bool first = true;
-    for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++) {
-	if (first) {
-	    first = false;
-	    continue;
-	}
-	
-	QStringList cols = QStringList::split(QChar('\t'), *it, true);
-	QString ssid, bssid, freq, signal, flags;
-	bssid = cols.count() > 0 ? cols[0] : "";
-	freq = cols.count() > 1 ? cols[1] : "";
-	signal = cols.count() > 2 ? cols[2] : "";
-	flags = cols.count() > 3 ? cols[3] : "";
-	ssid = cols.count() > 4 ? cols[4] : "";
-	new Q3ListViewItem(scanResultsView, ssid, bssid, freq, signal, flags);
-    }
-}
-
-
-void ScanResults::scanRequest()
-{
-    char reply[10];
-    size_t reply_len = sizeof(reply);
-    
-    if (wpagui == NULL)
-	return;
-    
-    wpagui->ctrlRequest("SCAN", reply, &reply_len);
-}
-
-
-void ScanResults::getResults()
-{
-    updateResults();
-}
-
-
-
-
-void ScanResults::bssSelected( Q3ListViewItem * sel )
-{
-    NetworkConfig *nc = new NetworkConfig();
-    if (nc == NULL)
-	return;
-    nc->setWpaGui(wpagui);
-    nc->paramsFromScanResults(sel);
-    nc->show();
-    nc->exec();
-}
diff --git a/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling b/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling
deleted file mode 100755
index e173b00..0000000
--- a/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-# qmake seems to be forcing include and lib paths from the original build
-# and I have no idea how to change these. For now, just override the
-# directories in the Makefile.Release file after qmake run.
-
-qmake -spec /q/jm/qt4-win/4.0.0/mkspecs/win32-g++ wpa_gui.pro -o Makefile
-cat Makefile.Release |
-    sed s%qt4/lib%qt4-win/4.0.0/lib%g |
-    sed s%qt4/include%qt4-win/4.0.0/include%g > tmp.Makefile.Release &&
-mv -f tmp.Makefile.Release Makefile.Release
diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui b/wpa_supplicant/wpa_gui/userdatarequest.ui
deleted file mode 100644
index 6106b1e..0000000
--- a/wpa_supplicant/wpa_gui/userdatarequest.ui
+++ /dev/null
@@ -1,163 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>UserDataRequest</class>
-<widget class="QDialog">
-    <property name="name">
-        <cstring>UserDataRequest</cstring>
-    </property>
-    <property name="geometry">
-        <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>216</width>
-            <height>103</height>
-        </rect>
-    </property>
-    <property name="caption">
-        <string>Authentication credentials required</string>
-    </property>
-    <property name="sizeGripEnabled">
-        <bool>true</bool>
-    </property>
-    <vbox>
-        <property name="name">
-            <cstring>unnamed</cstring>
-        </property>
-        <widget class="QLabel">
-            <property name="name">
-                <cstring>queryInfo</cstring>
-            </property>
-            <property name="text">
-                <string></string>
-            </property>
-        </widget>
-        <widget class="QLayoutWidget">
-            <property name="name">
-                <cstring>layout28</cstring>
-            </property>
-            <hbox>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <widget class="QLabel">
-                    <property name="name">
-                        <cstring>queryField</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLineEdit">
-                    <property name="name">
-                        <cstring>queryEdit</cstring>
-                    </property>
-                    <property name="enabled">
-                        <bool>true</bool>
-                    </property>
-                    <property name="echoMode">
-                        <enum>Password</enum>
-                    </property>
-                </widget>
-            </hbox>
-        </widget>
-        <widget class="QLayoutWidget">
-            <property name="name">
-                <cstring>layout27</cstring>
-            </property>
-            <hbox>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <spacer>
-                    <property name="name">
-                        <cstring>spacer4</cstring>
-                    </property>
-                    <property name="orientation">
-                        <enum>Horizontal</enum>
-                    </property>
-                    <property name="sizeType">
-                        <enum>Expanding</enum>
-                    </property>
-                    <property name="sizeHint">
-                        <size>
-                            <width>20</width>
-                            <height>20</height>
-                        </size>
-                    </property>
-                </spacer>
-                <widget class="QPushButton">
-                    <property name="name">
-                        <cstring>buttonOk</cstring>
-                    </property>
-                    <property name="text">
-                        <string>&amp;OK</string>
-                    </property>
-                    <property name="accel">
-                        <string></string>
-                    </property>
-                    <property name="autoDefault">
-                        <bool>true</bool>
-                    </property>
-                    <property name="default">
-                        <bool>true</bool>
-                    </property>
-                </widget>
-                <widget class="QPushButton">
-                    <property name="name">
-                        <cstring>buttonCancel</cstring>
-                    </property>
-                    <property name="text">
-                        <string>&amp;Cancel</string>
-                    </property>
-                    <property name="accel">
-                        <string></string>
-                    </property>
-                    <property name="autoDefault">
-                        <bool>true</bool>
-                    </property>
-                </widget>
-            </hbox>
-        </widget>
-    </vbox>
-</widget>
-<connections>
-    <connection>
-        <sender>buttonOk</sender>
-        <signal>clicked()</signal>
-        <receiver>UserDataRequest</receiver>
-        <slot>sendReply()</slot>
-    </connection>
-    <connection>
-        <sender>buttonCancel</sender>
-        <signal>clicked()</signal>
-        <receiver>UserDataRequest</receiver>
-        <slot>reject()</slot>
-    </connection>
-    <connection>
-        <sender>queryEdit</sender>
-        <signal>returnPressed()</signal>
-        <receiver>UserDataRequest</receiver>
-        <slot>sendReply()</slot>
-    </connection>
-</connections>
-<includes>
-    <include location="local" impldecl="in implementation">common/wpa_ctrl.h</include>
-    <include location="local" impldecl="in implementation">wpagui.h</include>
-    <include location="local" impldecl="in implementation">userdatarequest.ui.h</include>
-</includes>
-<forwards>
-    <forward>class WpaGui;</forward>
-</forwards>
-<variables>
-    <variable access="private">WpaGui *wpagui;</variable>
-    <variable access="private">int networkid;</variable>
-    <variable access="private">QString field;</variable>
-</variables>
-<slots>
-    <slot>sendReply()</slot>
-</slots>
-<functions>
-    <function specifier="non virtual" returnType="int">setParams( WpaGui * _wpagui, const char * reqMsg )</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui.h b/wpa_supplicant/wpa_gui/userdatarequest.ui.h
deleted file mode 100644
index 66d4478..0000000
--- a/wpa_supplicant/wpa_gui/userdatarequest.ui.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-#include <stdlib.h>
-
-int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg)
-{
-    char *tmp, *pos, *pos2;
-    wpagui = _wpagui;
-    tmp = strdup(reqMsg);
-    if (tmp == NULL)
-	return -1;
-    pos = strchr(tmp, '-');
-    if (pos == NULL) {
-	free(tmp);
-	return -1;
-    }
-    *pos++ = '\0';
-    field = tmp;
-    pos2 = strchr(pos, ':');
-    if (pos2 == NULL) {
-	free(tmp);
-	return -1;
-    }
-    *pos2++ = '\0';
-    
-    networkid = atoi(pos);
-    queryInfo->setText(pos2);
-    if (strcmp(tmp, "PASSWORD") == 0) {
-	queryField->setText("Password: ");
-	queryEdit->setEchoMode(QLineEdit::Password);
-    } else if (strcmp(tmp, "NEW_PASSWORD") == 0) {
-	queryField->setText("New password: ");
- 	queryEdit->setEchoMode(QLineEdit::Password);
-    } else if (strcmp(tmp, "IDENTITY") == 0)
-	queryField->setText("Identity: ");
-    else if (strcmp(tmp, "PASSPHRASE") == 0) {
-	queryField->setText("Private key passphrase: ");
- 	queryEdit->setEchoMode(QLineEdit::Password);
-    } else
-	queryField->setText(field + ":");
-    free(tmp);
-    
-    return 0;
-}
-
-
-void UserDataRequest::sendReply()
-{
-    char reply[10];
-    size_t reply_len = sizeof(reply);
-    
-    if (wpagui == NULL) {
-	reject();
-	return;
-    }
-    
-    QString cmd = QString(WPA_CTRL_RSP) + field + '-' +
-		  QString::number(networkid) + ':' +
-		  queryEdit->text();
-    wpagui->ctrlRequest(cmd.ascii(), reply, &reply_len);
-    accept();
-}
diff --git a/wpa_supplicant/wpa_gui/wpa_gui.pro b/wpa_supplicant/wpa_gui/wpa_gui.pro
deleted file mode 100644
index a42a4ac..0000000
--- a/wpa_supplicant/wpa_gui/wpa_gui.pro
+++ /dev/null
@@ -1,50 +0,0 @@
-TEMPLATE	= app
-LANGUAGE	= C++
-
-CONFIG	+= qt warn_on release
-
-DEFINES += CONFIG_CTRL_IFACE
-
-win32 {
-  LIBS += -lws2_32 -static
-  DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
-  SOURCES += ../../src/utils/os_win32.c
-} else:win32-g++ {
-  # cross compilation to win32
-  LIBS += -lws2_32 -static
-  DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
-  SOURCES += ../../src/utils/os_win32.c
-} else {
-  DEFINES += CONFIG_CTRL_IFACE_UNIX
-  SOURCES += ../../src/utils/os_unix.c
-}
-
-INCLUDEPATH	+= . .. ../../src ../../src/utils
-
-HEADERS	+= wpamsg.h
-
-SOURCES	+= main.cpp \
-	../../src/common/wpa_ctrl.c
-
-FORMS	= wpagui.ui \
-	eventhistory.ui \
-	scanresults.ui \
-	userdatarequest.ui \
-	networkconfig.ui
-
-
-unix {
-  UI_DIR = .ui
-  MOC_DIR = .moc
-  OBJECTS_DIR = .obj
-}
-
-qtver = $$[QT_VERSION]
-isEmpty( qtver ) {
-	message(Compiling for Qt 3.x)
-	DEFINES += Q3ListViewItem=QListViewItem
-} else {
-	message(Compiling for Qt $$qtver)
-	QT += qt3support
-	CONFIG += uic3
-}
diff --git a/wpa_supplicant/wpa_gui/wpagui.ui b/wpa_supplicant/wpa_gui/wpagui.ui
deleted file mode 100644
index b49d96b..0000000
--- a/wpa_supplicant/wpa_gui/wpagui.ui
+++ /dev/null
@@ -1,471 +0,0 @@
-<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
-<class>WpaGui</class>
-<widget class="QMainWindow">
-    <property name="name">
-        <cstring>WpaGui</cstring>
-    </property>
-    <property name="geometry">
-        <rect>
-            <x>0</x>
-            <y>0</y>
-            <width>279</width>
-            <height>308</height>
-        </rect>
-    </property>
-    <property name="caption">
-        <string>wpa_gui</string>
-    </property>
-    <grid>
-        <property name="name">
-            <cstring>unnamed</cstring>
-        </property>
-        <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
-            <property name="name">
-                <cstring>textLabel16</cstring>
-            </property>
-            <property name="text">
-                <string>Adapter:</string>
-            </property>
-        </widget>
-        <widget class="QComboBox" row="0" column="2" rowspan="1" colspan="2">
-            <property name="name">
-                <cstring>adapterSelect</cstring>
-            </property>
-        </widget>
-        <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2">
-            <property name="name">
-                <cstring>textLabel8</cstring>
-            </property>
-            <property name="text">
-                <string>Network:</string>
-            </property>
-        </widget>
-        <widget class="QComboBox" row="1" column="2" rowspan="1" colspan="2">
-            <property name="name">
-                <cstring>networkSelect</cstring>
-            </property>
-        </widget>
-        <widget class="QFrame" row="2" column="0" rowspan="1" colspan="4">
-            <property name="name">
-                <cstring>frame3</cstring>
-            </property>
-            <property name="frameShape">
-                <enum>StyledPanel</enum>
-            </property>
-            <property name="frameShadow">
-                <enum>Raised</enum>
-            </property>
-            <grid>
-                <property name="name">
-                    <cstring>unnamed</cstring>
-                </property>
-                <widget class="QLabel" row="0" column="0">
-                    <property name="name">
-                        <cstring>textLabel1</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Status:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="1" column="0">
-                    <property name="name">
-                        <cstring>textLabel2</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Last message:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="2" column="0">
-                    <property name="name">
-                        <cstring>textLabel3</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Authentication:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="3" column="0">
-                    <property name="name">
-                        <cstring>textLabel4</cstring>
-                    </property>
-                    <property name="text">
-                        <string>Encryption:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="4" column="0">
-                    <property name="name">
-                        <cstring>textLabel5</cstring>
-                    </property>
-                    <property name="text">
-                        <string>SSID:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="5" column="0">
-                    <property name="name">
-                        <cstring>textLabel6</cstring>
-                    </property>
-                    <property name="text">
-                        <string>BSSID:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="6" column="0">
-                    <property name="name">
-                        <cstring>textLabel7</cstring>
-                    </property>
-                    <property name="text">
-                        <string>IP address:</string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="0" column="1">
-                    <property name="name">
-                        <cstring>textStatus</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="1" column="1" rowspan="1" colspan="3">
-                    <property name="name">
-                        <cstring>textLastMessage</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="2" column="1">
-                    <property name="name">
-                        <cstring>textAuthentication</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="3" column="1">
-                    <property name="name">
-                        <cstring>textEncryption</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="4" column="1">
-                    <property name="name">
-                        <cstring>textSsid</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="5" column="1">
-                    <property name="name">
-                        <cstring>textBssid</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-                <widget class="QLabel" row="6" column="1">
-                    <property name="name">
-                        <cstring>textIpAddress</cstring>
-                    </property>
-                    <property name="text">
-                        <string></string>
-                    </property>
-                </widget>
-            </grid>
-        </widget>
-        <spacer row="3" column="0">
-            <property name="name">
-                <cstring>spacer7</cstring>
-            </property>
-            <property name="orientation">
-                <enum>Horizontal</enum>
-            </property>
-            <property name="sizeType">
-                <enum>Expanding</enum>
-            </property>
-            <property name="sizeHint">
-                <size>
-                    <width>16</width>
-                    <height>16</height>
-                </size>
-            </property>
-        </spacer>
-        <widget class="QPushButton" row="3" column="1">
-            <property name="name">
-                <cstring>connectButton</cstring>
-            </property>
-            <property name="text">
-                <string>Connect</string>
-            </property>
-        </widget>
-        <widget class="QPushButton" row="3" column="2">
-            <property name="name">
-                <cstring>disconnectButton</cstring>
-            </property>
-            <property name="text">
-                <string>Disconnect</string>
-            </property>
-        </widget>
-        <widget class="QPushButton" row="3" column="3">
-            <property name="name">
-                <cstring>scanButton</cstring>
-            </property>
-            <property name="text">
-                <string>Scan</string>
-            </property>
-        </widget>
-    </grid>
-</widget>
-<menubar>
-    <property name="name">
-        <cstring>MenuBar</cstring>
-    </property>
-    <item text="&amp;File" name="fileMenu">
-        <separator/>
-        <action name="fileEventHistoryAction"/>
-        <action name="fileAdd_NetworkAction"/>
-        <action name="fileEdit_networkAction"/>
-        <separator/>
-        <action name="fileExitAction"/>
-    </item>
-    <item text="&amp;Help" name="helpMenu">
-        <action name="helpContentsAction"/>
-        <action name="helpIndexAction"/>
-        <separator/>
-        <action name="helpAboutAction"/>
-    </item>
-</menubar>
-<toolbars>
-</toolbars>
-<actions>
-    <action>
-        <property name="name">
-            <cstring>fileExitAction</cstring>
-        </property>
-        <property name="text">
-            <string>Exit</string>
-        </property>
-        <property name="menuText">
-            <string>E&amp;xit</string>
-        </property>
-        <property name="accel">
-            <string>Ctrl+Q</string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>helpContentsAction</cstring>
-        </property>
-        <property name="enabled">
-            <bool>false</bool>
-        </property>
-        <property name="text">
-            <string>Contents</string>
-        </property>
-        <property name="menuText">
-            <string>&amp;Contents...</string>
-        </property>
-        <property name="accel">
-            <string></string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>helpIndexAction</cstring>
-        </property>
-        <property name="enabled">
-            <bool>false</bool>
-        </property>
-        <property name="text">
-            <string>Index</string>
-        </property>
-        <property name="menuText">
-            <string>&amp;Index...</string>
-        </property>
-        <property name="accel">
-            <string></string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>helpAboutAction</cstring>
-        </property>
-        <property name="text">
-            <string>About</string>
-        </property>
-        <property name="menuText">
-            <string>&amp;About</string>
-        </property>
-        <property name="accel">
-            <string></string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>fileEventHistoryAction</cstring>
-        </property>
-        <property name="text">
-            <string>Event History</string>
-        </property>
-        <property name="menuText">
-            <string>Event &amp;History</string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>fileAdd_NetworkAction</cstring>
-        </property>
-        <property name="text">
-            <string>Add Network</string>
-        </property>
-        <property name="menuText">
-            <string>&amp;Add Network</string>
-        </property>
-    </action>
-    <action>
-        <property name="name">
-            <cstring>fileEdit_networkAction</cstring>
-        </property>
-        <property name="text">
-            <string>Edit Network</string>
-        </property>
-        <property name="menuText">
-            <string>&amp;Edit Network</string>
-        </property>
-    </action>
-</actions>
-<connections>
-    <connection>
-        <sender>helpIndexAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>helpIndex()</slot>
-    </connection>
-    <connection>
-        <sender>helpContentsAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>helpContents()</slot>
-    </connection>
-    <connection>
-        <sender>helpAboutAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>helpAbout()</slot>
-    </connection>
-    <connection>
-        <sender>fileExitAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>close()</slot>
-    </connection>
-    <connection>
-        <sender>disconnectButton</sender>
-        <signal>clicked()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>disconnect()</slot>
-    </connection>
-    <connection>
-        <sender>scanButton</sender>
-        <signal>clicked()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>scan()</slot>
-    </connection>
-    <connection>
-        <sender>connectButton</sender>
-        <signal>clicked()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>connectB()</slot>
-    </connection>
-    <connection>
-        <sender>fileEventHistoryAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>eventHistory()</slot>
-    </connection>
-    <connection>
-        <sender>networkSelect</sender>
-        <signal>activated(const QString&amp;)</signal>
-        <receiver>WpaGui</receiver>
-        <slot>selectNetwork(const QString&amp;)</slot>
-    </connection>
-    <connection>
-        <sender>fileEdit_networkAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>editNetwork()</slot>
-    </connection>
-    <connection>
-        <sender>fileAdd_NetworkAction</sender>
-        <signal>activated()</signal>
-        <receiver>WpaGui</receiver>
-        <slot>addNetwork()</slot>
-    </connection>
-    <connection>
-        <sender>adapterSelect</sender>
-        <signal>activated(const QString&amp;)</signal>
-        <receiver>WpaGui</receiver>
-        <slot>selectAdapter(const QString&amp;)</slot>
-    </connection>
-</connections>
-<includes>
-    <include location="global" impldecl="in declaration">qtimer.h</include>
-    <include location="global" impldecl="in declaration">qsocketnotifier.h</include>
-    <include location="local" impldecl="in declaration">wpamsg.h</include>
-    <include location="local" impldecl="in declaration">eventhistory.h</include>
-    <include location="local" impldecl="in declaration">scanresults.h</include>
-    <include location="local" impldecl="in implementation">common/wpa_ctrl.h</include>
-    <include location="global" impldecl="in implementation">dirent.h</include>
-    <include location="global" impldecl="in implementation">qmessagebox.h</include>
-    <include location="global" impldecl="in implementation">qapplication.h</include>
-    <include location="local" impldecl="in implementation">userdatarequest.h</include>
-    <include location="local" impldecl="in implementation">networkconfig.h</include>
-    <include location="local" impldecl="in implementation">wpagui.ui.h</include>
-</includes>
-<forwards>
-    <forward>class UserDataRequest;</forward>
-</forwards>
-<variables>
-    <variable access="private">ScanResults *scanres;</variable>
-    <variable access="private">bool networkMayHaveChanged;</variable>
-    <variable access="private">char *ctrl_iface;</variable>
-    <variable access="private">EventHistory *eh;</variable>
-    <variable access="private">struct wpa_ctrl *ctrl_conn;</variable>
-    <variable access="private">QSocketNotifier *msgNotifier;</variable>
-    <variable access="private">QTimer *timer;</variable>
-    <variable access="private">int pingsToStatusUpdate;</variable>
-    <variable access="private">WpaMsgList msgs;</variable>
-    <variable access="private">char *ctrl_iface_dir;</variable>
-    <variable access="private">struct wpa_ctrl *monitor_conn;</variable>
-    <variable access="private">UserDataRequest *udr;</variable>
-</variables>
-<slots>
-    <slot>parse_argv()</slot>
-    <slot>updateStatus()</slot>
-    <slot>updateNetworks()</slot>
-    <slot>helpIndex()</slot>
-    <slot>helpContents()</slot>
-    <slot>helpAbout()</slot>
-    <slot>disconnect()</slot>
-    <slot>scan()</slot>
-    <slot>eventHistory()</slot>
-    <slot>ping()</slot>
-    <slot>processMsg( char * msg )</slot>
-    <slot>processCtrlReq( const char * req )</slot>
-    <slot>receiveMsgs()</slot>
-    <slot>connectB()</slot>
-    <slot>selectNetwork( const QString &amp; sel )</slot>
-    <slot>editNetwork()</slot>
-    <slot>addNetwork()</slot>
-    <slot>selectAdapter( const QString &amp; sel )</slot>
-</slots>
-<functions>
-    <function access="private" specifier="non virtual">init()</function>
-    <function access="private" specifier="non virtual">destroy()</function>
-    <function access="private" specifier="non virtual" returnType="int">openCtrlConnection( const char * ifname )</function>
-    <function returnType="int">ctrlRequest( const char * cmd, char * buf, size_t * buflen )</function>
-    <function>triggerUpdate()</function>
-</functions>
-<pixmapinproject/>
-<layoutdefaults spacing="6" margin="11"/>
-</UI>
diff --git a/wpa_supplicant/wpa_gui/wpagui.ui.h b/wpa_supplicant/wpa_gui/wpagui.ui.h
deleted file mode 100644
index 678ff1b..0000000
--- a/wpa_supplicant/wpa_gui/wpagui.ui.h
+++ /dev/null
@@ -1,730 +0,0 @@
-/****************************************************************************
-** ui.h extension file, included from the uic-generated form implementation.
-**
-** If you want to add, delete, or rename functions or slots, use
-** Qt Designer to update this file, preserving your code.
-**
-** You should not define a constructor or destructor in this file.
-** Instead, write your code in functions called init() and destroy().
-** These will automatically be called by the form's constructor and
-** destructor.
-*****************************************************************************/
-
-
-#ifdef __MINGW32__
-/* Need to get getopt() */
-#include <unistd.h>
-#endif
-
-#include <stdlib.h>
-
-void WpaGui::init()
-{
-    eh = NULL;
-    scanres = NULL;
-    udr = NULL;
-    ctrl_iface = NULL;
-    ctrl_conn = NULL;
-    monitor_conn = NULL;
-    msgNotifier = NULL;
-    ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
-    
-    parse_argv();
-
-    textStatus->setText("connecting to wpa_supplicant");
-    timer = new QTimer(this);
-    connect(timer, SIGNAL(timeout()), SLOT(ping()));
-    timer->start(1000, FALSE);
-    
-    if (openCtrlConnection(ctrl_iface) < 0) {
-	printf("Failed to open control connection to wpa_supplicant.\n");
-    }
-    
-    updateStatus();
-    networkMayHaveChanged = true;
-    updateNetworks();
-}
-
-
-void WpaGui::destroy()
-{
-    delete msgNotifier;
-
-    if (monitor_conn) {
-	wpa_ctrl_detach(monitor_conn);
-	wpa_ctrl_close(monitor_conn);
-	monitor_conn = NULL;
-    }
-    if (ctrl_conn) {
-	wpa_ctrl_close(ctrl_conn);
-	ctrl_conn = NULL;
-    }
-    
-    if (eh) {
-	eh->close();
-	delete eh;
-	eh = NULL;
-    }
-    
-    if (scanres) {
-	scanres->close();
-	delete scanres;
-	scanres = NULL;
-    }
-    
-    if (udr) {
-	udr->close();
-	delete udr;
-	udr = NULL;
-    }
-    
-    free(ctrl_iface);
-    ctrl_iface = NULL;
-    
-    free(ctrl_iface_dir);
-    ctrl_iface_dir = NULL;
-}
-
-
-void WpaGui::parse_argv()
-{
-    int c;
-    for (;;) {
-	c = getopt(qApp->argc(), qApp->argv(), "i:p:");
-	if (c < 0)
-	    break;
-	switch (c) {
-	case 'i':
-	    free(ctrl_iface);
-	    ctrl_iface = strdup(optarg);
-	    break;
-	case 'p':
-	    free(ctrl_iface_dir);
-	    ctrl_iface_dir = strdup(optarg);
-	    break;
-	}
-    }
-}
-
-
-int WpaGui::openCtrlConnection(const char *ifname)
-{
-    char *cfile;
-    int flen;
-    char buf[2048], *pos, *pos2;
-    size_t len;
-
-    if (ifname) {
-	if (ifname != ctrl_iface) {
-	    free(ctrl_iface);
-	    ctrl_iface = strdup(ifname);
-	}
-    } else {
-#ifdef CONFIG_CTRL_IFACE_UDP
-	free(ctrl_iface);
-	ctrl_iface = strdup("udp");
-#endif /* CONFIG_CTRL_IFACE_UDP */
-#ifdef CONFIG_CTRL_IFACE_UNIX
-	struct dirent *dent;
-	DIR *dir = opendir(ctrl_iface_dir);
-	free(ctrl_iface);
-	ctrl_iface = NULL;
-	if (dir) {
-	    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;
-		printf("Selected interface '%s'\n", dent->d_name);
-		ctrl_iface = strdup(dent->d_name);
-		break;
-	    }
-	    closedir(dir);
-	}
-#endif /* CONFIG_CTRL_IFACE_UNIX */
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
-	struct wpa_ctrl *ctrl;
-	int ret;
-
-	free(ctrl_iface);
-	ctrl_iface = NULL;
-
-	ctrl = wpa_ctrl_open(NULL);
-	if (ctrl) {
-	    len = sizeof(buf) - 1;
-	    ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
-	    if (ret >= 0) {
-		buf[len] = '\0';
-		pos = strchr(buf, '\n');
-		if (pos)
-		    *pos = '\0';
-		ctrl_iface = strdup(buf);
-	    }
-	    wpa_ctrl_close(ctrl);
-	}
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
-    }
-    
-    if (ctrl_iface == NULL)
-	return -1;
-
-#ifdef CONFIG_CTRL_IFACE_UNIX
-    flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
-    cfile = (char *) malloc(flen);
-    if (cfile == NULL)
-	return -1;
-    snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
-#else /* CONFIG_CTRL_IFACE_UNIX */
-    flen = strlen(ctrl_iface) + 1;
-    cfile = (char *) malloc(flen);
-    if (cfile == NULL)
-	return -1;
-    snprintf(cfile, flen, "%s", ctrl_iface);
-#endif /* CONFIG_CTRL_IFACE_UNIX */
-
-    if (ctrl_conn) {
-	wpa_ctrl_close(ctrl_conn);
-	ctrl_conn = NULL;
-    }
-
-    if (monitor_conn) {
-	delete msgNotifier;
-	msgNotifier = NULL;
-	wpa_ctrl_detach(monitor_conn);
-	wpa_ctrl_close(monitor_conn);
-	monitor_conn = NULL;
-    }
-
-    printf("Trying to connect to '%s'\n", cfile);
-    ctrl_conn = wpa_ctrl_open(cfile);
-    if (ctrl_conn == NULL) {
-	free(cfile);
-	return -1;
-    }
-    monitor_conn = wpa_ctrl_open(cfile);
-    free(cfile);
-    if (monitor_conn == NULL) {
-	wpa_ctrl_close(ctrl_conn);
-	return -1;
-    }
-    if (wpa_ctrl_attach(monitor_conn)) {
-	printf("Failed to attach to wpa_supplicant\n");
-	wpa_ctrl_close(monitor_conn);
-	monitor_conn = NULL;
-	wpa_ctrl_close(ctrl_conn);
-	ctrl_conn = NULL;
-	return -1;
-    }
-
-#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
-    msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
-				      QSocketNotifier::Read, this);
-    connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
-#endif
-
-    adapterSelect->clear();
-    adapterSelect->insertItem(ctrl_iface);
-    adapterSelect->setCurrentItem(0);
-
-    len = sizeof(buf) - 1;
-    if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 0) {
-	buf[len] = '\0';
-	pos = buf;
-	while (*pos) {
-		pos2 = strchr(pos, '\n');
-		if (pos2)
-			*pos2 = '\0';
-		if (strcmp(pos, ctrl_iface) != 0)
-			adapterSelect->insertItem(pos);
-		if (pos2)
-			pos = pos2 + 1;
-		else
-			break;
-	}
-    }
-
-    return 0;
-}
-
-
-static void wpa_gui_msg_cb(char *msg, size_t)
-{
-    /* This should not happen anymore since two control connections are used. */
-    printf("missed message: %s\n", msg);
-}
-
-
-int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
-{
-    int ret;
-    
-    if (ctrl_conn == NULL)
-	return -3;
-    ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
-			   wpa_gui_msg_cb);
-    if (ret == -2) {
-	printf("'%s' command timed out.\n", cmd);
-    } else if (ret < 0) {
-	printf("'%s' command failed.\n", cmd);
-    }
-    
-    return ret;
-}
-
-
-void WpaGui::updateStatus()
-{
-    char buf[2048], *start, *end, *pos;
-    size_t len;
-
-    pingsToStatusUpdate = 10;
-
-    len = sizeof(buf) - 1;
-    if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
-	textStatus->setText("Could not get status from wpa_supplicant");
-	textAuthentication->clear();
-	textEncryption->clear();
-	textSsid->clear();
-	textBssid->clear();
-	textIpAddress->clear();
-	return;
-    }
-    
-    buf[len] = '\0';
-    
-    bool auth_updated = false, ssid_updated = false;
-    bool bssid_updated = false, ipaddr_updated = false;
-    bool status_updated = false;
-    char *pairwise_cipher = NULL, *group_cipher = NULL;
-    
-    start = buf;
-    while (*start) {
-	bool last = false;
-	end = strchr(start, '\n');
-	if (end == NULL) {
-	    last = true;
-	    end = start;
-	    while (end[0] && end[1])
-		end++;
-	}
-	*end = '\0';
-	
-	pos = strchr(start, '=');
-	if (pos) {
-	    *pos++ = '\0';
-	    if (strcmp(start, "bssid") == 0) {
-		bssid_updated = true;
-		textBssid->setText(pos);
-	    } else if (strcmp(start, "ssid") == 0) {
-		ssid_updated = true;
-		textSsid->setText(pos);
-	    } else if (strcmp(start, "ip_address") == 0) {
-		ipaddr_updated = true;
-		textIpAddress->setText(pos);
-	    } else if (strcmp(start, "wpa_state") == 0) {
-		status_updated = true;
-		textStatus->setText(pos);
-	    } else if (strcmp(start, "key_mgmt") == 0) {
-		auth_updated = true;
-		textAuthentication->setText(pos);
-		/* TODO: could add EAP status to this */
-	    } else if (strcmp(start, "pairwise_cipher") == 0) {
-		pairwise_cipher = pos;
-	    } else if (strcmp(start, "group_cipher") == 0) {
-		group_cipher = pos;
-	    }
-	}
-	
-	if (last)
-	    break;
-	start = end + 1;
-    }
-    
-    if (pairwise_cipher || group_cipher) {
-	QString encr;
-	if (pairwise_cipher && group_cipher &&
-	    strcmp(pairwise_cipher, group_cipher) != 0) {
-	    encr.append(pairwise_cipher);
-	    encr.append(" + ");
-	    encr.append(group_cipher);
-	} else if (pairwise_cipher) {
-	    encr.append(pairwise_cipher);
-	} else {
-	    encr.append(group_cipher);
-	    encr.append(" [group key only]");
-	}
-	textEncryption->setText(encr);
-    } else
-	textEncryption->clear();
-
-    if (!status_updated)
-	textStatus->clear();
-    if (!auth_updated)
-	textAuthentication->clear();
-    if (!ssid_updated)
-	textSsid->clear();
-    if (!bssid_updated)
-	textBssid->clear();
-    if (!ipaddr_updated)
-	textIpAddress->clear();
-}
-
-
-void WpaGui::updateNetworks()
-{
-    char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
-    size_t len;
-    int first_active = -1;
-    bool selected = false;
-
-    if (!networkMayHaveChanged)
-	return;
-
-    networkSelect->clear();
-
-    if (ctrl_conn == NULL)
-	return;
-    
-    len = sizeof(buf) - 1;
-    if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
-	return;
-    
-    buf[len] = '\0';
-    start = strchr(buf, '\n');
-    if (start == NULL)
-	return;
-    start++;
-
-    while (*start) {
-	bool last = false;
-	end = strchr(start, '\n');
-	if (end == NULL) {
-	    last = true;
-	    end = start;
-	    while (end[0] && end[1])
-		end++;
-	}
-	*end = '\0';
-	
-	id = start;
-	ssid = strchr(id, '\t');
-	if (ssid == NULL)
-	    break;
-	*ssid++ = '\0';
-	bssid = strchr(ssid, '\t');
-	if (bssid == NULL)
-	    break;
-	*bssid++ = '\0';
-	flags = strchr(bssid, '\t');
-	if (flags == NULL)
-	    break;
-	*flags++ = '\0';
-	
-	QString network(id);
-	network.append(": ");
-	network.append(ssid);
-	networkSelect->insertItem(network);
-	
-	if (strstr(flags, "[CURRENT]")) {
-	    networkSelect->setCurrentItem(networkSelect->count() - 1);
-	    selected = true;
-	} else if (first_active < 0 && strstr(flags, "[DISABLED]") == NULL)
-	    first_active = networkSelect->count() - 1;
-	
-	if (last)
-	    break;
-	start = end + 1;
-    }
-
-    if (!selected && first_active >= 0)
-	networkSelect->setCurrentItem(first_active);
-
-    networkMayHaveChanged = false;
-}
-
-
-void WpaGui::helpIndex()
-{
-    printf("helpIndex\n");
-}
-
-
-void WpaGui::helpContents()
-{
-    printf("helpContents\n");
-}
-
-
-void WpaGui::helpAbout()
-{
-    QMessageBox::about(this, "wpa_gui for wpa_supplicant",
-		       "Copyright (c) 2003-2008,\n"
-		       "Jouni Malinen <j@w1.fi>\n"
-		       "and contributors.\n"
-		       "\n"
-		       "This program is free software. You can\n"
-		       "distribute it and/or modify it under the terms of\n"
-		       "the GNU General Public License version 2.\n"
-		       "\n"
-		       "Alternatively, this software may be distributed\n"
-		       "under the terms of the BSD license.\n"
-		       "\n"
-		       "This product includes software developed\n"
-		       "by the OpenSSL Project for use in the\n"
-		       "OpenSSL Toolkit (http://www.openssl.org/)\n");
-}
-
-
-void WpaGui::disconnect()
-{
-    char reply[10];
-    size_t reply_len = sizeof(reply);
-    ctrlRequest("DISCONNECT", reply, &reply_len);
-}
-
-
-void WpaGui::scan()
-{
-    if (scanres) {
-	scanres->close();
-	delete scanres;
-    }
-
-    scanres = new ScanResults();
-    if (scanres == NULL)
-	return;
-    scanres->setWpaGui(this);
-    scanres->show();
-    scanres->exec();
-}
-
-
-void WpaGui::eventHistory()
-{
-    if (eh) {
-	eh->close();
-	delete eh;
-    }
-
-    eh = new EventHistory();
-    if (eh == NULL)
-	return;
-    eh->addEvents(msgs);
-    eh->show();
-    eh->exec();
-}
-
-
-void WpaGui::ping()
-{
-    char buf[10];
-    size_t len;
-    
-#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
-    /*
-     * QSocketNotifier cannot be used with Windows named pipes, so use a timer
-     * to check for received messages for now. This could be optimized be doing
-     * something specific to named pipes or Windows events, but it is not clear
-     * what would be the best way of doing that in Qt.
-     */
-    receiveMsgs();
-#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
-
-    if (scanres && !scanres->isVisible()) {
-	delete scanres;
-	scanres = NULL;
-    }
-    
-    if (eh && !eh->isVisible()) {
-	delete eh;
-	eh = NULL;
-    }
-    
-    if (udr && !udr->isVisible()) {
-	delete udr;
-	udr = NULL;
-    }
-    
-    len = sizeof(buf) - 1;
-    if (ctrlRequest("PING", buf, &len) < 0) {
-	printf("PING failed - trying to reconnect\n");
-	if (openCtrlConnection(ctrl_iface) >= 0) {
-	    printf("Reconnected successfully\n");
-	    pingsToStatusUpdate = 0;
-	}
-    }
-
-    pingsToStatusUpdate--;
-    if (pingsToStatusUpdate <= 0) {
-	updateStatus();
-	updateNetworks();
-    }
-}
-
-
-static int str_match(const char *a, const char *b)
-{
-    return strncmp(a, b, strlen(b)) == 0;
-}
-
-
-void WpaGui::processMsg(char *msg)
-{
-    char *pos = msg, *pos2;
-    int priority = 2;
-    
-    if (*pos == '<') {
-	/* skip priority */
-	pos++;
-	priority = atoi(pos);
-	pos = strchr(pos, '>');
-	if (pos)
-	    pos++;
-	else
-	    pos = msg;
-    }
-
-    WpaMsg wm(pos, priority);
-    if (eh)
-	eh->addEvent(wm);
-    msgs.append(wm);
-    while (msgs.count() > 100)
-	msgs.pop_front();
-    
-    /* Update last message with truncated version of the event */
-    if (strncmp(pos, "CTRL-", 5) == 0) {
-	pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
-	if (pos2)
-	    pos2++;
-	else
-	    pos2 = pos;
-    } else
-	pos2 = pos;
-    QString lastmsg = pos2;
-    lastmsg.truncate(40);
-    textLastMessage->setText(lastmsg);
-    
-    pingsToStatusUpdate = 0;
-    networkMayHaveChanged = true;
-    
-    if (str_match(pos, WPA_CTRL_REQ))
-	processCtrlReq(pos + strlen(WPA_CTRL_REQ));
-}
-
-
-void WpaGui::processCtrlReq(const char *req)
-{
-    if (udr) {
-	udr->close();
-	delete udr;
-    }
-    udr = new UserDataRequest();
-    if (udr == NULL)
-	return;
-    if (udr->setParams(this, req) < 0) {
-	delete udr;
-	udr = NULL;
-	return;
-    }
-    udr->show();
-    udr->exec();
-}
-
-
-void WpaGui::receiveMsgs()
-{
-    char buf[256];
-    size_t len;
-    
-    while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
-	len = sizeof(buf) - 1;
-	if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
-	    buf[len] = '\0';
-	    processMsg(buf);
-	}
-    }
-}
-
-
-void WpaGui::connectB()
-{
-    char reply[10];
-    size_t reply_len = sizeof(reply);
-    ctrlRequest("REASSOCIATE", reply, &reply_len);
-}
-
-
-void WpaGui::selectNetwork( const QString &sel )
-{
-    QString cmd(sel);
-    char reply[10];
-    size_t reply_len = sizeof(reply);
-    
-    int pos = cmd.find(':');
-    if (pos < 0) {
-	printf("Invalid selectNetwork '%s'\n", cmd.ascii());
-	return;
-    }
-    cmd.truncate(pos);
-    cmd.prepend("SELECT_NETWORK ");
-    ctrlRequest(cmd.ascii(), reply, &reply_len);
-}
-
-
-void WpaGui::editNetwork()
-{
-    QString sel(networkSelect->currentText());
-    int pos = sel.find(':');
-    if (pos < 0) {
-	printf("Invalid selectNetwork '%s'\n", sel.ascii());
-	return;
-    }
-    sel.truncate(pos);
-    
-    NetworkConfig *nc = new NetworkConfig();
-    if (nc == NULL)
-	return;
-    nc->setWpaGui(this);
-    
-    nc->paramsFromConfig(sel.toInt());
-    nc->show();
-    nc->exec();
-}
-
-
-void WpaGui::triggerUpdate()
-{
-    updateStatus();
-    networkMayHaveChanged = true;
-    updateNetworks();
-}
-
-
-void WpaGui::addNetwork()
-{
-    NetworkConfig *nc = new NetworkConfig();
-    if (nc == NULL)
-	return;
-    nc->setWpaGui(this);
-    nc->newNetwork();
-    nc->show();
-    nc->exec();
-}
-
-
-void WpaGui::selectAdapter( const QString & sel )
-{
-    if (openCtrlConnection(sel.ascii()) < 0)
-	printf("Failed to open control connection to wpa_supplicant.\n");
-    updateStatus();
-    updateNetworks();
-}
diff --git a/wpa_supplicant/wpa_gui/wpamsg.h b/wpa_supplicant/wpa_gui/wpamsg.h
deleted file mode 100644
index f3fce06..0000000
--- a/wpa_supplicant/wpa_gui/wpamsg.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef WPAMSG_H
-#define WPAMSG_H
-
-class WpaMsg;
-
-#if QT_VERSION >= 0x040000
-#include <QDateTime>
-#include <QLinkedList>
-typedef QLinkedList<WpaMsg> WpaMsgList;
-#else
-#include <qdatetime.h>
-typedef QValueList<WpaMsg> WpaMsgList;
-#endif
-
-class WpaMsg {
-public:
-    WpaMsg() {}
-    WpaMsg(const QString &_msg, int _priority = 2)
-	: msg(_msg), priority(_priority)
-    {
-	timestamp = QDateTime::currentDateTime();
-    }
-    
-    QString getMsg() const { return msg; }
-    int getPriority() const { return priority; }
-    QDateTime getTimestamp() const { return timestamp; }
-    
-private:
-    QString msg;
-    int priority;
-    QDateTime timestamp;
-};
-
-#endif /* WPAMSG_H */
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index d2a991b..c8854da 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -825,7 +825,7 @@
 }
 
 
-void wpa_supplicant_event(void *ctx, wpa_event_type event,
+void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
 			  union wpa_event_data *data)
 {
 	struct wpa_priv_interface *iface = ctx;
@@ -915,7 +915,7 @@
 }
 
 
-static void wpa_priv_terminate(int sig, void *eloop_ctx, void *signal_ctx)
+static void wpa_priv_terminate(int sig, void *signal_ctx)
 {
 	wpa_printf(MSG_DEBUG, "wpa_priv termination requested");
 	eloop_terminate();
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index a1e5456..f626e2e 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -20,6 +20,7 @@
 
 #include "common.h"
 #include "crypto/random.h"
+#include "crypto/sha1.h"
 #include "eapol_supp/eapol_supp_sm.h"
 #include "eap_peer/eap.h"
 #include "eap_server/eap_methods.h"
@@ -35,7 +36,6 @@
 #include "rsn_supp/preauth.h"
 #include "rsn_supp/pmksa_cache.h"
 #include "common/wpa_ctrl.h"
-#include "mlme.h"
 #include "common/ieee802_11_defs.h"
 #include "p2p/p2p.h"
 #include "blacklist.h"
@@ -43,12 +43,14 @@
 #include "wps_supplicant.h"
 #include "ibss_rsn.h"
 #include "sme.h"
+#include "gas_query.h"
 #include "ap.h"
 #include "p2p_supplicant.h"
 #include "notify.h"
 #include "bgscan.h"
 #include "bss.h"
 #include "scan.h"
+#include "offchannel.h"
 
 const char *wpa_supplicant_version =
 "wpa_supplicant v" VERSION_STR "\n"
@@ -368,6 +370,22 @@
 }
 
 
+static void free_hw_features(struct wpa_supplicant *wpa_s)
+{
+	int i;
+	if (wpa_s->hw.modes == NULL)
+		return;
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		os_free(wpa_s->hw.modes[i].channels);
+		os_free(wpa_s->hw.modes[i].rates);
+	}
+
+	os_free(wpa_s->hw.modes);
+	wpa_s->hw.modes = NULL;
+}
+
+
 static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
 {
 	bgscan_deinit(wpa_s);
@@ -410,8 +428,11 @@
 
 	wpa_supplicant_cancel_scan(wpa_s);
 	wpa_supplicant_cancel_auth_timeout(wpa_s);
-
-	ieee80211_sta_deinit(wpa_s);
+	eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+	eloop_cancel_timeout(wpa_supplicant_delayed_mic_error_report,
+			     wpa_s, NULL);
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
 
 	wpas_wps_deinit(wpa_s);
 
@@ -433,8 +454,19 @@
 	wpas_p2p_deinit(wpa_s);
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_OFFCHANNEL
+	offchannel_deinit(wpa_s);
+#endif /* CONFIG_OFFCHANNEL */
+
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+
 	os_free(wpa_s->next_scan_freqs);
 	wpa_s->next_scan_freqs = NULL;
+
+	gas_query_deinit(wpa_s->gas);
+	wpa_s->gas = NULL;
+
+	free_hw_features(wpa_s);
 }
 
 
@@ -521,6 +553,8 @@
 
 static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
 {
+	if (wpas_driver_bss_selection(wpa_s))
+		return;
 	if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
 		return;
 
@@ -678,7 +712,6 @@
 int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
 {
 	struct wpa_config *conf;
-	struct wpa_ssid *old_ssid;
 	int reconf_ctrl;
 	int old_ap_scan;
 
@@ -703,10 +736,10 @@
 	}
 
 	eapol_sm_invalidate_cached_session(wpa_s->eapol);
-	old_ssid = wpa_s->current_ssid;
-	wpa_s->current_ssid = NULL;
-	if (old_ssid != wpa_s->current_ssid)
-		wpas_notify_network_changed(wpa_s);
+	if (wpa_s->current_ssid) {
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+	}
 
 	/*
 	 * TODO: should notify EAPOL SM about changes in opensc_engine_path,
@@ -721,6 +754,7 @@
 	}
 	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 	wpa_sm_set_config(wpa_s->wpa, NULL);
+	wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
 	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
 	rsn_preauth_deinit(wpa_s->wpa);
 
@@ -929,6 +963,7 @@
 	}
 #endif /* CONFIG_IEEE80211W */
 
+	wpa_s->wpa_proto = proto;
 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
 	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
 			 !!(ssid->proto & WPA_PROTO_RSN));
@@ -1039,10 +1074,20 @@
 		return -1;
 	}
 
-	if (ssid->key_mgmt &
-	    (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK | WPA_KEY_MGMT_PSK_SHA256))
+	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
 		wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
-	else
+#ifndef CONFIG_NO_PBKDF2
+		if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
+		    ssid->passphrase) {
+			u8 psk[PMK_LEN];
+		        pbkdf2_sha1(ssid->passphrase, (char *) bss->ssid,
+				    bss->ssid_len, 4096, psk, PMK_LEN);
+		        wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+					psk, PMK_LEN);
+			wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+		}
+#endif /* CONFIG_NO_PBKDF2 */
+	} else
 		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
 
 	return 0;
@@ -1070,6 +1115,9 @@
 	struct wpa_driver_capa capa;
 	int assoc_failed = 0;
 	struct wpa_ssid *old_ssid;
+#ifdef ANDROID_P2P
+	int freq = 0;
+#endif
 
 #ifdef CONFIG_IBSS_RSN
 	ibss_rsn_deinit(wpa_s->ibss_rsn);
@@ -1107,7 +1155,7 @@
 
 	os_memset(&params, 0, sizeof(params));
 	wpa_s->reassociate = 0;
-	if (bss) {
+	if (bss && !wpas_driver_bss_selection(wpa_s)) {
 #ifdef CONFIG_IEEE80211R
 		const u8 *ie, *md = NULL;
 #endif /* CONFIG_IEEE80211R */
@@ -1145,6 +1193,7 @@
 			wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
 		os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
 	}
+	wpa_supplicant_cancel_sched_scan(wpa_s);
 	wpa_supplicant_cancel_scan(wpa_s);
 
 	/* Starting new association, so clear the possibly used WPA IE from the
@@ -1170,11 +1219,7 @@
 
 	if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
 		    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
-	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
-			       WPA_KEY_MGMT_FT_IEEE8021X |
-			       WPA_KEY_MGMT_FT_PSK |
-			       WPA_KEY_MGMT_IEEE8021X_SHA256 |
-			       WPA_KEY_MGMT_PSK_SHA256))) {
+	    wpa_key_mgmt_wpa(ssid->key_mgmt)) {
 		int try_opportunistic;
 		try_opportunistic = ssid->proactive_key_caching &&
 			(ssid->proto & WPA_PROTO_RSN);
@@ -1189,11 +1234,7 @@
 				"key management and encryption suites");
 			return;
 		}
-	} else if (ssid->key_mgmt &
-		   (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X |
-		    WPA_KEY_MGMT_WPA_NONE | WPA_KEY_MGMT_FT_PSK |
-		    WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_PSK_SHA256 |
-		    WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+	} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
 		wpa_ie_len = sizeof(wpa_ie);
 		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
 					      wpa_ie, &wpa_ie_len)) {
@@ -1217,10 +1258,12 @@
 			params.wps = WPS_MODE_PRIVACY;
 		else
 			params.wps = WPS_MODE_OPEN;
+		wpa_s->wpa_proto = 0;
 #endif /* CONFIG_WPS */
 	} else {
 		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
 		wpa_ie_len = 0;
+		wpa_s->wpa_proto = 0;
 	}
 
 #ifdef CONFIG_P2P
@@ -1253,6 +1296,22 @@
 	}
 #endif /* CONFIG_P2P */
 
+#ifdef CONFIG_INTERWORKING
+	if (wpa_s->conf->interworking) {
+		u8 *pos = wpa_ie;
+		if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+			pos += 2 + pos[1];
+		os_memmove(pos + 6, pos, wpa_ie_len - (pos - wpa_ie));
+		wpa_ie_len += 6;
+		*pos++ = WLAN_EID_EXT_CAPAB;
+		*pos++ = 4;
+		*pos++ = 0x00;
+		*pos++ = 0x00;
+		*pos++ = 0x00;
+		*pos++ = 0x80; /* Bit 31 - Interworking */
+	}
+#endif /* CONFIG_INTERWORKING */
+
 	wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
 	use_crypt = 1;
 	cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
@@ -1292,10 +1351,12 @@
 
 	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
 	if (bss) {
-		params.bssid = bss->bssid;
 		params.ssid = bss->ssid;
 		params.ssid_len = bss->ssid_len;
-		params.freq = bss->freq;
+		if (!wpas_driver_bss_selection(wpa_s)) {
+			params.bssid = bss->bssid;
+			params.freq = bss->freq;
+		}
 	} else {
 		params.ssid = ssid->ssid;
 		params.ssid_len = ssid->ssid_len;
@@ -1308,6 +1369,7 @@
 	params.pairwise_suite = cipher_pairwise;
 	params.group_suite = cipher_group;
 	params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+	params.wpa_proto = wpa_s->wpa_proto;
 	params.auth_alg = algs;
 	params.mode = ssid->mode;
 	for (i = 0; i < NUM_WEP_KEYS; i++) {
@@ -1343,21 +1405,25 @@
 	}
 #endif /* CONFIG_IEEE80211W */
 
-#ifdef CONFIG_P2P
-	if (wpa_s->global->p2p &&
-	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_P2P_CAPABLE))
-		params.p2p = 1;
-#endif /* CONFIG_P2P */
+	params.p2p = ssid->p2p_group;
 
 	if (wpa_s->parent->set_sta_uapsd)
 		params.uapsd = wpa_s->parent->sta_uapsd;
 	else
 		params.uapsd = -1;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		ret = ieee80211_sta_associate(wpa_s, &params);
-	else
-		ret = wpa_drv_associate(wpa_s, &params);
+#ifdef ANDROID_P2P
+	/* If multichannel concurrency is not supported, check for any frequency
+	 * conflict and take appropriate action.
+	 */
+	if (((freq = wpa_drv_shared_freq(wpa_s)) > 0) && (freq != params.freq) &&
+		!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+		wpa_printf(MSG_ERROR, "Shared interface with conflicting frequency found (%d != %d)"
+																, freq, params.freq);
+		wpas_p2p_handle_frequency_conflicts(wpa_s, params.freq);
+	}
+#endif
+	ret = wpa_drv_associate(wpa_s, &params);
 	if (ret < 0) {
 		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
 			"failed");
@@ -1463,10 +1529,7 @@
 	u8 *addr = NULL;
 
 	if (!is_zero_ether_addr(wpa_s->bssid)) {
-		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-			ieee80211_sta_disassociate(wpa_s, reason_code);
-		else
-			wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
+		wpa_drv_disassociate(wpa_s, wpa_s->bssid, reason_code);
 		addr = wpa_s->bssid;
 	}
 
@@ -1488,11 +1551,7 @@
 	u8 *addr = NULL;
 
 	if (!is_zero_ether_addr(wpa_s->bssid)) {
-		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-			ieee80211_sta_deauthenticate(wpa_s, reason_code);
-		else
-			wpa_drv_deauthenticate(wpa_s, wpa_s->bssid,
-					       reason_code);
+		wpa_drv_deauthenticate(wpa_s, wpa_s->bssid, reason_code);
 		addr = wpa_s->bssid;
 	}
 
@@ -1628,6 +1687,14 @@
 		if (was_disabled != other_ssid->disabled)
 			wpas_notify_network_enabled_changed(wpa_s, other_ssid);
 	}
+
+	if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) {
+		/* We are already associated with the selected network */
+		wpa_printf(MSG_DEBUG, "Already associated with the "
+			   "selected network - do nothing");
+		return;
+	}
+
 	wpa_s->connect_without_scan = NULL;
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
@@ -1654,13 +1721,14 @@
 		return -1;
 
 #ifdef ANDROID
-	if ((ap_scan == 2) && ((wpa_s->wpa_state >= WPA_ASSOCIATING) &&
-		(wpa_s->wpa_state < WPA_COMPLETED))) {
-		wpa_printf(MSG_ERROR, "ap_scan = %d (%d)",wpa_s->conf->ap_scan,
-				ap_scan);
+	if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
+	    wpa_s->wpa_state >= WPA_ASSOCIATING &&
+	    wpa_s->wpa_state < WPA_COMPLETED) {
+		wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while "
+			   "associating", wpa_s->conf->ap_scan, ap_scan);
 		return 0;
 	}
-#endif
+#endif /* ANDROID */
 
 	old_ap_scan = wpa_s->conf->ap_scan;
 	wpa_s->conf->ap_scan = ap_scan;
@@ -1774,25 +1842,15 @@
 	u8 bssid[ETH_ALEN];
 	int wired;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-		if (ieee80211_sta_get_ssid(wpa_s, ssid, &ssid_len)) {
-			wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
-				"MLME");
-			return NULL;
-		}
-	} else {
-		res = wpa_drv_get_ssid(wpa_s, ssid);
-		if (res < 0) {
-			wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
-				"driver");
-			return NULL;
-		}
-		ssid_len = res;
+	res = wpa_drv_get_ssid(wpa_s, ssid);
+	if (res < 0) {
+		wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
+			"driver");
+		return NULL;
 	}
+	ssid_len = res;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
-	else if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+	if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
 		wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
 			"driver");
 		return NULL;
@@ -1817,6 +1875,12 @@
 		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
 			return entry;
 #endif /* CONFIG_WPS */
+
+		if (!entry->disabled && entry->bssid_set &&
+		    entry->ssid_len == 0 &&
+		    os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
+			return entry;
+
 		entry = entry->next;
 	}
 
@@ -1824,6 +1888,26 @@
 }
 
 
+static int select_driver(struct wpa_supplicant *wpa_s, int i)
+{
+	struct wpa_global *global = wpa_s->global;
+
+	if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
+		global->drv_priv[i] = wpa_drivers[i]->global_init();
+		if (global->drv_priv[i] == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to initialize driver "
+				   "'%s'", wpa_drivers[i]->name);
+			return -1;
+		}
+	}
+
+	wpa_s->driver = wpa_drivers[i];
+	wpa_s->global_drv_priv = global->drv_priv[i];
+
+	return 0;
+}
+
+
 static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
 				     const char *name)
 {
@@ -1842,9 +1926,7 @@
 
 	if (name == NULL) {
 		/* default to first driver in the list */
-		wpa_s->driver = wpa_drivers[0];
-		wpa_s->global_drv_priv = wpa_s->global->drv_priv[0];
-		return 0;
+		return select_driver(wpa_s, 0);
 	}
 
 	do {
@@ -1857,12 +1939,8 @@
 		for (i = 0; wpa_drivers[i]; i++) {
 			if (os_strlen(wpa_drivers[i]->name) == len &&
 			    os_strncmp(driver, wpa_drivers[i]->name, len) ==
-			    0) {
-				wpa_s->driver = wpa_drivers[i];
-				wpa_s->global_drv_priv =
-					wpa_s->global->drv_priv[i];
-				return 0;
-			}
+			    0)
+				return select_driver(wpa_s, i);
 		}
 
 		driver = pos + 1;
@@ -1984,25 +2062,15 @@
 }
 
 
-/**
- * wpa_supplicant_driver_init - Initialize driver interface parameters
- * @wpa_s: Pointer to wpa_supplicant data
- * Returns: 0 on success, -1 on failure
- *
- * This function is called to initialize driver interface parameters.
- * wpa_drv_init() must have been called before this function to initialize the
- * driver interface.
- */
-int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
+int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
 {
-	static int interface_count = 0;
-
 	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->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),
 					   ETH_P_EAPOL,
@@ -2022,6 +2090,27 @@
 
 	wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
 		MAC2STR(wpa_s->own_addr));
+	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_driver_init - Initialize driver interface parameters
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to initialize driver interface parameters.
+ * wpa_drv_init() must have been called before this function to initialize the
+ * driver interface.
+ */
+int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
+{
+	static int interface_count = 0;
+
+	if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
+		return -1;
 
 	if (wpa_s->bridge_ifname[0]) {
 		wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
@@ -2050,7 +2139,10 @@
 
 	wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
 	if (wpa_supplicant_enabled_networks(wpa_s->conf)) {
-		wpa_supplicant_req_scan(wpa_s, interface_count, 100000);
+		if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
+						      100000))
+			wpa_supplicant_req_scan(wpa_s, interface_count,
+						100000);
 		interface_count++;
 	} else
 		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
@@ -2077,6 +2169,7 @@
 	wpa_s->scan_interval = 5;
 	wpa_s->new_connection = 1;
 	wpa_s->parent = wpa_s;
+	wpa_s->sched_scanning = 0;
 
 	return wpa_s;
 }
@@ -2234,13 +2327,18 @@
 		return -1;
 	}
 
+	wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
+						      &wpa_s->hw.num_modes,
+						      &wpa_s->hw.flags);
+
 	if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+		wpa_s->drv_capa_known = 1;
 		wpa_s->drv_flags = capa.flags;
-		if (capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-			if (ieee80211_sta_init(wpa_s))
-				return -1;
-		}
+		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;
+		wpa_s->sched_scan_supported = capa.sched_scan_supported;
+		wpa_s->max_match_sets = capa.max_match_sets;
 		wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
 		wpa_s->max_stations = capa.max_stations;
 	}
@@ -2261,8 +2359,6 @@
 		return -1;
 	}
 
-	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
-
 	if (wpas_wps_init(wpa_s))
 		return -1;
 
@@ -2284,6 +2380,12 @@
 		return -1;
 	}
 
+	wpa_s->gas = gas_query_init(wpa_s);
+	if (wpa_s->gas == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
+		return -1;
+	}
+
 #ifdef CONFIG_P2P
 	if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
 		wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
@@ -2517,6 +2619,13 @@
 	if (params == NULL)
 		return NULL;
 
+#ifdef CONFIG_DRIVER_NDIS
+	{
+		void driver_ndis_init_ops(void);
+		driver_ndis_init_ops();
+	}
+#endif /* CONFIG_DRIVER_NDIS */
+
 #ifndef CONFIG_NO_WPA_MSG
 	wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
 #endif /* CONFIG_NO_WPA_MSG */
@@ -2593,17 +2702,6 @@
 		wpa_supplicant_deinit(global);
 		return NULL;
 	}
-	for (i = 0; wpa_drivers[i]; i++) {
-		if (!wpa_drivers[i]->global_init)
-			continue;
-		global->drv_priv[i] = wpa_drivers[i]->global_init();
-		if (global->drv_priv[i] == NULL) {
-			wpa_printf(MSG_ERROR, "Failed to initialize driver "
-				   "'%s'", wpa_drivers[i]->name);
-			wpa_supplicant_deinit(global);
-			return NULL;
-		}
-	}
 
 	return global;
 }
@@ -2655,6 +2753,7 @@
 
 	if (global == NULL)
 		return;
+
 #ifdef CONFIG_P2P
 	wpas_p2p_deinit_global(global);
 #endif /* CONFIG_P2P */
@@ -2723,23 +2822,6 @@
 }
 
 
-void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
-				    size_t num_hw_features)
-{
-	size_t i;
-
-	if (hw_features == NULL)
-		return;
-
-	for (i = 0; i < num_hw_features; i++) {
-		os_free(hw_features[i].channels);
-		os_free(hw_features[i].rates);
-	}
-
-	os_free(hw_features);
-}
-
-
 static void add_freq(int *freqs, int *num_freqs, int freq)
 {
 	int i;
@@ -2846,3 +2928,10 @@
 	wpa_supplicant_req_scan(wpa_s, timeout / 1000,
 				1000 * (timeout % 1000));
 }
+
+
+int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
+{
+	return wpa_s->conf->ap_scan == 2 ||
+		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
+}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 62c111d..8a66a80 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -228,98 +228,11 @@
 };
 
 
-struct wpa_client_mlme {
-#ifdef CONFIG_CLIENT_MLME
-	enum {
-		IEEE80211_DISABLED, IEEE80211_AUTHENTICATE,
-		IEEE80211_ASSOCIATE, IEEE80211_ASSOCIATED,
-		IEEE80211_IBSS_SEARCH, IEEE80211_IBSS_JOINED
-	} state;
-	u8 prev_bssid[ETH_ALEN];
-	u8 ssid[32];
-	size_t ssid_len;
-	u16 aid;
-	u16 ap_capab, capab;
-	u8 *extra_ie; /* to be added to the end of AssocReq */
-	size_t extra_ie_len;
-	u8 *extra_probe_ie; /* to be added to the end of ProbeReq */
-	size_t extra_probe_ie_len;
-	enum wpa_key_mgmt key_mgmt;
-
-	/* The last AssocReq/Resp IEs */
-	u8 *assocreq_ies, *assocresp_ies;
-	size_t assocreq_ies_len, assocresp_ies_len;
-
-	int auth_tries, assoc_tries;
-
-	unsigned int ssid_set:1;
-	unsigned int bssid_set:1;
-	unsigned int prev_bssid_set:1;
-	unsigned int authenticated:1;
-	unsigned int associated:1;
-	unsigned int probereq_poll:1;
-	unsigned int use_protection:1;
-	unsigned int create_ibss:1;
-	unsigned int mixed_cell:1;
-	unsigned int wmm_enabled:1;
-
-	struct os_time last_probe;
-
-	unsigned int auth_algs; /* bitfield of allowed auth algs
-				 * (WPA_AUTH_ALG_*) */
-	int auth_alg; /* currently used IEEE 802.11 authentication algorithm */
-	int auth_transaction;
-
-	struct os_time ibss_join_req;
-	u8 *probe_resp; /* ProbeResp template for IBSS */
-	size_t probe_resp_len;
-	u32 supp_rates_bits;
-
-	int wmm_last_param_set;
-
-	int sta_scanning;
-	int scan_hw_mode_idx;
-	int scan_channel_idx;
-	enum { SCAN_SET_CHANNEL, SCAN_SEND_PROBE } scan_state;
-	struct os_time last_scan_completed;
-	int scan_oper_channel;
-	int scan_oper_freq;
-	int scan_oper_phymode;
-	u8 scan_ssid[32];
-	size_t scan_ssid_len;
-	int scan_skip_11b;
-	int *scan_freqs;
-
-	struct ieee80211_sta_bss *sta_bss_list;
-#define STA_HASH_SIZE 256
-#define STA_HASH(sta) (sta[5])
-	struct ieee80211_sta_bss *sta_bss_hash[STA_HASH_SIZE];
-
-	int cts_protect_erp_frames;
-
-	enum hostapd_hw_mode phymode; /* current mode */
-	struct hostapd_hw_modes *modes;
-	size_t num_modes;
-	unsigned int hw_modes; /* bitfield of allowed hardware modes;
-				* (1 << HOSTAPD_MODE_*) */
-	int num_curr_rates;
-	int *curr_rates;
-	int freq; /* The current frequency in MHz */
-	int channel; /* The current IEEE 802.11 channel number */
-
-#ifdef CONFIG_IEEE80211R
-	u8 current_md[6];
-	u8 *ft_ies;
-	size_t ft_ies_len;
-#endif /* CONFIG_IEEE80211R */
-
-	void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
-				 int freq);
-	void *public_action_cb_ctx;
-
-#else /* CONFIG_CLIENT_MLME */
-	int dummy; /* to keep MSVC happy */
-#endif /* CONFIG_CLIENT_MLME */
+enum offchannel_send_action_result {
+	OFFCHANNEL_SEND_ACTION_SUCCESS /* Frame was send and acknowledged */,
+	OFFCHANNEL_SEND_ACTION_NO_ACK /* Frame was sent, but not acknowledged
+				       */,
+	OFFCHANNEL_SEND_ACTION_FAILED /* Frame was not sent due to a failure */
 };
 
 /**
@@ -353,7 +266,7 @@
 	os_time_t last_michael_mic_error;
 	u8 bssid[ETH_ALEN];
 	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
-				     * field contains the targer BSSID. */
+				     * field contains the target BSSID. */
 	int reassociate; /* reassociation requested */
 	int disconnected; /* all connections disabled; i.e., do no reassociate
 			   * before this has been cleared */
@@ -366,6 +279,7 @@
 	int pairwise_cipher;
 	int group_cipher;
 	int key_mgmt;
+	int wpa_proto;
 	int mgmt_group_cipher;
 
 	void *drv_priv; /* private data used by driver_ops */
@@ -379,6 +293,12 @@
 					  */
 #define WILDCARD_SSID_SCAN ((struct wpa_ssid *) 1)
 
+	struct wpa_ssid *prev_sched_ssid; /* last SSID used in sched scan */
+	int sched_scan_timeout;
+	int sched_scan_interval;
+	int first_sched_scan;
+	int sched_scan_timed_out;
+
 	void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
 				 struct wpa_scan_results *scan_res);
 	struct dl_list bss; /* struct wpa_bss::list */
@@ -397,6 +317,7 @@
 
 	enum wpa_states wpa_state;
 	int scanning;
+	int sched_scanning;
 	int new_connection;
 	int reassociated_connection;
 
@@ -416,10 +337,20 @@
 	int scan_runs; /* number of scan runs since WPS was started */
 	int *next_scan_freqs;
 	int scan_interval; /* time in sec between scans to find suitable AP */
+	int normal_scans; /* normal scans run before sched_scan */
 
-	struct wpa_client_mlme mlme;
 	unsigned int drv_flags;
+
+	/*
+	 * A bitmap of supported protocols for probe response offload. See
+	 * struct wpa_driver_capa in driver.h
+	 */
+	unsigned int probe_resp_offloads;
+
 	int max_scan_ssids;
+	int max_sched_scan_ssids;
+	int sched_scan_supported;
+	unsigned int max_match_sets;
 	unsigned int max_remain_on_chan;
 	unsigned int max_stations;
 
@@ -458,6 +389,7 @@
 		u8 prev_bssid[ETH_ALEN];
 		int prev_bssid_set;
 		int auth_alg;
+		int proto;
 
 		int sa_query_count; /* number of pending SA Query requests;
 				     * 0 = no SA Query in progress */
@@ -476,6 +408,23 @@
 	void *ap_configured_cb_data;
 #endif /* CONFIG_AP */
 
+	unsigned int off_channel_freq;
+	struct wpabuf *pending_action_tx;
+	u8 pending_action_src[ETH_ALEN];
+	u8 pending_action_dst[ETH_ALEN];
+	u8 pending_action_bssid[ETH_ALEN];
+	unsigned int pending_action_freq;
+	int pending_action_no_cck;
+	int pending_action_without_roc;
+	void (*pending_action_tx_status_cb)(struct wpa_supplicant *wpa_s,
+					    unsigned int freq, const u8 *dst,
+					    const u8 *src, const u8 *bssid,
+					    const u8 *data, size_t data_len,
+					    enum offchannel_send_action_result
+					    result);
+	unsigned int roc_waiting_drv_freq;
+	int action_tx_wait_time;
+
 #ifdef CONFIG_P2P
 	struct p2p_go_neg_results *go_params;
 	int create_p2p_iface;
@@ -483,13 +432,6 @@
 	char pending_interface_name[100];
 	int pending_interface_type;
 	int p2p_group_idx;
-	unsigned int off_channel_freq;
-	struct wpabuf *pending_action_tx;
-	u8 pending_action_src[ETH_ALEN];
-	u8 pending_action_dst[ETH_ALEN];
-	u8 pending_action_bssid[ETH_ALEN];
-	unsigned int pending_action_freq;
-	int pending_action_without_roc;
 	unsigned int pending_listen_freq;
 	unsigned int pending_listen_duration;
 	enum {
@@ -513,8 +455,6 @@
 	u8 pending_join_dev_addr[ETH_ALEN];
 	int pending_join_wps_method;
 	int p2p_join_scan_count;
-	unsigned int roc_waiting_drv_freq;
-	int action_tx_wait_time;
 	int force_long_sd;
 
 	/*
@@ -544,6 +484,8 @@
 		P2P_GROUP_REMOVAL_IDLE_TIMEOUT,
 		P2P_GROUP_REMOVAL_UNAVAILABLE
 	} removal_reason;
+
+	unsigned int p2p_cb_on_scan_complete:1;
 #endif /* CONFIG_P2P */
 
 	struct wpa_ssid *bgscan_ssid;
@@ -561,6 +503,23 @@
 	int best_24_freq;
 	int best_5_freq;
 	int best_overall_freq;
+
+	struct gas_query *gas;
+
+#ifdef CONFIG_INTERWORKING
+	unsigned int fetch_anqp_in_progress:1;
+	unsigned int network_select:1;
+	unsigned int auto_select:1;
+#endif /* CONFIG_INTERWORKING */
+	unsigned int drv_capa_known;
+
+	struct {
+		struct hostapd_hw_modes *modes;
+		u16 num_modes;
+		u16 flags;
+	} hw;
+
+	int pno;
 };
 
 
@@ -570,6 +529,7 @@
 int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
 
 const char * wpa_supplicant_state_txt(enum wpa_states state);
+int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s);
 int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s);
 int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
 			      struct wpa_bss *bss, struct wpa_ssid *ssid,
@@ -631,19 +591,16 @@
 enum wpa_cipher cipher_suite2driver(int cipher);
 void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
-void ieee80211_sta_free_hw_features(struct hostapd_hw_modes *hw_features,
-				    size_t num_hw_features);
 void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
 
 /* events.c */
 void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
-#ifdef ANDROID_BRCM_P2P_PATCH
 int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
-#else
-void wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
-#endif /* ANDROID_BRCM_P2P_PATCH */
-			    struct wpa_bss *selected,
-			    struct wpa_ssid *ssid);
+			   struct wpa_bss *selected,
+			   struct wpa_ssid *ssid);
+void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
+void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
 
 /* eap_register.c */
 int eap_register_methods(void);
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index edb9475..69b0cf8 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -24,7 +24,6 @@
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
 #include "rsn_supp/pmksa_cache.h"
-#include "mlme.h"
 #include "sme.h"
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
@@ -438,10 +437,6 @@
 static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME) {
-		os_memcpy(bssid, wpa_s->bssid, ETH_ALEN);
-		return 0;
-	}
 	return wpa_drv_get_bssid(wpa_s, bssid);
 }
 
@@ -489,8 +484,6 @@
 					const u8 *ies, size_t ies_len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		return ieee80211_sta_update_ft_ies(wpa_s, md, ies, ies_len);
 	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
 		return sme_update_ft_ies(wpa_s, md, ies, ies_len);
 	return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len);
@@ -502,9 +495,6 @@
 					 const u8 *ies, size_t ies_len)
 {
 	struct wpa_supplicant *wpa_s = ctx;
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		return ieee80211_sta_send_ft_action(wpa_s, action, target_ap,
-						    ies, ies_len);
 	return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len);
 }
 
@@ -515,9 +505,6 @@
 	struct wpa_driver_auth_params params;
 	struct wpa_bss *bss;
 
-	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
-		return -1;
-
 	bss = wpa_bss_get_bssid(wpa_s, target_ap);
 	if (bss == NULL)
 		return -1;
@@ -538,6 +525,27 @@
 
 #ifdef CONFIG_TDLS
 
+static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
+					int *tdls_ext_setup)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	*tdls_supported = 0;
+	*tdls_ext_setup = 0;
+
+	if (!wpa_s->drv_capa_known)
+		return -1;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)
+		*tdls_supported = 1;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP)
+		*tdls_ext_setup = 1;
+
+	return 0;
+}
+
+
 static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst,
 					 u8 action_code, u8 dialog_token,
 					 u16 status_code, const u8 *buf,
@@ -555,16 +563,102 @@
 	return wpa_drv_tdls_oper(wpa_s, oper, peer);
 }
 
+
+static int wpa_supplicant_tdls_peer_addset(
+	void *ctx, const u8 *peer, int add, u16 capability,
+	const u8 *supp_rates, size_t supp_rates_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct hostapd_sta_add_params params;
+
+	params.addr = peer;
+	params.aid = 1;
+	params.capability = capability;
+	params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
+	params.ht_capabilities = NULL;
+	params.listen_interval = 0;
+	params.supp_rates = supp_rates;
+	params.supp_rates_len = supp_rates_len;
+	params.set = !add;
+
+	return wpa_drv_sta_add(wpa_s, &params);
+}
+
 #endif /* CONFIG_TDLS */
 
 
+enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
+{
+	if (os_strcmp(field, "IDENTITY") == 0)
+		return WPA_CTRL_REQ_EAP_IDENTITY;
+	else if (os_strcmp(field, "PASSWORD") == 0)
+		return WPA_CTRL_REQ_EAP_PASSWORD;
+	else if (os_strcmp(field, "NEW_PASSWORD") == 0)
+		return WPA_CTRL_REQ_EAP_NEW_PASSWORD;
+	else if (os_strcmp(field, "PIN") == 0)
+		return WPA_CTRL_REQ_EAP_PIN;
+	else if (os_strcmp(field, "OTP") == 0)
+		return WPA_CTRL_REQ_EAP_OTP;
+	else if (os_strcmp(field, "PASSPHRASE") == 0)
+		return WPA_CTRL_REQ_EAP_PASSPHRASE;
+	return WPA_CTRL_REQ_UNKNOWN;
+}
+
+
+const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
+					       const char *default_txt,
+					       const char **txt)
+{
+	const char *ret = NULL;
+
+	*txt = default_txt;
+
+	switch (field) {
+	case WPA_CTRL_REQ_EAP_IDENTITY:
+		*txt = "Identity";
+		ret = "IDENTITY";
+		break;
+	case WPA_CTRL_REQ_EAP_PASSWORD:
+		*txt = "Password";
+		ret = "PASSWORD";
+		break;
+	case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+		*txt = "New Password";
+		ret = "NEW_PASSWORD";
+		break;
+	case WPA_CTRL_REQ_EAP_PIN:
+		*txt = "PIN";
+		ret = "PIN";
+		break;
+	case WPA_CTRL_REQ_EAP_OTP:
+		ret = "OTP";
+		break;
+	case WPA_CTRL_REQ_EAP_PASSPHRASE:
+		*txt = "Private key passphrase";
+		ret = "PASSPHRASE";
+		break;
+	default:
+		break;
+	}
+
+	/* txt needs to be something */
+	if (*txt == NULL) {
+		wpa_printf(MSG_WARNING, "No message for request %d", field);
+		ret = NULL;
+	}
+
+	return ret;
+}
+
 #ifdef IEEE8021X_EAPOL
 #if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
-static void wpa_supplicant_eap_param_needed(void *ctx, const char *field,
-					    const char *txt)
+static void wpa_supplicant_eap_param_needed(void *ctx,
+					    enum wpa_ctrl_req_type field,
+					    const char *default_txt)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	const char *field_name, *txt = NULL;
 	char *buf;
 	size_t buflen;
 	int len;
@@ -572,13 +666,23 @@
 	if (ssid == NULL)
 		return;
 
+	wpas_notify_network_request(wpa_s, ssid, field, default_txt);
+
+	field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
+						       &txt);
+	if (field_name == NULL) {
+		wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed",
+			   field);
+		return;
+	}
+
 	buflen = 100 + os_strlen(txt) + ssid->ssid_len;
 	buf = os_malloc(buflen);
 	if (buf == NULL)
 		return;
 	len = os_snprintf(buf, buflen,
 			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
-			  field, ssid->id, txt);
+			  field_name, ssid->id, txt);
 	if (len < 0 || (size_t) len >= buflen) {
 		os_free(buf);
 		return;
@@ -667,6 +771,16 @@
 }
 
 
+static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
+					     const u8 *kck,
+					     const u8 *replay_ctr)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr);
+}
+
+
 int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
 {
 #ifndef CONFIG_NO_WPA
@@ -703,9 +817,12 @@
 	ctx->mark_authenticated = wpa_supplicant_mark_authenticated;
 #endif /* CONFIG_IEEE80211R */
 #ifdef CONFIG_TDLS
+	ctx->tdls_get_capa = wpa_supplicant_tdls_get_capa;
 	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;
 #endif /* CONFIG_TDLS */
+	ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
 
 	wpa_s->wpa = wpa_sm_init(ctx);
 	if (wpa_s->wpa == NULL) {
@@ -729,6 +846,7 @@
 		conf.peerkey_enabled = ssid->peerkey;
 		conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
 #ifdef IEEE8021X_EAPOL
+		conf.proactive_key_caching = ssid->proactive_key_caching;
 		conf.eap_workaround = ssid->eap_workaround;
 		conf.eap_conf_ctx = &ssid->eap;
 #endif /* IEEE8021X_EAPOL */
diff --git a/wpa_supplicant/wpas_glue.h b/wpa_supplicant/wpas_glue.h
index b571e4d..78c1b3d 100644
--- a/wpa_supplicant/wpas_glue.h
+++ b/wpa_supplicant/wpas_glue.h
@@ -15,9 +15,17 @@
 #ifndef WPAS_GLUE_H
 #define WPAS_GLUE_H
 
+enum wpa_ctrl_req_type;
+
 int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s);
 int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s);
 void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
 					struct wpa_ssid *ssid);
 
+const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
+					       const char *default_txt,
+					       const char **txt);
+
+enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field);
+
 #endif /* WPAS_GLUE_H */
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index e3388bd..870aff5 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -88,6 +88,7 @@
 		}
 		wpa_s->after_wps = 5;
 		wpa_s->wps_freq = wpa_s->assoc_freq;
+		wpa_s->normal_scans = 0;
 		wpa_s->reassociate = 1;
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
 		return 1;
@@ -127,6 +128,8 @@
 	if (wpa_drv_get_capa(wpa_s, &capa))
 		return; /* Unknown what driver supports */
 
+	if (ssid->ssid == NULL)
+		return;
 	bss = wpa_bss_get(wpa_s, cred->mac_addr, ssid->ssid, ssid->ssid_len);
 	if (bss == NULL) {
 		wpa_printf(MSG_DEBUG, "WPS: The AP was not found from BSS "
@@ -192,7 +195,9 @@
 	struct wpa_ssid *ssid = wpa_s->current_ssid;
 	u8 key_idx = 0;
 	u16 auth_type;
+#ifdef CONFIG_WPS_REG_DISABLE_OPEN
 	int registrar = 0;
+#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
 
 	if ((wpa_s->conf->wps_cred_processing == 1 ||
 	     wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
@@ -246,11 +251,13 @@
 	if (ssid && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
 		wpa_printf(MSG_DEBUG, "WPS: Replace WPS network block based "
 			   "on the received credential");
+#ifdef CONFIG_WPS_REG_DISABLE_OPEN
 		if (ssid->eap.identity &&
 		    ssid->eap.identity_len == WSC_ID_REGISTRAR_LEN &&
 		    os_memcmp(ssid->eap.identity, WSC_ID_REGISTRAR,
 			      WSC_ID_REGISTRAR_LEN) == 0)
 			registrar = 1;
+#endif /* CONFIG_WPS_REG_DISABLE_OPEN */
 		os_free(ssid->eap.identity);
 		ssid->eap.identity = NULL;
 		ssid->eap.identity_len = 0;
@@ -787,6 +794,10 @@
 {
 	struct wpa_ssid *ssid;
 
+	if (wpa_s->current_ssid)
+		wpa_supplicant_deauthenticate(
+			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
 	/* Mark all other networks disabled and trigger reassociation */
 	ssid = wpa_s->conf->ssid;
 	while (ssid) {
@@ -808,6 +819,7 @@
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
 	wpa_s->scan_runs = 0;
+	wpa_s->normal_scans = 0;
 	wpa_s->wps_success = 0;
 	wpa_s->blacklist_cleared = 0;
 	wpa_supplicant_req_scan(wpa_s, 0, 0);
@@ -1114,6 +1126,8 @@
 {
 	struct wps_context *wps;
 	struct wps_registrar_config rcfg;
+	struct hostapd_hw_modes *modes;
+	u16 m;
 
 	wps = os_zalloc(sizeof(*wps));
 	if (wps == NULL)
@@ -1138,6 +1152,7 @@
 		return -1;
 	}
 	wps->config_methods = wps_fix_config_methods(wps->config_methods);
+	wps->dev.config_methods = wps->config_methods;
 	os_memcpy(wps->dev.pri_dev_type, wpa_s->conf->device_type,
 		  WPS_DEV_TYPE_LEN);
 
@@ -1146,7 +1161,23 @@
 		  WPS_DEV_TYPE_LEN * wps->dev.num_sec_dev_types);
 
 	wps->dev.os_version = WPA_GET_BE32(wpa_s->conf->os_version);
-	wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ; /* TODO: config */
+	modes = wpa_s->hw.modes;
+	if (modes) {
+		for (m = 0; m < wpa_s->hw.num_modes; m++) {
+			if (modes[m].mode == HOSTAPD_MODE_IEEE80211B ||
+			    modes[m].mode == HOSTAPD_MODE_IEEE80211G)
+				wps->dev.rf_bands |= WPS_RF_24GHZ;
+			else if (modes[m].mode == HOSTAPD_MODE_IEEE80211A)
+				wps->dev.rf_bands |= WPS_RF_50GHZ;
+		}
+	}
+	if (wps->dev.rf_bands == 0) {
+		/*
+		 * Default to claiming support for both bands if the driver
+		 * does not provide support for fetching supported bands.
+		 */
+		wps->dev.rf_bands = WPS_RF_24GHZ | WPS_RF_50GHZ;
+	}
 	os_memcpy(wps->dev.mac_addr, wpa_s->own_addr, ETH_ALEN);
 	wpas_wps_set_uuid(wpa_s, wps);