Accumulative patch from commit 376204934db44d45f798bdde4db005bc88d666f0

3762049 wpa_cli: Support tab completion with ifname= prefix
13b11ba wpa_cli: Allow IFNAME= prefix to be used
ae8535b WNM: Make ESS Disassoc Imminent event more convenient to use
6df634f WNM: Do not reject ESS Disassoc Imminent
7b53acd WNM: Use defines for BSS Trans Mgmt field values
8e1bc70 WNM: Fix ess_disassoc timeout to be specified in TBTTs
901d1fe WNM: Remove PMKSA cache entry on ESS disassoc imminent notification
dad153d Try to use fast-associate on ENABLE_NETWORK
b068001 Fix already-associated detection with driver-based BSS selection
72728c6 P2P: Relax channel forcing for invitation processing with MCC support
4033935 Fix OKC-based PMKSA cache entry clearing
1045ec3 nl80211: Add couple of additional iftypes to debug prints
2cadc8e TDLS: Retry TDLS Setup Response more quickly

Change-Id: Ib02db74ca336a4d2da66c21d361c5529ee85f864
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 7fc520c..dc9ede7 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -29,6 +29,7 @@
 #include "ap/wps_hostapd.h"
 #include "ap/ctrl_iface_ap.h"
 #include "ap/ap_drv_ops.h"
+#include "ap/wpa_auth.h"
 #include "wps/wps_defs.h"
 #include "wps/wps.h"
 #include "config_file.h"
@@ -594,6 +595,14 @@
 	/* send disassociation frame after time-out */
 	if (disassoc_timer) {
 		struct sta_info *sta;
+		int timeout, beacon_int;
+
+		/*
+		 * Prevent STA from reconnecting using cached PMKSA to force
+		 * full authentication with the authentication server (which may
+		 * decide to reject the connection),
+		 */
+		wpa_auth_pmksa_remove(hapd->wpa_auth, addr);
 
 		sta = ap_get_sta(hapd, addr);
 		if (sta == NULL) {
@@ -603,10 +612,18 @@
 			return -1;
 		}
 
+		beacon_int = hapd->iconf->beacon_int;
+		if (beacon_int < 1)
+			beacon_int = 100; /* best guess */
+		/* Calculate timeout in ms based on beacon_int in TU */
+		timeout = disassoc_timer * beacon_int * 128 / 125;
+		wpa_printf(MSG_DEBUG, "Disassociation timer for " MACSTR
+			   " set to %d ms", MAC2STR(addr), timeout);
+
 		sta->timeout_next = STA_DISASSOC_FROM_CLI;
 		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
-		eloop_register_timeout(disassoc_timer / 1000,
-				       disassoc_timer % 1000 * 1000,
+		eloop_register_timeout(timeout / 1000,
+				       timeout % 1000 * 1000,
 				       ap_handle_timer, hapd, sta);
 	}
 
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index d27fd30..40972e9 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -48,8 +48,8 @@
 }
 
 
-static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
-				   struct rsn_pmksa_cache_entry *entry)
+void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+			    struct rsn_pmksa_cache_entry *entry)
 {
 	struct rsn_pmksa_cache_entry *pos, *prev;
 
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index d473f3f..aa90024 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -55,5 +55,7 @@
 		    const u8 *aa, const u8 *pmkid);
 void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
 			       struct eapol_state_machine *eapol);
+void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+			    struct rsn_pmksa_cache_entry *entry);
 
 #endif /* PMKSA_CACHE_H */
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 18ae86c..83cc857 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -2944,6 +2944,22 @@
 }
 
 
+void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
+			   const u8 *sta_addr)
+{
+	struct rsn_pmksa_cache_entry *pmksa;
+
+	if (wpa_auth == NULL || wpa_auth->pmksa == NULL)
+		return;
+	pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sta_addr, NULL);
+	if (pmksa) {
+		wpa_printf(MSG_DEBUG, "WPA: Remove PMKSA cache entry for "
+			   MACSTR " based on request", MAC2STR(sta_addr));
+		pmksa_cache_free_entry(wpa_auth->pmksa, pmksa);
+	}
+}
+
+
 static struct wpa_group *
 wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
 {
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 9126b90..ebfe86f 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -263,6 +263,8 @@
 			       const u8 *pmk, size_t len, const u8 *sta_addr,
 			       int session_timeout,
 			       struct eapol_state_machine *eapol);
