diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index 52df06d29..404f243af 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -7102,6 +7102,54 @@ static size_t hostapd_eid_nr_db_len(struct hostapd_data *hapd, } +static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd, + struct hostapd_data *reporting_hapd, + size_t *current_len) +{ + size_t total_len = 0, len = *current_len; + int tbtt_count = 0; + size_t i, start = 0; + + while (start < hapd->iface->num_bss) { + if (!len || + len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) { + len = RNR_HEADER_LEN; + total_len += RNR_HEADER_LEN; + } + + len += RNR_TBTT_HEADER_LEN; + total_len += RNR_TBTT_HEADER_LEN; + + for (i = start; i < hapd->iface->num_bss; i++) { + struct hostapd_data *bss = hapd->iface->bss[i]; + + if (!bss || !bss->conf || !bss->started) + continue; + + if (bss == reporting_hapd || + bss->conf->ignore_broadcast_ssid) + continue; + + if (len + RNR_TBTT_INFO_LEN > 255 || + tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) + break; + + len += RNR_TBTT_INFO_LEN; + total_len += RNR_TBTT_INFO_LEN; + tbtt_count++; + } + start = i; + } + + if (!tbtt_count) + total_len = 0; + else + *current_len = len; + + return total_len; +} + + size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type) { size_t total_len = 0, current_len = 0; @@ -7110,6 +7158,12 @@ size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type) case WLAN_FC_STYPE_BEACON: if (hapd->conf->rnr) total_len += hostapd_eid_nr_db_len(hapd, ¤t_len); + /* fallthrough */ + + case WLAN_FC_STYPE_PROBE_RESP: + if (hapd->conf->rnr && hapd->iface->num_bss > 1) + total_len += hostapd_eid_rnr_iface_len(hapd, hapd, + ¤t_len); break; default: @@ -7175,6 +7229,92 @@ static u8 * hostapd_eid_nr_db(struct hostapd_data *hapd, u8 *eid, } +static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd, + struct hostapd_data *reporting_hapd, + u8 *eid, size_t *current_len) +{ + struct hostapd_data *bss; + struct hostapd_iface *iface = hapd->iface; + size_t i, start = 0; + size_t len = *current_len; + u8 *tbtt_count_pos, *eid_start = eid, *size_offset = (eid - len) + 1; + u8 tbtt_count = 0, op_class, channel, bss_param; + + if (!(iface->drv_flags & WPA_DRIVER_FLAGS_AP_CSA) || !iface->freq) + return eid; + + if (ieee80211_freq_to_channel_ext(iface->freq, + hapd->iconf->secondary_channel, + hostapd_get_oper_chwidth(hapd->iconf), + &op_class, &channel) == + NUM_HOSTAPD_MODES) + return eid; + + while (start < iface->num_bss) { + if (!len || + len + RNR_TBTT_HEADER_LEN + RNR_TBTT_INFO_LEN > 255) { + eid_start = eid; + *eid++ = WLAN_EID_REDUCED_NEIGHBOR_REPORT; + size_offset = eid++; + len = RNR_HEADER_LEN; + tbtt_count = 0; + } + + tbtt_count_pos = eid++; + *eid++ = RNR_TBTT_INFO_LEN; + *eid++ = op_class; + *eid++ = hapd->iconf->channel; + len += RNR_TBTT_HEADER_LEN; + + for (i = start; i < iface->num_bss; i++) { + bss_param = 0; + bss = iface->bss[i]; + if (!bss || !bss->conf || !bss->started) + continue; + + if (bss == reporting_hapd || + bss->conf->ignore_broadcast_ssid) + continue; + + if (len + RNR_TBTT_INFO_LEN > 255 || + tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) + break; + + *eid++ = RNR_NEIGHBOR_AP_OFFSET_UNKNOWN; + os_memcpy(eid, bss->conf->bssid, ETH_ALEN); + eid += ETH_ALEN; + os_memcpy(eid, &bss->conf->ssid.short_ssid, 4); + eid += 4; + if (bss->conf->ssid.short_ssid == + reporting_hapd->conf->ssid.short_ssid) + bss_param |= RNR_BSS_PARAM_SAME_SSID; + + if (is_6ghz_op_class(hapd->iconf->op_class) && + bss->conf->unsol_bcast_probe_resp_interval) + bss_param |= + RNR_BSS_PARAM_UNSOLIC_PROBE_RESP_ACTIVE; + + bss_param |= RNR_BSS_PARAM_CO_LOCATED; + + *eid++ = bss_param; + *eid++ = RNR_20_MHZ_PSD_MAX_TXPOWER - 1; + len += RNR_TBTT_INFO_LEN; + tbtt_count += 1; + } + + start = i; + *tbtt_count_pos = RNR_TBTT_INFO_COUNT(tbtt_count - 1); + *size_offset = (eid - size_offset) - 1; + } + + if (tbtt_count == 0) + return eid_start; + + *current_len = len; + return eid; +} + + u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type) { u8 *eid_start = eid; @@ -7184,6 +7324,12 @@ u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type) case WLAN_FC_STYPE_BEACON: if (hapd->conf->rnr) eid = hostapd_eid_nr_db(hapd, eid, ¤t_len); + /* fallthrough */ + + case WLAN_FC_STYPE_PROBE_RESP: + if (hapd->conf->rnr && hapd->iface->num_bss > 1) + eid = hostapd_eid_rnr_iface(hapd, hapd, eid, + ¤t_len); break; default: