]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
AP MLD: Generate and keep per STA profiles for each link
authorSriram R <quic_srirrama@quicinc.com>
Wed, 7 Aug 2024 06:41:41 +0000 (12:11 +0530)
committerJouni Malinen <j@w1.fi>
Wed, 7 Aug 2024 15:57:09 +0000 (18:57 +0300)
Currently, upon receiving a Probe Request frame, per STA profile is
generated and added to the Probe Response frame. However, the per STA
profile remains unchanged unless there’s a property change in one of the
affliated link of the AP MLD. This approach introduces unnecessary delay
in forming and sending out the Probe Response frame.

To optimize this process, generate the per STA profile for each link at
the start and store it. When needed, it can be simply copied into the
Probe Response frame. Additionally, whenever there’s a change in the
link’s properties, re-generate the per STA profiles for all affiliated
links of the AP MLD.

As an initial step, copy the complete per STA profile and store it
within the links. The intersection with reporting BSS and inheritance
will be addressed in a subsequent change. Then finally, this will be
used to generate the Probe Response frame. As of this commit, no change
in adding per STA profiles in the Probe Response frame.

Signed-off-by: Sriram R <quic_srirrama@quicinc.com>
Co-developed-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
src/ap/beacon.c
src/ap/hostapd.c
src/ap/hostapd.h

index 4a13ea7914bbfc07dba6c16067e9658c7b28b92a..1fd56384e5228b26a9380290f53ae97ad87ce19f 100644 (file)
@@ -2825,12 +2825,175 @@ void ieee802_11_set_beacon_per_bss_only(struct hostapd_data *hapd)
 }
 
 
+#ifdef CONFIG_IEEE80211BE
+
+static int hostapd_get_probe_resp_tmpl(struct hostapd_data *hapd,
+                                      struct probe_resp_params *params,
+                                      bool is_ml_sta_info)
+{
+       os_memset(params, 0, sizeof(*params));
+       hostapd_gen_probe_resp(hapd, params);
+       if (!params->resp)
+               return -1;
+
+       /* The caller takes care of freeing params->resp. */
+       return 0;
+}
+
+
+/* Create the link STA profiles.
+ *
+ * NOTE: The same function is used for length calculation as well as filling
+ * data in the given buffer. This avoids risk of not updating the length
+ * function but filling function or vice versa.
+ */
+static size_t hostapd_add_sta_profile(struct ieee80211_mgmt *link_fdata,
+                                     size_t link_data_len, u8 *sta_profile)
+{
+       const struct element *link_elem;
+       size_t sta_profile_len = 0;
+       const u8 *link_elem_data;
+       u8 link_ele_len;
+       u8 *link_data;
+       /* extra len used in the logic includes the element id and len */
+       u8 extra_len = 2;
+
+       /* Include len for capab info */
+       sta_profile_len += sizeof(le16);
+       if (sta_profile) {
+               os_memcpy(sta_profile, &link_fdata->u.probe_resp.capab_info,
+                         sizeof(le16));
+               sta_profile += sizeof(le16);
+       }
+
+       link_data = link_fdata->u.probe_resp.variable;
+
+       for_each_element(link_elem, link_data, link_data_len) {
+               link_elem_data = link_elem->data;
+               link_ele_len = link_elem->datalen;
+
+               sta_profile_len += link_ele_len + extra_len;
+               if (sta_profile) {
+                       os_memcpy(sta_profile, link_elem_data - extra_len,
+                                 link_ele_len + extra_len);
+                       sta_profile += link_ele_len + extra_len;
+               }
+       }
+
+       return sta_profile_len;
+}
+
+
+static u8 * hostapd_gen_sta_profile(struct ieee80211_mgmt *link_data,
+                                   size_t link_data_len,
+                                   size_t *sta_profile_len)
+{
+       u8 *sta_profile;
+
+       /* Get the length first */
+       *sta_profile_len = hostapd_add_sta_profile(link_data, link_data_len,
+                                                  NULL);
+       if (!(*sta_profile_len) || *sta_profile_len > EHT_ML_MAX_STA_PROF_LEN)
+               return NULL;
+
+       sta_profile = os_zalloc(*sta_profile_len);
+       if (!sta_profile)
+               return NULL;
+
+       /* Now fill in the data */
+       hostapd_add_sta_profile(link_data, link_data_len, sta_profile);
+
+       /* The caller takes care of freeing the returned sta_profile */
+       return sta_profile;
+}
+
+
+static void hostapd_gen_per_sta_profiles(struct hostapd_data *hapd)
+{
+       size_t link_data_len, sta_profile_len;
+       struct probe_resp_params link_params;
+       struct ieee80211_mgmt *link_data;
+       struct mld_link_info *link_info;
+       struct hostapd_data *link_bss;
+       u8 link_id, *sta_profile;
+
+       if (!hapd->conf->mld_ap)
+               return;
+
+       wpa_printf(MSG_DEBUG, "MLD: Generating per STA profiles for MLD %s",
+                  hapd->conf->iface);
+
+       wpa_printf(MSG_DEBUG, "MLD: Reporting link %d", hapd->mld_link_id);
+
+       for_each_mld_link(link_bss, hapd) {
+               if (link_bss == hapd || !link_bss->started)
+                       continue;
+
+               link_id = link_bss->mld_link_id;
+               if (link_id > MAX_NUM_MLD_LINKS)
+                       continue;
+
+               sta_profile = NULL;
+               sta_profile_len = 0;
+
+               /* Generate a Probe Response frame template for partner link */
+               if (hostapd_get_probe_resp_tmpl(link_bss, &link_params, true)) {
+                       wpa_printf(MSG_ERROR,
+                                  "MLD: Could not get link STA probe response template for link %d",
+                                  link_id);
+                       continue;
+               }
+
+               link_data = link_params.resp;
+               link_data_len = link_params.resp_len;
+
+               /* Consider length of the variable fields */
+               link_data_len -= offsetof(struct ieee80211_mgmt,
+                                         u.probe_resp.variable);
+
+               sta_profile = hostapd_gen_sta_profile(link_data, link_data_len,
+                                                     &sta_profile_len);
+               if (!sta_profile) {
+                       wpa_printf(MSG_ERROR,
+                                  "MLD: Could not generate link STA profile for link %d",
+                                  link_id);
+                       continue;
+               }
+
+               link_info = &hapd->partner_links[link_id];
+               link_info->valid = true;
+
+               os_free(link_info->resp_sta_profile);
+               link_info->resp_sta_profile_len = sta_profile_len;
+
+               link_info->resp_sta_profile = os_memdup(sta_profile,
+                                                       sta_profile_len);
+               if (!link_info->resp_sta_profile)
+                       link_info->resp_sta_profile_len = 0;
+
+               os_memcpy(link_info->local_addr, link_bss->own_addr, ETH_ALEN);
+
+               wpa_printf(MSG_DEBUG,
+                          "MLD: Reported link STA info for %d: %u bytes",
+                          link_id, link_info->resp_sta_profile_len);
+
+               os_free(sta_profile);
+               os_free(link_params.resp);
+       }
+}
+
+#endif /* CONFIG_IEEE80211BE */
+
+
 int ieee802_11_set_beacon(struct hostapd_data *hapd)
 {
        struct hostapd_iface *iface = hapd->iface;
        int ret;
        size_t i, j;
        bool is_6g, hapd_mld = false;
+#ifdef CONFIG_IEEE80211BE
+       struct hostapd_data *link_bss;
+#endif /* CONFIG_IEEE80211BE */
 
        ret = __ieee802_11_set_beacon(hapd);
        if (ret != 0)
@@ -2871,6 +3034,15 @@ int ieee802_11_set_beacon(struct hostapd_data *hapd)
                }
        }
 