+void wpa_auth_pmksa_remove(struct wpa_authenticator *wpa_auth,
+			   const u8 *sta_addr);
 int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
 void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
 				  struct wpa_state_machine *sm, int ack);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 0848590..137c309 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1057,6 +1057,19 @@
 #define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
 #define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
 
+/* IEEE Std 802.11-2012 - Table 8-253 */
+enum bss_trans_mgmt_status_code {
+	WNM_BSS_TM_ACCEPT = 0,
+	WNM_BSS_TM_REJECT_UNSPECIFIED = 1,
+	WNM_BSS_TM_REJECT_INSUFFICIENT_BEACON = 2,
+	WNM_BSS_TM_REJECT_INSUFFICIENT_CAPABITY = 3,
+	WNM_BSS_TM_REJECT_UNDESIRED = 4,
+	WNM_BSS_TM_REJECT_DELAY_REQUEST = 5,
+	WNM_BSS_TM_REJECT_STA_CANDIDATE_LIST_PROVIDED = 6,
+	WNM_BSS_TM_REJECT_NO_SUITABLE_CANDIDATES = 7,
+	WNM_BSS_TM_REJECT_LEAVING_ESS = 8
+};
+
 #define WNM_NEIGHBOR_TSF                         1
 #define WNM_NEIGHBOR_CONDENSED_COUNTRY_STRING    2
 #define WNM_NEIGHBOR_BSS_TRANSITION_CANDIDATE    3
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index aab228b..0c05a41 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -136,6 +136,9 @@
 #define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
 #define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
 
+/* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
+#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
+
 #define INTERWORKING_AP "INTERWORKING-AP "
 #define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
 
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
index c8f7478..3d16330 100644
--- a/src/drivers/driver_nl80211.c
+++ b/src/drivers/driver_nl80211.c
@@ -6298,8 +6298,14 @@
 		return "STATION";
 	case NL80211_IFTYPE_AP:
 		return "AP";
+	case NL80211_IFTYPE_AP_VLAN:
+		return "AP_VLAN";
+	case NL80211_IFTYPE_WDS:
+		return "WDS";
 	case NL80211_IFTYPE_MONITOR:
 		return "MONITOR";
+	case NL80211_IFTYPE_MESH_POINT:
+		return "MESH_POINT";
 	case NL80211_IFTYPE_P2P_CLIENT:
 		return "P2P_CLIENT";
 	case NL80211_IFTYPE_P2P_GO:
diff --git a/src/p2p/p2p.h b/src/p2p/p2p.h
index 499b62e..c392d57 100644
--- a/src/p2p/p2p.h
+++ b/src/p2p/p2p.h
@@ -702,6 +702,7 @@
 	 * @persistent_group: Whether this is an invitation to reinvoke a
 	 *	persistent group (instead of invitation to join an active
 	 *	group)
+	 * @channels: Available operating channels for the group
 	 * Returns: Status code (P2P_SC_*)
 	 *
 	 * This optional callback can be used to implement persistent reconnect
@@ -722,7 +723,8 @@
 	u8 (*invitation_process)(void *ctx, const u8 *sa, const u8 *bssid,
 				 const u8 *go_dev_addr, const u8 *ssid,
 				 size_t ssid_len, int *go, u8 *group_bssid,
-				 int *force_freq, int persistent_group);
+				 int *force_freq, int persistent_group,
+				 const struct p2p_channels *channels);
 
 	/**
 	 * invitation_received - Callback on Invitation Request RX
diff --git a/src/p2p/p2p_invitation.c b/src/p2p/p2p_invitation.c
index 214eae0..e3e760d 100644
--- a/src/p2p/p2p_invitation.c
+++ b/src/p2p/p2p_invitation.c
@@ -221,11 +221,14 @@
 		goto fail;
 	}
 
+	p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
+			       &intersection);
+
 	if (p2p->cfg->invitation_process) {
 		status = p2p->cfg->invitation_process(
 			p2p->cfg->cb_ctx, sa, msg.group_bssid, msg.group_id,
 			msg.group_id + ETH_ALEN, msg.group_id_len - ETH_ALEN,
-			&go, group_bssid, &op_freq, persistent);
+			&go, group_bssid, &op_freq, persistent, &intersection);
 	}
 
 	if (op_freq) {
@@ -238,8 +241,6 @@
 			goto fail;
 		}
 
-		p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
-				       &intersection);
 		if (!p2p_channels_includes(&intersection, reg_class, channel))
 		{
 			p2p_dbg(p2p, "forced freq %d MHz not in the supported channels interaction",
@@ -253,8 +254,6 @@
 	} else {
 		p2p_dbg(p2p, "No forced channel from invitation processing - figure out best one to use");
 
-		p2p_channels_intersect(&p2p->cfg->channels, &dev->channels,
-				       &intersection);
 		/* Default to own configuration as a starting point */
 		p2p->op_reg_class = p2p->cfg->op_reg_class;
 		p2p->op_channel = p2p->cfg->op_channel;
diff --git a/src/rsn_supp/pmksa_cache.c b/src/rsn_supp/pmksa_cache.c
index df67583..93056ea 100644
--- a/src/rsn_supp/pmksa_cache.c
+++ b/src/rsn_supp/pmksa_cache.c
@@ -164,17 +164,23 @@
 				pmksa->pmksa = pos->next;
 			else
 				prev->next = pos->next;
-			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
-				   "the current AP");
-			pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
 
 			/*
 			 * If OKC is used, there may be other PMKSA cache
 			 * entries based on the same PMK. These needs to be
 			 * flushed so that a new entry can be created based on
-			 * the new PMK.
+			 * the new PMK. Only clear other entries if they have a
+			 * matching PMK and this PMK has been used successfully
+			 * with the current AP, i.e., if opportunistic flag has
+			 * been cleared in wpa_supplicant_key_neg_complete().
 			 */
-			pmksa_cache_flush(pmksa, network_ctx);
+			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
+				   "the current AP and any PMKSA cache entry "
+				   "that was based on the old PMK");
+			if (!pos->opportunistic)
+				pmksa_cache_flush(pmksa, network_ctx, pos->pmk,
+						  pos->pmk_len);
+			pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
 			break;
 		}
 		prev = pos;
@@ -235,15 +241,22 @@
  * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
  * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
  * @network_ctx: Network configuration context or %NULL to flush all entries
+ * @pmk: PMK to match for or %NYLL to match all PMKs
+ * @pmk_len: PMK length
  */
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+		       const u8 *pmk, size_t pmk_len)
 {
 	struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
 	int removed = 0;
 
 	entry = pmksa->pmksa;
 	while (entry) {
-		if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+		if ((entry->network_ctx == network_ctx ||
+		     network_ctx == NULL) &&
+		    (pmk == NULL ||
+		     (pmk_len == entry->pmk_len &&
+		      os_memcmp(pmk, entry->pmk, pmk_len) == 0))) {
 			wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
 				   "for " MACSTR, MAC2STR(entry->aa));
 			if (prev)
diff --git a/src/rsn_supp/pmksa_cache.h b/src/rsn_supp/pmksa_cache.h
index 6f3dfb3..d5aa229 100644
--- a/src/rsn_supp/pmksa_cache.h
+++ b/src/rsn_supp/pmksa_cache.h
@@ -66,7 +66,8 @@
 struct rsn_pmksa_cache_entry *
 pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
 			      void *network_ctx, const u8 *aa);
-void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+		       const u8 *pmk, size_t pmk_len);
 
 #else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
 
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 81e2a5c..221d5fd 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -37,8 +37,10 @@
 #endif /* CONFIG_TDLS_TESTING */
 
 #define TPK_LIFETIME 43200 /* 12 hours */
