merge in KFS78N (no-op)
diff --git a/src/p2p/p2p_go_neg.c b/src/p2p/p2p_go_neg.c
index 8740ed5..17fb329 100644
--- a/src/p2p/p2p_go_neg.c
+++ b/src/p2p/p2p_go_neg.c
@@ -416,6 +416,27 @@
 		}
 	}
 
+	/* Prefer a 5 GHz channel */
+	for (i = 0; i < intersection->reg_classes; i++) {
+		struct p2p_reg_class *c = &intersection->reg_class[i];
+		if ((c->reg_class == 115 || c->reg_class == 124) &&
+		    c->channels) {
+			unsigned int r;
+
+			/*
+			 * Pick one of the available channels in the operating
+			 * class at random.
+			 */
+			os_get_random((u8 *) &r, sizeof(r));
+			r %= c->channels;
+			p2p_dbg(p2p, "Pick possible 5 GHz channel (op_class %u channel %u) from intersection",
+				c->reg_class, c->channel[r]);
+			p2p->op_reg_class = c->reg_class;
+			p2p->op_channel = c->channel[r];
+			return;
+		}
+	}
+
 	/*
 	 * Try to see if the original channel is in the intersection. If
 	 * so, no need to change anything, as it already contains some
diff --git a/src/p2p/p2p_utils.c b/src/p2p/p2p_utils.c
index a34c8de..0769ede 100644
--- a/src/p2p/p2p_utils.c
+++ b/src/p2p/p2p_utils.c
@@ -250,7 +250,6 @@
 
 #ifdef ANDROID_P2P
 	if (freq >= 5170 && freq < 5745)
-
 		return 0;
 #endif
 	if (p2p_freq_to_channel(freq, &op_reg_class, &op_channel) < 0)
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index b7ca075..e911ad0 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -81,6 +81,8 @@
 static u8 * wpa_add_tdls_timeoutie(u8 *pos, u8 *ie, size_t ie_len, u32 tsecs);
 static void wpa_tdls_tpk_retry_timeout(void *eloop_ctx, void *timeout_ctx);
 static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer);
+static void wpa_tdls_disable_peer_link(struct wpa_sm *sm,
+				       struct wpa_tdls_peer *peer);
 
 
 #define TDLS_MAX_IE_LEN 80
@@ -107,6 +109,7 @@
 	} tpk;
 	int tpk_set;
 	int tpk_success;
+	int tpk_in_progress;
 
 	struct tpk_timer {
 		u8 dest[ETH_ALEN];
@@ -276,21 +279,13 @@
 
 
 static int wpa_tdls_do_teardown(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
-				u16 reason_code, int free_peer)
+				u16 reason_code)
 {
 	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);
+	ret = wpa_tdls_send_teardown(sm, peer->addr, reason_code);
+	/* disable the link after teardown was sent */
+	wpa_tdls_disable_peer_link(sm, peer);
 
 	return ret;
 }
@@ -338,7 +333,7 @@
 
 		wpa_printf(MSG_DEBUG, "TDLS: Sending Teardown Request");
 		wpa_tdls_do_teardown(sm, peer,
-				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
 	}
 }
 
@@ -616,7 +611,7 @@
 		wpa_printf(MSG_DEBUG, "TDLS: TPK lifetime expired for " MACSTR
 			   " - tear down", MAC2STR(peer->addr));
 		wpa_tdls_do_teardown(sm, peer,
-				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
 	}
 }
 
@@ -629,6 +624,7 @@
 	eloop_cancel_timeout(wpa_tdls_tpk_retry_timeout, sm, peer);
 	peer->reconfig_key = 0;
 	peer->initiator = 0;
+	peer->tpk_in_progress = 0;
 	os_free(peer->sm_tmr.buf);
 	peer->sm_tmr.buf = NULL;
 	os_free(peer->ht_capabilities);
@@ -775,7 +771,15 @@
 		return -1;
 	}
 
-	return wpa_tdls_do_teardown(sm, peer, reason_code, 0);
+	return wpa_tdls_do_teardown(sm, peer, reason_code);
+}
+
+
+static void wpa_tdls_disable_peer_link(struct wpa_sm *sm,
+				       struct wpa_tdls_peer *peer)
+{
+	wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+	wpa_tdls_peer_free(sm, peer);
 }
 
 
@@ -788,10 +792,8 @@
 			break;
 	}
 
-	if (peer) {
-		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, addr);
-		wpa_tdls_peer_free(sm, peer);
-	}
+	if (peer)
+		wpa_tdls_disable_peer_link(sm, peer);
 }
 
 
