Cumulative patch from commit 853b49a030c00fd6b2dde14e183ca2bf108eaa16

853b49a tests: Increase test_ap_wps_init connection timeout
28de68a P2P: Update peer operating channel from GO Negotiation Confirm
6701fdc P2P: Use the first pref_chan entry as operating channel preference
99d7c76 P2P: Add more debug info on operating channel selection
8d660e0 P2P: Add GO negotiation results into the P2P-GO-NEG-SUCCESS event
2c6f8cf Replace perror() with wpa_printf(strerror) in ctrl_iface calls
e743db4 IBSS RSN: Add IBSS-RSN-COMPLETED event message
4c55901 P2P: Add state info to global STATUS command
ae8c27f Add STATUS command to global control interface
42868f1 Add SAVE_CONFIG command to global control interface
1b9b31c Add SET command for global control interface
0185007 hostapd: Add survey dump support
245e026 hostapd: Split up channel checking into helpers
ba873bd wired: Wait for the link to become active before sending packets
d393de1 P2P: Validate the freq in p2p_group_add
973622c wpa_supplicant: Fix AP mode frequency initialization
d99ca89 P2P: Skip non-P2P interface in p2p_group_remove *
239abaf WPS: Set currently used RF band in RF Bands attribute
bf83eab nl80211: Start P2P Device when rfkill is unblocked
60b13c2 nl80211: Do not change type to station on P2P interfaces
e0591c3 wpa_supplicant: Reduce wait time for control interfaces
5046eb4 P2P: Allow separate interface GO to disconnect low-ack STAs
5bcd5c5 FT RRB: Clear pad field to avoid sending out uninitialized data
b378c41 nl80211: Fix deinit path to unregister nl_mgmt socket
a235aca Fix DETACH command debug prints to avoid use of freed memory
8d6e035 Make global UNIX socket non-blocking for ctrl_iface
86bd141 Change WEP network selection to reject WPA/WPA2 APs
2e145e9 WPS: Fix failure path to allow WSC_NACK and EAP-Failure to be exchanged
3351a38 WPS: Add control interface command for fetching latest status
e96872a WPS: Track peer MAC address from the last operations
ae23935 WPS: Track PBC status
61b6520 WPS: Track result of the latest WPS operation
50396e2 WPS: Add PBC mode activated/disabled events
961750c WPS: Share a common function for error strings
30158a0 nl80211: Update the assoc_freq during connect
83e7bb0 nl80211: Add more debug prints for DEL_STATION commands

Bug: 9056601

Change-Id: I8bc671eb13f4c2c388a4c15cf1ba968c24c9656a
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/wpa_supplicant/ap.c b/wpa_supplicant/ap.c
index c48a286..2950d2d 100644
--- a/wpa_supplicant/ap.c
+++ b/wpa_supplicant/ap.c
@@ -14,6 +14,7 @@
 #include "utils/uuid.h"
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
+#include "eapol_supp/eapol_supp_sm.h"
 #include "ap/hostapd.h"
 #include "ap/ap_config.h"
 #include "ap/ap_drv_ops.h"
@@ -51,18 +52,12 @@
 
 	os_strlcpy(bss->iface, wpa_s->ifname, sizeof(bss->iface));
 
-	if (ssid->frequency == 0) {
-		/* default channel 11 */
-		conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
-		conf->channel = 11;
-	} else {
-		conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
-						       &conf->channel);
-		if (conf->hw_mode == NUM_HOSTAPD_MODES) {
-			wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: "
-				   "%d MHz", ssid->frequency);
-			return -1;
-		}
+	conf->hw_mode = ieee80211_freq_to_chan(ssid->frequency,
+					       &conf->channel);
+	if (conf->hw_mode == NUM_HOSTAPD_MODES) {
+		wpa_printf(MSG_ERROR, "Unsupported AP mode frequency: %d MHz",
+			   ssid->frequency);
+		return -1;
 	}
 
 	/* TODO: enable HT40 if driver supports it;
@@ -461,6 +456,8 @@
 		params.mode = IEEE80211_MODE_AP;
 		break;
 	}
+	if (ssid->frequency == 0)
+		ssid->frequency = 2462; /* default channel 11 */
 	params.freq = ssid->frequency;
 
 	params.wpa_proto = ssid->proto;
