Cumulative patch from commit ea18024d78bde140fb8f74d216d757816bfd6e9b

ea18024 dbus: Add PropertiesChanged signal to Peer object
36716ee P2P: Add a utility function to run a method on every known peer
bf03566 dbus: Remove GroupMember object type and use Peer instead
17a37d7 dbus: Add a Groups property to a Peer object on which it belongs
6f04642 P2P: Add utility functions to get GO/client interface
c6386e5 P2P Add a utility to run a callback on all available groups
8e76f48 P2P: Add a utility function to get the group configuration
37d8a27 TDLS: Clean up add/set peer operations
bcd2baa TDLS: Tear down connection on malformed Setup Confirm
8190540 TDLS: Abort local setup when failing to add STA
1dce7a2 TDLS: Update peer STA as soon as full peer info is available
819c943 TDLS: Remove peer from global peer-list on free
5841958 hostapd: Use channel switch fallback on error
8974620 hostapd: Perform multi-BSS CSA for DFS properly
ccac7c6 hostapd: Make chan_switch command per-interface not per-BSS
6782b68 hostapd: Move CSA parameters to hostapd_data
1de809e eapol_test: Fix -R option to not replace -s option value
3c5d34e Change channel before IBSS associations
ebffdbc nl80211: Refactor mode switch logic

Change-Id: I1cbdc4dce586ec69f693b3b04eb340a5332f6b40
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/rsn_supp/tdls.c b/src/rsn_supp/tdls.c
index 652e52c..cda6957 100644
--- a/src/rsn_supp/tdls.c
+++ b/src/rsn_supp/tdls.c
@@ -631,7 +631,33 @@
 }
 
 
-static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+static void wpa_tdls_peer_remove_from_list(struct wpa_sm *sm,
+					   struct wpa_tdls_peer *peer)
+{
+	struct wpa_tdls_peer *cur, *prev;
+
+	cur = sm->tdls;
+	prev = NULL;
+	while (cur && cur != peer) {
+		prev = cur;
+		cur = cur->next;
+	}
+
+	if (cur != peer) {
+		wpa_printf(MSG_ERROR, "TDLS: Could not find peer " MACSTR
+			   " to remove it from the list",
+			   MAC2STR(peer->addr));
+		return;
+	}
+
+	if (prev)
+		prev->next = peer->next;
+	else
+		sm->tdls = peer->next;
+}
+
+
+static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
 {
 	wpa_printf(MSG_DEBUG, "TDLS: Clear state for peer " MACSTR,
 		   MAC2STR(peer->addr));
@@ -663,6 +689,14 @@
 }
 
 
+static void wpa_tdls_peer_free(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
+{
+	wpa_tdls_peer_clear(sm, peer);
+	wpa_tdls_peer_remove_from_list(sm, peer);
+	os_free(peer);
+}
+
+
 static void wpa_tdls_linkid(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
 			    struct wpa_tdls_lnkid *lnkid)
 {
@@ -1597,6 +1631,23 @@
 }
 
 
+static int wpa_tdls_addset_peer(struct wpa_sm *sm, struct wpa_tdls_peer *peer,
+				int add)
+{
+	return wpa_sm_tdls_peer_addset(sm, peer->addr, add, peer->aid,
+				       peer->capability,
+				       peer->supp_rates, peer->supp_rates_len,
+				       peer->ht_capabilities,
+				       peer->vht_capabilities,
+				       peer->qos_info, peer->ext_capab,
+				       peer->ext_capab_len,
+				       peer->supp_channels,
+				       peer->supp_channels_len,
+				       peer->supp_oper_classes,
+				       peer->supp_oper_classes_len);
+}
+
+
 static int wpa_tdls_process_tpk_m1(struct wpa_sm *sm, const u8 *src_addr,
 				   const u8 *buf, size_t len)
 {
@@ -1644,16 +1695,16 @@
 			wpa_printf(MSG_DEBUG, "TDLS: TDLS Setup Request while "
 				   "direct link is enabled - tear down the "
 				   "old link first");
-			wpa_tdls_disable_peer_link(sm, peer);
-		}
-
-		/*
-		 * An entry is already present, so check if we already sent a
-		 * TDLS Setup Request. If so, compare MAC addresses and let the
-		 * STA with the lower MAC address continue as the initiator.
-		 * The other negotiation is terminated.
-		 */
-		if (peer->initiator) {
+			wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
+			wpa_tdls_peer_clear(sm, peer);
+		} else if (peer->initiator) {
+			/*
+			 * An entry is already present, so check if we already
+			 * sent a TDLS Setup Request. If so, compare MAC
+			 * addresses and let the STA with the lower MAC address
+			 * continue as the initiator. The other negotiation is
+			 * terminated.
+			 */
 			if (os_memcmp(sm->own_addr, src_addr, ETH_ALEN) < 0) {
 				wpa_printf(MSG_DEBUG, "TDLS: Discard request "
 					   "from peer with higher address "
@@ -1665,7 +1716,9 @@
 					   MACSTR " (terminate previously "
 					   "initiated negotiation",
 					   MAC2STR(src_addr));
-				wpa_tdls_disable_peer_link(sm, peer);
+				wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK,
+						 peer->addr);
+				wpa_tdls_peer_clear(sm, peer);
 			}
 		}
 	}
