diff --git a/src/ap/beacon.c b/src/ap/beacon.c index c25a5bbc3..d66d83173 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -468,8 +468,9 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd, { struct hostapd_iface *iface = hapd->iface; struct hostapd_data *tx_bss; - size_t len; + size_t len, rnr_len = 0; u8 elem_count = 0, *elem = NULL, **elem_offset = NULL, *end; + u8 rnr_elem_count = 0, *rnr_elem = NULL, **rnr_elem_offset = NULL; if (!iface->mbssid_max_interfaces || iface->num_bss > iface->mbssid_max_interfaces || @@ -479,7 +480,7 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd, tx_bss = hostapd_mbssid_get_tx_bss(hapd); len = hostapd_eid_mbssid_len(tx_bss, WLAN_FC_STYPE_BEACON, &elem_count, - NULL, 0); + NULL, 0, &rnr_len); if (!len || (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED && elem_count > iface->ema_max_periodicity)) goto fail; @@ -492,8 +493,19 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd, if (!elem_offset) goto fail; + if (rnr_len) { + rnr_elem = os_zalloc(rnr_len); + if (!rnr_elem) + goto fail; + + rnr_elem_offset = os_calloc(elem_count + 1, sizeof(u8 *)); + if (!rnr_elem_offset) + goto fail; + } + end = hostapd_eid_mbssid(tx_bss, elem, elem + len, WLAN_FC_STYPE_BEACON, - elem_count, elem_offset, NULL, 0); + elem_count, elem_offset, NULL, 0, rnr_elem, + &rnr_elem_count, rnr_elem_offset, rnr_len); params->mbssid_tx_iface = tx_bss->conf->iface; params->mbssid_index = hostapd_mbssid_get_bss_index(hapd); @@ -501,12 +513,19 @@ ieee802_11_build_ap_params_mbssid(struct hostapd_data *hapd, params->mbssid_elem_len = end - elem; params->mbssid_elem_count = elem_count; params->mbssid_elem_offset = elem_offset; + params->rnr_elem = rnr_elem; + params->rnr_elem_len = rnr_len; + params->rnr_elem_count = rnr_elem_count; + params->rnr_elem_offset = rnr_elem_offset; if (iface->conf->mbssid == ENHANCED_MBSSID_ENABLED) params->ema = true; return 0; fail: + os_free(rnr_elem); + os_free(rnr_elem_offset); + os_free(elem_offset); os_free(elem); wpa_printf(MSG_ERROR, "MBSSID: Configuration failed"); return -1; @@ -590,7 +609,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, #endif /* CONFIG_IEEE80211BE */ buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL, - known_bss, known_bss_len); + known_bss, known_bss_len, NULL); buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP); buflen += hostapd_mbo_ie_len(hapd); buflen += hostapd_eid_owe_trans_len(hapd); @@ -658,7 +677,8 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd, pos = hostapd_get_rsne(hapd, pos, epos - pos); pos = hostapd_eid_bss_load(hapd, pos, epos - pos); pos = hostapd_eid_mbssid(hapd, pos, epos, WLAN_FC_STYPE_PROBE_RESP, 0, - NULL, known_bss, known_bss_len); + NULL, known_bss, known_bss_len, NULL, NULL, + NULL, 0); pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos); pos = hostapd_get_mde(hapd, pos, epos - pos); @@ -2026,6 +2046,10 @@ void ieee802_11_free_ap_params(struct wpa_driver_ap_params *params) params->mbssid_elem = NULL; os_free(params->mbssid_elem_offset); params->mbssid_elem_offset = NULL; + os_free(params->rnr_elem); + params->rnr_elem = NULL; + os_free(params->rnr_elem_offset); + params->rnr_elem_offset = NULL; #ifdef CONFIG_FILS os_free(params->fd_frame_tmpl); params->fd_frame_tmpl = NULL; diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c index c5962abb0..0fa19debf 100644 --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -6421,9 +6421,16 @@ 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) +struct mbssid_ie_profiles { + u8 start; + u8 end; +}; + +static size_t +hostapd_eid_rnr_iface_len(struct hostapd_data *hapd, + struct hostapd_data *reporting_hapd, + size_t *current_len, + struct mbssid_ie_profiles *skip_profiles) { size_t total_len = 0, len = *current_len; int tbtt_count = 0; @@ -6449,6 +6456,10 @@ static size_t hostapd_eid_rnr_iface_len(struct hostapd_data *hapd, bss->conf->ignore_broadcast_ssid) continue; + if (skip_profiles && + i >= skip_profiles->start && i < skip_profiles->end) + continue; + if (len + RNR_TBTT_INFO_LEN > 255 || tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) break; @@ -6527,7 +6538,7 @@ static size_t hostapd_eid_rnr_colocation_len(struct hostapd_data *hapd, continue; len += hostapd_eid_rnr_iface_len(iface->bss[0], hapd, - current_len); + current_len, NULL); } return len; @@ -6553,13 +6564,15 @@ size_t hostapd_eid_rnr_len(struct hostapd_data *hapd, u32 type) if (hapd->conf->rnr && hapd->iface->num_bss > 1 && !hapd->iconf->mbssid) total_len += hostapd_eid_rnr_iface_len(hapd, hapd, - ¤t_len); + ¤t_len, + NULL); break; case WLAN_FC_STYPE_ACTION: if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ) total_len += hostapd_eid_rnr_iface_len(hapd, hapd, - ¤t_len); + ¤t_len, + NULL); break; default: @@ -6627,7 +6640,8 @@ 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) + u8 *eid, size_t *current_len, + struct mbssid_ie_profiles *skip_profiles) { struct hostapd_data *bss; struct hostapd_iface *iface = hapd->iface; @@ -6672,6 +6686,10 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd, bss->conf->ignore_broadcast_ssid) continue; + if (skip_profiles && + i >= skip_profiles->start && i < skip_profiles->end) + continue; + if (len + RNR_TBTT_INFO_LEN > 255 || tbtt_count >= RNR_TBTT_INFO_COUNT_MAX) break; @@ -6688,7 +6706,7 @@ static u8 * hostapd_eid_rnr_iface(struct hostapd_data *hapd, if (iface->conf->mbssid != MBSSID_DISABLED && iface->num_bss > 1) { bss_param |= RNR_BSS_PARAM_MULTIPLE_BSSID; - if (i == 0) + if (bss == hostapd_mbssid_get_tx_bss(hapd)) bss_param |= RNR_BSS_PARAM_TRANSMITTED_BSSID; } @@ -6736,7 +6754,7 @@ static u8 * hostapd_eid_rnr_colocation(struct hostapd_data *hapd, u8 *eid, continue; eid = hostapd_eid_rnr_iface(iface->bss[0], hapd, eid, - current_len); + current_len, NULL); } return eid; @@ -6763,13 +6781,13 @@ u8 * hostapd_eid_rnr(struct hostapd_data *hapd, u8 *eid, u32 type) if (hapd->conf->rnr && hapd->iface->num_bss > 1 && !hapd->iconf->mbssid) eid = hostapd_eid_rnr_iface(hapd, hapd, eid, - ¤t_len); + ¤t_len, NULL); break; case WLAN_FC_STYPE_ACTION: if (hapd->iface->num_bss > 1 && mode == STANDALONE_6GHZ) eid = hostapd_eid_rnr_iface(hapd, hapd, eid, - ¤t_len); + ¤t_len, NULL); break; default: @@ -6858,7 +6876,7 @@ static size_t hostapd_eid_mbssid_elem_len(struct hostapd_data *hapd, size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type, u8 *elem_count, const u8 *known_bss, - size_t known_bss_len) + size_t known_bss_len, size_t *rnr_len) { size_t len = 0, bss_index = 1; @@ -6877,13 +6895,29 @@ size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type, } while (bss_index < hapd->iface->num_bss) { + size_t rnr_count = bss_index; + len += hostapd_eid_mbssid_elem_len(hapd, frame_type, &bss_index, known_bss, known_bss_len); if (frame_type == WLAN_FC_STYPE_BEACON) *elem_count += 1; + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) { + size_t rnr_cur_len = 0; + struct mbssid_ie_profiles skip_profiles = { + rnr_count, bss_index + }; + + *rnr_len += hostapd_eid_rnr_iface_len( + hapd, hostapd_mbssid_get_tx_bss(hapd), + &rnr_cur_len, &skip_profiles); + } } + + if (hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && rnr_len) + *rnr_len += hostapd_eid_rnr_len(hapd, frame_type); + return len; } @@ -6995,10 +7029,12 @@ static u8 * hostapd_eid_mbssid_elem(struct hostapd_data *hapd, u8 *eid, u8 *end, u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, unsigned int frame_stype, u8 elem_count, u8 **elem_offset, - const u8 *known_bss, size_t known_bss_len) + const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid, + u8 *rnr_count, u8 **rnr_offset, size_t rnr_len) { - size_t bss_index = 1; - u8 elem_index = 0; + size_t bss_index = 1, cur_len = 0; + u8 elem_index = 0, *rnr_start_eid = rnr_eid; + bool add_rnr; if (!hapd->iconf->mbssid || hapd->iface->num_bss <= 1 || (frame_stype != WLAN_FC_STYPE_BEACON && @@ -7011,7 +7047,13 @@ u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, return eid; } + add_rnr = hapd->iconf->mbssid == ENHANCED_MBSSID_ENABLED && + frame_stype == WLAN_FC_STYPE_BEACON && + rnr_eid && rnr_count && rnr_offset && rnr_len; + while (bss_index < hapd->iface->num_bss) { + unsigned int rnr_start_count = bss_index; + if (frame_stype == WLAN_FC_STYPE_BEACON) { if (elem_index == elem_count) { wpa_printf(MSG_WARNING, @@ -7026,6 +7068,31 @@ u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, hostapd_max_bssid_indicator(hapd), &bss_index, elem_count, known_bss, known_bss_len); + + if (add_rnr) { + struct mbssid_ie_profiles skip_profiles = { + rnr_start_count, bss_index + }; + + rnr_offset[*rnr_count] = rnr_eid; + *rnr_count = *rnr_count + 1; + cur_len = 0; + rnr_eid = hostapd_eid_rnr_iface( + hapd, hostapd_mbssid_get_tx_bss(hapd), + rnr_eid, &cur_len, &skip_profiles); + } + } + + if (add_rnr && (size_t) (rnr_eid - rnr_start_eid) < rnr_len) { + rnr_offset[*rnr_count] = rnr_eid; + *rnr_count = *rnr_count + 1; + cur_len = 0; + + if (hapd->conf->rnr) + rnr_eid = hostapd_eid_nr_db(hapd, rnr_eid, &cur_len); + if (get_colocation_mode(hapd) == COLOCATED_LOWER_BAND) + rnr_eid = hostapd_eid_rnr_colocation(hapd, rnr_eid, + &cur_len); } return eid; diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index 1e4c843f6..1190a5ea8 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -218,11 +218,12 @@ u16 copy_sta_eht_capab(struct hostapd_data *hapd, struct sta_info *sta, const u8 *eht_capab, size_t eht_capab_len); size_t hostapd_eid_mbssid_len(struct hostapd_data *hapd, u32 frame_type, u8 *elem_count, const u8 *known_bss, - size_t known_bss_len); + size_t known_bss_len, size_t *rnr_len); u8 * hostapd_eid_mbssid(struct hostapd_data *hapd, u8 *eid, u8 *end, unsigned int frame_stype, u8 elem_count, u8 **elem_offset, - const u8 *known_bss, size_t known_bss_len); + const u8 *known_bss, size_t known_bss_len, u8 *rnr_eid, + u8 *rnr_count, u8 **rnr_offset, size_t rnr_len); void punct_update_legacy_bw(u16 bitmap, u8 pri_chan, enum oper_chan_width *width, u8 *seg0, u8 *seg1); diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 7c0e949b9..bcb0c92d6 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -1726,6 +1726,28 @@ struct wpa_driver_ap_params { * subchannel is punctured, otherwise active. */ u16 punct_bitmap; + + /** + * rnr_elem - This buffer contains all of reduced neighbor report (RNR) + * elements + */ + u8 *rnr_elem; + + /** + * rnr_elem_len - Length of rnr_elem buffer + */ + size_t rnr_elem_len; + + /** + * rnr_elem_count - Number of RNR elements + */ + unsigned int rnr_elem_count; + + /** + * rnr_elem_offset - The offsets to the elements in rnr_elem. + * The driver will use these to include RNR elements in EMA beacons. + */ + u8 **rnr_elem_offset; }; struct wpa_driver_mesh_bss_params {