Cumulative patch from commit 5bb7327a697108c880dd31c9e421df386c904b1a

5bb7327 Share a common helper function for restarting sched_scan
be7ebd8 wpa_supplicant: Cancel sched_scan on SELECT_NETWORK initiated scan
8b7c5b8 QCA vendor command for antenna diversity feature
61bcc85 Update ChangeLog files for v2.6
64c92c0 MBO: Do not parse reason_detail in non_pref_chan attr (AP)
4a83d4b MBO: Do not add reason_detail in non_pref_chan attr (STA)
a483c6f WNM: Add testing option to reject BSS Transition Management Request
2800ec8 MBO: Add QCA vendor option to configure driver to ignore assoc disallow
6ad37d7 MBO: Add support to ignore association disallowed set by AP
320caea Add attributes for QCA_NL80211_VENDOR_SUBCMD_LL_STATS_EXT
0df12cb IEEE P802.11ah/D10.0 PV1 CCMP test vectors
02adead Add ignore_auth_resp control interface debug parameter
ef24ad3 nl80211: Remove unnecessary duplication from nl80211_set_param()
4d584d8 nl80211: Add driver parameter force_bss_selection
04e3d81 Blacklist correct BSSID on authentication timeout
dc2744f P2P: Fix common frequencies calculation for a group
5cdd729 P2P: Fix compilation warning in p2p_supplicant.c
14220fe Flush the BSS (scan) entries when an interface becomes disabled
b223b55 doc: Remove duplicate description for -t
cee0be7 Show mode=mesh in STATUS command
0d7eba5 Define a QCA vendor command to validate encryption engine
4428194 taxonomy: Store Probe Request frames in hostapd_sta_info
04059ab Passive Client Taxonomy
5e99339 Initialize iface->sta_seen on allocation
4424aa5 P2P: Fix D-Bus persistent parameter in group started event on GO
81258ef Remove unused generation of Request Authenticator in Account-Request
ea19b39 Revert "nl80211: Remove duplicated check in nl80211_setup_ap()"
205d2d1 Fix typos in wpa_supplicant configuration parameter documentation
660103e nl80211: Use the monitor interface only without device_ap_sme support
c7f9d44 FST: Fix search for peer's "other" connection
a62dea4 Fix mistakes in definition of QCA vendor commands for indoor location
711e3ca Handle NULL return from os_zalloc() in sta_track_add()

Test: manual

Change-Id: I1d8bd5d084c3e72594004d10ceb254a2f766dfab
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/fst/fst_group.c b/src/fst/fst_group.c
index d6157b1..321d40d 100644
--- a/src/fst/fst_group.c
+++ b/src/fst/fst_group.c
@@ -196,44 +196,35 @@
 }
 
 
