From 4d8eb3c7f31f66085dfb7f7652bf3b333d776896 Mon Sep 17 00:00:00 2001
From: Chung-Hsien Hsu <stanley.hsu@cypress.com>
Date: Tue, 29 Oct 2019 15:22:57 +0800
Subject: [PATCH 02/49] wpa_supplicant: Notify Neighbor Report for
 driver-triggered request

Sending a Neighbor Report request can be triggered by either supplicant
or device driver. This patch adds the notification of incoming Neighbor
Report response for the driver-triggered request.

Signed-off-by: Chung-Hsien Hsu <chung-hsien.hsu@infineon.com>
---
 wpa_supplicant/rrm.c | 100 +++++++++++++++++++++++++++++++++++--------
 1 file changed, 83 insertions(+), 17 deletions(-)

diff --git a/wpa_supplicant/rrm.c b/wpa_supplicant/rrm.c
index cf107ebaf..16e3ab318 100644
--- a/wpa_supplicant/rrm.c
+++ b/wpa_supplicant/rrm.c
@@ -52,6 +52,71 @@ void wpas_rrm_reset(struct wpa_supplicant *wpa_s)
 	wpas_clear_beacon_rep_data(wpa_s);
 }
 
+/*
+ * wpas_rrm_notify_neighbor_rep - Notify received neighbor report
+ * @wpa_s: Pointer to wpa_supplicant
+ * @neighbor_rep: Pointer to neighbor report elements
+ */
+void wpas_rrm_notify_neighbor_rep(struct wpa_supplicant *wpa_s,
+				  struct wpabuf *neighbor_rep)
+{
+	size_t len;
+	const u8 *data;
+
+	/*
+	 * Neighbor Report element (IEEE Std 802.11-2016: 9.4.2.37)
+	 * Element ID[1]
+	 * Length[1]
+	 * BSSID[6]
+	 * BSSID Information[4]
+	 * Operating Class[1]
+	 * Channel Number[1]
+	 * PHY Type[1]
+	 * Optional Subelements[variable]
+	 */
+#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
+
+	if (wpabuf_len(neighbor_rep) == 0) {
+		wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
+			"No neighbors of the associated AP");
+		goto out;
+	}
+
+	data = wpabuf_head_u8(neighbor_rep);
+	len = wpabuf_len(neighbor_rep);
+
+	while (len >= 2 + NR_IE_MIN_LEN) {
+		const u8 *nr;
+		u8 nr_len = data[1];
+		const u8 *pos = data, *end;
+
+		if ((pos[0] != WLAN_EID_NEIGHBOR_REPORT) ||
+		    (nr_len < NR_IE_MIN_LEN) ||
+		    (2U + nr_len > len)) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"RRM: Invalid Neighbor Report element: "
+				"id=%u len=%zu nr_len=%u",
+				data[0], len, nr_len);
+			goto out;
+		}
+
+		pos += 2;
+		end = pos + nr_len;
+		nr = pos;
+
+		wpa_msg(wpa_s, MSG_INFO, RRM_EVENT_NEIGHBOR_REP_RXED
+			"bssid=" MACSTR
+			" info=0x%x op_class=%u chan=%u phy_type=%u",
+			MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
+			nr[ETH_ALEN + 4], nr[ETH_ALEN + 5], nr[ETH_ALEN + 6]);
+
+		data = end;
+		len -= 2 + nr_len;
+	}
+
+out:
+	wpabuf_free(neighbor_rep);
+}
 
 /*
  * wpas_rrm_process_neighbor_rep - Handle incoming neighbor report
@@ -68,19 +133,17 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
 	if (report_len < 1)
 		return;
 
-	if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
-		wpa_printf(MSG_DEBUG,
-			   "RRM: Discarding neighbor report with token %d (expected %d)",
-			   report[0], wpa_s->rrm.next_neighbor_rep_token - 1);
-		return;
-	}
-
-	eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler, &wpa_s->rrm,
-			     NULL);
+	if (wpa_s->rrm.notify_neighbor_rep) {
+		if (report[0] != wpa_s->rrm.next_neighbor_rep_token - 1) {
+			wpa_printf(MSG_DEBUG,
+				   "RRM: Discarding neighbor report with token "
+				   "%d (expected %d)", report[0],
+				   wpa_s->rrm.next_neighbor_rep_token - 1);
+			return;
+		}
 
-	if (!wpa_s->rrm.notify_neighbor_rep) {
-		wpa_msg(wpa_s, MSG_INFO, "RRM: Unexpected neighbor report");
-		return;
+		eloop_cancel_timeout(wpas_rrm_neighbor_rep_timeout_handler,
+				     &wpa_s->rrm, NULL);
 	}
 
 	/* skipping the first byte, which is only an id (dialog token) */
@@ -92,12 +155,15 @@ void wpas_rrm_process_neighbor_rep(struct wpa_supplicant *wpa_s,
 	wpabuf_put_data(neighbor_rep, report + 1, report_len - 1);
 	wpa_dbg(wpa_s, MSG_DEBUG, "RRM: Notifying neighbor report (token = %d)",
 		report[0]);
-	wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
-				       neighbor_rep);
-	wpa_s->rrm.notify_neighbor_rep = NULL;
-	wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
-}
 
+	if (wpa_s->rrm.notify_neighbor_rep) {
+		wpa_s->rrm.notify_neighbor_rep(wpa_s->rrm.neighbor_rep_cb_ctx,
+					       neighbor_rep);
+		wpa_s->rrm.notify_neighbor_rep = NULL;
+		wpa_s->rrm.neighbor_rep_cb_ctx = NULL;
+	} else
+		wpas_rrm_notify_neighbor_rep(wpa_s, neighbor_rep);
+}
 
 #if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
 /* Workaround different, undefined for Windows, error codes used here */
-- 
2.17.1