-#define TPK_RETRY_COUNT 3
-#define TPK_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M1_RETRY_COUNT 3
+#define TPK_M1_TIMEOUT 5000 /* in milliseconds */
+#define TPK_M2_RETRY_COUNT 10
+#define TPK_M2_TIMEOUT 500 /* in milliseconds */
 
 #define TDLS_MIC_LEN		16
 
@@ -244,8 +246,13 @@
 
 	eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
 
-	peer->sm_tmr.count = TPK_RETRY_COUNT;
-	peer->sm_tmr.timer = TPK_TIMEOUT;
+	if (action_code == WLAN_TDLS_SETUP_RESPONSE) {
+		peer->sm_tmr.count = TPK_M2_RETRY_COUNT;
+		peer->sm_tmr.timer = TPK_M2_TIMEOUT;
+	} else {
+		peer->sm_tmr.count = TPK_M1_RETRY_COUNT;
+		peer->sm_tmr.timer = TPK_M1_TIMEOUT;
+	}
 
 	/* Copy message to resend on timeout */
 	os_memcpy(peer->sm_tmr.dest, dest, ETH_ALEN);
@@ -261,7 +268,8 @@
 
 	wpa_printf(MSG_DEBUG, "TDLS: Retry timeout registered "
 		   "(action_code=%u)", action_code);
-	eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+	eloop_register_timeout(peer->sm_tmr.timer / 1000,
+			       (peer->sm_tmr.timer % 1000) * 1000,
 			       wpa_tdls_tpk_retry_timeout, sm, peer);
 	return 0;
 }
@@ -296,7 +304,6 @@
 
 	if (peer->sm_tmr.count) {
 		peer->sm_tmr.count--;
-		peer->sm_tmr.timer = TPK_TIMEOUT;
 
 		wpa_printf(MSG_INFO, "TDLS: Retrying sending of message "
 			   "(action_code=%u)",
@@ -323,7 +330,8 @@
 		}
 
 		eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
-		eloop_register_timeout(peer->sm_tmr.timer / 1000, 0,
+		eloop_register_timeout(peer->sm_tmr.timer / 1000,
+				       (peer->sm_tmr.timer % 1000) * 1000,
 				       wpa_tdls_tpk_retry_timeout, sm, peer);
 	} else {
 		eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index e50404c..d83700a 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -2412,6 +2412,21 @@
 }
 
 
+int wpa_sm_pmf_enabled(struct wpa_sm *sm)
+{
+	struct wpa_ie_data rsn;
+
+	if (sm->mfp == NO_MGMT_FRAME_PROTECTION || !sm->ap_rsn_ie)
+		return 0;
+
+	if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn) >= 0 &&
+	    rsn.capabilities & (WPA_CAPABILITY_MFPR | WPA_CAPABILITY_MFPC))
+		return 1;
+
+	return 0;
+}
+
+
 /**
  * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
  * @sm: Pointer to WPA state machine data from wpa_sm_init()
@@ -2622,7 +2637,7 @@
 void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
 {
 #ifndef CONFIG_NO_WPA2
-	pmksa_cache_flush(sm->pmksa, network_ctx);
+	pmksa_cache_flush(sm->pmksa, network_ctx, NULL, 0);
 #endif /* CONFIG_NO_WPA2 */
 }
 
diff --git a/src/rsn_supp/wpa.h b/src/rsn_supp/wpa.h
index 78dfb52..c757dcf 100644
--- a/src/rsn_supp/wpa.h
+++ b/src/rsn_supp/wpa.h
@@ -123,6 +123,7 @@
 
 int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
 		      int verbose);
+int wpa_sm_pmf_enabled(struct wpa_sm *sm);
 
 void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
 
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 6d9b587..60e71b6 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -929,6 +929,15 @@
 		return -1;
 	}
 
