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/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);