@@ -586,6 +583,7 @@
 	hapd_iface->bss[0]->drv_priv = wpa_s->drv_priv;
 
 	wpa_s->current_ssid = ssid;
+	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 	os_memcpy(wpa_s->bssid, wpa_s->own_addr, ETH_ALEN);
 	wpa_s->assoc_freq = ssid->frequency;
 
@@ -609,6 +607,7 @@
 		return;
 
 	wpa_s->current_ssid = NULL;
+	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 	wpa_s->assoc_freq = 0;
 #ifdef CONFIG_P2P
 	if (wpa_s->ap_iface->bss)
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index fb3eacc..55f6a06 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -5939,7 +5939,6 @@
 #ifdef ANDROID_P2P
 		"LIST_NETWORKS",
 		"SAVE_CONFIG",
-		"STATUS",
 #endif
 		"P2P_FIND",
 		"P2P_STOP_FIND",
@@ -6038,6 +6037,102 @@
 }
 
 
+static int wpas_global_ctrl_iface_set(struct wpa_global *global, char *cmd)
+{
+	char *value;
+
+	value = os_strchr(cmd, ' ');
+	if (value == NULL)
+		return -1;
+	*value++ = '\0';
+
+	wpa_printf(MSG_DEBUG, "GLOBAL_CTRL_IFACE SET '%s'='%s'", cmd, value);
+
+#ifdef CONFIG_WIFI_DISPLAY
+	if (os_strcasecmp(cmd, "wifi_display") == 0) {
+		wifi_display_enable(global, !!atoi(value));
+		return 0;
+	}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+	return -1;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+static int wpas_global_ctrl_iface_save_config(struct wpa_global *global)
+{
+	int ret = 0;
+	struct wpa_supplicant *wpa_s;
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (!wpa_s->conf->update_config) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed to update configuration (update_config=0)");
+			continue;
+		}
+
+		if (wpa_config_write(wpa_s->confname, wpa_s->conf)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to update configuration");
+			ret = 1;
+		} else {
+			wpa_dbg(wpa_s, MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration updated");
+		}
+	}
+
+	return ret;
+}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
+static int wpas_global_ctrl_iface_status(struct wpa_global *global,
+					 char *buf, size_t buflen)
+{
+	char *pos, *end;
+	int ret;
+	struct wpa_supplicant *wpa_s;
+
+	pos = buf;
+	end = buf + buflen;
+
+#ifdef CONFIG_P2P
+	if (global->p2p && !global->p2p_disabled) {
+		ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
+				  "\n"
+				  "p2p_state=%s\n",
+				  MAC2STR(global->p2p_dev_addr),
+				  p2p_get_state_txt(global->p2p));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	} else if (global->p2p) {
+		ret = os_snprintf(pos, end - pos, "p2p_state=DISABLED\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+	ret = os_snprintf(pos, end - pos, "wifi_display=%d\n",
+			  !!global->wifi_display);
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+#endif /* CONFIG_WIFI_DISPLAY */
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		ret = os_snprintf(pos, end - pos, "ifname=%s\n"
+				  "address=" MACSTR "\n",
+				  wpa_s->ifname, MAC2STR(wpa_s->own_addr));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
 char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
 						char *buf, size_t *resp_len)
 {
@@ -6095,6 +6190,17 @@
 		wpas_notify_suspend(global);
 	} else if (os_strcmp(buf, "RESUME") == 0) {
 		wpas_notify_resume(global);
+	} else if (os_strncmp(buf, "SET ", 4) == 0) {
+		if (wpas_global_ctrl_iface_set(global, buf + 4))
+			reply_len = -1;
+#ifndef CONFIG_NO_CONFIG_WRITE
+	} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
+		if (wpas_global_ctrl_iface_save_config(global))
+			reply_len = -1;
+#endif /* CONFIG_NO_CONFIG_WRITE */
+	} else if (os_strcmp(buf, "STATUS") == 0) {
+		reply_len = wpas_global_ctrl_iface_status(global, reply,
+							  reply_size);
 	} else {
 		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
 		reply_len = 16;
diff --git a/wpa_supplicant/ctrl_iface_udp.c b/wpa_supplicant/ctrl_iface_udp.c
index f3b660d..8c09ba1 100644
--- a/wpa_supplicant/ctrl_iface_udp.c
+++ b/wpa_supplicant/ctrl_iface_udp.c
@@ -80,14 +80,14 @@
 	while (dst) {
 		if (from->sin_addr.s_addr == dst->addr.sin_addr.s_addr &&
 		    from->sin_port == dst->addr.sin_port) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
+				   "%s:%d", inet_ntoa(from->sin_addr),
+				   ntohs(from->sin_port));
 			if (prev == NULL)
 				priv->ctrl_dst = dst->next;
 			else
 				prev->next = dst->next;
 			os_free(dst);
-			wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached "
-				   "%s:%d", inet_ntoa(from->sin_addr),
-				   ntohs(from->sin_port));
 			return 0;
 		}
 		prev = dst;
