diff --git a/hostapd/Makefile b/hostapd/Makefile
index a8d77fed36..fbf0ee8535 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -157,6 +157,7 @@ OBJS_c += ../src/utils/wpa_debug.o
 OBJS += ../src/utils/wpabuf.o
 OBJS += ../src/utils/os_$(CONFIG_OS).o
 OBJS += ../src/utils/ip_addr.o
+OBJS += ../src/utils/crc32.o
 
 OBJS += ../src/common/ieee802_11_common.o
 OBJS += ../src/common/wpa_common.o
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index 21671721c0..322afe9115 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -2411,6 +2411,27 @@ fail:
 }
 #endif /* CONFIG_SAE */
 
+static int parse_coloc_iface(struct hostapd_bss_config *bss, char *pos,
+				  int line)
+{
+	char **n;
+
+	if (bss->n_coloc_ifaces >= MAX_COLOC_IFACES_NUM)
+		return -1;
+
+	n = os_realloc_array(bss->coloc_ifaces,
+			     bss->n_coloc_ifaces + 1, sizeof(char *));
+	if (!n)
+		return -1;
+
+	bss->coloc_ifaces = n;
+	bss->coloc_ifaces[bss->n_coloc_ifaces] = os_strdup(pos);
+	if (!bss->coloc_ifaces[bss->n_coloc_ifaces])
+		return -1;
+	bss->n_coloc_ifaces++;
+
+	return 0;
+}
 
 #ifdef CONFIG_DPP2
 static int hostapd_dpp_controller_parse(struct hostapd_bss_config *bss,
@@ -4557,6 +4578,9 @@ static int hostapd_config_fill(struct hostapd_config *conf,
 		}
 		bss->mka_psk_set |= MKA_PSK_SET_CKN;
 #endif /* CONFIG_MACSEC */
+	} else if (os_strcmp(buf, "co_located_iface") == 0) {
+		if (parse_coloc_iface(bss, pos, line) < 0)
+			return 1;
 	} else {
 		wpa_printf(MSG_ERROR,
 			   "Line %d: unknown configuration item '%s'",
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index a25d3f0092..ae33f0d5d9 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -2666,3 +2666,9 @@ own_ip_addr=127.0.0.1
 #bss=wlan0_1
 #bssid=00:13:10:95:fe:0b
 # ...
+
+# Co-located interfaces
+# A list of co-located APs. These APs will be reported in Reduced Neighbor
+# Report element in probe responses and beacons.
+#co_located_iface=wlan1
+#co_located_iface=wlan2
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 5f0f2e0da7..b371f87f99 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -788,6 +788,10 @@ void hostapd_config_free_bss(struct hostapd_bss_config *conf)
 	}
 #endif /* CONFIG_AIRTIME_POLICY */
 
+	for (i = 0; i < conf->n_coloc_ifaces; i++)
+		os_free(conf->coloc_ifaces[i]);
+	os_free(conf->coloc_ifaces);
+
 	os_free(conf);
 }
 
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index fc6524c9e9..09e787b4c7 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -88,6 +88,7 @@ typedef enum hostap_security_policy {
 struct hostapd_ssid {
 	u8 ssid[SSID_MAX_LEN];
 	size_t ssid_len;
+	u32 short_ssid;
 	unsigned int ssid_set:1;
 	unsigned int utf8_ssid:1;
 	unsigned int wpa_passphrase_set:1;
@@ -820,6 +821,11 @@ struct hostapd_bss_config {
 	 */
 	u8 mka_psk_set;
 #endif /* CONFIG_MACSEC */
+
+#define MAX_COLOC_IFACES_NUM 16
+	/* Array of colocated interfaces */
+	char **coloc_ifaces;
+	size_t n_coloc_ifaces;
 };
 
 /**
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index c1aeb03a3d..724e1d8ca5 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -365,6 +365,78 @@ static u8 * hostapd_eid_supported_op_classes(struct hostapd_data *hapd, u8 *eid)
 }
 
 
+/*
+ * Add Reduced Neighbor Report element to Beacons and Probe Responses
+ */
+static u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_FILS
+	u8 *len;
+	size_t i;
+
+	if (!hapd->conf->n_coloc_ifaces || !hapd->iface->interfaces)
+		return eid;
+
+	*pos++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT;
+	len = pos++;
+	for (i = 0; i < hapd->conf->n_coloc_ifaces; i++) {
+		struct ieee80211_neighbor_ap_info *rnr;
+		struct hostapd_data *h =
+			hostapd_get_iface(hapd->iface->interfaces,
+					  hapd->conf->coloc_ifaces[i]);
+
+		if (!h || !h->started || !h->iface->current_mode || h == hapd)
+			continue;
+
+		rnr = (struct ieee80211_neighbor_ap_info *)pos;
+		rnr->tbtt_info_hdr = 0;
+		if (h->conf->ssid.ssid_len == hapd->conf->ssid.ssid_len &&
+		    os_memcmp(h->conf->ssid.ssid, hapd->conf->ssid.ssid,
+			      h->conf->ssid.ssid_len) == 0) {
+			rnr->tbtt_info_hdr |= RNR_TBTT_INFO_HDR_FILTERED;
+			/* TBTT offset + BSSID */
+			rnr->tbtt_info_len = 7;
+		} else {
+			/* TBTT offset + BSSID + Short SSID */
+			rnr->tbtt_info_len = 11;
+		}
+		rnr->tbtt_info_hdr |= RNR_TBTT_INFO_HDR_COLOC;
+		if (ieee80211_freq_to_channel_ext(h->iface->freq,
+						  h->iconf->secondary_channel,
+						  h->iconf->vht_oper_chwidth,
+						  &rnr->op_class,
+						  &rnr->channel) ==
+		    NUM_HOSTAPD_MODES) {
+			wpa_printf(MSG_DEBUG,
+				   "Skipping colocated iface with invalid channel configuration (%s)",
+				   hapd->conf->coloc_ifaces[i]);
+			/* It's safe to continue as pos isn't advanced yet */
+			continue;
+		}
+		rnr->neighbor_ap_tbtt_offset = 255; /* Unknown */
+		pos += sizeof(*rnr);
+		os_memcpy(pos, h->own_addr, ETH_ALEN);
+		pos += ETH_ALEN;
+
+		/* Include Short SSID if needed */
+		if (rnr->tbtt_info_len == 11) {
+			WPA_PUT_LE32(pos, h->conf->ssid.short_ssid);
+			pos += 4;
+		}
+	}
+
+	*len = pos - eid - 2;
+
+	/* don't add empty IE */
+	if (*len == 0)
+		return eid;
+#endif /* CONFIG_FILS */
+
+	return pos;
+}
+
+
 static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 				   const struct ieee80211_mgmt *req,
 				   int is_p2p, size_t *resp_len)
