]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
AP: Support building Basic Multi-Link element
authorAndrei Otcheretianski <andrei.otcheretianski@intel.com>
Mon, 22 May 2023 19:33:41 +0000 (22:33 +0300)
committerJouni Malinen <j@w1.fi>
Wed, 7 Jun 2023 17:23:21 +0000 (20:23 +0300)
Define a struct to hold MLD station info and implement publishing of the
Basic Multi-Link element. Add it into Beacon and Probe Response frames.

Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
src/ap/beacon.c
src/ap/hostapd.c
src/ap/hostapd.h
src/ap/ieee802_11.h
src/ap/ieee802_11_eht.c
src/ap/sta_info.h
src/common/ieee802_11_defs.h

index 7ff678319779f95198e434601fbb9d4b51861e4d..32c143a2b064e6fc0e1a7d566b4ef045e51873b7 100644 (file)
@@ -605,6 +605,14 @@ static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
                buflen += 3 + sizeof(struct ieee80211_eht_operation);
                if (hapd->iconf->punct_bitmap)
                        buflen += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
+
+               /*
+                * TODO: Multi-Link element has variable length and can be
+                * long based on the common info and number of per
+                * station profiles. For now use 256.
+                */
+               if (hapd->conf->mld_ap)
+                       buflen += 256;
        }
 #endif /* CONFIG_IEEE80211BE */
 
@@ -755,6 +763,8 @@ 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_capab(hapd, pos, IEEE80211_MODE_AP);
                pos = hostapd_eid_eht_operation(hapd, pos);
        }
@@ -1711,6 +1721,14 @@ int ieee802_11_build_ap_params(struct hostapd_data *hapd,
                tail_len += 3 + sizeof(struct ieee80211_eht_operation);
                if (hapd->iconf->punct_bitmap)
                        tail_len += EHT_OPER_DISABLED_SUBCHAN_BITMAP_SIZE;
+
+               /*
+                * TODO: Multi-Link element has variable length and can be
+                * long based on the common info and number of per
+                * station profiles. For now use 256.
+                */
+               if (hapd->conf->mld_ap)
+                       tail_len += 256;
        }
 #endif /* CONFIG_IEEE80211BE */
 
@@ -1881,6 +1899,9 @@ 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_capab(hapd, tailpos,
                                                IEEE80211_MODE_AP);
                tailpos = hostapd_eid_eht_operation(hapd, tailpos);
index f82b87c7c03338a15f78b0325758b5bdf743ec8f..0f6574f5d5b87af9628087088809959af86346ba 100644 (file)
@@ -4260,3 +4260,26 @@ void hostapd_ocv_check_csa_sa_query(void *eloop_ctx, void *timeout_ctx)
        }
 }
 #endif /* CONFIG_OCV */
+
+
+#ifdef CONFIG_IEEE80211BE
+struct hostapd_data * hostapd_mld_get_link_bss(struct hostapd_data *hapd,
+                                              u8 link_id)
+{
+       unsigned int i;
+
+       for (i = 0; i < hapd->iface->interfaces->count; i++) {
+               struct hostapd_iface *h = hapd->iface->interfaces->iface[i];
+               struct hostapd_data *h_hapd = h->bss[0];
+               struct hostapd_bss_config *hconf = h_hapd->conf;
+
+               if (!hconf->mld_ap || hconf->mld_id != hapd->conf->mld_id)
+                       continue;
+
+               if (h_hapd->mld_link_id == link_id)
+                       return h_hapd;
+       }
+
+       return NULL;
+}
+#endif /* CONFIG_IEEE80211BE */
index d0de971bbac5b0d36d695fa5f40fb7f7a1b226e1..d721d15b5ac32732ab5d9a16080ada55ab11805b 100644 (file)
@@ -764,5 +764,7 @@ void fst_hostapd_fill_iface_obj(struct hostapd_data *hapd,
 int hostapd_set_acl(struct hostapd_data *hapd);
 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);
 
 #endif /* HOSTAPD_H */
index 1190a5ea86a26a31d435770166d9ee5fda838df8..b174fdd1f7e411832bedac57bf5f03a196f33b78 100644 (file)
@@ -84,6 +84,8 @@ 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);
 int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta);
 u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
                      const u8 *ht_capab);
index 6ebe0f91d3a1582fd5a570b604644cfcddccba55..79062b003b2184947af106bd48d76d1e304ed827 100644 (file)
@@ -417,3 +417,207 @@ void hostapd_get_eht_capab(struct hostapd_data *hapd,
        os_memset(dest, 0, sizeof(*dest));
        os_memcpy(dest, src, len);
 }