+	wpa_msg(wpa_s, MSG_DEBUG,
+		"Considering connect request: reassociate: %d  selected: "
+		MACSTR "  bssid: " MACSTR "  pending: " MACSTR
+		"  wpa_state: %s  ssid=%p  current_ssid=%p",
+		wpa_s->reassociate, MAC2STR(selected->bssid),
+		MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+		wpa_supplicant_state_txt(wpa_s->wpa_state),
+		ssid, wpa_s->current_ssid);
+
 	/*
 	 * Do not trigger new association unless the BSSID has changed or if
 	 * reassociation is requested. If we are in process of associating with
@@ -938,22 +947,21 @@
 	    (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
 	     ((wpa_s->wpa_state != WPA_ASSOCIATING &&
 	       wpa_s->wpa_state != WPA_AUTHENTICATING) ||
-	      os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
-	      0))) {
+	      (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+	       os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
+	       0) ||
+	      (is_zero_ether_addr(wpa_s->pending_bssid) &&
+	       ssid != wpa_s->current_ssid)))) {
 		if (wpa_supplicant_scard_init(wpa_s, ssid)) {
 			wpa_supplicant_req_new_scan(wpa_s, 10, 0);
 			return 0;
 		}
-		wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
-			"reassociate: %d  selected: "MACSTR "  bssid: " MACSTR
-			"  pending: " MACSTR "  wpa_state: %s",
-			wpa_s->reassociate, MAC2STR(selected->bssid),
-			MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
-			wpa_supplicant_state_txt(wpa_s->wpa_state));
+		wpa_msg(wpa_s, MSG_DEBUG, "Request association with " MACSTR,
+			MAC2STR(selected->bssid));
 		wpa_supplicant_associate(wpa_s, selected, ssid);
 	} else {
-		wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
-			"selected AP");
+		wpa_dbg(wpa_s, MSG_DEBUG, "Already associated or trying to "
+			"connect with the selected AP");
 	}
 
 	return 0;
diff --git a/wpa_supplicant/p2p_supplicant.c b/wpa_supplicant/p2p_supplicant.c
index 7c19d0c..c36f61c 100644
--- a/wpa_supplicant/p2p_supplicant.c
+++ b/wpa_supplicant/p2p_supplicant.c
@@ -2427,10 +2427,20 @@
 }
 
 
+static int freq_included(const struct p2p_channels *channels, unsigned int freq)
+{
+	if (channels == NULL)
+		return 1; /* Assume no restrictions */
+	return p2p_channels_includes_freq(channels, freq);
+
+}
+
+
 static u8 wpas_invitation_process(void *ctx, const u8 *sa, const u8 *bssid,
 				  const u8 *go_dev_addr, const u8 *ssid,
 				  size_t ssid_len, int *go, u8 *group_bssid,
-				  int *force_freq, int persistent_group)
+				  int *force_freq, int persistent_group,
+				  const struct p2p_channels *channels)
 {
 	struct wpa_supplicant *wpa_s = ctx;
 	struct wpa_ssid *s;
@@ -2528,6 +2538,25 @@
 		wpas_p2p_set_own_freq_preference(wpa_s, res);
 	}
 
+	if (*force_freq > 0 &&
+	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT)) {
+		if (*go == 0) {
+			/* We are the client */
+			wpa_printf(MSG_DEBUG, "P2P: Peer was found to be "
+				   "running a GO but we are capable of MCC, "
+				   "figure out the best channel to use");
+			*force_freq = 0;
+		} else if (!freq_included(channels, *force_freq)) {
+			/* We are the GO, and *force_freq is not in the
+			 * intersection */
+			wpa_printf(MSG_DEBUG, "P2P: Forced GO freq %d MHz not "
+				   "in intersection but we are capable of MCC, "
+				   "figure out the best channel to use",
+				   *force_freq);
+			*force_freq = 0;
+		}
+	}
+
 	return P2P_SC_SUCCESS;
 }
 
