diff mbox series

[V3,7/7] rnr: add reduced neighbor reporting

Message ID 20200921115102.5643-7-john@phrozen.org
State Changes Requested
Headers show
Series [V3,1/7] co-located: add a config option to indicate co locate | expand

Commit Message

John Crispin Sept. 21, 2020, 11:51 a.m. UTC
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@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(+)

Comments

Aloka Dixit Sept. 21, 2020, 9:54 p.m. UTC | #1
On 2020-09-21 04:51, John Crispin wrote:
> 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@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(+)
> 
> @@ -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);
> 

Should the last input parameter 'bool probe_resp' be 0 instead of 1 when 
called during beacon template generation?
Jouni Malinen Dec. 1, 2020, 10:03 p.m. UTC | #2
On Mon, Sep 21, 2020 at 01:51:02PM +0200, John Crispin wrote:
> The Reduced Neighbor Report (rnr) element contains channel and other
> information related to neighbor APs. It is part of the OCE requirement.

> diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
> @@ -2775,6 +2775,9 @@ own_ip_addr=127.0.0.1
> +# Enable reduced neighbour reporting (RNR)
> +#rnr_beacon=0

It would be helpful to provide some more detail on when this should be
enabled and whether it is enabled on all the radios of a co-located AP
with 2.4/5/6 GHz radios. Similarly to the other hostapd.conf change, it
would be good to explicitly document to possible values and their
meaning.

Is rnr_beacon appropriate name for this parameter? The change in
hostapd_gen_probe_resp() seems to imply that this would not be limited
to Beacon frames.

> diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
> +	u8 rnr_beacon;

If this is a boolean parameter, it would likely make more sense to use
bool instead of u8 now that hostap.git has started using bool in new
changes.

> diff --git 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,
> +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;

Is there any risk of len being too large to fit into an information
element? If so, this design would not seem to work without support for
dropping out some extra entries or supporting fragmentation of the IEs.


PS.

I dropped the full patchset from my queue now since the couple of
patches for which I did not have a comment do not make much sense on
their own without this last patch and/or would depend on the other
patches for which there are open comments.
diff mbox series

Patch

diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index eb7d9ff78..b55487a27 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -4577,6 +4577,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 e54e1bcd2..70d7d43e0 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 */