-static struct fst_iface *
-fst_group_get_new_iface_by_mbie_and_band_id(struct fst_group *g,
-					    const u8 *mb_ies_buff,
-					    size_t mb_ies_size,
-					    u8 band_id,
-					    u8 *iface_peer_addr)
+static const u8 * fst_mbie_get_peer_addr_for_band(const struct wpabuf *mbies,
+						  u8 band_id)
 {
-	while (mb_ies_size >= 2) {
+	const u8 *p = wpabuf_head(mbies);
+	size_t s = wpabuf_len(mbies);
+
+	while (s >= 2) {
 		const struct multi_band_ie *mbie =
-			(const struct multi_band_ie *) mb_ies_buff;
+			(const struct multi_band_ie *) p;
 
-		if (mbie->eid != WLAN_EID_MULTI_BAND ||
-		    (size_t) 2 + mbie->len < sizeof(*mbie))
-			break;
-
-		if (mbie->band_id == band_id) {
-			struct fst_iface *iface;
-
-			foreach_fst_group_iface(g, iface) {
-				const u8 *peer_addr =
-					fst_mbie_get_peer_addr(mbie);
-
-				if (peer_addr &&
-				    fst_iface_is_connected(iface, peer_addr,
-							   FALSE) &&
-				    band_id == fst_iface_get_band_id(iface)) {
-					os_memcpy(iface_peer_addr, peer_addr,
-						  ETH_ALEN);
-					return iface;
-				}
-			}
-			break;
+		if (mbie->eid != WLAN_EID_MULTI_BAND) {
+			fst_printf(MSG_INFO, "unexpected eid %d", mbie->eid);
+			return NULL;
 		}
 
-		mb_ies_buff += 2 + mbie->len;
-		mb_ies_size -= 2 + mbie->len;
+		if (mbie->len < sizeof(*mbie) - 2 || mbie->len > s - 2) {
+			fst_printf(MSG_INFO, "invalid mbie len %d",
+				   mbie->len);
+			return NULL;
+		}
+
+		if (mbie->band_id == band_id)
+			return fst_mbie_get_peer_addr(mbie);
+
+		p += 2 + mbie->len;
+		s -= 2 + mbie->len;
 	}
 
+	fst_printf(MSG_INFO, "mbie doesn't contain band %d", band_id);
 	return NULL;
 }
 
@@ -270,78 +261,172 @@
 }
 
 
-static Boolean
-fst_group_does_iface_appear_in_other_mbies(struct fst_group *g,
-					   struct fst_iface *iface,
-					   struct fst_iface *other,
-					   u8 *peer_addr)
+/**
+ * fst_group_get_peer_other_connection_1 - Find peer's "other" connection
+ * (iface, MAC tuple) by using peer's MB IE on iface.
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ *   "other" iface)
+ *
+ * This function parses peer's MB IE on iface. It looks for peer's MAC address
+ * on band_id (tmp_peer_addr). Next all interfaces are iterated to find an
+ * interface which correlates with band_id. If such interface is found, peer
+ * database is iterated to see if tmp_peer_addr is connected over it.
+ */
+static struct fst_iface *
+fst_group_get_peer_other_connection_1(struct fst_iface *iface,
+				      const u8 *peer_addr, u8 band_id,
+				      u8 *other_peer_addr)
 {
-	struct fst_get_peer_ctx *ctx;
-	const u8 *addr;
-	const u8 *iface_addr;
-	enum mb_band_id  iface_band_id;
+	const struct wpabuf *mbies;
+	struct fst_iface *other_iface;
+	const u8 *tmp_peer_addr;
 
-	WPA_ASSERT(g == fst_iface_get_group(iface));
-	WPA_ASSERT(g == fst_iface_get_group(other));
+	/* Get peer's MB IEs on iface */
+	mbies = fst_iface_get_peer_mb_ie(iface, peer_addr);
+	if (!mbies)
+		return NULL;
 
-	iface_addr = fst_iface_get_addr(iface);
-	iface_band_id = fst_iface_get_band_id(iface);
+	/* Get peer's MAC address on the "other" interface */
+	tmp_peer_addr = fst_mbie_get_peer_addr_for_band(mbies, band_id);
+	if (!tmp_peer_addr) {
+		fst_printf(MSG_INFO,
+			   "couldn't extract other peer addr from mbies");
+		return NULL;
+	}
 
-	addr = fst_iface_get_peer_first(other, &ctx, TRUE);
-	for (; addr; addr = fst_iface_get_peer_next(other, &ctx, TRUE)) {
-		const struct wpabuf *mbies;
-		u8 other_iface_peer_addr[ETH_ALEN];
-		struct fst_iface *other_new_iface;
+	fst_printf(MSG_DEBUG, "found other peer addr from mbies: " MACSTR,
+		   MAC2STR(tmp_peer_addr));
 
-		mbies = fst_iface_get_peer_mb_ie(other, addr);
-		if (!mbies)
+	foreach_fst_group_iface(fst_iface_get_group(iface), other_iface) {
+		if (other_iface == iface ||
+		    band_id != fst_iface_get_band_id(other_iface))
 			continue;
-
-		other_new_iface = fst_group_get_new_iface_by_mbie_and_band_id(
-			g, wpabuf_head(mbies), wpabuf_len(mbies),
-			iface_band_id, other_iface_peer_addr);
-		if (other_new_iface == iface &&
-		    os_memcmp(iface_addr, other_iface_peer_addr,
-			      ETH_ALEN) != 0) {
-			os_memcpy(peer_addr, addr, ETH_ALEN);
-			return TRUE;
+		if (fst_iface_is_connected(other_iface, tmp_peer_addr, FALSE)) {
+			os_memcpy(other_peer_addr, tmp_peer_addr, ETH_ALEN);
+			return other_iface;
 		}
 	}
 
-	return FALSE;
-}
-
-
-struct fst_iface *
-fst_group_find_new_iface_by_stie(struct fst_group *g,
-				 struct fst_iface *iface,
-				 const u8 *peer_addr,
-				 const struct session_transition_ie *stie,
-				 u8 *iface_peer_addr)
-{
-	struct fst_iface *i;
-
-	foreach_fst_group_iface(g, i) {
-		if (i == iface ||
-		    stie->new_band_id != fst_iface_get_band_id(i))
-			continue;
-		if (fst_group_does_iface_appear_in_other_mbies(g, iface, i,
-			iface_peer_addr))
-			return i;
-		break;
-	}
 	return NULL;
 }
 
 
-struct fst_iface *
-fst_group_get_new_iface_by_stie_and_mbie(
-	struct fst_group *g, const u8 *mb_ies_buff, size_t mb_ies_size,
-	const struct session_transition_ie *stie, u8 *iface_peer_addr)
+/**
+ * fst_group_get_peer_other_connection_2 - Find peer's "other" connection
+ * (iface, MAC tuple) by using MB IEs of other peers.
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ *   "other" iface)
+ *
+ * This function iterates all connection (other_iface, cur_peer_addr tuples).
+ * For each connection, MB IE (of cur_peer_addr on other_iface) is parsed and
+ * MAC address on iface's band_id is extracted (this_peer_addr).
+ * this_peer_addr is then compared to peer_addr. A match indicates we have
+ * found the "other" connection.
+ */
+static struct fst_iface *
+fst_group_get_peer_other_connection_2(struct fst_iface *iface,
+				      const u8 *peer_addr, u8 band_id,
+				      u8 *other_peer_addr)
 {
-	return fst_group_get_new_iface_by_mbie_and_band_id(
-		g, mb_ies_buff, mb_ies_size, stie->new_band_id,
-		iface_peer_addr);
+	u8 this_band_id = fst_iface_get_band_id(iface);
+	const u8 *cur_peer_addr, *this_peer_addr;
+	struct fst_get_peer_ctx *ctx;
+	struct fst_iface *other_iface;
+	const struct wpabuf *cur_mbie;
+
+	foreach_fst_group_iface(fst_iface_get_group(iface), other_iface) {
+		if (other_iface == iface ||
+		    band_id != fst_iface_get_band_id(other_iface))
+			continue;
+		cur_peer_addr = fst_iface_get_peer_first(other_iface, &ctx,
+							 TRUE);
+		for (; cur_peer_addr;
+		     cur_peer_addr = fst_iface_get_peer_next(other_iface, &ctx,
+							     TRUE)) {
+			cur_mbie = fst_iface_get_peer_mb_ie(other_iface,
+							    cur_peer_addr);
+			if (!cur_mbie)
+				continue;
+			this_peer_addr = fst_mbie_get_peer_addr_for_band(
+				cur_mbie, this_band_id);
+			if (!this_peer_addr)
+				continue;
+			if (os_memcmp(this_peer_addr, peer_addr, ETH_ALEN) ==
+			    0) {
+				os_memcpy(other_peer_addr, cur_peer_addr,
+					  ETH_ALEN);
+				return other_iface;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+
+/**
+ * fst_group_get_peer_other_connection - Find peer's "other" connection (iface,
+ * MAC tuple).
+ *
+ * @iface: iface on which FST Setup Request was received
+ * @peer_addr: Peer address on iface
+ * @band_id: "other" connection band id
+ * @other_peer_addr (out): Peer's MAC address on the "other" connection (on the
+ *   "other" iface)
+ *
+ * This function is called upon receiving FST Setup Request from some peer who
+ * has peer_addr on iface. It searches for another connection of the same peer
+ * on different interface which correlates with band_id. MB IEs received from
+ * peer (on the two different interfaces) are used to identify same peer.
+ */
+struct fst_iface *
+fst_group_get_peer_other_connection(struct fst_iface *iface,
+				    const u8 *peer_addr, u8 band_id,
+				    u8 *other_peer_addr)
+{
+	struct fst_iface *other_iface;
+
+	fst_printf(MSG_DEBUG, "%s: %s:" MACSTR ", %d", __func__,
+		   fst_iface_get_name(iface), MAC2STR(peer_addr), band_id);
+
+	/*
+	 * Two search methods are used:
+	 * 1. Use peer's MB IE on iface to extract peer's MAC address on
+	 *    "other" connection. Then check if such "other" connection exists.
+	 * 2. Iterate peer database, examine each MB IE to see if it points to
+	 *    (iface, peer_addr) tuple
+	 */
+
+	other_iface = fst_group_get_peer_other_connection_1(iface, peer_addr,
+							    band_id,
+							    other_peer_addr);
+	if (other_iface) {
+		fst_printf(MSG_DEBUG, "found by method #1. %s:" MACSTR,
+			   fst_iface_get_name(other_iface),
+			   MAC2STR(other_peer_addr));
+		return other_iface;
+	}
+
+	other_iface = fst_group_get_peer_other_connection_2(iface, peer_addr,
+							    band_id,
+							    other_peer_addr);
+	if (other_iface) {
+		fst_printf(MSG_DEBUG, "found by method #2. %s:" MACSTR,
+			   fst_iface_get_name(other_iface),
+			   MAC2STR(other_peer_addr));
+		return other_iface;
+	}
+
+	fst_printf(MSG_INFO, "%s: other connection not found", __func__);
+	return NULL;
 }