@@ -4102,14 +4131,6 @@
 }
 
 
-static int freq_included(const struct p2p_channels *channels, unsigned int freq)
-{
-	if (channels == NULL)
-		return 1; /* Assume no restrictions */
-	return p2p_channels_includes_freq(channels, freq);
-}
-
-
 static int wpas_p2p_init_go_params(struct wpa_supplicant *wpa_s,
 				   struct p2p_go_neg_results *params,
 				   int freq, int ht40,
diff --git a/wpa_supplicant/wnm_sta.c b/wpa_supplicant/wnm_sta.c
index 7de96c5..4f8d895 100644
--- a/wpa_supplicant/wnm_sta.c
+++ b/wpa_supplicant/wnm_sta.c
@@ -1,6 +1,6 @@
 /*
  * wpa_supplicant - WNM
- * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ * Copyright (c) 2011-2013, Qualcomm Atheros, Inc.
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
 #include "rsn_supp/wpa.h"
 #include "wpa_supplicant_i.h"
 #include "driver_i.h"
@@ -491,9 +492,10 @@
 }
 
 
-static void wnm_send_bss_transition_mgmt_resp(struct wpa_supplicant *wpa_s,
-					      u8 dialog_token, u8 status,
-					      u8 delay, const u8 *target_bssid)
+static void wnm_send_bss_transition_mgmt_resp(
+	struct wpa_supplicant *wpa_s, u8 dialog_token,
+	enum bss_trans_mgmt_status_code status, u8 delay,
+	const u8 *target_bssid)
 {
 	u8 buf[1000], *pos;
 	struct ieee80211_mgmt *mgmt;
@@ -559,7 +561,7 @@
 		if (wpa_s->wnm_reply) {
 			wnm_send_bss_transition_mgmt_resp(wpa_s,
 						  wpa_s->wnm_dialog_token,
-						  0, /* Accept */
+						  WNM_BSS_TM_ACCEPT,
 						  0, NULL);
 		}
 
@@ -575,7 +577,7 @@
 	if (wpa_s->wnm_reply) {
 		wnm_send_bss_transition_mgmt_resp(wpa_s,
 						  wpa_s->wnm_dialog_token,
-						  1 /* Reject - unspecified */,
+						  WNM_BSS_TM_REJECT_UNSPECIFIED,
 						  0, NULL);
 	}
 	return;
@@ -603,7 +605,7 @@
 
 	pos += 5;
 
-	if (wpa_s->wnm_mode & 0x08) {
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED) {
 		if (pos + 12 > end) {
 			wpa_printf(MSG_DEBUG, "WNM: Too short BSS TM Request");
 			return;
@@ -612,8 +614,10 @@
 		pos += 12; /* BSS Termination Duration */
 	}
 
-	if (wpa_s->wnm_mode & 0x10) {
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT) {
 		char url[256];
+		unsigned int beacon_int;
+
 		if (pos + 1 > end || pos + 1 + pos[0] > end) {
 			wpa_printf(MSG_DEBUG, "WNM: Invalid BSS Transition "
 				   "Management Request (URL)");
@@ -622,11 +626,18 @@
 		os_memcpy(url, pos + 1, pos[0]);
 		url[pos[0]] = '\0';
 		pos += 1 + pos[0];
-		wpa_msg(wpa_s, MSG_INFO, "WNM: ESS Disassociation Imminent - "
-			"session_info_url=%s", url);
+
+		if (wpa_s->current_bss)
+			beacon_int = wpa_s->current_bss->beacon_int;
+		else
+			beacon_int = 100; /* best guess */
+
+		wpa_msg(wpa_s, MSG_INFO, ESS_DISASSOC_IMMINENT "%d %u %s",
+			wpa_sm_pmf_enabled(wpa_s->wpa),
+			wpa_s->wnm_dissoc_timer * beacon_int * 128 / 125, url);
 	}
 
-	if (wpa_s->wnm_mode & 0x04) {
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_DISASSOC_IMMINENT) {
 		wpa_msg(wpa_s, MSG_INFO, "WNM: Disassociation Imminent - "
 			"Disassociation Timer %u", wpa_s->wnm_dissoc_timer);
 		if (wpa_s->wnm_dissoc_timer && !wpa_s->scanning) {
@@ -637,7 +648,7 @@
 		}
 	}
 
-	if (wpa_s->wnm_mode & 0x01) {
+	if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED) {
 		wpa_msg(wpa_s, MSG_INFO, "WNM: Preferred List Available");
 		wpa_s->wnm_num_neighbor_report = 0;
 		os_free(wpa_s->wnm_neighbor_report_elements);
@@ -671,12 +682,16 @@
 		wpa_s->scan_res_handler = wnm_scan_response;
 		wpa_supplicant_req_scan(wpa_s, 0, 0);
 	} else if (reply) {
-		wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management "
-			"Request Mode is zero");
+		enum bss_trans_mgmt_status_code status;
+		if (wpa_s->wnm_mode & WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT)
+			status = WNM_BSS_TM_ACCEPT;
+		else {
+			wpa_msg(wpa_s, MSG_INFO, "WNM: BSS Transition Management Request did not include candidates");
+			status = WNM_BSS_TM_REJECT_UNSPECIFIED;
+		}
 		wnm_send_bss_transition_mgmt_resp(wpa_s,
 						  wpa_s->wnm_dialog_token,
-						  1 /* Reject - unspecified */,
-						  0, NULL);
+						  status, 0, NULL);
 	}
 }
 
