[PATCH v2] Pass more capabilities of MLO link to framework
Bruno.Kremp at sony.com
Bruno.Kremp at sony.com
Fri Dec 19 02:25:46 PST 2025
Pass Channel Bandwidth and Maximum Number of Spatial Stream
of MLO link to framework, the information is necessary to
calculate the theoretical maximum speed for MLO link.
Signed-off-by: Bruno Kremp <bruno.kremp at sony.com>
---
src/common/ieee802_11_common.c | 55 +++++++++++++++++++++++++++----
src/common/ieee802_11_common.h | 9 +++--
wpa_supplicant/events.c | 51 ++++++++++++++++++++++++++++
wpa_supplicant/wpa_supplicant_i.h | 3 ++
4 files changed, 108 insertions(+), 10 deletions(-)
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 5d1e02f81..c0ae42591 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1001,9 +1001,10 @@ void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems,
}
-ParseRes ieee802_11_parse_link_assoc_req(struct ieee802_11_elems *elems,
- struct wpabuf *mlbuf,
- u8 link_id, bool show_errors)
+static ParseRes ieee802_11_parse_link_profile(struct ieee802_11_elems *elems,
+ struct wpabuf *mlbuf,
+ u8 link_id, bool show_errors,
+ bool is_assoc_resp)
{
const struct ieee80211_eht_ml *ml;
const u8 *pos;
@@ -1042,7 +1043,8 @@ ParseRes ieee802_11_parse_link_assoc_req(struct ieee802_11_elems *elems,
"MLD: Failed to parse MLE subelem");
goto out;
}
-
+ if ((size_t) num_frag_subelems * 2 > len)
+ goto out;
len -= num_frag_subelems * 2;
wpa_printf(MSG_DEBUG,
@@ -1101,6 +1103,26 @@ ParseRes ieee802_11_parse_link_assoc_req(struct ieee802_11_elems *elems,
pos += 2;
sub_elem_len -= 2;
+ /* For association response, check status code */
+ if (is_assoc_resp) {
+ if (sub_elem_len < 2) {
+ if (show_errors)
+ wpa_printf(MSG_DEBUG,
+ "MLD: missing status code");
+ goto out;
+ }
+
+ le16 status_code = WPA_GET_LE16(pos);
+ if (le_to_host16(status_code) != WLAN_STATUS_SUCCESS) {
+ wpa_printf(MSG_DEBUG,
+ "MLD: status code %u", status_code);
+ goto out;
+ }
+
+ pos += 2;
+ sub_elem_len -= 2;
+ }
+
/* Handle non-inheritance */
non_inherit = get_ie_ext(pos, sub_elem_len,
WLAN_EID_EXT_NON_INHERITANCE);
@@ -1160,6 +1182,24 @@ out:
}
+ParseRes ieee802_11_parse_link_assoc_req(struct ieee802_11_elems *elems,
+ struct wpabuf *mlbuf,
+ u8 link_id, bool show_errors)
+{
+ return ieee802_11_parse_link_profile(elems, mlbuf, link_id,
+ show_errors, false);
+}
+
+ParseRes ieee802_11_parse_link_assoc_resp(struct ieee802_11_elems *elems,
+ struct wpabuf *mlbuf,
+ u8 link_id, bool show_errors)
+{
+ /* ieee802_11_defrag_mle_subelem() handles subelement defragmentation
+ * in-place within mlbuf */
+ return ieee802_11_parse_link_profile(elems, mlbuf, link_id,
+ show_errors, true);
+}
+
int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
{
const struct element *elem;
@@ -3486,9 +3526,9 @@ struct wpabuf * ieee802_11_defrag(const u8 *data, size_t len, bool ext_elem)
* of data, see IEEE Std 802.11be-2024, Figure 35-4 - Per-STA Profile subelement
* fragmentation within a fragmented Multi-Link element.
*/
-ssize_t ieee802_11_defrag_mle_subelem(struct wpabuf *mlbuf,
- const u8 *parent_subelem,
- size_t *defrag_len)
+int ieee802_11_defrag_mle_subelem(struct wpabuf *mlbuf,
+ const u8 *parent_subelem,
+ size_t *defrag_len)
{
u8 *buf, *pos, *end;
size_t len, subelem_len;
@@ -3524,6 +3564,7 @@ ssize_t ieee802_11_defrag_mle_subelem(struct wpabuf *mlbuf,
return -1;
os_memmove(pos, pos + 2, end - (pos + 2));
+ end -= 2;
pos += elen - 2;
subelem_len += elen - 2;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 09bd0675a..f63379a7f 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -217,6 +217,9 @@ void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems,
ParseRes ieee802_11_parse_link_assoc_req(struct ieee802_11_elems *elems,
struct wpabuf *mlbuf,
u8 link_id, bool show_errors);
+ParseRes ieee802_11_parse_link_assoc_resp(struct ieee802_11_elems *elems,
+ struct wpabuf *mlbuf,
+ u8 link_id, bool show_errors);
int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
u32 oui_type);
@@ -382,9 +385,9 @@ int ieee802_edmg_is_allowed(struct ieee80211_edmg_config allowed,
struct ieee80211_edmg_config requested);
struct wpabuf * ieee802_11_defrag(const u8 *data, size_t len, bool ext_elem);
-ssize_t ieee802_11_defrag_mle_subelem(struct wpabuf *mlbuf,
- const u8 *parent_subelem,
- size_t *defrag_len);
+int ieee802_11_defrag_mle_subelem(struct wpabuf *mlbuf,
+ const u8 *parent_subelem,
+ size_t *defrag_len);
const u8 * get_ml_ie(const u8 *ies, size_t len, u8 type);
const u8 * get_basic_mle_mld_addr(const u8 *buf, size_t len);
const u8 * get_basic_mle_eml_capa(const u8 *buf, size_t len);
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index d831557b3..7a6c0ddf0 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -3501,6 +3501,57 @@ static void wpas_parse_connection_info(struct wpa_supplicant *wpa_s,
} else {
wpa_s->connection_channel_bandwidth = CHAN_WIDTH_20;
}
+
+ struct wpabuf *req_mlbuf = NULL, *resp_mlbuf = NULL;
+
+ req_mlbuf = ieee802_11_defrag(req_elems.basic_mle, req_elems.basic_mle_len, true);
+ resp_mlbuf = ieee802_11_defrag(resp_elems.basic_mle, resp_elems.basic_mle_len, true);
+
+ if (req_mlbuf && resp_mlbuf) {
+ for (int i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(wpa_s->valid_links & BIT(i)))
+ continue;
+
+ struct ieee802_11_elems req_persta_elems = req_elems;
+ struct ieee802_11_elems resp_persta_elems = resp_elems;
+
+ if (ieee802_11_parse_link_assoc_req(&req_persta_elems, req_mlbuf, i, true) == ParseFailed ||
+ ieee802_11_parse_link_assoc_resp(&resp_persta_elems, resp_mlbuf, i, true) == ParseFailed) {
+ wpa_s->links[i].max_nss_rx = wpa_s->connection_max_nss_rx;
+ wpa_s->links[i].max_nss_tx = wpa_s->connection_max_nss_tx;
+ wpa_s->links[i].channel_bandwidth = wpa_s->connection_channel_bandwidth;
+ continue;
+ }
+
+ wpa_s->links[i].max_nss_rx =
+ get_max_nss_capability(&req_persta_elems, 1) > get_max_nss_capability(&resp_persta_elems, 1)
+ ? get_max_nss_capability(&resp_persta_elems, 1)
+ : get_max_nss_capability(&req_persta_elems, 1);
+
+ wpa_s->links[i].max_nss_tx =
+ get_max_nss_capability(&req_persta_elems, 0) > get_max_nss_capability(&resp_persta_elems, 0)
+ ? get_max_nss_capability(&resp_persta_elems, 0)
+ : get_max_nss_capability(&req_persta_elems, 0);
+
+ struct supported_chan_width sta_link_supported_chan_width =
+ get_supported_channel_width(&req_persta_elems);
+ enum chan_width ap_link_operation_chan_width =
+ get_operation_channel_width(&resp_persta_elems);
+
+ if (wpa_s->connection_vht || wpa_s->connection_he || wpa_s->connection_eht) {
+ wpa_s->links[i].channel_bandwidth =
+ get_sta_operation_chan_width(ap_link_operation_chan_width,
+ sta_link_supported_chan_width);
+ } else if (wpa_s->connection_ht) {
+ wpa_s->links[i].channel_bandwidth =
+ (ap_link_operation_chan_width == CHAN_WIDTH_40) ? CHAN_WIDTH_40 : CHAN_WIDTH_20;
+ } else {
+ wpa_s->links[i].channel_bandwidth = CHAN_WIDTH_20;
+ }
+ }
+ wpabuf_free(req_mlbuf);
+ wpabuf_free(resp_mlbuf);
+ }
}
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 4379b053c..485cf6825 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -758,6 +758,9 @@ struct wpa_supplicant {
struct wpa_bss *bss;
bool disabled;
struct wpabuf *ies;
+ unsigned int max_nss_rx:4;
+ unsigned int max_nss_tx:4;
+ enum chan_width channel_bandwidth;
} links[MAX_NUM_MLD_LINKS];
u8 *last_con_fail_realm;
size_t last_con_fail_realm_len;
--
2.50.1
More information about the Hostap
mailing list