From: Bruno.Kremp@sony.com Date: Fri, 19 Dec 2025 10:25:46 +0000 (+0000) Subject: Determine NSS and bandwidth for each setup link on association event X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9bd9dceae28ace652b9cad2c7b12827d14f966c2;p=thirdparty%2Fhostap.git Determine NSS and bandwidth for each setup link on association event Parse the MLE from the (Re)Association Request and Response frames to get the channel bandwidth and maximum number of spatial streams for each setup link of an ML association. Signed-off-by: Bruno Kremp --- diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c index 387c417a6..74ad41d35 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; @@ -1102,6 +1103,28 @@ 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) { + u16 status_code; + + if (sub_elem_len < 2) { + if (show_errors) + wpa_printf(MSG_DEBUG, + "MLD: missing status code"); + goto out; + } + + status_code = WPA_GET_LE16(pos); + if (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); @@ -1161,6 +1184,26 @@ 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; diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h index 09bd0675a..b1eba593b 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); diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index e74099eec..4ad6c5138 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -3445,6 +3445,53 @@ static int wpa_supplicant_use_own_rsne_params(struct wpa_supplicant *wpa_s, } +static void wpas_parse_connection_info_link(struct wpa_supplicant *wpa_s, + int i, + struct ieee802_11_elems *req_elems, + struct ieee802_11_elems *resp_elems, + struct wpabuf *req_mlbuf, + struct wpabuf *resp_mlbuf) +{ + struct ieee802_11_elems req_persta_elems = *req_elems; + struct ieee802_11_elems resp_persta_elems = *resp_elems; + struct supported_chan_width sta_cw; + enum chan_width ap_cw; + + 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; + return; + } + + wpa_s->links[i].max_nss_rx = + MIN(get_max_nss_capability(&req_persta_elems, true), + get_max_nss_capability(&resp_persta_elems, false)); + + wpa_s->links[i].max_nss_tx = + MIN(get_max_nss_capability(&req_persta_elems, false), + get_max_nss_capability(&resp_persta_elems, true)); + + sta_cw = get_supported_channel_width(&req_persta_elems); + ap_cw = 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_cw, sta_cw); + } else if (wpa_s->connection_ht) { + wpa_s->links[i].channel_bandwidth = (ap_cw == CHAN_WIDTH_40) ? + CHAN_WIDTH_40 : CHAN_WIDTH_20; + } else { + wpa_s->links[i].channel_bandwidth = CHAN_WIDTH_20; + } +} + + static void wpas_parse_connection_info(struct wpa_supplicant *wpa_s, unsigned int freq, const u8 *req_ies, size_t req_ies_len, @@ -3454,6 +3501,7 @@ static void wpas_parse_connection_info(struct wpa_supplicant *wpa_s, int max_nss_rx_req, max_nss_rx_resp, max_nss_tx_req, max_nss_tx_resp; struct supported_chan_width sta_supported_chan_width; enum chan_width ap_operation_chan_width; + struct wpabuf *req_mlbuf, *resp_mlbuf; wpa_s->connection_set = 0; @@ -3502,6 +3550,21 @@ static void wpas_parse_connection_info(struct wpa_supplicant *wpa_s, } else { wpa_s->connection_channel_bandwidth = CHAN_WIDTH_20; } + + 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) { + int i; + + for_each_link(wpa_s->valid_links, i) + wpas_parse_connection_info_link(wpa_s, i, + &req_elems, &resp_elems, + req_mlbuf, resp_mlbuf); + } + 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 8c784304d..968c777d7 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;