@@ -864,11 +866,7 @@
 	 * Request the driver to disable the direct link and clear associated
 	 * keys.
 	 */
-	wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
-
-	/* clear the Peerkey statemachine */
-	wpa_tdls_peer_free(sm, peer);
-
+	wpa_tdls_disable_peer_link(sm, peer);
 	return 0;
 }
 
@@ -1483,19 +1481,7 @@
 			wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
 				   "direct link is enabled - tear down the "
 				   "old link first");
-#if 0
-			/* TODO: Disabling the link would be more proper
-			 * operation here, but it seems to trigger a race with
-			 * some drivers handling the new request frame. */
-			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, src_addr);
-#else
-			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);
+			wpa_tdls_disable_peer_link(sm, peer);
 		}
 
 		/*
@@ -1516,12 +1502,7 @@
 					   MACSTR " (terminate previously "
 					   "initiated negotiation",
 					   MAC2STR(src_addr));
-				if (sm->tdls_external_setup)
-					wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
-							 src_addr);
-				else
-					wpa_tdls_del_key(sm, peer);
-				wpa_tdls_peer_free(sm, peer);
+				wpa_tdls_disable_peer_link(sm, peer);
 			}
 		}
 	}
@@ -1683,16 +1664,27 @@
 	}
 
 	ftie = (struct wpa_tdls_ftie *) kde.ftie;
-	os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
 	os_memcpy(peer->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
 	peer->rsnie_i_len = kde.rsn_ie_len;
 	peer->cipher = cipher;
 
-	if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
-		wpa_msg(sm->ctx->ctx, MSG_WARNING,
-			"TDLS: Failed to get random data for responder nonce");
-		wpa_tdls_peer_free(sm, peer);
-		goto error;
+	if (os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) != 0) {
+		/*
+		 * There is no point in updating the RNonce for every obtained
+		 * TPK M1 frame (e.g., retransmission due to timeout) with the
+		 * same INonce (SNonce in FTIE). However, if the TPK M1 is
+		 * retransmitted with a different INonce, update the RNonce
+		 * since this is for a new TDLS session.
+		 */
+		wpa_printf(MSG_DEBUG,
+			   "TDLS: New TPK M1 INonce - generate new RNonce");
+		os_memcpy(peer->inonce, ftie->Snonce, WPA_NONCE_LEN);
+		if (os_get_random(peer->rnonce, WPA_NONCE_LEN)) {
+			wpa_msg(sm->ctx->ctx, MSG_WARNING,
+				"TDLS: Failed to get random data for responder nonce");
+			wpa_tdls_peer_free(sm, peer);
+			goto error;
+		}
 	}
 
 #if 0
@@ -1748,10 +1740,11 @@
 	/* add the peer to the driver as a "setup in progress" peer */
 	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
 				NULL, 0);
+	peer->tpk_in_progress = 1;
 
 	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Response / TPK M2");
 	if (wpa_tdls_send_tpk_m2(sm, src_addr, dtoken, lnkid, peer) < 0) {
-		wpa_tdls_disable_link(sm, peer->addr);
+		wpa_tdls_disable_peer_link(sm, peer);
 		goto error;
 	}
 
@@ -1767,6 +1760,7 @@
 static int wpa_tdls_enable_link(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
 {
 	peer->tpk_success = 1;
+	peer->tpk_in_progress = 0;
 	eloop_cancel_timeout(wpa_tdls_tpk_timeout, sm, peer);
 	if (wpa_tdls_get_privacy(sm)) {
 		u32 lifetime = peer->lifetime;
@@ -1848,8 +1842,11 @@
 	}
 	wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_REQUEST);
 
-	if (len < 3 + 2 + 1)
+	if (len < 3 + 2 + 1) {
+		wpa_tdls_disable_peer_link(sm, peer);
 		return -1;
+	}
+
 	pos = buf;
 	pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
 	status = WPA_GET_LE16(pos);
@@ -1858,8 +1855,7 @@
 	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);
+		wpa_tdls_disable_peer_link(sm, peer);
 		return -1;
 	}
 
@@ -1870,8 +1866,10 @@
 
 	wpa_printf(MSG_DEBUG, "TDLS: Dialog Token in TPK M2 %d", dtoken);
 
-	if (len < 3 + 2 + 1 + 2)
+	if (len < 3 + 2 + 1 + 2) {
+		wpa_tdls_disable_peer_link(sm, peer);
 		return -1;
+	}
 
 	/* capability information */
 	peer->capability = WPA_GET_LE16(pos);