@@ -331,13 +331,13 @@
 		eloop_unregister_read_sock(priv->sock);
 		if (priv->ctrl_dst) {
 			/*
-			 * Wait a second before closing the control socket if
+			 * Wait before closing the control socket if
 			 * there are any attached monitors in order to allow
 			 * them to receive any pending messages.
 			 */
 			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
 				   "monitors to receive messages");
-			os_sleep(1, 0);
+			os_sleep(0, 100000);
 		}
 		close(priv->sock);
 		priv->sock = -1;
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index fc0d649..e35d2c3 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -94,12 +94,12 @@
 		    os_memcmp(from->sun_path, dst->addr.sun_path,
 			      fromlen - offsetof(struct sockaddr_un, sun_path))
 		    == 0) {
-			dl_list_del(&dst->list);
-			os_free(dst);
 			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
 				    (u8 *) from->sun_path,
 				    fromlen -
 				    offsetof(struct sockaddr_un, sun_path));
+			dl_list_del(&dst->list);
+			os_free(dst);
 			return 0;
 		}
 	}
@@ -150,7 +150,8 @@
 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (res < 0) {
-		perror("recvfrom(ctrl_iface)");
+		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+			   strerror(errno));
 		return;
 	}
 	buf[res] = '\0';
@@ -327,7 +328,8 @@
 			wpa_printf(MSG_DEBUG, "Using existing control "
 				   "interface directory.");
 		} else {
-			perror("mkdir[ctrl_interface]");
+			wpa_printf(MSG_ERROR, "mkdir[ctrl_interface=%s]: %s",
+				   dir, strerror(errno));
 			goto fail;
 		}
 	}
@@ -371,7 +373,8 @@
 	}
 
 	if (gid_set && chown(dir, -1, gid) < 0) {
-		perror("chown[ctrl_interface]");
+		wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+			   dir, (int) gid, strerror(errno));
 		goto fail;
 	}
 
@@ -391,7 +394,7 @@
 
 	priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (priv->sock < 0) {
-		perror("socket(PF_UNIX)");
+		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
 		goto fail;
 	}
 
