From: Benjamin Berg <benjamin.berg@xxxxxxxxx> This responds by simply embedding most of the IEs from the other links into the ML element. This is not correct really, as inheritance rules should be applied and an inheritance element may need to be added. Signed-off-by: Benjamin Berg <benjamin.berg@xxxxxxxxx> Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@xxxxxxxxx> --- src/ap/beacon.c | 216 +++++++++++++++++++++++++++++++++------- src/ap/ieee802_11.h | 3 + src/ap/ieee802_11_eht.c | 64 ++++++++++-- 3 files changed, 241 insertions(+), 42 deletions(-) diff --git a/src/ap/beacon.c b/src/ap/beacon.c index e8acedd32b..c72da1b88d 100644 --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -568,6 +568,11 @@ struct probe_resp_params { const struct ieee80211_mgmt *req; bool is_p2p; + /* Generated IEs will be included inside an ML element */ + bool is_ml_sta_info; + struct hostapd_data *mld_ap; + struct mld_info *mld_info; + struct ieee80211_mgmt *resp; size_t resp_len; u8 *csa_pos; @@ -629,20 +634,18 @@ static size_t hostapd_probe_resp_elems_len(struct hostapd_data *hapd, 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; + if (!params->is_ml_sta_info && hapd->conf->mld_ap) { + struct hostapd_data *ml_elem_ap = + params->mld_ap ? params->mld_ap : hapd; + + buflen += hostapd_eid_eht_ml_beacon_len( + ml_elem_ap, params->mld_info, !!params->mld_ap); + } } #endif /* CONFIG_IEEE80211BE */ - buflen += hostapd_eid_mbssid_len(hapd, WLAN_FC_STYPE_PROBE_RESP, NULL, - params->known_bss, - params->known_bss_len, NULL); - buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP); + if (!params->is_ml_sta_info) + buflen += hostapd_eid_rnr_len(hapd, WLAN_FC_STYPE_PROBE_RESP); buflen += hostapd_mbo_ie_len(hapd); buflen += hostapd_eid_owe_trans_len(hapd); buflen += hostapd_eid_dpp_cc_len(hapd); @@ -660,10 +663,13 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd, epos = pos + len; - *pos++ = WLAN_EID_SSID; - *pos++ = hapd->conf->ssid.ssid_len; - os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len); - pos += hapd->conf->ssid.ssid_len; + if (!params->is_ml_sta_info) { + *pos++ = WLAN_EID_SSID; + *pos++ = hapd->conf->ssid.ssid_len; + os_memcpy(pos, hapd->conf->ssid.ssid, + hapd->conf->ssid.ssid_len); + pos += hapd->conf->ssid.ssid_len; + } /* Supported rates */ pos = hostapd_eid_supp_rates(hapd, pos); @@ -676,13 +682,18 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd, /* Power Constraint element */ pos = hostapd_eid_pwr_constraint(hapd, pos); - /* CSA IE */ - csa_pos = hostapd_eid_csa(hapd, pos); - if (csa_pos != pos) - params->csa_pos = csa_pos - 1; - else - params->csa_pos = NULL; - pos = csa_pos; + /* + * CSA IE + * TODO: This should be included inside the ML sta profile + */ + if (!params->is_ml_sta_info) { + csa_pos = hostapd_eid_csa(hapd, pos); + if (csa_pos != pos) + params->csa_pos = csa_pos - 1; + else + params->csa_pos = NULL; + pos = csa_pos; + } /* ERP Information element */ pos = hostapd_eid_erp_info(hapd, pos); @@ -698,13 +709,18 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd, pos = hostapd_eid_rm_enabled_capab(hapd, pos, epos - pos); pos = hostapd_get_mde(hapd, pos, epos - pos); - /* eCSA IE */ - csa_pos = hostapd_eid_ecsa(hapd, pos); - if (csa_pos != pos) - params->ecsa_pos = csa_pos - 1; - else - params->ecsa_pos = NULL; - pos = csa_pos; + /* + * eCSA IE + * TODO: This should be included inside the ML sta profile + */ + if (!params->is_ml_sta_info) { + csa_pos = hostapd_eid_ecsa(hapd, pos); + if (csa_pos != pos) + params->ecsa_pos = csa_pos - 1; + else + params->ecsa_pos = NULL; + pos = csa_pos; + } pos = hostapd_eid_supported_op_classes(hapd, pos); pos = hostapd_eid_ht_capabilities(hapd, pos); @@ -748,7 +764,8 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd, pos = hostapd_eid_wb_chsw_wrapper(hapd, pos); - pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP); + if (!params->is_ml_sta_info) + pos = hostapd_eid_rnr(hapd, pos, WLAN_FC_STYPE_PROBE_RESP); pos = hostapd_eid_fils_indic(hapd, pos, 0); pos = hostapd_get_rsnxe(hapd, pos, epos - pos); @@ -775,8 +792,14 @@ static u8 * hostapd_probe_resp_fill_elems(struct hostapd_data *hapd, #ifdef CONFIG_IEEE80211BE if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { - if (hapd->conf->mld_ap) - pos = hostapd_eid_eht_ml_beacon(hapd, NULL, pos, true); + struct hostapd_data *ml_elem_ap = + params->mld_ap ? params->mld_ap : hapd; + + if (ml_elem_ap->conf->mld_ap) + pos = hostapd_eid_eht_ml_beacon( + ml_elem_ap, params->mld_info, + pos, !!params->mld_ap); + pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP); pos = hostapd_eid_eht_operation(hapd, pos); } @@ -882,6 +905,117 @@ void hostapd_gen_probe_resp(struct hostapd_data *hapd, } +#ifdef CONFIG_IEEE80211BE +static void hostapd_fill_probe_resp_ml_params(struct hostapd_data *hapd, + struct probe_resp_params *params, + const struct ieee80211_mgmt *mgmt, + int mld_id, u16 links) +{ + struct probe_resp_params sta_info_params; + struct hostapd_data *link; + u8 probed_mld_id, i, j; + + params->mld_ap = NULL; + params->mld_info = os_zalloc(sizeof(*params->mld_info)); + if (!params->mld_info) + return; + + wpa_printf(MSG_DEBUG, + "MLD: Got ML probe request with AP MLD ID %d for links %04x", + mld_id, links); + + /* + * We want to include the AP MLD ID in the response if it was + * included in the request. + */ + probed_mld_id = mld_id != -1 ? mld_id : hapd->conf->mld_id; + + for_each_mld_link(link, i, j, hapd->iface->interfaces, + probed_mld_id) { + struct mld_link_info *link_info; + size_t buflen; + u8 mld_link_id = link->mld_link_id; + u8 *epos; + + /* + * Set mld_ap iff the ML probe request explicitly + * requested a specific MLD ID. In that case, targeted + * AP may have been a nontransmitted BSSID on the same + * interface. + */ + if (mld_id != -1 && link->iface == hapd->iface) + params->mld_ap = link; + + /* Never duplicate main probe response body */ + if (link == hapd) + continue; + + /* Only include requested links */ + if (!(BIT(mld_link_id) & links)) + continue; + + link_info = ¶ms->mld_info->links[mld_link_id]; + + sta_info_params.req = params->req; + sta_info_params.is_p2p = false; + sta_info_params.is_ml_sta_info = true; + sta_info_params.mld_ap = NULL; + sta_info_params.mld_info = NULL; + + buflen = MAX_PROBERESP_LEN; + buflen += hostapd_probe_resp_elems_len(link, &sta_info_params); + + if (buflen > sizeof(link_info->resp_sta_profile)) { + wpa_printf(MSG_DEBUG, + "MLD: Not including link %d in ML probe response (%zu bytes is too long)", + mld_link_id, buflen); + goto fail; + } + + /* + * NOTE: This does not properly handle inheritance and + * various other things. + */ + link_info->valid = true; + epos = link_info->resp_sta_profile; + + /* capabilities is the only fixed parameter */ + WPA_PUT_LE16(link_info->resp_sta_profile, + hostapd_own_capab_info(hapd)); + + epos = hostapd_probe_resp_fill_elems( + link, &sta_info_params, + link_info->resp_sta_profile + 2, + sizeof(link_info->resp_sta_profile) - 2); + link_info->resp_sta_profile_len = + epos - link_info->resp_sta_profile; + os_memcpy(link_info->local_addr, link->own_addr, + ETH_ALEN); + + wpa_printf(MSG_DEBUG, + "MLD: ML probe response includes link sta info for %d: %zu bytes (estimate %zu)", + mld_link_id, + link_info->resp_sta_profile_len, + buflen); + } + + if (mld_id != -1 && !params->mld_ap) { + wpa_printf(MSG_DEBUG, + "MLD: No nontransmitted BSSID for MLD ID %d", + mld_id); + goto fail; + } + + return; + +fail: + os_free(params->mld_info); + params->mld_ap = NULL; + params->mld_info = NULL; +} +#endif /* CONFIG_IEEE80211BE */ + + enum ssid_match_result { NO_SSID_MATCH, EXACT_SSID_MATCH, @@ -1330,13 +1464,14 @@ void handle_probe_req(struct hostapd_data *hapd, wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, RX_PROBE_REQUEST "sa=" MACSTR " signal=%d", MAC2STR(mgmt->sa), ssi_signal); + os_memset(¶ms, 0, sizeof(params)); + #ifdef CONFIG_IEEE80211BE if (hapd->conf->mld_ap && elems.probe_req_mle && parse_ml_probe_req((struct ieee80211_eht_ml *)elems.probe_req_mle, elems.probe_req_mle_len, &mld_id, &links)) { - wpa_printf(MSG_DEBUG, - "MLD: Got ML probe request with AP MLD ID %d for links %04x", - mld_id, links); + hostapd_fill_probe_resp_ml_params(hapd, ¶ms, mgmt, + mld_id, links); } #endif /* CONFIG_IEEE80211BE */ @@ -1344,7 +1479,12 @@ void handle_probe_req(struct hostapd_data *hapd, params.is_p2p = !!elems.p2p; params.known_bss = elems.mbssid_known_bss; params.known_bss_len = elems.mbssid_known_bss_len; + params.is_ml_sta_info = false; + hostapd_gen_probe_resp(hapd, ¶ms); + + os_free(params.mld_info); + if (!params.resp) return; @@ -1419,6 +1559,9 @@ static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd, params.is_p2p = false; params.known_bss = NULL; params.known_bss_len = 0; + params.is_ml_sta_info = false; + params.mld_ap = NULL; + params.mld_info = NULL; hostapd_gen_probe_resp(hapd, ¶ms); *resp_len = params.resp_len; @@ -1453,6 +1596,9 @@ static u8 * hostapd_unsol_bcast_probe_resp(struct hostapd_data *hapd, probe_params.is_p2p = false; probe_params.known_bss = NULL; probe_params.known_bss_len = 0; + probe_params.is_ml_sta_info = false; + probe_params.mld_ap = NULL; + probe_params.mld_info = NULL; hostapd_gen_probe_resp(hapd, &probe_params); params->unsol_bcast_probe_resp_tmpl_len = probe_params.resp_len; diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h index ada6dc5e88..dce26c398d 100644 --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -94,6 +94,9 @@ u8 * hostapd_eid_eht_ml_beacon(struct hostapd_data *hapd, u8 *eid, bool include_mld_id); u8 * hostapd_eid_eht_ml_assoc(struct hostapd_data *hapd, struct sta_info *info, u8 *eid); +size_t hostapd_eid_eht_ml_beacon_len(struct hostapd_data *hapd, + struct mld_info *info, + bool include_mld_id); 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, diff --git a/src/ap/ieee802_11_eht.c b/src/ap/ieee802_11_eht.c index 7b60e6647a..3c5334a203 100644 --- a/src/ap/ieee802_11_eht.c +++ b/src/ap/ieee802_11_eht.c @@ -455,7 +455,8 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd, * BSS Parameters Change Count (1) + EML Capabilities (2) + * MLD Capabilities and Operations (2) */ - common_info_len = 13; +#define EHT_ML_COMMON_INFO_LEN 13 + common_info_len = EHT_ML_COMMON_INFO_LEN; if (include_mld_id) { /* AP MLD ID */ @@ -503,8 +504,9 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd, * 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; +#define EHT_ML_STA_INFO_LEN 22 + size_t total_len = EHT_ML_STA_INFO_LEN + + link->resp_sta_profile_len; /* Skip the local one */ if (link_id == hapd->mld_link_id || !link->valid) @@ -535,10 +537,8 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd, 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_u8(buf, EHT_ML_STA_INFO_LEN - 2); wpabuf_put_data(buf, link->local_addr, ETH_ALEN); wpabuf_put_le16(buf, link_bss->iconf->beacon_int); @@ -563,7 +563,7 @@ static u8 * hostapd_eid_eht_basic_ml_common(struct hostapd_data *hapd, ptr = link->resp_sta_profile; len = link->resp_sta_profile_len; - slice_len = 255 - fixed_len; + slice_len = 255 - EHT_ML_STA_INFO_LEN; wpabuf_put_data(buf, ptr, slice_len); len -= slice_len; @@ -700,6 +700,48 @@ static u8 *hostapd_eid_eht_reconf_ml(struct hostapd_data *hapd, } +static size_t hostapd_eid_eht_ml_len(struct mld_info *info, + bool include_mld_id) +{ + size_t len = 0; + size_t eht_ml_len = 2 + EHT_ML_COMMON_INFO_LEN; + u8 link_id; + + if (include_mld_id) + eht_ml_len += 1; + + for (link_id = 0; + info && link_id < ARRAY_SIZE(info->links); + link_id++) { + struct mld_link_info *link; + int sta_len = EHT_ML_STA_INFO_LEN; + + link = &info->links[link_id]; + if (!link->valid) + continue; + + sta_len += link->resp_sta_profile_len; + + /* Element data and (fragmentation) headers */ + eht_ml_len += sta_len; + eht_ml_len += 2 + sta_len / 255 * 2; + } + + /* Element data */ + len += eht_ml_len; + + /* First header (254 bytes of data) */ + len += 3; + + /* Fragmentation headers; +1 for shorter first chunk */ + len += (eht_ml_len + 1) / 255 * 2; + + return len; +} +#undef EHT_ML_COMMON_INFO_LEN +#undef EHT_ML_STA_INFO_LEN + + u8 * hostapd_eid_eht_ml_beacon(struct hostapd_data *hapd, struct mld_info *info, u8 *eid, bool include_mld_id) @@ -721,6 +763,14 @@ u8 * hostapd_eid_eht_ml_assoc(struct hostapd_data *hapd, struct sta_info *info, } +size_t hostapd_eid_eht_ml_beacon_len(struct hostapd_data *hapd, + struct mld_info *info, + bool include_mld_id) +{ + return hostapd_eid_eht_ml_len(info, include_mld_id); +} + + struct wpabuf * hostapd_ml_auth_resp(struct hostapd_data *hapd) { struct wpabuf *buf = wpabuf_alloc(12); -- 2.38.1 _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap