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

@ -3445,6 +3445,32 @@ static int hostapd_ctrl_iface_driver_cmd(struct hostapd_data *hapd, char *cmd,
#endif /* ANDROID */ #endif /* ANDROID */
#ifdef CONFIG_IEEE80211BE
#ifdef CONFIG_TESTING_OPTIONS
static int hostapd_ctrl_iface_link_remove(struct hostapd_data *hapd, char *cmd,
char *buf, size_t buflen)
{
int ret;
u32 count = atoi(cmd);
if (!count)
count = 1;
ret = hostapd_link_remove(hapd, count);
if (ret == 0) {
ret = os_snprintf(buf, buflen, "%s\n", "OK");
if (os_snprintf_error(buflen, ret))
ret = -1;
else
ret = 0;
}
return ret;
}
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_IEEE80211BE */
static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd, static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
char *buf, char *reply, char *buf, char *reply,
int reply_size, int reply_size,
@ -3996,6 +4022,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply, reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply,
reply_size); reply_size);
#endif /* ANDROID */ #endif /* ANDROID */
#ifdef CONFIG_IEEE80211BE
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strncmp(buf, "LINK_REMOVE ", 12) == 0) {
if (hostapd_ctrl_iface_link_remove(hapd, buf + 12,
reply, reply_size))
reply_len = -1;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_IEEE80211BE */
} else { } else {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16); os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16; reply_len = 16;

View file

@ -780,7 +780,7 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211BE #ifdef CONFIG_IEEE80211BE
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
if (hapd->conf->mld_ap) 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_capab(hapd, pos, IEEE80211_MODE_AP);
pos = hostapd_eid_eht_operation(hapd, pos); pos = hostapd_eid_eht_operation(hapd, pos);
} }
@ -1966,8 +1966,8 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
#ifdef CONFIG_IEEE80211BE #ifdef CONFIG_IEEE80211BE
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
if (hapd->conf->mld_ap) if (hapd->conf->mld_ap)
tailpos = hostapd_eid_eht_basic_ml(hapd, tailpos, NULL, tailpos = hostapd_eid_eht_ml_beacon(hapd, NULL,
true); tailpos, true);
tailpos = hostapd_eid_eht_capab(hapd, tailpos, tailpos = hostapd_eid_eht_capab(hapd, tailpos,
IEEE80211_MODE_AP); IEEE80211_MODE_AP);
tailpos = hostapd_eid_eht_operation(hapd, tailpos); 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) void hostapd_free_hapd_data(struct hostapd_data *hapd)
{ {
os_free(hapd->probereq_cb); os_free(hapd->probereq_cb);
@ -525,6 +580,12 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
#ifdef CONFIG_IEEE80211AX #ifdef CONFIG_IEEE80211AX
eloop_cancel_timeout(hostapd_switch_color_timeout_handler, hapd, NULL); 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 */ #endif /* CONFIG_IEEE80211AX */
} }

View file

@ -471,6 +471,9 @@ struct hostapd_data {
#ifdef CONFIG_IEEE80211BE #ifdef CONFIG_IEEE80211BE
u8 eht_mld_bss_param_change; u8 eht_mld_bss_param_change;
#ifdef CONFIG_TESTING_OPTIONS
u8 eht_mld_link_removal_count;
#endif /* CONFIG_TESTING_OPTIONS */
#endif /* CONFIG_IEEE80211BE */ #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); int hostapd_mbssid_get_bss_index(struct hostapd_data *hapd);
struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd, struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
u8 link_id); u8 link_id);
int hostapd_link_remove(struct hostapd_data *hapd, u32 count);
#endif /* HOSTAPD_H */ #endif /* HOSTAPD_H */

View file