@@ -413,15 +416,15 @@
 				   " allow connections - assuming it was left"
 				   "over from forced program termination");
 			if (unlink(fname) < 0) {
-				perror("unlink[ctrl_iface]");
-				wpa_printf(MSG_ERROR, "Could not unlink "
-					   "existing ctrl_iface socket '%s'",
-					   fname);
+				wpa_printf(MSG_ERROR,
+					   "Could not unlink existing ctrl_iface socket '%s': %s",
+					   fname, strerror(errno));
 				goto fail;
 			}
 			if (bind(priv->sock, (struct sockaddr *) &addr,
 				 sizeof(addr)) < 0) {
-				perror("supp-ctrl-iface-init: bind(PF_UNIX)");
+				wpa_printf(MSG_ERROR, "supp-ctrl-iface-init: bind(PF_UNIX): %s",
+					   strerror(errno));
 				goto fail;
 			}
 			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -438,12 +441,14 @@
 	}
 
 	if (gid_set && chown(fname, -1, gid) < 0) {
-		perror("chown[ctrl_interface/ifname]");
+		wpa_printf(MSG_ERROR, "chown[ctrl_interface=%s,gid=%d]: %s",
+			   fname, (int) gid, strerror(errno));
 		goto fail;
 	}
 
 	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
-		perror("chmod[ctrl_interface/ifname]");
+		wpa_printf(MSG_ERROR, "chmod[ctrl_interface=%s]: %s",
+			   fname, strerror(errno));
 		goto fail;
 	}
 	os_free(fname);
@@ -460,7 +465,8 @@
 	if (flags >= 0) {
 		flags |= O_NONBLOCK;
 		if (fcntl(priv->sock, F_SETFL, flags) < 0) {
-			perror("fcntl(ctrl, O_NONBLOCK)");
+			wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
+				   strerror(errno));
 			/* Not fatal, continue on.*/
 		}
 	}
@@ -495,13 +501,13 @@
 		eloop_unregister_read_sock(priv->sock);
 		if (!dl_list_empty(&priv->ctrl_dst)) {
 			/*
-			 * Wait a second before closing the control socket if
+			 * Wait before closing the control socket if
 			 * there are any attached monitors in order to allow
 			 * them to receive any pending messages.
 			 */
 			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
 				   "monitors to receive messages");
-			os_sleep(1, 0);
+			os_sleep(0, 100000);
 		}
 		close(priv->sock);
 		priv->sock = -1;
@@ -530,7 +536,9 @@
 					   "directory not empty - leaving it "
 					   "behind");
 			} else {
-				perror("rmdir[ctrl_interface]");
+				wpa_printf(MSG_ERROR,
+					   "rmdir[ctrl_interface=%s]: %s",
+					   dir, strerror(errno));
 			}
 		}
 		os_free(buf);
@@ -638,7 +646,8 @@
 		res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
 			       (struct sockaddr *) &from, &fromlen);
 		if (res < 0) {
-			perror("recvfrom(ctrl_iface)");
+			wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+				   strerror(errno));
 			continue;
 		}
 		buf[res] = '\0';
@@ -681,7 +690,8 @@
 	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
 		       (struct sockaddr *) &from, &fromlen);
 	if (res < 0) {
-		perror("recvfrom(ctrl_iface)");
+		wpa_printf(MSG_ERROR, "recvfrom(ctrl_iface): %s",
+			   strerror(errno));
 		return;
 	}
 	buf[res] = '\0';
@@ -722,6 +732,7 @@
 	struct ctrl_iface_global_priv *priv;
 	struct sockaddr_un addr;
 	const char *ctrl = global->params.ctrl_interface;
+	int flags;
 
 	priv = os_zalloc(sizeof(*priv));
 	if (priv == NULL)
@@ -766,7 +777,7 @@
 
 	priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
 	if (priv->sock < 0) {
-		perror("socket(PF_UNIX)");
+		wpa_printf(MSG_ERROR, "socket(PF_UNIX): %s", strerror(errno));
 		goto fail;
 	}
 
@@ -783,7 +794,8 @@
 		if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) <
 		    0) {
 			wpa_printf(MSG_ERROR, "supp-global-ctrl-iface-init: "
-				   "bind(PF_UNIX) failed: %s", strerror(errno));
+				   "bind(PF_UNIX;%s) failed: %s",
+				   ctrl, strerror(errno));
 			goto fail;
 		}
 		wpa_printf(MSG_DEBUG, "Using Abstract control socket '%s'",
@@ -793,23 +805,23 @@
 
 	os_strlcpy(addr.sun_path, ctrl, sizeof(addr.sun_path));
 	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-		perror("supp-global-ctrl-iface-init (will try fixup): "
-		       "bind(PF_UNIX)");
+		wpa_printf(MSG_INFO, "supp-global-ctrl-iface-init(%s) (will try fixup): bind(PF_UNIX): %s",
+			   ctrl, strerror(errno));
 		if (connect(priv->sock, (struct sockaddr *) &addr,
 			    sizeof(addr)) < 0) {
 			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
 				   " allow connections - assuming it was left"
 				   "over from forced program termination");
 			if (unlink(ctrl) < 0) {
-				perror("unlink[ctrl_iface]");
-				wpa_printf(MSG_ERROR, "Could not unlink "
-					   "existing ctrl_iface socket '%s'",
-					   ctrl);
+				wpa_printf(MSG_ERROR,
+					   "Could not unlink existing ctrl_iface socket '%s': %s",
+					   ctrl, strerror(errno));
 				goto fail;
 			}
 			if (bind(priv->sock, (struct sockaddr *) &addr,
 				 sizeof(addr)) < 0) {
-				perror("supp-glb-iface-init: bind(PF_UNIX)");
+				wpa_printf(MSG_ERROR, "supp-glb-iface-init: bind(PF_UNIX;%s): %s",
+					   ctrl, strerror(errno));
 				goto fail;
 			}
 			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
@@ -851,12 +863,16 @@
 				   (int) gid);
 		}
 		if (chown(ctrl, -1, gid) < 0) {
-			perror("chown[global_ctrl_interface/ifname]");
+			wpa_printf(MSG_ERROR,
+				   "chown[global_ctrl_interface=%s,gid=%d]: %s",
+				   ctrl, (int) gid, strerror(errno));
 			goto fail;
 		}
 
 		if (chmod(ctrl, S_IRWXU | S_IRWXG) < 0) {
-			perror("chmod[global_ctrl_interface/ifname]");
+			wpa_printf(MSG_ERROR,
+				   "chmod[global_ctrl_interface=%s]: %s",
+				   ctrl, strerror(errno));
 			goto fail;
 		}
 	} else {
@@ -864,6 +880,21 @@
 	}
 
 havesock:
+
+	/*
+	 * Make socket non-blocking so that we don't hang forever if
+	 * target dies unexpectedly.
+	 */
+	flags = fcntl(priv->sock, F_GETFL);
+	if (flags >= 0) {
+		flags |= O_NONBLOCK;
+		if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+			wpa_printf(MSG_INFO, "fcntl(ctrl, O_NONBLOCK): %s",
+				   strerror(errno));
+			/* Not fatal, continue on.*/
+		}
+	}
+
 	eloop_register_read_sock(priv->sock,
 				 wpa_supplicant_global_ctrl_iface_receive,
 				 global, priv);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 7c0d2e8..d77e96b 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -190,6 +190,7 @@
 		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
 	wpa_s->ap_ies_from_associnfo = 0;
 	wpa_s->current_ssid = NULL;
+	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
 	wpa_s->key_mgmt = 0;
 }
 
@@ -337,10 +338,24 @@
 
 
 #ifndef CONFIG_NO_SCAN_PROCESSING
+
+static int has_wep_key(struct wpa_ssid *ssid)
+{
+	int i;
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (ssid->wep_key_len[i])
+			return 1;
+	}
+
+	return 0;
+}
+
+
 static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
 					struct wpa_ssid *ssid)
 {
-	int i, privacy = 0;
+	int privacy = 0;
 
 	if (ssid->mixed_cell)
 		return 1;
@@ -350,12 +365,9 @@
 		return 1;
 #endif /* CONFIG_WPS */
 
-	for (i = 0; i < NUM_WEP_KEYS; i++) {
-		if (ssid->wep_key_len[i]) {
-			privacy = 1;
-			break;
-		}
-	}
+	if (has_wep_key(ssid))
+		privacy = 1;
+
 #ifdef IEEE8021X_EAPOL
 	if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
 	    ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
@@ -821,6 +833,12 @@
 			continue;
 		}
 
