AP MLD: Generate and keep per STA profiles for each link

Currently, upon receiving a Probe Request frame, per STA profile is
generated and added to the Probe Response frame. However, the per STA
profile remains unchanged unless there’s a property change in one of the
affliated link of the AP MLD. This approach introduces unnecessary delay
in forming and sending out the Probe Response frame.

To optimize this process, generate the per STA profile for each link at
the start and store it. When needed, it can be simply copied into the
Probe Response frame. Additionally, whenever there’s a change in the
link’s properties, re-generate the per STA profiles for all affiliated
links of the AP MLD.

As an initial step, copy the complete per STA profile and store it
within the links. The intersection with reporting BSS and inheritance
will be addressed in a subsequent change. Then finally, this will be
used to generate the Probe Response frame. As of this commit, no change
in adding per STA profiles in the Probe Response frame.

Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Co-developed-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
This commit is contained in:
Sriram R 2024-08-07 12:11:41 +05:30 committed by Jouni Malinen
parent 8f07e9699b
commit 2042cae9b3
3 changed files with 186 additions and 0 deletions

View file

@ -2825,12 +2825,175 @@ void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd)
}
#ifdef CONFIG_IEEE80211BE
static int hostapd_get_probe_resp_tmpl(struct hostapd_data *hapd,
struct probe_resp_params *params,
bool is_ml_sta_info)
{
os_memset(params, 0, sizeof(*params));
hostapd_gen_probe_resp(hapd, params);
if (!params->resp)
return -1;
/* The caller takes care of freeing params->resp. */
return 0;
}
/* Create the link STA profiles.
*
* NOTE: The same function is used for length calculation as well as filling
* data in the given buffer. This avoids risk of not updating the length
* function but filling function or vice versa.
*/
static size_t hostapd_add_sta_profile(struct ieee80211_mgmt *link_fdata,
size_t link_data_len, u8 *sta_profile)
{
const struct element *link_elem;
size_t sta_profile_len = 0;
const u8 *link_elem_data;
u8 link_ele_len;
u8 *link_data;
/* extra len used in the logic includes the element id and len */
u8 extra_len = 2;
/* Include len for capab info */
sta_profile_len += sizeof(le16);
if (sta_profile) {
os_memcpy(sta_profile, &link_fdata->u.probe_resp.capab_info,
sizeof(le16));
sta_profile += sizeof(le16);
}
link_data = link_fdata->u.probe_resp.variable;
for_each_element(link_elem, link_data, link_data_len) {
link_elem_data = link_elem->data;
link_ele_len = link_elem->datalen;
sta_profile_len += link_ele_len + extra_len;
if (sta_profile) {
os_memcpy(sta_profile, link_elem_data - extra_len,
link_ele_len + extra_len);
sta_profile += link_ele_len + extra_len;
}
}
return sta_profile_len;
}
static u8 * hostapd_gen_sta_profile(struct ieee80211_mgmt *link_data,
size_t link_data_len,
size_t *sta_profile_len)
{
u8 *sta_profile;
/* Get the length first */
*sta_profile_len = hostapd_add_sta_profile(link_data, link_data_len,
NULL);
if (!(*sta_profile_len) || *sta_profile_len > EHT_ML_MAX_STA_PROF_LEN)
return NULL;
sta_profile = os_zalloc(*sta_profile_len);
if (!sta_profile)
return NULL;
/* Now fill in the data */
hostapd_add_sta_profile(link_data, link_data_len, sta_profile);
/* The caller takes care of freeing the returned sta_profile */
return sta_profile;
}
static void hostapd_gen_per_sta_profiles(struct hostapd_data *hapd)
{
size_t link_data_len, sta_profile_len;
struct probe_resp_params link_params;
struct ieee80211_mgmt *link_data;
struct mld_link_info *link_info;
struct hostapd_data *link_bss;
u8 link_id, *sta_profile;
if (!hapd->conf->mld_ap)
return;
wpa_printf(MSG_DEBUG, "MLD: Generating per STA profiles for MLD %s",
hapd->conf->iface);
wpa_printf(MSG_DEBUG, "MLD: Reporting link %d", hapd->mld_link_id);
for_each_mld_link(link_bss, hapd) {
if (link_bss == hapd || !link_bss->started)
continue;
link_id = link_bss->mld_link_id;
if (link_id > MAX_NUM_MLD_LINKS)
continue;
sta_profile = NULL;
sta_profile_len = 0;
/* Generate a Probe Response frame template for partner link */
if (hostapd_get_probe_resp_tmpl(link_bss, &link_params, true)) {
wpa_printf(MSG_ERROR,
"MLD: Could not get link STA probe response template for link %d",
link_id);
continue;
}
link_data = link_params.resp;
link_data_len = link_params.resp_len;
/* Consider length of the variable fields */
link_data_len -= offsetof(struct ieee80211_mgmt,
u.probe_resp.variable);
sta_profile = hostapd_gen_sta_profile(link_data, link_data_len,
&sta_profile_len);
if (!sta_profile) {
wpa_printf(MSG_ERROR,
"MLD: Could not generate link STA profile for link %d",
link_id);
continue;
}
link_info = &hapd->partner_links[link_id];
link_info->valid = true;
os_free(link_info->resp_sta_profile);
link_info->resp_sta_profile_len = sta_profile_len;
link_info->resp_sta_profile = os_memdup(sta_profile,
sta_profile_len);
if (!link_info->resp_sta_profile)
link_info->resp_sta_profile_len = 0;
os_memcpy(link_info->local_addr, link_bss->own_addr, ETH_ALEN);
wpa_printf(MSG_DEBUG,
"MLD: Reported link STA info for %d: %u bytes",
link_id, link_info->resp_sta_profile_len);
os_free(sta_profile);
os_free(link_params.resp);
}
}
#endif /* CONFIG_IEEE80211BE */
int ieee802_11_set_beacon(struct hostapd_data *hapd)
{
struct hostapd_iface *iface = hapd->iface;
int ret;
size_t i, j;
bool is_6g, hapd_mld = false;
#ifdef CONFIG_IEEE80211BE
struct hostapd_data *link_bss;
#endif /* CONFIG_IEEE80211BE */
ret = __ieee802_11_set_beacon(hapd);
if (ret != 0)
@ -2871,6 +3034,15 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
}
}
#ifdef CONFIG_IEEE80211BE
if (!hapd_mld)
return 0;
/* Generate per STA profiles for each affiliated APs */
for_each_mld_link(link_bss, hapd)
hostapd_gen_per_sta_profiles(link_bss);
#endif /* CONFIG_IEEE80211BE */
return 0;
}

View file

@ -620,9 +620,19 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
static void hostapd_bss_link_deinit(struct hostapd_data *hapd)
{
#ifdef CONFIG_IEEE80211BE
int i;
if (!hapd->conf || !hapd->conf->mld_ap)
return;
/* Free per STA profiles */
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
os_free(hapd->partner_links[i].resp_sta_profile);
os_memset(&hapd->partner_links[i], 0,
sizeof(hapd->partner_links[i]));
}
/* Put all freeing logic above this */
if (!hapd->mld->num_links)
return;

View file

@ -491,6 +491,10 @@ struct hostapd_data {
struct hostapd_mld *mld;
struct dl_list link;
u8 mld_link_id;
/* Cached partner info for ML probe response */
struct mld_link_info partner_links[MAX_NUM_MLD_LINKS];
#ifdef CONFIG_TESTING_OPTIONS
u8 eht_mld_link_removal_count;
#endif /* CONFIG_TESTING_OPTIONS */