@@ -2012,9 +2010,7 @@
 					   (u8 *) timeoutie, ftie) < 0) {
 		/* 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);
+		wpa_tdls_disable_peer_link(sm, peer);
 		return -1;
 	}
 
@@ -2034,7 +2030,7 @@
 	wpa_printf(MSG_DEBUG, "TDLS: Sending TDLS Setup Confirm / "
 		   "TPK Handshake Message 3");
 	if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0) {
-		wpa_tdls_disable_link(sm, peer->addr);
+		wpa_tdls_disable_peer_link(sm, peer);
 		return -1;
 	}
 
@@ -2042,14 +2038,14 @@
 	if (ret < 0) {
 		wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
 		wpa_tdls_do_teardown(sm, peer,
-				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
 	}
 	return ret;
 
 error:
 	wpa_tdls_send_error(sm, src_addr, WLAN_TDLS_SETUP_CONFIRM, dtoken,
 			    status);
-	wpa_tdls_disable_link(sm, peer->addr);
+	wpa_tdls_disable_peer_link(sm, peer);
 	return -1;
 }
 
@@ -2082,7 +2078,7 @@
 	wpa_tdls_tpk_retry_timeout_cancel(sm, peer, WLAN_TDLS_SETUP_RESPONSE);
 
 	if (len < 3 + 3)
-		return -1;
+		goto error;
 	pos = buf;
 	pos += 1 /* pkt_type */ + 1 /* Category */ + 1 /* Action */;
 
@@ -2091,21 +2087,19 @@
 	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;
+		goto error;
 	}
 	pos += 2 /* status code */ + 1 /* dialog token */;
 
 	ielen = len - (pos - buf); /* start of IE in buf */
 	if (wpa_supplicant_parse_ies((const u8 *) pos, ielen, &kde) < 0) {
 		wpa_printf(MSG_INFO, "TDLS: Failed to parse KDEs in TPK M3");
-		return -1;
+		goto error;
 	}
 
 	if (kde.lnkid == NULL || kde.lnkid_len < 3 * ETH_ALEN) {
 		wpa_printf(MSG_INFO, "TDLS: No Link Identifier IE in TPK M3");
-		return -1;
+		goto error;
 	}
 	wpa_hexdump(MSG_DEBUG, "TDLS: Link ID Received from TPK M3",
 		    (u8 *) kde.lnkid, kde.lnkid_len);
@@ -2113,7 +2107,7 @@
 
 	if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0) {
 		wpa_printf(MSG_INFO, "TDLS: TPK M3 from diff BSS");
-		return -1;
+		goto error;
 	}
 
 	if (!wpa_tdls_get_privacy(sm))
@@ -2121,7 +2115,7 @@
 
 	if (kde.ftie == NULL || kde.ftie_len < sizeof(*ftie)) {
 		wpa_printf(MSG_INFO, "TDLS: No FTIE in TPK M3");
-		return -1;
+		goto error;
 	}
 	wpa_hexdump(MSG_DEBUG, "TDLS: FTIE Received from TPK M3",
 		    kde.ftie, sizeof(*ftie));
@@ -2129,7 +2123,7 @@
 
 	if (kde.rsn_ie == NULL) {
 		wpa_printf(MSG_INFO, "TDLS: No RSN IE in TPK M3");
-		return -1;
+		goto error;
 	}
 	wpa_hexdump(MSG_DEBUG, "TDLS: RSN IE Received from TPK M3",
 		    kde.rsn_ie, kde.rsn_ie_len);
