AP: Add support for testing ML link removal

Add support for testing ML link removal to hostapd. While such support
should inherently be integrated with the underlining driver, simulate
the inclusion of the ML reconfiguration element in hostapd.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
This commit is contained in:
Ilan Peer 2023-11-21 01:51:23 +02:00 committed by Jouni Malinen
parent 73a6f5c37e
commit d95838b793
8 changed files with 220 additions and 10 deletions

View file

@ -780,7 +780,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211BE
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
if (hapd->conf->mld_ap)
pos = hostapd_eid_eht_basic_ml(hapd, pos, NULL, true);
pos = hostapd_eid_eht_ml_beacon(hapd, NULL, pos, true);
pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP);
pos = hostapd_eid_eht_operation(hapd, pos);
}
@ -1966,8 +1966,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211BE
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
if (hapd->conf->mld_ap)
tailpos = hostapd_eid_eht_basic_ml(hapd, tailpos, NULL,
true);
tailpos = hostapd_eid_eht_ml_beacon(hapd, NULL,
tailpos, true);
tailpos = hostapd_eid_eht_capab(hapd, tailpos,
IEEE80211_MODE_AP);
tailpos = hostapd_eid_eht_operation(hapd, tailpos);

View file

@ -413,6 +413,61 @@ static void hostapd_clear_drv_priv(struct hostapd_data *hapd)
}
#ifdef CONFIG_IEEE80211BE
#ifdef CONFIG_TESTING_OPTIONS
#define TU_TO_USEC(_val) ((_val) * 1024)
static void hostapd_link_remove_timeout_handler(void *eloop_data,
void *user_ctx)
{
struct hostapd_data *hapd = (struct hostapd_data *) eloop_data;
if (hapd->eht_mld_link_removal_count == 0)
return;
hapd->eht_mld_link_removal_count--;
wpa_printf(MSG_DEBUG, "MLD: Remove link_id=%u in %u beacons",
hapd->mld_link_id,
hapd->eht_mld_link_removal_count);
ieee802_11_set_beacon(hapd);
if (!hapd->eht_mld_link_removal_count) {
hostapd_disable_iface(hapd->iface);
return;
}
eloop_register_timeout(0, TU_TO_USEC(hapd->iconf->beacon_int),
hostapd_link_remove_timeout_handler,
hapd, NULL);
}
int hostapd_link_remove(struct hostapd_data *hapd, u32 count)
{
if (!hapd->conf->mld_ap)
return -1;
wpa_printf(MSG_DEBUG,
"MLD: Remove link_id=%u in %u beacons",
hapd->mld_link_id, count);
hapd->eht_mld_link_removal_count = count;
hapd->eht_mld_bss_param_change++;
eloop_register_timeout(0, TU_TO_USEC(hapd->iconf->beacon_int),
hostapd_link_remove_timeout_handler,
hapd, NULL);
ieee802_11_set_beacon(hapd);
return 0;
}
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_IEEE80211BE */
void hostapd_free_hapd_data(struct hostapd_data *hapd)
{
os_free(hapd->probereq_cb);
@ -525,6 +580,12 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211AX
eloop_cancel_timeout(hostapd_switch_color_timeout_handler, hapd, NULL);
#ifdef CONFIG_TESTING_OPTIONS
#ifdef CONFIG_IEEE80211BE
eloop_cancel_timeout(hostapd_link_remove_timeout_handler, hapd, NULL);
#endif /* CONFIG_IEEE80211BE */
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_IEEE80211AX */
}

View file

@ -471,6 +471,9 @@ struct hostapd_data {
#ifdef CONFIG_IEEE80211BE
u8 eht_mld_bss_param_change;
#ifdef CONFIG_TESTING_OPTIONS
u8 eht_mld_link_removal_count;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_IEEE80211BE */
};
@ -772,5 +775,6 @@ struct hostapd_data * hostapd_mbssid_get_tx_bss(struct hostapd_data *hapd);
int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd);
struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
u8 link_id);
int hostapd_link_remove(struct hostapd_data *hapd, u32 count);
#endif /* HOSTAPD_H */

View file

@ -4893,7 +4893,7 @@ rsnxe_done:
#ifdef CONFIG_IEEE80211BE
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
if (hapd->conf->mld_ap)
p = hostapd_eid_eht_basic_ml(hapd, p, sta, false);
p = hostapd_eid_eht_ml_assoc(hapd, sta, p);
p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP);
p = hostapd_eid_eht_operation(hapd, p);
}

View file