+		if (wpa && !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
+		    has_wep_key(ssid)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - ignore WPA/WPA2 AP for WEP network block");
+			continue;
+		}
+
 		if (!wpa_supplicant_match_privacy(bss, ssid)) {
 			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - privacy "
 				"mismatch");
diff --git a/wpa_supplicant/ibss_rsn.c b/wpa_supplicant/ibss_rsn.c
index 62d68b8..b694bde 100644
--- a/wpa_supplicant/ibss_rsn.c
+++ b/wpa_supplicant/ibss_rsn.c
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - IBSS RSN
- * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -9,6 +9,7 @@
 #include "includes.h"
 
 #include "common.h"
+#include "common/wpa_ctrl.h"
 #include "l2_packet/l2_packet.h"
 #include "rsn_supp/wpa.h"
 #include "rsn_supp/wpa_ie.h"
@@ -114,6 +115,22 @@
 }
 
 
+static void ibss_check_rsn_completed(struct ibss_rsn_peer *peer)
+{
+	struct wpa_supplicant *wpa_s = peer->ibss_rsn->wpa_s;
+
+	if ((peer->authentication_status &
+	     (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH)) !=
+	    (IBSS_RSN_SET_PTK_SUPP | IBSS_RSN_SET_PTK_AUTH))
+		return;
+	if (peer->authentication_status & IBSS_RSN_REPORTED_PTK)
+		return;
+	peer->authentication_status |= IBSS_RSN_REPORTED_PTK;
+	wpa_msg(wpa_s, MSG_INFO, IBSS_RSN_COMPLETED MACSTR,
+		MAC2STR(peer->addr));
+}
+
+
 static int supp_set_key(void *ctx, enum wpa_alg alg,
 			const u8 *addr, int key_idx, int set_tx,
 			const u8 *seq, size_t seq_len,
@@ -128,6 +145,8 @@
 	wpa_hexdump_key(MSG_DEBUG, "SUPP: set_key - key", key, key_len);
 
 	if (key_idx == 0) {
+		peer->authentication_status |= IBSS_RSN_SET_PTK_SUPP;
+		ibss_check_rsn_completed(peer);
 		/*
 		 * In IBSS RSN, the pairwise key from the 4-way handshake
 		 * initiated by the peer with highest MAC address is used.
@@ -281,6 +300,15 @@
 	wpa_hexdump_key(MSG_DEBUG, "AUTH: set_key - key", key, key_len);
 
 	if (idx == 0) {
+		if (addr) {
+			struct ibss_rsn_peer *peer;
+			peer = ibss_rsn_get_peer(ibss_rsn, addr);
+			if (peer) {
+				peer->authentication_status |=
+					IBSS_RSN_SET_PTK_AUTH;
+				ibss_check_rsn_completed(peer);
+			}
+		}
 		/*
 		 * In IBSS RSN, the pairwise key from the 4-way handshake
 		 * initiated by the peer with highest MAC address is used.
diff --git a/wpa_supplicant/ibss_rsn.h b/wpa_supplicant/ibss_rsn.h
index 5a8eda4..6b89f7a 100644
--- a/wpa_supplicant/ibss_rsn.h
+++ b/wpa_supplicant/ibss_rsn.h
@@ -19,6 +19,12 @@
 #define IBSS_RSN_AUTH_BY_US		0x02
 /* we sent an EAPOL message */
 #define IBSS_RSN_AUTH_EAPOL_BY_US	0x04
+/* PTK derived as supplicant */
+#define IBSS_RSN_SET_PTK_SUPP		0x08
+/* PTK derived as authenticator */
+#define IBSS_RSN_SET_PTK_AUTH		0x10
+/* PTK completion reported */
+#define IBSS_RSN_REPORTED_PTK		0x20
 
 struct ibss_rsn_peer {
 	struct ibss_rsn_peer *next;
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index e039594..0827f35 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -1058,6 +1058,7 @@
 	d->pbc_in_m1 = s->pbc_in_m1;
 	d->ignore_old_scan_res = s->ignore_old_scan_res;
 	d->beacon_int = s->beacon_int;
+	d->disassoc_low_ack = s->disassoc_low_ack;
 }
 
 
@@ -1237,7 +1238,13 @@
 	if (wpa_s->p2p_go_ht40)
 		res->ht40 = 1;
 
-	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS);
+	wpa_msg_global(wpa_s, MSG_INFO, P2P_EVENT_GO_NEG_SUCCESS "role=%s "
+		       "freq=%d ht40=%d peer_dev=" MACSTR " peer_iface=" MACSTR
+		       " wps_method=%s",
+		       res->role_go ? "GO" : "client", res->freq, res->ht40,
+		       MAC2STR(res->peer_device_addr),
+		       MAC2STR(res->peer_interface_addr),
+		       p2p_wps_method_text(res->wps_method));
 	wpas_notify_p2p_go_neg_completed(wpa_s, res);
 
 	if (res->role_go && wpa_s->p2p_persistent_id >= 0) {
@@ -3894,6 +3901,9 @@
 
 	num = get_shared_radio_freqs(wpa_s, freqs,
 				     wpa_s->num_multichan_concurrent);
+	wpa_printf(MSG_DEBUG,
+		   "P2P: Setup freqs: freq=%d num_MCC=%d shared_freqs=%u",
+		   freq, wpa_s->num_multichan_concurrent, num);
 
 	if (freq > 0) {
 		if (!p2p_supported_freq(wpa_s->global->p2p, freq)) {
@@ -4186,7 +4196,11 @@
 		while (wpa_s) {
 			prev = wpa_s;
 			wpa_s = wpa_s->next;
-			wpas_p2p_disconnect(prev);
+			if (prev->p2p_group_interface !=
+			    NOT_P2P_GROUP_INTERFACE ||
+			    (prev->current_ssid &&
+			     prev->current_ssid->p2p_group))
+				wpas_p2p_disconnect(prev);
 		}
 		return 0;
 	}
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 9b6cd46..a0f51d0 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -266,17 +266,13 @@
 				int interval)
 {
 	int ret;
-#ifndef ANDROID_P2P
+
 	wpa_supplicant_notify_scanning(wpa_s, 1);
-#endif
 	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;
-#ifdef ANDROID_P2P
-		wpa_supplicant_notify_scanning(wpa_s, 1);
-#endif
 	}
 
 	return ret;
@@ -1048,11 +1044,9 @@
 					sizeof(struct wpa_driver_scan_filter));
 
 	prev_state = wpa_s->wpa_state;
-#ifndef ANDROID_P2P
 	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
 	    wpa_s->wpa_state == WPA_INACTIVE)
 		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
