]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
AP: Add support for testing ML link removal
authorIlan Peer <ilan.peer@intel.com>
Mon, 20 Nov 2023 23:51:23 +0000 (01:51 +0200)
committerJouni Malinen <j@w1.fi>
Sat, 25 Nov 2023 11:58:37 +0000 (13:58 +0200)
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>
hostapd/ctrl_iface.c
src/ap/beacon.c
src/ap/hostapd.c
src/ap/hostapd.h
src/ap/ieee802_11.c
src/ap/ieee802_11.h
src/ap/ieee802_11_eht.c
src/common/ieee802_11_defs.h

index f91bb1bcba5a422fd18069775092f0b4287017a3..2bc54a52ffe3d75dd543e5ceba2c6748cdd2a71b 100644 (file)
@@ -3445,6 +3445,32 @@ 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,
                                              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_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;
index 1b5cea96b23b816fca4c6bc45a67f9487e30473e..d5f6821e7d3fd102a93b8bd66ad77d38548e851d 100644 (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);
index 236381fe87ef55d841cf8013a6ecd83794a64bee..0fcc4378c04e1064a3aa72c9c23ac63d27474ab6 100644 (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 */
 }
 
index 6dbe569cb796fca559497a6ce2b85cba08b33033..8987b33375d2aba9ab0e520ce3544595a279569a 100644 (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 */
index 30edc5bfc36789aa07597801bb82aa04ad921d00..7de12284d96a850da2daef83f9ce32c23871ac41 100644 (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);
        }
index 4b58fee6243c6e6876da273914b535b68b89bc7a..ada6dc5e88c10a4a5e61d8b29ea94e879f40cd92 100644 (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,
index dce2acf74147f21d5563792de73e8eabf834d2f6..69ff60dd93e745d320d95db67a8c7078bceed8ca 100644 (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);
index 1267c10ebdfa9836283a069912be0451f649293d..7d791d22288f5dbd759365650942dc9318239f69 100644 (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_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 */
 struct ieee80211_eht_per_sta_profile {
        le16 sta_control;