@@ -508,6 +580,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
 	}
 #endif /* CONFIG_IEEE80211AC */
 
+	pos = hostapd_eid_rnr(hapd, pos);
 	pos = hostapd_eid_fils_indic(hapd, pos, 0);
 
 #ifdef CONFIG_IEEE80211AX
@@ -1224,6 +1297,7 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
 	}
 #endif /* CONFIG_IEEE80211AC */
 
+	tailpos = hostapd_eid_rnr(hapd, tailpos);
 	tailpos = hostapd_eid_fils_indic(hapd, tailpos, 0);
 
 #ifdef CONFIG_IEEE80211AX
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index c83fb2a464..5e886a44fd 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -10,6 +10,7 @@
 
 #include "utils/common.h"
 #include "utils/eloop.h"
+#include "utils/crc32.h"
 #include "common/ieee802_11_defs.h"
 #include "common/wpa_ctrl.h"
 #include "common/hw_features_common.h"
@@ -1155,6 +1156,12 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
 		os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
 	}
 
+	/*
+	 * Short SSID calculation is identical to FCS and it is defined in
+	 * IEEE802.11-REVmd/D2.2 9.4.2.170.3
+	 */
+	conf->ssid.short_ssid = crc32(conf->ssid.ssid, conf->ssid.ssid_len);
+
 	if (!hostapd_drv_none(hapd)) {
 		wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
 			   " and ssid \"%s\"",
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index a1e11c7143..30d81dade4 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -2228,4 +2228,19 @@ struct ieee80211_he_mu_edca_parameter_set {
 /* DPP Public Action frame identifiers - OUI_WFA */
 #define DPP_OUI_TYPE 0x1A
 
+#define RNR_TBTT_INFO_HDR_FILTERED BIT(2)
+#define RNR_TBTT_INFO_HDR_COLOC    BIT(3)
+#define RNR_TBTT_INFO_COUNT_OFFSET 4
+
+struct ieee80211_neighbor_ap_info {
+	u8 tbtt_info_hdr;
+	u8 tbtt_info_len;
+	u8 op_class;
+	u8 channel;
+	/* The Neighbor AP TBTT Offset subfield is always present */
+	u8 neighbor_ap_tbtt_offset;
+	/* Followed by the rest of  the TBTT Information field contents */
+	u8 data[0];
+} STRUCT_PACKED;
+
 #endif /* IEEE802_11_DEFS_H */
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
index 348f9015c2..ca83391174 100644
--- a/wpa_supplicant/Makefile
+++ b/wpa_supplicant/Makefile
@@ -891,6 +891,7 @@ OBJS += ../src/ap/utils.o
 OBJS += ../src/ap/authsrv.o
 OBJS += ../src/ap/ap_config.o
 OBJS += ../src/utils/ip_addr.o
+OBJS += ../src/utils/crc32.o
 OBJS += ../src/ap/sta_info.o
 OBJS += ../src/ap/tkip_countermeasures.o
 OBJS += ../src/ap/ap_mlme.o