@ -4893,7 +4893,7 @@ rsnxe_done:
#ifdef CONFIG_IEEE80211BE #ifdef CONFIG_IEEE80211BE
if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) {
if (hapd->conf->mld_ap) 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_capab(hapd, p, IEEE80211_MODE_AP);
p = hostapd_eid_eht_operation(hapd, p); p = hostapd_eid_eht_operation(hapd, p);
} }

View file

@ -23,6 +23,7 @@ struct ieee802_11_elems;
struct sae_pk; struct sae_pk;
struct sae_pt; struct sae_pt;
struct sae_password_entry; struct sae_password_entry;
struct mld_info;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len, int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
struct hostapd_frame_info *fi); struct hostapd_frame_info *fi);
@ -88,8 +89,11 @@ void hostapd_get_eht_capab(struct hostapd_data *hapd,
const struct ieee80211_eht_capabilities *src, const struct ieee80211_eht_capabilities *src,
struct ieee80211_eht_capabilities *dest, struct ieee80211_eht_capabilities *dest,
size_t len); size_t len);
u8 * hostapd_eid_eht_basic_ml(struct hostapd_data *hapd, u8 *eid, u8 * hostapd_eid_eht_ml_beacon(struct hostapd_data *hapd,
struct sta_info *info, bool include_mld_id); 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); struct wpabuf * hostapd_ml_auth_resp(struct hostapd_data *hapd);
const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd, const u8 * hostapd_process_ml_auth(struct hostapd_data *hapd,
const struct ieee80211_mgmt *mgmt, 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, static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd,
struct sta_info *info, bool include_mld_id) u8 *eid, struct mld_info *mld_info,
bool include_mld_id)
{ {
struct wpabuf *buf; struct wpabuf *buf;
u16 control; 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); wpabuf_put_u8(buf, hapd->conf->mld_id);
} }
if (!info) if (!mld_info)
goto out; goto out;
/* Add link info for the other links */ /* Add link info for the other links */
for (link_id = 0; link_id < MAX_NUM_MLD_LINKS; link_id++) { 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; 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 * hostapd_ml_auth_resp(struct hostapd_data *hapd)
{ {
struct wpabuf *buf = wpabuf_alloc(12); struct wpabuf *buf = wpabuf_alloc(12);

View file

@ -2690,6 +2690,17 @@ struct eht_ml_basic_common_info {
#define EHT_PER_STA_CTRL_NSTR_BM_SIZE_MSK 0x0400 #define EHT_PER_STA_CTRL_NSTR_BM_SIZE_MSK 0x0400
#define EHT_PER_STA_CTRL_BSS_PARAM_CNT_PRESENT_MSK 0x0800 #define EHT_PER_STA_CTRL_BSS_PARAM_CNT_PRESENT_MSK 0x0800
/* IEEE P802.11be/D4.1, Figure 9-1001x - STA Control field format for the
* Reconfiguration Multi-Link element */
#define EHT_PER_STA_RECONF_CTRL_LINK_ID_MSK 0x000f
#define EHT_PER_STA_RECONF_CTRL_COMPLETE_PROFILE 0x0010
#define EHT_PER_STA_RECONF_CTRL_MAC_ADDR 0x0020
#define EHT_PER_STA_RECONF_CTRL_AP_REMOVAL_TIMER 0x0040
#define EHT_PER_STA_RECONF_CTRL_OP_UPDATE_TYPE_MSK 0x0780
#define EHT_PER_STA_RECONF_CTRL_OP_PARAMS 0x0800
#define EHT_PER_STA_RECONF_CTRL_NSTR_BITMAP_SIZE 0x1000
#define EHT_PER_STA_RECONF_CTRL_NSTR_INDIC_BITMAP 0x2000
/* IEEE P802.11be/D2.0, 9.4.2.312.2.4 - Per-STA Profile subelement format */ /* IEEE P802.11be/D2.0, 9.4.2.312.2.4 - Per-STA Profile subelement format */
struct ieee80211_eht_per_sta_profile { struct ieee80211_eht_per_sta_profile {
le16 sta_control; le16 sta_control;