@@ -1909,16 +1962,15 @@
 	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 */
-	if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
-				    NULL, 0, NULL, 0, NULL, 0, NULL, 0))
+	/* add supported rates, capabilities, and qos_info to the TDLS peer */
+	if (wpa_tdls_addset_peer(sm, peer, 1) < 0)
 		goto error;
 
 	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_peer_link(sm, peer);
+		wpa_sm_tdls_oper(sm, TDLS_DISABLE_LINK, peer->addr);
 		goto error;
 	}
 
@@ -1957,20 +2009,6 @@
 #endif /* CONFIG_TDLS_TESTING */
 	}
 
-	/* add supported rates, capabilities, and qos_info to the TDLS peer */
-	if (wpa_sm_tdls_peer_addset(sm, peer->addr, 0, peer->aid,
-				    peer->capability,
-				    peer->supp_rates, peer->supp_rates_len,
-				    peer->ht_capabilities,
-				    peer->vht_capabilities,
-				    peer->qos_info, peer->ext_capab,
-				    peer->ext_capab_len,
-				    peer->supp_channels,
-				    peer->supp_channels_len,
-				    peer->supp_oper_classes,
-				    peer->supp_oper_classes_len) < 0)
-		return -1;
-
 	if (peer->reconfig_key && wpa_tdls_set_key(sm, peer) < 0) {
 		wpa_printf(MSG_INFO, "TDLS: Could not configure key to the "
 			   "driver");
@@ -2224,12 +2262,14 @@
 skip_rsn:
 	peer->dtoken = dtoken;
 
+	/* add supported rates, capabilities, and qos_info to the TDLS peer */
+	if (wpa_tdls_addset_peer(sm, peer, 0) < 0)
+		goto error;
+
 	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_peer_link(sm, peer);
-		return -1;
-	}
+	if (wpa_tdls_send_tpk_m3(sm, src_addr, dtoken, lnkid, peer) < 0)
+		goto error;
 
 	if (!peer->tpk_success) {
 		/*
@@ -2391,6 +2431,10 @@
 	}
 
 skip_rsn:
+	/* add supported rates, capabilities, and qos_info to the TDLS peer */
+	if (wpa_tdls_addset_peer(sm, peer, 0) < 0)
+		goto error;
+
 	if (!peer->tpk_success) {
 		/*
 		 * Enable Link only when tpk_success is 0, signifying that this
@@ -2400,14 +2444,12 @@
 		ret = wpa_tdls_enable_link(sm, peer);
 		if (ret < 0) {
 			wpa_printf(MSG_DEBUG, "TDLS: Could not enable link");
-			wpa_tdls_do_teardown(
-				sm, peer,
-				WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+			goto error;
 		}
 	}
 	return ret;
 error:
-	wpa_tdls_disable_peer_link(sm, peer);
+	wpa_tdls_do_teardown(sm, peer, WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
 	return -1;
 }
 
@@ -2470,8 +2512,11 @@
 	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, NULL, 0, NULL, 0);
+	if (wpa_sm_tdls_peer_addset(sm, peer->addr, 1, 0, 0, NULL, 0, NULL,
+				    NULL, 0, NULL, 0, NULL, 0, NULL, 0)) {
+		wpa_tdls_disable_peer_link(sm, peer);
+		return -1;
+	}
 
 	peer->tpk_in_progress = 1;
 
@@ -2621,13 +2666,14 @@
 
 void wpa_tdls_teardown_peers(struct wpa_sm *sm)
 {
-	struct wpa_tdls_peer *peer;
+	struct wpa_tdls_peer *peer, *tmp;
 
 	peer = sm->tdls;
 
 	wpa_printf(MSG_DEBUG, "TDLS: Tear down peers");
 
 	while (peer) {
+		tmp = peer->next;
 		wpa_printf(MSG_DEBUG, "TDLS: Tear down peer " MACSTR,
 			   MAC2STR(peer->addr));
 		if (sm->tdls_external_setup)
@@ -2636,7 +2682,7 @@
 		else
 			wpa_sm_tdls_oper(sm, TDLS_TEARDOWN, peer->addr);
 
-		peer = peer->next;
+		peer = tmp;
 	}
 }
 
@@ -2646,7 +2692,6 @@
 	struct wpa_tdls_peer *peer, *tmp;
 
 	peer = sm->tdls;
-	sm->tdls = NULL;
 
 	while (peer) {
 		int res;
@@ -2655,7 +2700,6 @@
 		wpa_printf(MSG_DEBUG, "TDLS: Remove peer " MACSTR " (res=%d)",
 			   MAC2STR(peer->addr), res);
 		wpa_tdls_peer_free(sm, peer);
-		os_free(peer);
 		peer = tmp;
 	}
 }