[PATCH 09/42] AP: Add support for testing ML link removal
Andrei Otcheretianski
andrei.otcheretianski at intel.com
Mon Nov 20 15:51:23 PST 2023
From: Ilan Peer <ilan.peer at intel.com>
Add support for testing ML link removal to hostapd.
While such support should inherently be integrated with
the underline driver, simulate the inclusion of the
ML reconfiguration element in hostapd.
Signed-off-by: Ilan Peer <ilan.peer at intel.com>
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski at intel.com>
---
hostapd/ctrl_iface.c | 35 ++++++++++++
src/ap/beacon.c | 6 +-
src/ap/hostapd.c | 59 +++++++++++++++++++
src/ap/hostapd.h | 5 +-
src/ap/ieee802_11.c | 2 +-
src/ap/ieee802_11.h | 8 ++-
src/ap/ieee802_11_eht.c | 106 +++++++++++++++++++++++++++++++++--
src/common/ieee802_11_defs.h | 7 +++
8 files changed, 217 insertions(+), 11 deletions(-)
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index f91bb1bcba..6ad86142e6 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -3444,6 +3444,33 @@ static int hostapd_ctrl_iface_driver_cmd(struct hostapd_data *hapd, char *cmd,
}
#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,
char *buf, char *reply,
@@ -3996,6 +4023,14 @@ static int hostapd_ctrl_iface_receive_process(struct hostapd_data *hapd,
reply_len = hostapd_ctrl_iface_driver_cmd(hapd, buf + 7, reply,
reply_size);
#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 {
os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 1b5cea96b2..d5f6821e7d 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -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);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 236381fe87..b6031014d4 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -412,6 +412,59 @@ static void hostapd_clear_drv_priv(struct hostapd_data *hapd)
hapd->drv_priv = NULL;
}
+#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;
+
+ 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)
{
@@ -525,6 +578,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 */
}
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index 6dbe569cb7..6f0c0fc66d 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -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,5 @@ 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 */
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 30edc5bfc3..7de12284d9 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -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);
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index 4b58fee624..ada6dc5e88 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -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,
diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c
index 3167764fff..7b60e6647a 100644
--- a/src/ap/ieee802_11_eht.c
+++ b/src/ap/ieee802_11_eht.c
@@ -421,8 +421,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;
@@ -489,12 +490,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;
/*
@@ -623,6 +624,103 @@ 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;
+ u32 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 would 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;
+
+ /* sub element 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 dump: ",
+ eid, eid[1] + 2);
+ return pos;
+#else
+ 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);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 3c08ef19cf..312b1bc0bf 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -2690,6 +2690,13 @@ struct eht_ml_basic_common_info {
#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_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
+
/* IEEE P802.11be/D2.0, 9.4.2.312.2.4 - Per-STA Profile subelement format */
struct ieee80211_eht_per_sta_profile {
le16 sta_control;
--
2.38.1
More information about the Hostap
mailing list