-#endif
 
 	if (wpa_s->autoscan_params != NULL) {
 		scan_params = wpa_s->autoscan_params;
@@ -1264,12 +1258,7 @@
 				    int scanning)
 {
 	if (wpa_s->scanning != scanning) {
-#ifdef ANDROID_P2P
-		if(!wpa_s->sched_scanning)
-			wpa_s->scanning = scanning;
-#else
 		wpa_s->scanning = scanning;
-#endif
 		wpas_notify_scanning(wpa_s);
 	}
 }
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 35ecfea..caab28b 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1933,8 +1933,10 @@
 		return;
 	}
 
-	if (ssid)
+	if (ssid) {
 		wpa_s->current_ssid = ssid;
+		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+	}
 	wpa_s->connect_without_scan = NULL;
 	wpa_s->disconnected = 0;
 	wpa_s->reassociate = 1;
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 8e0207c..b855dbd 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -567,11 +567,13 @@
 }
 
 
-static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = {
-	"No Error", /* WPS_EI_NO_ERROR */
-	"TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */
-	"WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */
-};
+static void wpas_wps_clear_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	wpa_printf(MSG_DEBUG, "WPS: Clear WPS network from timeout");
+	wpas_clear_wps(wpa_s);
+}
+
 
 static void wpa_supplicant_wps_event_fail(struct wpa_supplicant *wpa_s,
 					  struct wps_event_fail *fail)