diff --git a/wpa_supplicant/wpa_cli.c b/wpa_supplicant/wpa_cli.c
index 966ee83..20cd45e 100644
--- a/wpa_supplicant/wpa_cli.c
+++ b/wpa_supplicant/wpa_cli.c
@@ -1,6 +1,6 @@
 /*
  * WPA Supplicant - command line interface for wpa_supplicant daemon
- * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
  *
  * This software may be distributed under the terms of the BSD license.
  * See README for more details.
@@ -81,6 +81,7 @@
 static const char *action_file = NULL;
 static int ping_interval = 5;
 static int interactive = 0;
+static char *ifname_prefix = NULL;
 #if defined(CONFIG_P2P) && defined(ANDROID_P2P)
 static char* redirect_interface = NULL;
 #endif
@@ -93,6 +94,7 @@
 static DEFINE_DL_LIST(bsses); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_peers); /* struct cli_txt_entry */
 static DEFINE_DL_LIST(p2p_groups); /* struct cli_txt_entry */
+static DEFINE_DL_LIST(ifnames); /* struct cli_txt_entry */
 
 
 static void print_help(const char *cmd);
@@ -1650,6 +1652,12 @@
 		printf("Not connected to hostapd - command dropped.\n");
 		return -1;
 	}
+	if (ifname_prefix) {
+		os_snprintf(buf, sizeof(buf), "IFNAME=%s %s",
+			    ifname_prefix, cmd);
+		buf[sizeof(buf) - 1] = '\0';
+		cmd = buf;
+	}
 	len = sizeof(buf) - 1;
 	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len,
 			       wpa_cli_msg_cb);
@@ -2874,9 +2882,12 @@
 {
 	char **res;
 	int i, count;
+	struct cli_txt_entry *e;
 
 	count = sizeof(wpa_cli_commands) / sizeof(wpa_cli_commands[0]);
-	res = os_calloc(count, sizeof(char *));
+	count += dl_list_len(&p2p_groups);
+	count += dl_list_len(&ifnames);
+	res = os_calloc(count + 1, sizeof(char *));
 	if (res == NULL)
 		return NULL;
 
@@ -2886,6 +2897,22 @@
 			break;
 	}
 
