[PATCH V2 7/7] rnr: add reduced neighbor reporting

John Crispin john at phrozen.org
Mon Sep 21 07:46:22 EDT 2020


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

Signed-off-by: John Crispin <john at phrozen.org>
---
 hostapd/config_file.c        |   2 +
 hostapd/hostapd.conf         |   3 +
 src/ap/ap_config.h           |   1 +
 src/ap/beacon.c              |   8 +++
 src/ap/ieee802_11.c          | 136 +++++++++++++++++++++++++++++++++++
 src/ap/ieee802_11.h          |   2 +
 src/common/ieee802_11_defs.h |  14 ++++
 7 files changed, 166 insertions(+)

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 68780cb98..dd358ec0b 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4575,6 +4575,8 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 #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 {
 		wpa_printf(MSG_ERROR,
 			   "Line %d: unknown configuration item '%s'",
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 280316c0c..a5012cc9a 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -2775,6 +2775,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:
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index 3a363bc4e..8032a90b6 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -860,6 +860,7 @@ struct hostapd_bss_config {
 	 */
 	u8 mka_psk_set;
 #endif /* CONFIG_MACSEC */
+	u8 rnr_beacon;
 };
 
 /**
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index b59e34623..20939e0ea 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -477,6 +477,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 	buflen += hostapd_eid_dpp_cc_len(hapd);
 	if (hapd->iconf->multiple_bssid)
 		buflen += hostapd_eid_multiple_bssid_len(hapd);
+	if (hapd->conf->rnr_beacon)
+		buflen += hostapd_eid_reduced_neighbor_report_len(hapd, 1);
 
 	resp = os_zalloc(buflen);
 	if (resp == NULL)
@@ -635,6 +637,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 	pos = hostapd_eid_mbo(hapd, pos, (u8 *) resp + buflen - pos);
 	pos = hostapd_eid_owe_trans(hapd, pos, (u8 *) resp + buflen - pos);
 	pos = hostapd_eid_dpp_cc(hapd, pos, (u8 *) resp + buflen - pos);
+	if (hapd->conf->rnr_beacon)
+		pos = hostapd_eid_reduced_neighbor_report(hapd, pos, 1);
 
 	if (hapd->conf->vendor_elements) {
 		os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
@@ -1195,6 +1199,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	tail_len += hostapd_mbo_ie_len(hapd);
 	tail_len += hostapd_eid_owe_trans_len(hapd);
 	tail_len += hostapd_eid_dpp_cc_len(hapd);
+	if (hapd->conf->rnr_beacon)
+		tail_len += hostapd_eid_reduced_neighbor_report_len(hapd, 0);
 
 	tailpos = tail = os_malloc(tail_len);
 	if (head == NULL || tail == NULL) {
@@ -1370,6 +1376,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	tailpos = hostapd_eid_owe_trans(hapd, tailpos,
 					tail + tail_len - tailpos);
 	tailpos = hostapd_eid_dpp_cc(hapd, tailpos, tail + tail_len - tailpos);
+	if (hapd->conf->rnr_beacon)
+		tailpos = hostapd_eid_reduced_neighbor_report(hapd, tailpos, 1);
 
 	if (hapd->conf->vendor_elements) {
 		os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 4d925b412..cb76d8e82 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -5745,4 +5745,140 @@ u8 * hostapd_eid_multiple_bssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
 	return eid;
 }
 
+
+size_t hostapd_eid_reduced_neighbor_report_len(struct hostapd_data *hapd, bool probe_resp)
+{
+	size_t len = 0;
+	int i;
+
+	if (hapd->iface->num_bss > 1)
+		len += TBTT_HEADER_LENGTH + ((hapd->iface->num_bss - 1) * TBTT_INFO_LENGTH);
+	for (i = 0; i < hapd->iface->interfaces->count; i++) {
+		struct hostapd_iface *iface = hapd->iface->interfaces->iface[i];
+
+		if (iface == hapd->iface || !iface->conf->he_co_locate)
+			continue;
+
+		len += TBTT_HEADER_LENGTH + (iface->num_bss * TBTT_INFO_LENGTH);
+	}
+
+	if (!probe_resp && !dl_list_empty(&hapd->nr_db))
+		len += dl_list_len(&hapd->nr_db) * (TBTT_HEADER_LENGTH + TBTT_INFO_LENGTH);
+
+	return len;
+}
+
+
+static u8 *hostapd_eid_reduced_neighbor_report_iface(struct hostapd_data *hapd, u8 *eid, int *count)
+{
+	int tbtt_count = hapd->iface->num_bss;
+	u8 op_class, channel;
+	int i;
+
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) ||
+	    !hapd->iface->freq)
+		return eid;
+
+	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)
+		return eid;
+
+	if (hapd->iface->conf->he_co_locate)
+		tbtt_count -= 1;
+	else
+		tbtt_count -= 2;
+
+	*eid++ = TBTT_INFO_COUNT(tbtt_count);
+	*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 && !hapd->iface->conf->he_co_locate)
+			continue;
+		*eid++ = TBTT_AP_OFFSET_UNKNOWN;
+		os_memcpy(eid, hapd->iface->bss[i]->own_addr, 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;
+		if (!i && hapd->iconf->multiple_bssid && hapd->iface->conf->he_co_locate)
+			bss_param |= TBTT_BSS_PARAM_TRANSMITTED_BSSID;
+		if (hapd->iface->conf->he_co_locate)
+			bss_param |= TBTT_BSS_PARAM_CO_LOCATED;
+
+		*eid++ = bss_param;
+		*count += 1;
+	}
+
+	return eid;
+}
+
+
+static u8 *hostapd_eid_reduced_neighbor_report_nr_db(struct hostapd_data *hapd, u8 *eid, int *count)
+{
+        struct hostapd_neighbor_entry *nr;
+
+	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 += 1;
+	}
+
+	return eid;
+}
+
+u8 * hostapd_eid_reduced_neighbor_report(struct hostapd_data *hapd, u8 *eid, bool probe_resp)
+{
+	size_t len = hostapd_eid_reduced_neighbor_report_len(hapd, probe_resp);
+	int i, count = 0;
+
+	if (!len)
+		return eid;
+
+	*eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
+	*eid++ = len;
+
+	if (hapd->iface->num_bss > 1)
+		eid = hostapd_eid_reduced_neighbor_report_iface(hapd, eid, &count);
+
+	for (i = 0; i < hapd->iface->interfaces->count; i++) {
+		struct hostapd_iface *iface = hapd->iface->interfaces->iface[i];
+
+		if (iface == hapd->iface || !iface->conf->he_co_locate)
+			continue;
+
+		eid = hostapd_eid_reduced_neighbor_report_iface(iface->bss[0], eid, &count);
+	}
+
+	if (!probe_resp)
+		hostapd_eid_reduced_neighbor_report_nr_db(hapd, eid, &count);
+
+	if (!count)
+		eid -= 2;
+
+	return eid;
+}
+
 #endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 17b4cfe39..66e90d8b4 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -124,6 +124,8 @@ u8 * hostapd_eid_multiple_bssid(struct hostapd_data *hapd, u8 *eid, u8 *end,
 				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, bool probe_resp);
+size_t hostapd_eid_reduced_neighbor_report_len(struct hostapd_data *hapd, bool probe_resp);
 
 int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
 #ifdef CONFIG_SAE
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 6c0eef885..e00186142 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -2352,4 +2352,18 @@ enum edmg_bw_config {
  */
 #define DOT11BSS_COLOR_COLLISION_AP_PERIOD	50
 
+/* 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_MEMBER_CO_LOCATED_ESS	BIT(4)
+#define TBTT_BSS_PARAM_20_TU_PROBE_RESP_ACTIVE	BIT(5)
+#define TBTT_BSS_PARAM_CO_LOCATED		BIT(6)
+
 #endif /* IEEE802_11_DEFS_H */
-- 
2.25.1




More information about the Hostap mailing list