AP MLD: Reduce struct mld_link_info size

Replace the fixed length maximum buffer size for STA profile with
dynamically allocated buffers for active links. This reduces struct
mld_link_info size by almost 16 kB and drops the per-STA information in
struct sta_info to a more reasonable size to avoid the almost 10x
increase from MLO support.

In addition, free the resp_sta_profile buffers as soon as the ML element
has bee generated for (Re)Association Response frame since those buffers
are not needed after that.

Signed-off-by: Jouni Malinen <j@w1.fi>
This commit is contained in:
Jouni Malinen 2024-01-21 21:06:18 +02:00
parent b91572b308
commit 512b925240
5 changed files with 78 additions and 33 deletions

View file

@ -617,6 +617,19 @@ struct probe_resp_params {
#endif /* CONFIG_IEEE80211AX */ #endif /* CONFIG_IEEE80211AX */
}; };
static void hostapd_free_probe_resp_params(struct probe_resp_params *params)
{
#ifdef CONFIG_IEEE80211BE
if (!params)
return;
ap_sta_free_sta_profile(params->mld_info);
os_free(params->mld_info);
params->mld_info = NULL;
#endif /* CONFIG_IEEE80211BE */
}
static size_t hostapd_probe_resp_elems_len(struct hostapd_data *hapd, static size_t hostapd_probe_resp_elems_len(struct hostapd_data *hapd,
struct probe_resp_params *params) struct probe_resp_params *params)
{ {
@ -955,6 +968,7 @@ static void hostapd_fill_probe_resp_ml_params(struct hostapd_data *hapd,
size_t buflen; size_t buflen;
u8 mld_link_id = link->mld_link_id; u8 mld_link_id = link->mld_link_id;
u8 *epos; u8 *epos;
u8 buf[EHT_ML_MAX_STA_PROF_LEN];
/* /*
* Set mld_ap iff the ML probe request explicitly * Set mld_ap iff the ML probe request explicitly
@ -984,7 +998,7 @@ static void hostapd_fill_probe_resp_ml_params(struct hostapd_data *hapd,
buflen = MAX_PROBERESP_LEN; buflen = MAX_PROBERESP_LEN;
buflen += hostapd_probe_resp_elems_len(link, &sta_info_params); buflen += hostapd_probe_resp_elems_len(link, &sta_info_params);
if (buflen > sizeof(link_info->resp_sta_profile)) { if (buflen > EHT_ML_MAX_STA_PROF_LEN) {
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
"MLD: Not including link %d in ML probe response (%zu bytes is too long)", "MLD: Not including link %d in ML probe response (%zu bytes is too long)",
mld_link_id, buflen); mld_link_id, buflen);
@ -996,18 +1010,21 @@ static void hostapd_fill_probe_resp_ml_params(struct hostapd_data *hapd,
* various other things. * various other things.
*/ */
link_info->valid = true; link_info->valid = true;
epos = link_info->resp_sta_profile; epos = buf;
/* Capabilities is the only fixed parameter */ /* Capabilities is the only fixed parameter */
WPA_PUT_LE16(link_info->resp_sta_profile, WPA_PUT_LE16(epos, hostapd_own_capab_info(hapd));
hostapd_own_capab_info(hapd)); epos += 2;
epos = hostapd_probe_resp_fill_elems( epos = hostapd_probe_resp_fill_elems(
link, &sta_info_params, link, &sta_info_params, epos,
link_info->resp_sta_profile + 2, EHT_ML_MAX_STA_PROF_LEN - 2);
sizeof(link_info->resp_sta_profile) - 2); link_info->resp_sta_profile_len = epos - buf;
link_info->resp_sta_profile_len = os_free(link_info->resp_sta_profile);
epos - link_info->resp_sta_profile; link_info->resp_sta_profile = os_memdup(
buf, link_info->resp_sta_profile_len);
if (!link_info->resp_sta_profile)
link_info->resp_sta_profile_len = 0;
os_memcpy(link_info->local_addr, link->own_addr, ETH_ALEN); os_memcpy(link_info->local_addr, link->own_addr, ETH_ALEN);
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,
@ -1026,7 +1043,7 @@ static void hostapd_fill_probe_resp_ml_params(struct hostapd_data *hapd,
return; return;
fail: fail:
os_free(params->mld_info); hostapd_free_probe_resp_params(params);
params->mld_ap = NULL; params->mld_ap = NULL;
params->mld_info = NULL; params->mld_info = NULL;
} }
@ -1584,7 +1601,7 @@ void handle_probe_req(struct hostapd_data *hapd,
hostapd_gen_probe_resp(hapd, &params); hostapd_gen_probe_resp(hapd, &params);
os_free(params.mld_info); hostapd_free_probe_resp_params(&params);
if (!params.resp) if (!params.resp)
return; return;

View file

@ -3078,6 +3078,7 @@ static void handle_auth(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211BE #ifdef CONFIG_IEEE80211BE
if (auth_transaction == 1) { if (auth_transaction == 1) {
ap_sta_free_sta_profile(&sta->mld_info);
os_memset(&sta->mld_info, 0, sizeof(sta->mld_info)); os_memset(&sta->mld_info, 0, sizeof(sta->mld_info));
if (mld_sta) { if (mld_sta) {
@ -4319,22 +4320,23 @@ static int check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
#ifdef CONFIG_IEEE80211BE #ifdef CONFIG_IEEE80211BE
static size_t ieee80211_ml_build_assoc_resp(struct hostapd_data *hapd, static void ieee80211_ml_build_assoc_resp(struct hostapd_data *hapd,
u16 status_code, struct mld_link_info *link)
u8 *buf, size_t buflen)
{ {
u8 buf[EHT_ML_MAX_STA_PROF_LEN];
u8 *p = buf; u8 *p = buf;
size_t buflen = sizeof(buf);
/* Capability Info */ /* Capability Info */
WPA_PUT_LE16(p, hostapd_own_capab_info(hapd)); WPA_PUT_LE16(p, hostapd_own_capab_info(hapd));
p += 2; p += 2;
/* Status Code */ /* Status Code */
WPA_PUT_LE16(p, status_code); WPA_PUT_LE16(p, link->status);
p += 2; p += 2;
if (status_code != WLAN_STATUS_SUCCESS) if (link->status != WLAN_STATUS_SUCCESS)
return p - buf; goto out;
/* AID is not included */ /* AID is not included */
p = hostapd_eid_supp_rates(hapd, p); p = hostapd_eid_supp_rates(hapd, p);
@ -4372,7 +4374,10 @@ static size_t ieee80211_ml_build_assoc_resp(struct hostapd_data *hapd,
p += wpabuf_len(hapd->conf->assocresp_elements); p += wpabuf_len(hapd->conf->assocresp_elements);
} }
return p - buf; out:
os_free(link->resp_sta_profile);
link->resp_sta_profile = os_memdup(buf, p - buf);
link->resp_sta_profile_len = link->resp_sta_profile ? p - buf : 0;
} }
@ -4386,6 +4391,7 @@ static void ieee80211_ml_process_link(struct hostapd_data *hapd,
struct wpabuf *mlbuf = NULL; struct wpabuf *mlbuf = NULL;
struct sta_info *sta = NULL; struct sta_info *sta = NULL;
u16 status = WLAN_STATUS_SUCCESS; u16 status = WLAN_STATUS_SUCCESS;
int i;
wpa_printf(MSG_DEBUG, "MLD: link: link_id=%u, peer=" MACSTR, wpa_printf(MSG_DEBUG, "MLD: link: link_id=%u, peer=" MACSTR,
hapd->mld_link_id, MAC2STR(link->peer_addr)); hapd->mld_link_id, MAC2STR(link->peer_addr));
@ -4435,6 +4441,12 @@ static void ieee80211_ml_process_link(struct hostapd_data *hapd,
sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id; sta->mld_assoc_link_id = origin_sta->mld_assoc_link_id;
os_memcpy(&sta->mld_info, &origin_sta->mld_info, sizeof(sta->mld_info)); os_memcpy(&sta->mld_info, &origin_sta->mld_info, sizeof(sta->mld_info));
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
struct mld_link_info *li = &sta->mld_info.links[i];
li->resp_sta_profile = NULL;
li->resp_sta_profile_len = 0;
}
/* /*
* Get the AID from the station on which the association was performed, * Get the AID from the station on which the association was performed,
@ -4485,10 +4497,7 @@ out:
if (sta && status != WLAN_STATUS_SUCCESS) if (sta && status != WLAN_STATUS_SUCCESS)
ap_free_sta(hapd, sta); ap_free_sta(hapd, sta);
link->resp_sta_profile_len = ieee80211_ml_build_assoc_resp(hapd, link);
ieee80211_ml_build_assoc_resp(hapd, link->status,
link->resp_sta_profile,
sizeof(link->resp_sta_profile));
} }
@ -4552,19 +4561,11 @@ static void hostapd_process_assoc_ml_info(struct hostapd_data *hapd,
"MLD: No link match for link_id=%u", i); "MLD: No link match for link_id=%u", i);
link->status = WLAN_STATUS_UNSPECIFIED_FAILURE; link->status = WLAN_STATUS_UNSPECIFIED_FAILURE;
link->resp_sta_profile_len = ieee80211_ml_build_assoc_resp(hapd, link);
ieee80211_ml_build_assoc_resp(
hapd, link->status,
link->resp_sta_profile,
sizeof(link->resp_sta_profile));
} else if (tx_link_status != WLAN_STATUS_SUCCESS) { } else if (tx_link_status != WLAN_STATUS_SUCCESS) {
/* TX link rejected the connection */ /* TX link rejected the connection */
link->status = WLAN_STATUS_DENIED_TX_LINK_NOT_ACCEPTED; link->status = WLAN_STATUS_DENIED_TX_LINK_NOT_ACCEPTED;
link->resp_sta_profile_len = ieee80211_ml_build_assoc_resp(hapd, link);
ieee80211_ml_build_assoc_resp(
hapd, link->status,
link->resp_sta_profile,
sizeof(link->resp_sta_profile));
} else { } else {
ieee80211_ml_process_link(iface->bss[0], sta, link, ieee80211_ml_process_link(iface->bss[0], sta, link,
ies, ies_len, reassoc); ies, ies_len, reassoc);

View file

@ -583,6 +583,9 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd,
/* BSS Parameters Change Count */ /* BSS Parameters Change Count */
wpabuf_put_u8(buf, hapd->eht_mld_bss_param_change); wpabuf_put_u8(buf, hapd->eht_mld_bss_param_change);
if (!link->resp_sta_profile)
continue;
/* Fragment the sub element if needed */ /* Fragment the sub element if needed */
if (total_len <= 255) { if (total_len <= 255) {
wpabuf_put_data(buf, link->resp_sta_profile, wpabuf_put_data(buf, link->resp_sta_profile,
@ -784,6 +787,7 @@ u8 * hostapd_eid_eht_ml_assoc(struct hostapd_data *hapd, struct sta_info *info,
eid = hostapd_eid_eht_basic_ml_common(hapd, eid, &info->mld_info, eid = hostapd_eid_eht_basic_ml_common(hapd, eid, &info->mld_info,
false); false);
ap_sta_free_sta_profile(&info->mld_info);
return hostapd_eid_eht_reconf_ml(hapd, eid); return hostapd_eid_eht_reconf_ml(hapd, eid);
} }

View file

@ -350,6 +350,7 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
#ifdef CONFIG_INTERWORKING #ifdef CONFIG_INTERWORKING
if (sta->gas_dialog) { if (sta->gas_dialog) {
int i; int i;
for (i = 0; i < GAS_DIALOG_MAX; i++) for (i = 0; i < GAS_DIALOG_MAX; i++)
gas_serv_dialog_clear(&sta->gas_dialog[i]); gas_serv_dialog_clear(&sta->gas_dialog[i]);
os_free(sta->gas_dialog); os_free(sta->gas_dialog);
@ -420,6 +421,10 @@ void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
os_free(sta->ifname_wds); os_free(sta->ifname_wds);
#ifdef CONFIG_IEEE80211BE
ap_sta_free_sta_profile(&sta->mld_info);
#endif /* CONFIG_IEEE80211BE */
#ifdef CONFIG_TESTING_OPTIONS #ifdef CONFIG_TESTING_OPTIONS
os_free(sta->sae_postponed_commit); os_free(sta->sae_postponed_commit);
forced_memzero(sta->last_tk, WPA_TK_MAX_LEN); forced_memzero(sta->last_tk, WPA_TK_MAX_LEN);
@ -1791,3 +1796,19 @@ int ap_sta_re_add(struct hostapd_data *hapd, struct sta_info *sta)
sta->added_unassoc = 1; sta->added_unassoc = 1;
return 0; return 0;
} }
#ifdef CONFIG_IEEE80211BE
void ap_sta_free_sta_profile(struct mld_info *info)
{
int i;
if (!info)
return;
for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
os_free(info->links[i].resp_sta_profile);
info->links[i].resp_sta_profile = NULL;
}
}
#endif /* CONFIG_IEEE80211BE */

View file

@ -93,7 +93,7 @@ struct mld_info {
u16 status; u16 status;
size_t resp_sta_profile_len; size_t resp_sta_profile_len;
u8 resp_sta_profile[EHT_ML_MAX_STA_PROF_LEN]; u8 *resp_sta_profile;
const u8 *rsne, *rsnxe; const u8 *rsne, *rsnxe;
} links[MAX_NUM_MLD_LINKS]; } links[MAX_NUM_MLD_LINKS];
@ -438,4 +438,6 @@ static inline void ap_sta_set_mld(struct sta_info *sta, bool mld)
#endif /* CONFIG_IEEE80211BE */ #endif /* CONFIG_IEEE80211BE */
} }
void ap_sta_free_sta_profile(struct mld_info *info);
#endif /* STA_INFO_H */ #endif /* STA_INFO_H */