@ -23,6 +23,7 @@ struct ieee802_11_elems;
struct sae_pk;
struct sae_pt;
struct sae_password_entry;
struct mld_info;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi);
@ -88,8 +89,11 @@ void hostapd_get_eht_capab(struct hostapd_data *hapd,
const struct ieee80211_eht_capabilities *src,
struct ieee80211_eht_capabilities *dest,
size_t len);
u8 * hostapd_eid_eht_basic_ml(struct hostapd_data *hapd, u8 *eid,
struct sta_info *info, bool include_mld_id);
u8 * hostapd_eid_eht_ml_beacon(struct hostapd_data *hapd,
struct mld_info *mld_info,
u8 *eid, bool include_mld_id);
u8 * hostapd_eid_eht_ml_assoc(struct hostapd_data *hapd, struct sta_info *info,
u8 *eid);
struct wpabuf * hostapd_ml_auth_resp(struct hostapd_data *hapd);
const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt,

View file

@ -432,8 +432,9 @@ void hostapd_get_eht_capab(struct hostapd_data *hapd,
}
u8 * hostapd_eid_eht_basic_ml(struct hostapd_data *hapd, u8 *eid,
struct sta_info *info, bool include_mld_id)
static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd,
u8 *eid, struct mld_info *mld_info,
bool include_mld_id)
{
struct wpabuf *buf;
u16 control;
@ -500,12 +501,12 @@ u8 * hostapd_eid_eht_basic_ml(struct hostapd_data *hapd, u8 *eid,
wpabuf_put_u8(buf, hapd->conf->mld_id);
}
if (!info)
if (!mld_info)
goto out;
/* Add link info for the other links */
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) {
struct mld_link_info *link = &info->mld_info.links[link_id];
struct mld_link_info *link = &mld_info->links[link_id];
struct hostapd_data *link_bss;
/*
@ -634,6 +635,101 @@ out:
}
static u8 * hostapd_eid_eht_reconf_ml(struct hostapd_data *hapd, u8 *eid)
{
#ifdef CONFIG_TESTING_OPTIONS
struct hostapd_data *other_hapd;
u16 control;
u8 *pos = eid;
unsigned int i;
wpa_printf(MSG_DEBUG, "MLD: Reconfiguration ML");
/* First check if the element needs to be added */
for (i = 0; i < hapd->iface->interfaces->count; i++) {
other_hapd = hapd->iface->interfaces->iface[i]->bss[0];
wpa_printf(MSG_DEBUG, "MLD: Reconfiguration ML: %u",
other_hapd->eht_mld_link_removal_count);
if (other_hapd->eht_mld_link_removal_count)
break;
}
/* No link is going to be removed */
if (i == hapd->iface->interfaces->count)
return eid;
wpa_printf(MSG_DEBUG, "MLD: Reconfiguration ML: Adding element");
/* The length will be set at the end */
*pos++ = WLAN_EID_EXTENSION;
*pos++ = 0;
*pos++ = WLAN_EID_EXT_MULTI_LINK;
/* Set the Multi-Link Control field */
control = MULTI_LINK_CONTROL_TYPE_RECONF;
WPA_PUT_LE16(pos, control);
pos += 2;
/* Common Info doesn't include any information */
*pos++ = 1;
/* Add the per station profiles */
for (i = 0; i < hapd->iface->interfaces->count; i++) {
other_hapd = hapd->iface->interfaces->iface[i]->bss[0];
if (!other_hapd->eht_mld_link_removal_count)
continue;
/* Subelement ID is 0 */
*pos++ = 0;
*pos++ = 5;
control = other_hapd->mld_link_id |
EHT_PER_STA_RECONF_CTRL_AP_REMOVAL_TIMER;
WPA_PUT_LE16(pos, control);
pos += 2;
/* STA profile length */
*pos++ = 3;
WPA_PUT_LE16(pos, other_hapd->eht_mld_link_removal_count);
pos += 2;
}
eid[1] = pos - eid - 2;
wpa_hexdump(MSG_DEBUG, "MLD: Reconfiguration ML", eid, eid[1] + 2);
return pos;
#else /* CONFIG_TESTING_OPTIONS */
return eid;
#endif /* CONFIG_TESTING_OPTIONS */
}
u8 * hostapd_eid_eht_ml_beacon(struct hostapd_data *hapd,
struct mld_info *info,
u8 *eid, bool include_mld_id)
{
eid = hostapd_eid_eht_basic_ml_common(hapd, eid, info, include_mld_id);
return hostapd_eid_eht_reconf_ml(hapd, eid);
}
u8 * hostapd_eid_eht_ml_assoc(struct hostapd_data *hapd, struct sta_info *info,
u8 *eid)
{
if (!info || !info->mld_info.mld_sta)
return eid;
eid = hostapd_eid_eht_basic_ml_common(hapd, eid, &info->mld_info,
false);
return hostapd_eid_eht_reconf_ml(hapd, eid);
}
struct wpabuf * hostapd_ml_auth_resp(struct hostapd_data *hapd)
{
struct wpabuf *buf = wpabuf_alloc(12);