@@ -2137,24 +2131,24 @@
 	    os_memcmp(kde.rsn_ie, peer->rsnie_p, peer->rsnie_p_len) != 0) {
 		wpa_printf(MSG_INFO, "TDLS: RSN IE in TPK M3 does not match "
 			   "with the one sent in TPK M2");
-		return -1;
+		goto error;
 	}
 
 	if (!os_memcmp(peer->rnonce, ftie->Anonce, WPA_NONCE_LEN) == 0) {
 		wpa_printf(MSG_INFO, "TDLS: FTIE ANonce in TPK M3 does "
 			   "not match with FTIE ANonce used in TPK M2");
-		return -1;
+		goto error;
 	}
 
 	if (!os_memcmp(peer->inonce, ftie->Snonce, WPA_NONCE_LEN) == 0) {
 		wpa_printf(MSG_INFO, "TDLS: FTIE SNonce in TPK M3 does not "
 			   "match with FTIE SNonce used in TPK M1");
-		return -1;
+		goto error;
 	}
 
 	if (kde.key_lifetime == NULL) {
 		wpa_printf(MSG_INFO, "TDLS: No Key Lifetime IE in TPK M3");
-		return -1;
+		goto error;
 	}
 	timeoutie = (struct wpa_tdls_timeoutie *) kde.key_lifetime;
 	wpa_hexdump(MSG_DEBUG, "TDLS: Timeout IE Received from TPK M3",
@@ -2165,16 +2159,13 @@
 	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;
+		goto error;
 	}
 
 	if (wpa_supplicant_verify_tdls_mic(3, peer, (u8 *) lnkid,
 					   (u8 *) timeoutie, ftie) < 0) {
 		wpa_tdls_del_key(sm, peer);
-		wpa_tdls_peer_free(sm, peer);
-		return -1;
+		goto error;
 	}
 
 	if (wpa_tdls_set_key(sm, peer) < 0) {
@@ -2192,9 +2183,12 @@
 	if (ret < 0) {
 		wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
 		wpa_tdls_do_teardown(sm, peer,
-				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED, 1);
+				     WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
 	}
 	return ret;
+error:
+	wpa_tdls_disable_peer_link(sm, peer);
+	return -1;
 }
 
 
@@ -2248,14 +2242,21 @@
 	if (peer == NULL)
 		return -1;
 
+	if (peer->tpk_in_progress) {
+		wpa_printf(MSG_DEBUG, "TDLS: Setup is already in progress with the peer");
+		return 0;
+	}
+
 	peer->initiator = 1;
 
 	/* add the peer to the driver as a "setup in progress" peer */
 	wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL, NULL, 0,
 				NULL, 0);
 
+	peer->tpk_in_progress = 1;
+
 	if (wpa_tdls_send_tpk_m1(sm, peer) < 0) {
-		wpa_tdls_disable_link(sm, peer->addr);
+		wpa_tdls_disable_peer_link(sm, peer);
 		return -1;
 	}
 
diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 0e1576b..67a9f97 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -343,6 +343,14 @@
 	os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
 	wpa_bss_set_hessid(bss);
 
+	if (wpa_s->num_bss + 1 > wpa_s->conf->bss_max_count &&
+	    wpa_bss_remove_oldest(wpa_s) != 0) {
+		wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
+			   "because all BSSes are in use. We should normally "
+			   "not get here!", (int) wpa_s->num_bss + 1);
+		wpa_s->conf->bss_max_count = wpa_s->num_bss + 1;
+	}
+
 	dl_list_add_tail(&wpa_s->bss, &bss->list);
 	dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
 	wpa_s->num_bss++;
@@ -350,13 +358,6 @@
 		" 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 &&
-	    wpa_bss_remove_oldest(wpa_s) != 0) {
-		wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
-			   "because all BSSes are in use. We should normally "
-			   "not get here!", (int) wpa_s->num_bss);
-		wpa_s->conf->bss_max_count = wpa_s->num_bss;
-	}
 	return bss;
 }
 
diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c
index 8736b07..af57afa 100644
--- a/wpa_supplicant/ctrl_iface.c
+++ b/wpa_supplicant/ctrl_iface.c
@@ -5150,8 +5150,19 @@
 	int ret;
 
 	ret = wpa_drv_driver_cmd(wpa_s, cmd, buf, buflen);
-	if (ret == 0)
+	if (ret == 0) {
+		if (os_strncasecmp(cmd, "COUNTRY", 7) == 0) {
+			struct p2p_data *p2p = wpa_s->global->p2p;
+			if (p2p) {
+				char country[3];
+				country[0] = cmd[8];
+				country[1] = cmd[9];
+				country[2] = 0x04;
+				p2p_set_country(p2p, country);
+			}
+		}
 		ret = sprintf(buf, "%s\n", "OK");
+	}
 	return ret;
 }
 #endif
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index 8c29b20..9de8d7f 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -2292,8 +2292,12 @@
 			wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, data->tdls.peer);
 		break;
 	case TDLS_REQUEST_TEARDOWN:
-		wpa_tdls_teardown_link(wpa_s->wpa, data->tdls.peer,
-				       data->tdls.reason_code);
+		if (wpa_tdls_is_external_setup(wpa_s->wpa))
+			wpa_tdls_teardown_link(wpa_s->wpa, data->tdls.peer,
+					       data->tdls.reason_code);
+		else
+			wpa_drv_tdls_oper(wpa_s, TDLS_TEARDOWN,
+					  data->tdls.peer);
 		break;
 	}
 }