+
+
+u8 * hostapd_eid_eht_basic_ml(struct hostapd_data *hapd, u8 *eid,
+                             struct sta_info *info, bool include_mld_id)
+{
+       struct wpabuf *buf;
+       u16 control;
+       u8 *pos = eid;
+       const u8 *ptr;
+       size_t len, slice_len;
+       u8 link_id;
+       u8 common_info_len;
+
+       /*
+        * As the Multi-Link element can exceed the size of 255 bytes need to
+        * first build it and then handle fragmentation.
+        */
+       buf = wpabuf_alloc(1024);
+       if (!buf)
+               return pos;
+
+       /* Multi-Link Control field */
+       control = MULTI_LINK_CONTROL_TYPE_BASIC |
+               BASIC_MULTI_LINK_CTRL_PRES_LINK_ID |
+               BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
+               BASIC_MULTI_LINK_CTRL_PRES_EML_CAPA |
+               BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA;
+
+       /*
+        * Set the basic Multi-Link common information. Hard code the common
+        * info length to 13 based on the length of the present fields:
+        * Length (1) + MLD address (6) + Link ID (1) +
+        * BSS Parameters Change Count (1) + EML Capabilities (2) +
+        * MLD Capabilities and Operations (2)
+        */
+       common_info_len = 13;
+
+       if (include_mld_id) {
+               /* AP MLD ID */
+               control |= BASIC_MULTI_LINK_CTRL_PRES_AP_MLD_ID;
+               common_info_len++;
+       }
+
+       wpabuf_put_le16(buf, control);
+
+       wpabuf_put_u8(buf, common_info_len);
+
+       /* Own MLD MAC Address */
+       wpabuf_put_data(buf, hapd->mld_addr, ETH_ALEN);
+
+       /* Own Link ID */
+       wpabuf_put_u8(buf, hapd->mld_link_id);
+
+       /* Currently hard code the BSS Parameters Change Count to 0x1 */
+       wpabuf_put_u8(buf, 0x1);
+
+       wpa_printf(MSG_DEBUG, "MLD: EML Capabilities=0x%x",
+                  hapd->iface->mld_eml_capa);
+       wpabuf_put_le16(buf, hapd->iface->mld_eml_capa);
+
+       wpa_printf(MSG_DEBUG, "MLD: MLD Capabilities and Operations=0x%x",
+                  hapd->iface->mld_mld_capa);
+       wpabuf_put_le16(buf, hapd->iface->mld_mld_capa);
+
+       if (include_mld_id) {
+               wpa_printf(MSG_DEBUG, "MLD: AP MLD ID=0x%x",
+                          hapd->conf->mld_id);
+               wpabuf_put_u8(buf, hapd->conf->mld_id);
+       }
+
+       if (!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 hostapd_data *link_bss;
+
+               /*
+                * control (2) + station info length (1) + MAC address (6) +
+                * beacon interval (2) + TSF offset (8) + DTIM info (2) + BSS
+                * parameters change counter (1) + station profile length.
+                */
+               const size_t fixed_len = 22;
+               size_t total_len = fixed_len + link->resp_sta_profile_len;
+
+               /* Skip the local one */
+               if (link_id == hapd->mld_link_id || !link->valid)
+                       continue;
+
+               link_bss = hostapd_mld_get_link_bss(hapd, link_id);
+               if (!link_bss) {
+                       wpa_printf(MSG_ERROR,
+                                  "MLD: Couldn't find link BSS - skip it");
+                       continue;
+               }
+
+               /* Per-STA Profile subelement */
+               wpabuf_put_u8(buf, EHT_ML_SUB_ELEM_PER_STA_PROFILE);
+
+               if (total_len <= 255)
+                       wpabuf_put_u8(buf, total_len);
+               else
+                       wpabuf_put_u8(buf, 255);
+
+               /* STA Control */
+               control = (link_id & 0xf) |
+                       EHT_PER_STA_CTRL_MAC_ADDR_PRESENT_MSK |
+                       EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK |
+                       EHT_PER_STA_CTRL_TSF_OFFSET_PRESENT_MSK |
+                       EHT_PER_STA_CTRL_BEACON_INTERVAL_PRESENT_MSK |
+                       EHT_PER_STA_CTRL_DTIM_INFO_PRESENT_MSK |
+                       EHT_PER_STA_CTRL_BSS_PARAM_CNT_PRESENT_MSK;
+               wpabuf_put_le16(buf, control);
+
+               /* STA Info */
+
+               /* STA Info Length */
+               wpabuf_put_u8(buf, fixed_len - 2);
+               wpabuf_put_data(buf, link->local_addr, ETH_ALEN);
+               wpabuf_put_le16(buf, link_bss->iconf->beacon_int);
+
+               /* TSF Offset */
+               /*
+                * TODO: Currently setting TSF offset to zero. However, this
+                * information needs to come from the driver.
+                */
+               wpabuf_put_le64(buf, 0);
+
+               /* DTIM Info */
+               wpabuf_put_le16(buf, link_bss->conf->dtim_period);
+
+               /* BSS Parameters Change Count */
+               /* TODO: Currently hard code the BSS Parameters Change Count to
+                * 0x1 */
+               wpabuf_put_u8(buf, 0x1);
+
+               /* Fragment the sub element if needed */
+               if (total_len <= 255) {
+                       wpabuf_put_data(buf, link->resp_sta_profile,
+                                       link->resp_sta_profile_len);
+               } else {
+                       ptr = link->resp_sta_profile;
+                       len = link->resp_sta_profile_len;
+
+                       slice_len = 255 - fixed_len;
+
+                       wpabuf_put_data(buf, ptr, slice_len);
+                       len -= slice_len;
+                       ptr += slice_len;
+
+                       while (len) {
+                               if (len <= 255)
+                                       slice_len = len;
+                               else
+                                       slice_len = 255;
+
+                               wpabuf_put_u8(buf, EHT_ML_SUB_ELEM_FRAGMENT);
+                               wpabuf_put_u8(buf, slice_len);
+                               wpabuf_put_data(buf, ptr, slice_len);
+
+                               len -= slice_len;
+                               ptr += slice_len;
+                       }
+               }
+       }
+
+out:
+       /* Fragment the Multi-Link element, if needed */
+       len = wpabuf_len(buf);
+       ptr = wpabuf_head(buf);
+
+       if (len <= 254)
+               slice_len = len;
+       else
+               slice_len = 254;
+
+       *pos++ = WLAN_EID_EXTENSION;
+       *pos++ = slice_len + 1;
+       *pos++ = WLAN_EID_EXT_MULTI_LINK;
+       os_memcpy(pos, ptr, slice_len);
+
+       ptr += slice_len;
+       pos += slice_len;
+       len -= slice_len;
+
+       while (len) {
+               if (len <= 255)
+                       slice_len = len;
+               else
+                       slice_len = 255;
+
+               *pos++ = WLAN_EID_FRAGMENT;
+               *pos++ = slice_len;
+               os_memcpy(pos, ptr, slice_len);
+
+               ptr += slice_len;
+               pos += slice_len;
+               len -= slice_len;
+       }
+
+       wpabuf_free(buf);
+       return pos;
+}
index 8433ff8d6071acf5bd1c59ebe049297f57a27cc6..e2b9dde876792a506b14fdc561736936eb777fdb 100644 (file)
@@ -69,6 +69,35 @@ struct pending_eapol_rx {
        enum frame_encryption encrypted;
 };
 
+#define EHT_ML_MAX_STA_PROF_LEN 1024
+struct mld_info {
+       bool mld_sta;
+
+       struct ml_common_info {
+               u8 mld_addr[ETH_ALEN];
+               u16 medium_sync_delay;
+               u16 eml_capa;
+               u16 mld_capa;
+       } common_info;
+
+       struct mld_link_info {
+               u8 valid;
+               u8 local_addr[ETH_ALEN];
+               u8 peer_addr[ETH_ALEN];
+
+               size_t nstr_bitmap_len;
+               u8 nstr_bitmap[2];
+
+               u16 capability;
+
+               u16 status;
+               size_t resp_sta_profile_len;
+               u8 resp_sta_profile[EHT_ML_MAX_STA_PROF_LEN];
+
+               const u8 *rsne, *rsnxe;
+       } links[MAX_NUM_MLD_LINKS];
+};
+
 struct sta_info {
        struct sta_info *next; /* next entry in sta list */
        struct sta_info *hnext; /* next entry in hash table list */
@@ -299,6 +328,11 @@ struct sta_info {
 #ifdef CONFIG_PASN
        struct pasn_data *pasn;
 #endif /* CONFIG_PASN */
+
+#ifdef CONFIG_IEEE80211BE
+       struct mld_info mld_info;
+       u8 mld_assoc_link_id;
+#endif /* CONFIG_IEEE80211BE */
 };
 
 
index b86906828271af0bf55352187caa711090bca648..571ace2f5100aa08a560710f859341d1fbc436a9 100644 (file)
@@ -2660,6 +2660,16 @@ struct eht_ml_basic_common_info {
 #define EHT_ML_MLD_CAPA_FREQ_SEP_FOR_STR_MASK         0x0f80
 #define EHT_ML_MLD_CAPA_AAR_SUPP                      0x1000
 
+#define EHT_PER_STA_CTRL_LINK_ID_MSK                  0x000f
+#define EHT_PER_STA_CTRL_COMPLETE_PROFILE_MSK         0x0010
+#define EHT_PER_STA_CTRL_MAC_ADDR_PRESENT_MSK         0x0020
+#define EHT_PER_STA_CTRL_BEACON_INTERVAL_PRESENT_MSK  0x0040
+#define EHT_PER_STA_CTRL_TSF_OFFSET_PRESENT_MSK       0x0080
+#define EHT_PER_STA_CTRL_DTIM_INFO_PRESENT_MSK        0x0100
+#define EHT_PER_STA_CTRL_NSTR_LINK_PAIR_PRESENT_MSK   0x0200
+#define EHT_PER_STA_CTRL_NSTR_BM_SIZE_MSK             0x0400
+#define EHT_PER_STA_CTRL_BSS_PARAM_CNT_PRESENT_MSK    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;