+#ifdef CONFIG_IEEE80211BE
+       if (!hapd_mld)
+               return 0;
+
+       /* Generate per STA profiles for each affiliated APs */
+       for_each_mld_link(link_bss, hapd)
+               hostapd_gen_per_sta_profiles(link_bss);
+#endif /* CONFIG_IEEE80211BE */
+
        return 0;
 }
 
index 37e08e35dc995ded782b10ac6b98969f23b866e3..146b4960f409f82a90e9c61e7b741cb9c7dbbac7 100644 (file)
@@ -620,9 +620,19 @@ void hostapd_free_hapd_data(struct hostapd_data *hapd)
 static void hostapd_bss_link_deinit(struct hostapd_data *hapd)
 {
 #ifdef CONFIG_IEEE80211BE
+       int i;
+
        if (!hapd->conf || !hapd->conf->mld_ap)
                return;
 
+       /* Free per STA profiles */
+       for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+               os_free(hapd->partner_links[i].resp_sta_profile);
+               os_memset(&hapd->partner_links[i], 0,
+                         sizeof(hapd->partner_links[i]));
+       }
+
+       /* Put all freeing logic above this */
        if (!hapd->mld->num_links)
                return;
 
index 4dc1067cca196215f56dec428c4e15aacb6c2633..0df67038314dda7793e02fba51ae14a399411b0d 100644 (file)
@@ -491,6 +491,10 @@ struct hostapd_data {
        struct hostapd_mld *mld;
        struct dl_list link;
        u8 mld_link_id;
+
+       /* Cached partner info for ML probe response */
+       struct mld_link_info partner_links[MAX_NUM_MLD_LINKS];
+
 #ifdef CONFIG_TESTING_OPTIONS
        u8 eht_mld_link_removal_count;
 #endif /* CONFIG_TESTING_OPTIONS */