@@ -581,13 +583,13 @@
 		wpa_msg(wpa_s, MSG_INFO,
 			WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
 			fail->msg, fail->config_error, fail->error_indication,
-			wps_event_fail_reason[fail->error_indication]);
+			wps_ei_str(fail->error_indication));
 		if (wpa_s->parent && wpa_s->parent != wpa_s)
 			wpa_msg(wpa_s->parent, MSG_INFO, WPS_EVENT_FAIL
 				"msg=%d config_error=%d reason=%d (%s)",
 				fail->msg, fail->config_error,
 				fail->error_indication,
-				wps_event_fail_reason[fail->error_indication]);
+				wps_ei_str(fail->error_indication));
 	} else {
 		wpa_msg(wpa_s, MSG_INFO,
 			WPS_EVENT_FAIL "msg=%d config_error=%d",
@@ -597,7 +599,14 @@
 				"msg=%d config_error=%d",
 				fail->msg, fail->config_error);
 	}
-	wpas_clear_wps(wpa_s);
+
+	/*
+	 * Need to allow WPS processing to complete, e.g., by sending WSC_NACK.
+	 */
+	wpa_printf(MSG_DEBUG, "WPS: Register timeout to clear WPS network");
+	eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
+	eloop_register_timeout(0, 100000, wpas_wps_clear_timeout, wpa_s, NULL);
+
 	wpas_notify_wps_event_fail(wpa_s, fail);
 #ifdef CONFIG_P2P
 	wpas_p2p_wps_failed(wpa_s, fail);
@@ -813,6 +822,12 @@
 		break;
 	case WPS_EV_PBC_TIMEOUT:
 		break;
+	case WPS_EV_PBC_ACTIVE:
+		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_ACTIVE);
+		break;
+	case WPS_EV_PBC_DISABLE:
+		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_DISABLE);
+		break;
 	case WPS_EV_ER_AP_ADD:
 		wpa_supplicant_wps_event_er_ap_add(wpa_s, &data->ap);
 		break;
@@ -841,6 +856,17 @@
 }
 
 
+static int wpa_supplicant_wps_rf_band(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	if (!wpa_s->current_ssid || !wpa_s->assoc_freq)
+		return 0;
+
+	return (wpa_s->assoc_freq > 2484) ? WPS_RF_50GHZ : WPS_RF_24GHZ;
+}
+
+
 enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid)
 {
 	if (eap_is_wps_pbc_enrollee(&ssid->eap) ||
@@ -1312,6 +1338,7 @@
 
 	wps->cred_cb = wpa_supplicant_wps_cred;
 	wps->event_cb = wpa_supplicant_wps_event;
+	wps->rf_band_cb = wpa_supplicant_wps_rf_band;
 	wps->cb_ctx = wpa_s;
 
 	wps->dev.device_name = wpa_s->conf->device_name;
@@ -1385,6 +1412,7 @@
 void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
 {
 	eloop_cancel_timeout(wpas_wps_timeout, wpa_s, NULL);
+	eloop_cancel_timeout(wpas_wps_clear_timeout, wpa_s, NULL);
 	eloop_cancel_timeout(wpas_wps_reenable_networks_cb, wpa_s, NULL);
 	wpas_wps_clear_ap_info(wpa_s);