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@xxxxxxxxxxx> --- 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 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 */ -- 2.25.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap