From: John Crispin <john@phrozen.org>
Date: Thu, 16 Jul 2020 17:31:40 -0700
Subject: [PATCH 4/4] RNR: add reduced neighbor reporting

The Reduced Neighbor Report (RNR) element contains channel and other
information related to neighbor APs. It is part of the OCE requirement.

Fix bssid field in RNR when there are multiple BSS.

Signed-off-by: John Crispin <john@phrozen.org>
Signed-off-by: Pradeep Kumar Chitrapu <pradeepc@codeaurora.org>
---
 hostapd/config_file.c        |  2 +
 hostapd/hostapd.conf         |  3 ++
 src/ap/ap_config.h           |  1 +
 src/ap/beacon.c              |  2 +
 src/ap/ieee802_11.c          | 89 ++++++++++++++++++++++++++++++++++++
 src/ap/ieee802_11.h          |  2 +
 src/common/ieee802_11_defs.h | 14 ++++++
 7 files changed, 113 insertions(+)

Index: hostapd-2021-02-18/hostapd/config_file.c
===================================================================
--- hostapd-2021-02-18.orig/hostapd/config_file.c
+++ hostapd-2021-02-18/hostapd/config_file.c
@@ -4672,6 +4672,8 @@ static int hostapd_config_fill(struct ho
 #endif /* CONFIG_MACSEC */
 	} else if (os_strcmp(buf, "multiple_bssid") == 0) {
 		conf->multiple_bssid = atoi(pos);
+	} else if (os_strcmp(buf, "rnr_beacon") == 0) {
+		bss->rnr_beacon = atoi(pos);
 	} else if (os_strcmp(buf, "disable_11n") == 0) {
 		bss->disable_11n = !!atoi(pos);
 	} else if (os_strcmp(buf, "disable_11ac") == 0) {
Index: hostapd-2021-02-18/hostapd/hostapd.conf
===================================================================
--- hostapd-2021-02-18.orig/hostapd/hostapd.conf
+++ hostapd-2021-02-18/hostapd/hostapd.conf
@@ -2885,6 +2885,9 @@ own_ip_addr=127.0.0.1
 # that allows sending of such data. Default: 0.
 #stationary_ap=0
 
+# Enable reduced neighbour reporting (RNR)
+#rnr_beacon=0
+
 ##### Airtime policy configuration ###########################################
 
 # Set the airtime policy operating mode:
Index: hostapd-2021-02-18/src/ap/ap_config.h
===================================================================
--- hostapd-2021-02-18.orig/src/ap/ap_config.h
+++ hostapd-2021-02-18/src/ap/ap_config.h
@@ -885,6 +885,7 @@ struct hostapd_bss_config {
 #endif /* CONFIG_PASN */
 
 	unsigned int unsol_bcast_probe_resp_interval;
+	u8 rnr_beacon;
 };
 
 /**
Index: hostapd-2021-02-18/src/ap/beacon.c
===================================================================
--- hostapd-2021-02-18.orig/src/ap/beacon.c
+++ hostapd-2021-02-18/src/ap/beacon.c
@@ -1467,6 +1467,7 @@ int ieee802_11_build_ap_params(struct ho
 	tail_len += hostapd_mbo_ie_len(hapd);
 	tail_len += hostapd_eid_owe_trans_len(hapd);
 	tail_len += hostapd_eid_dpp_cc_len(hapd);
+	tail_len += hostapd_eid_reduced_neighbor_report_len(hapd);
 
 	tailpos = tail = os_malloc(tail_len);
 	if (head == NULL || tail == NULL) {
@@ -1643,6 +1644,7 @@ int ieee802_11_build_ap_params(struct ho
 	tailpos = hostapd_eid_owe_trans(hapd, tailpos,
 					tail + tail_len - tailpos);
 	tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
+	tailpos = hostapd_eid_reduced_neighbor_report(hapd, tailpos);
 
 	if (hapd->conf->vendor_elements) {
 		os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
Index: hostapd-2021-02-18/src/ap/ieee802_11.c
===================================================================
--- hostapd-2021-02-18.orig/src/ap/ieee802_11.c
+++ hostapd-2021-02-18/src/ap/ieee802_11.c
@@ -7079,4 +7079,93 @@ u8 * hostapd_eid_multiple_bssid(struct h
 	return eid;
 }
 
+
+size_t hostapd_eid_reduced_neighbor_report_len(struct hostapd_data *hapd)
+{
+	size_t len = 0;
+
+	if (hapd->iface->num_bss > 1)
+		len += TBTT_HEADER_LENGTH + ((hapd->iface->num_bss - 1) * TBTT_INFO_LENGTH);
+	if (!dl_list_empty(&hapd->nr_db))
+		len += dl_list_len(&hapd->nr_db) * (TBTT_HEADER_LENGTH + TBTT_INFO_LENGTH);
+
+	return len;
+}
+
+
+u8 * hostapd_eid_reduced_neighbor_report(struct hostapd_data *hapd, u8 *eid)
+{
+	size_t len = hostapd_eid_reduced_neighbor_report_len(hapd);
+        struct hostapd_neighbor_entry *nr;
+	int i, count = 0;
+
+	if (!len)
+		return eid;
+
+	*eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
+	*eid++ = len;
+
+	if (hapd->iface->num_bss > 1) {
+		u8 op_class, channel;
+
+		if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) ||
+		    !hapd->iface->freq)
+			goto nr_db;
+
+		if (ieee80211_freq_to_channel_ext(hapd->iface->freq,
+						  hapd->iconf->secondary_channel,
+						  hostapd_get_oper_chwidth(hapd->iconf),
+						  &op_class, &channel) ==
+		    NUM_HOSTAPD_MODES)
+			goto nr_db;
+
+		*eid++ = TBTT_INFO_COUNT(hapd->iface->num_bss - 2);
+		*eid++ = TBTT_INFO_LENGTH;
+		*eid++ = op_class;
+		*eid++ = hapd->iconf->channel;
+		for (i = 0; i < hapd->iface->num_bss; i++) {
+			u8 bss_param = 0;
+
+			if (hapd->iface->bss[i] == hapd)
+				continue;
+			*eid++ = TBTT_AP_OFFSET_UNKNOWN;
+			os_memcpy(eid, hapd->iface->bss[i]->conf->bssid, ETH_ALEN);
+			eid += 6;
+			os_memcpy(eid, &hapd->iface->bss[i]->conf->ssid.short_ssid, 4);
+			eid += 4;
+			if (hapd->iface->bss[i]->conf->ssid.short_ssid ==
+			    hapd->conf->ssid.short_ssid)
+				bss_param |= TBTT_BSS_PARAM_SAME_SSID;
+			if (hapd->iconf->multiple_bssid)
+				bss_param |= TBTT_BSS_PARAM_MULTIPLE_BSSID;
+			*eid++ = bss_param;
+			count++;
+		}
+	}
+
+nr_db:
+	dl_list_for_each(nr, &hapd->nr_db, struct hostapd_neighbor_entry,
+			 list) {
+		if (!nr->nr || wpabuf_len(nr->nr) < 12)
+			continue;
+		if (nr->short_ssid == hapd->conf->ssid.short_ssid)
+			continue;
+		*eid++ = 0;
+		*eid++ = TBTT_INFO_LENGTH;
+		*eid++ = wpabuf_head_u8(nr->nr)[10];
+		*eid++ = wpabuf_head_u8(nr->nr)[11];
+		*eid++ = TBTT_AP_OFFSET_UNKNOWN;
+		os_memcpy(eid, nr->bssid, ETH_ALEN);
+		eid += 6;
+		os_memcpy(eid, &nr->short_ssid, 4);
+		eid += 4;
+		*eid++ = nr->bss_parameters;
+		count++;
+	}
+
+	if (!count)
+		eid -= 2;
+	return eid;
+}
+
 #endif /* CONFIG_NATIVE_WINDOWS */
Index: hostapd-2021-02-18/src/ap/ieee802_11.h
===================================================================
--- hostapd-2021-02-18.orig/src/ap/ieee802_11.h
+++ hostapd-2021-02-18/src/ap/ieee802_11.h
@@ -123,6 +123,8 @@ u8 * hostapd_eid_multiple_bssid(struct h
 				u8 is_beacon, u8 **eid_offsets, int *eid_count,
 				int eid_max);
 int hostapd_eid_multiple_bssid_len(struct hostapd_data *hapd);
+u8 * hostapd_eid_reduced_neighbor_report(struct hostapd_data *hapd, u8 *eid);
+size_t hostapd_eid_reduced_neighbor_report_len(struct hostapd_data *hapd);
 int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
 #ifdef CONFIG_SAE
 void sae_clear_retransmit_timer(struct hostapd_data *hapd,
Index: hostapd-2021-02-18/src/common/ieee802_11_defs.h
===================================================================
--- hostapd-2021-02-18.orig/src/common/ieee802_11_defs.h
+++ hostapd-2021-02-18/src/common/ieee802_11_defs.h
@@ -2437,4 +2437,17 @@ enum mscs_description_subelem {
  */
 #define FD_MAX_INTERVAL_6GHZ                  20 /* TUs */
 
+/* TBTT Information field defines */
+#define TBTT_HEADER_LENGTH			4
+#define TBTT_INFO_LENGTH			12
+#define TBTT_INFO_FILTERED_NEIGH_AP		BIT(2)
+#define TBTT_INFO_COUNT(x)			(((x) & 0xf) << 4)
+#define TBTT_AP_OFFSET_UNKNOWN			255
+#define TBTT_BSS_PARAM_OCT_RECOMMENDED		BIT(0)
+#define TBTT_BSS_PARAM_SAME_SSID		BIT(1)
+#define TBTT_BSS_PARAM_MULTIPLE_BSSID		BIT(2)
+#define TBTT_BSS_PARAM_TRANSMITTED_BSSID	BIT(3)
+#define TBTT_BSS_PARAM_CO_LOCATED_ESS		BIT(4)
+#define TBTT_BSS_PARAM_20_TU_PROBE_RESP_ACTIVE	BIT(5)
+
 #endif /* IEEE802_11_DEFS_H */