+	dl_list_for_each(e, &p2p_groups, struct cli_txt_entry, list) {
+		size_t len = 8 + os_strlen(e->txt);
+		res[i] = os_malloc(len);
+		if (res[i] == NULL)
+			break;
+		os_snprintf(res[i], len, "ifname=%s", e->txt);
+		i++;
+	}
+
+	dl_list_for_each(e, &ifnames, struct cli_txt_entry, list) {
+		res[i] = os_strdup(e->txt);
+		if (res[i] == NULL)
+			break;
+		i++;
+	}
+
 	return res;
 }
 
@@ -2917,6 +2944,14 @@
 	const char *end;
 	char *cmd;
 
+	if (pos > 7 && os_strncasecmp(str, "IFNAME=", 7) == 0) {
+		end = os_strchr(str, ' ');
+		if (end && pos > end - str) {
+			pos -= end - str + 1;
+			str = end + 1;
+		}
+	}
+
 	end = os_strchr(str, ' ');
 	if (end == NULL || str + pos < end)
 		return wpa_list_cmd_list();
@@ -2938,6 +2973,16 @@
 	int count;
 	int ret = 0;
 
+	if (argc > 1 && os_strncasecmp(argv[0], "IFNAME=", 7) == 0) {
+		ifname_prefix = argv[0] + 7;
+		argv = &argv[1];
+		argc--;
+	} else
+		ifname_prefix = NULL;
+
+	if (argc == 0)
+		return -1;
+
 	count = 0;
 	cmd = wpa_cli_commands;
 	while (cmd->cmd) {
@@ -3092,6 +3137,8 @@
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
 	} else if (str_match(pos, AP_STA_DISCONNECTED)) {
 		wpa_cli_exec(action_file, ctrl_ifname, pos);
+	} else if (str_match(pos, ESS_DISASSOC_IMMINENT)) {
+		wpa_cli_exec(action_file, ctrl_ifname, pos);
 	} else if (str_match(pos, WPA_EVENT_TERMINATING)) {
 		printf("wpa_supplicant is terminating - stop monitoring\n");
 		wpa_cli_quit = 1;
@@ -3384,6 +3431,38 @@
 }
 
 
+static void update_ifnames(struct wpa_ctrl *ctrl)
+{
+	char buf[4096];
+	size_t len = sizeof(buf);
+	int ret;
+	char *cmd = "INTERFACES";
+	char *pos, *end;
+	char txt[200];
+
+	cli_txt_list_flush(&ifnames);
+
+	if (ctrl == NULL)
+		return;
+	ret = wpa_ctrl_request(ctrl, cmd, os_strlen(cmd), buf, &len, NULL);
+	if (ret < 0)
+		return;
+	buf[len] = '\0';
+
+	pos = buf;
+	while (pos) {
+		end = os_strchr(pos, '\n');
+		if (end == NULL)
+			break;
+		*end = '\0';
+		ret = os_snprintf(txt, sizeof(txt), "ifname=%s", pos);
+		if (ret > 0 && ret < (int) sizeof(txt))
+			cli_txt_list_add(&ifnames, txt);
+		pos = end + 1;
+	}
+}
+
+
 static void try_connection(void *eloop_ctx, void *timeout_ctx)
 {
 	if (ctrl_conn)
@@ -3423,6 +3502,7 @@
 	cli_txt_list_flush(&p2p_peers);
 	cli_txt_list_flush(&p2p_groups);
 	cli_txt_list_flush(&bsses);
+	cli_txt_list_flush(&ifnames);
 	if (edit_started)
 		edit_deinit(hfile, wpa_cli_edit_filter_history_cb);
 	os_free(hfile);
@@ -3625,6 +3705,7 @@
 		}
 
 		if (interactive) {
+			update_ifnames(ctrl_conn);
 			mon_conn = wpa_ctrl_open(global);
 			if (mon_conn) {
 				if (wpa_ctrl_attach(mon_conn) == 0) {
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index 58605de..27791b3 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -1824,7 +1824,8 @@
 			wpa_supplicant_cancel_sched_scan(wpa_s);
 		}
 
-		wpa_supplicant_req_scan(wpa_s, 0, 0);
+		if (wpa_supplicant_fast_associate(wpa_s) != 1)
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
 	}
 }