From 8eac2331ffb149d6323c8d47fbe4da146a9324db Mon Sep 17 00:00:00 2001 From: Yuvarani V Date: Thu, 21 Mar 2024 02:38:07 +0530 Subject: [PATCH] hostapd: Add support for parsing ML Probe request Currently, AP responds with all Per-STA Profile, included in MLE for a ML Probe Request. Add support to parse link_id from ML Probe Request and include only STA requested APs in MLE in Probe response. Signed-off-by: Yuvarani V --- src/ap/beacon.c | 43 +++++++++++++++++++++------------- src/ap/ieee802_11.c | 6 ++--- src/ap/ieee802_11.h | 6 +++-- src/ap/ieee802_11_eht.c | 15 ++++++++++-- src/ap/wpa_auth_glue.c | 4 ++-- src/common/ieee802_11_common.c | 43 +++++++++++++++++++++++++++++----- src/common/ieee802_11_common.h | 3 ++- src/common/ieee802_11_defs.h | 6 +++++ 8 files changed, 94 insertions(+), 32 deletions(-) --- a/src/ap/beacon.c +++ b/src/ap/beacon.c @@ -43,7 +43,7 @@ static u8 * hostapd_gen_probe_resp(struc const struct ieee80211_mgmt *req, int is_p2p, size_t *resp_len, const u8 *known_bss, u8 known_bss_len, - bool ml_probe); + bool ml_probe, struct multi_link_data *ml_data); static u8 * hostapd_eid_bss_load(struct hostapd_data *hapd, u8 *eid, size_t len) { @@ -848,7 +848,7 @@ void hostapd_gen_per_sta_profiles(struct own_data = (struct ieee80211_mgmt *)hostapd_gen_probe_resp(hapd, NULL, false, &own_data_len, - NULL, 0, false); + NULL, 0, false, NULL); if (own_data == NULL) { wpa_printf(MSG_ERROR, "Error building per sta profile"); @@ -871,7 +871,7 @@ void hostapd_gen_per_sta_profiles(struct link_data = (struct ieee80211_mgmt *)hostapd_gen_probe_resp(link_bss, NULL, false, &link_data_len, - NULL, 0, false); + NULL, 0, false, NULL); if (link_data == NULL) { wpa_printf(MSG_ERROR, "Couldnt generate Link STA profile"); @@ -906,7 +906,7 @@ static u8 * hostapd_gen_probe_resp(struc const struct ieee80211_mgmt *req, int is_p2p, size_t *resp_len, const u8 *known_bss, u8 known_bss_len, - bool ml_probe) + bool ml_probe, struct multi_link_data *ml_data) { struct ieee80211_mgmt *resp; u8 *pos, *epos, *csa_pos; @@ -986,10 +986,18 @@ static u8 * hostapd_gen_probe_resp(struc buflen += (6 + 2 + 4 + sizeof(struct ieee80211_240mhz_vendor_oper)); - if (hapd_probed != hapd && hapd_probed->conf->mld_ap && ml_probe) - buflen += hostapd_eid_eht_basic_ml_len(hapd_probed, - hapd->partner_links, true, - WLAN_FC_STYPE_PROBE_RESP); + if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { + if (hapd->conf->mld_ap) { + if (hapd_probed == hapd && ml_probe) + buflen += hostapd_eid_eht_basic_ml_len(hapd, + hapd->partner_links, false, WLAN_FC_STYPE_PROBE_RESP, ml_data); + else + buflen += hostapd_eid_eht_basic_ml_len(hapd, NULL, false, WLAN_FC_STYPE_PROBE_RESP, NULL); + } + if (hapd_probed != hapd && hapd_probed->conf->mld_ap && ml_probe) + buflen += hostapd_eid_eht_basic_ml_len(hapd_probed, + hapd_probed->partner_links, true, WLAN_FC_STYPE_PROBE_RESP, ml_data); + } } #endif /* CONFIG_IEEE80211BE */ @@ -1166,10 +1174,10 @@ static u8 * hostapd_gen_probe_resp(struc if (hapd_probed == hapd && ml_probe) pos = hostapd_eid_eht_basic_ml(hapd, pos, hapd->partner_links, false, - WLAN_FC_STYPE_PROBE_RESP); + WLAN_FC_STYPE_PROBE_RESP, ml_data); else pos = hostapd_eid_eht_basic_ml(hapd, pos, NULL, false, - WLAN_FC_STYPE_PROBE_RESP); + WLAN_FC_STYPE_PROBE_RESP, NULL); } pos = hostapd_eid_eht_capab(hapd, pos, IEEE80211_MODE_AP); pos = hostapd_eid_eht_operation(hapd, pos, IEEE80211_MODE_AP); @@ -1178,7 +1186,7 @@ static u8 * hostapd_gen_probe_resp(struc if (hapd_probed != hapd && hapd_probed->conf->mld_ap && ml_probe) pos = hostapd_eid_eht_basic_ml(hapd_probed, pos, hapd_probed->partner_links, true, - WLAN_FC_STYPE_PROBE_RESP); + WLAN_FC_STYPE_PROBE_RESP, ml_data); } #endif /* CONFIG_IEEE80211BE */ @@ -1460,7 +1468,9 @@ void handle_probe_req(struct hostapd_dat bool ml_probe = false; struct hostapd_data *hapd_probed = hapd; struct wpabuf *mlbuf = NULL; - u8 mld_id = 0; + struct multi_link_data ml_data; + + os_memset(&ml_data, 0, sizeof(struct multi_link_data)); if (hapd->iconf->rssi_ignore_probe_request && ssi_signal && ssi_signal < hapd->iconf->rssi_ignore_probe_request) @@ -1700,17 +1710,17 @@ void handle_probe_req(struct hostapd_dat #ifdef CONFIG_IEEE80211BE mlbuf = ieee802_11_defrag_mle(&elems, MULTI_LINK_CONTROL_TYPE_PROBE_REQ); - if (hapd->conf->mld_ap && mlbuf && ieee802_11_parse_ml_probe_req(mlbuf, &mld_id)) { + if (hapd->conf->mld_ap && mlbuf && ieee802_11_parse_ml_probe_req(mlbuf, &ml_data)) { ml_probe = true; /* MLD ID Probing */ - if ((hapd == hostapd_mbssid_get_tx_bss(hapd)) && mld_id) { - if (mld_id < hapd->iface->num_bss) - hapd_probed = hapd->iface->bss[mld_id]; + if ((hapd == hostapd_mbssid_get_tx_bss(hapd)) && ml_data.preq.mld_id) { + if (ml_data.preq.mld_id < hapd->iface->num_bss) + hapd_probed = hapd->iface->bss[ml_data.preq.mld_id]; else { wpa_printf(MSG_INFO, "Ignore Probe Request from " MACSTR " since No Matched Non-tx vap found for BSSID Index %d", - MAC2STR(mgmt->sa), mld_id); + MAC2STR(mgmt->sa), ml_data.preq.mld_id); return; } } @@ -1719,7 +1729,7 @@ void handle_probe_req(struct hostapd_dat #endif resp = hostapd_gen_probe_resp(hapd_probed, mgmt, elems.p2p != NULL, &resp_len, elems.mbssid_known_bss, - elems.mbssid_known_bss_len, ml_probe); + elems.mbssid_known_bss_len, ml_probe, &ml_data); if (resp == NULL) return; @@ -1789,7 +1799,7 @@ static u8 * hostapd_probe_resp_offloads( "this"); /* Generate a Probe Response template for the non-P2P case */ - return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, NULL, 0, false); + return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len, NULL, 0, false, NULL); } #endif /* NEED_AP_MLME */ @@ -1820,7 +1830,7 @@ u8 *hostapd_unsol_bcast_probe_resp(struc return hostapd_gen_probe_resp(hapd, NULL, 0, &ubpr->unsol_bcast_probe_resp_tmpl_len, - NULL, 0, false); + NULL, 0, false, NULL); } #endif /* CONFIG_IEEE80211AX */ @@ -2469,7 +2479,7 @@ int ieee802_11_build_ap_params(struct ho if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { if (hapd->conf->mld_ap) tailpos = hostapd_eid_eht_basic_ml(hapd, tailpos, NULL, - false, WLAN_FC_STYPE_BEACON); + false, WLAN_FC_STYPE_BEACON, NULL); tailpos = hostapd_eid_eht_capab(hapd, tailpos, IEEE80211_MODE_AP); startpos = tailpos; --- a/src/ap/ieee802_11.c +++ b/src/ap/ieee802_11.c @@ -5128,7 +5128,7 @@ rsnxe_done: if (hapd->iconf->ieee80211be && !hapd->conf->disable_11be) { if (hapd->conf->mld_ap && sta->mld_info.mld_sta) p = hostapd_eid_eht_basic_ml(hapd, p, sta->mld_info.links, false, - WLAN_FC_STYPE_ASSOC_RESP); + WLAN_FC_STYPE_ASSOC_RESP, NULL); p = hostapd_eid_eht_capab(hapd, p, IEEE80211_MODE_AP); p = hostapd_eid_eht_operation(hapd, p, IEEE80211_MODE_AP); p = hostapd_eid_vendor_240mhz(hapd, p, IEEE80211_MODE_AP); @@ -8750,7 +8750,7 @@ static size_t hostapd_eid_mbssid_elem_le /* For ML Probe resp, solicited hapd's MLE will be in the frame body */ if (bss->conf->mld_ap && (bss != hapd_probed || !ml_probe)) nontx_profile_len += hostapd_eid_eht_basic_ml_len(bss, NULL, true, - frame_type); + frame_type, NULL); #endif /* CONFIG_IEEE80211BE */ if (ie_count || ext_ie_count) { @@ -8932,7 +8932,7 @@ static u8 * hostapd_eid_mbssid_elem(stru #ifdef CONFIG_IEEE80211BE /* For ML Probe resp, solicited hapd's MLE will be in the frame body */ if (bss->conf->mld_ap && (bss != hapd_probed || !ml_probe)) - eid = hostapd_eid_eht_basic_ml(bss, eid, NULL, true, frame_type); + eid = hostapd_eid_eht_basic_ml(bss, eid, NULL, true, frame_type, NULL); #endif /* CONFIG_IEEE80211BE */ if (ie_count || ext_ie_count) { *eid++ = WLAN_EID_EXTENSION; --- a/src/ap/ieee802_11.h +++ b/src/ap/ieee802_11.h @@ -102,10 +102,12 @@ void hostapd_get_eht_capab(struct hostap size_t len); u8 * hostapd_eid_eht_basic_ml(struct hostapd_data *hapd, u8 *eid, struct mld_link_info *link_info, - bool include_mld_id, u32 type); + bool include_mld_id, u32 type, + struct multi_link_data *ml_data); size_t hostapd_eid_eht_basic_ml_len(struct hostapd_data *hapd, struct mld_link_info *info, - bool include_mld_id, u32 type); + bool include_mld_id, u32 type, + struct multi_link_data *ml_data); 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, --- a/src/ap/ieee802_11_eht.c +++ b/src/ap/ieee802_11_eht.c @@ -601,7 +601,8 @@ void hostapd_get_eht_capab(struct hostap */ #define MLE_COMMON_INFO_LEN 13 u8 * hostapd_eid_eht_basic_ml(struct hostapd_data *hapd, u8 *eid, - struct mld_link_info *info, bool include_mld_id, u32 type) + struct mld_link_info *info, bool include_mld_id, u32 type, + struct multi_link_data *ml_data) { struct wpabuf *buf; u16 control, mld_cap; @@ -707,6 +708,11 @@ u8 * hostapd_eid_eht_basic_ml(struct hos struct mld_link_info *link = &info[link_id]; struct hostapd_data *link_bss; + if (ml_data) { + if (!(ml_data->preq.link_bmap & BIT(link_id))) + continue; + } + /* * control (2) + station info length (1) + MAC address (6) + * beacon interval (2) + TSF offset (8) + DTIM info (2) + BSS @@ -850,7 +856,8 @@ out: */ size_t hostapd_eid_eht_basic_ml_len(struct hostapd_data *hapd, struct mld_link_info *info, - bool include_mld_id, u32 type) + bool include_mld_id, u32 type, + struct multi_link_data *ml_data) { int link_id; size_t len, num_frags; @@ -879,6 +886,10 @@ size_t hostapd_eid_eht_basic_ml_len(stru struct mld_link_info *link = &info[link_id]; struct hostapd_data *link_bss; + if (ml_data) { + if (!(ml_data->preq.link_bmap & BIT(link_id))) + continue; + } size_t sta_prof_len = MLE_STA_INFO_LENGTH + link->resp_sta_profile_len; /* Add BSS Parameters Change Count in per STA for (Re)Assoc resp */ --- a/src/ap/wpa_auth_glue.c +++ b/src/ap/wpa_auth_glue.c @@ -1566,7 +1566,7 @@ static u8 *hostapd_wpa_ft_add_bmle(void { struct hostapd_data *hapd = ctx; - return hostapd_eid_eht_basic_ml(hapd, bmle_ie, NULL, true, WLAN_FC_STYPE_AUTH); + return hostapd_eid_eht_basic_ml(hapd, bmle_ie, NULL, true, WLAN_FC_STYPE_AUTH, NULL); } @@ -1574,7 +1574,7 @@ static size_t hostapd_wpa_ft_add_bmle_le { struct hostapd_data *hapd = ctx; - return hostapd_eid_eht_basic_ml_len(hapd, NULL, true, WLAN_FC_STYPE_AUTH); + return hostapd_eid_eht_basic_ml_len(hapd, NULL, true, WLAN_FC_STYPE_AUTH, NULL); } --- a/src/common/ieee802_11_common.c +++ b/src/common/ieee802_11_common.c @@ -1070,10 +1070,11 @@ void ieee802_11_elems_clear_ext_ids(stru } } -bool ieee802_11_parse_ml_probe_req(struct wpabuf *mlbuf, u8 *mld_id) +bool ieee802_11_parse_ml_probe_req(struct wpabuf *mlbuf, struct multi_link_data *ml_data) { const struct ieee80211_eht_ml *ml; const u8 *pos; + const struct element *sub; size_t len, cmn_info_len; u16 ml_control; @@ -1095,21 +1096,51 @@ bool ieee802_11_parse_ml_probe_req(struc return false; } - cmn_info_len = pos; pos += sizeof(ml->ml_control); + cmn_info_len = *pos; if (ml_control & EHT_ML_PRES_BM_PROBE_REQ_AP_MLD_ID) { if (cmn_info_len < 2) { wpa_printf(MSG_DEBUG, "MLD: ML probe req too short for MLD ID"); return false; } - if (mld_id != NULL) - *mld_id = *(pos + 1); + ml_data->preq.mld_id = *(pos + 1); } - /* TODO parse the ML probe request and send response accordingly - * Currently if ML probe request is sent, we support sending all - * link's profile in the ML probe response - */ + pos += cmn_info_len; + len = len - cmn_info_len - sizeof(ml->ml_control); + + /* Link Info not present, send response for all affiliated AP in this MLD */ + if (!len) { + ml_data->preq.link_bmap = 0xffff; + return true; + } + + /* Parse subelements */ + for_each_element_id(sub, 0, pos, len) { + const struct ieee80211_eht_per_sta_profile *sta; + u16 sta_control; + + if (sub->datalen < + sizeof(struct ieee80211_eht_per_sta_profile)) { + ml_data->preq.link_bmap = 0xffff; + wpa_printf(MSG_DEBUG, + "MLD: ML probe req %d too short for sta profile", + sub->datalen); + return true; + } + + sta = (struct ieee80211_eht_per_sta_profile *) sub->data; + + sta_control = le_to_host16(sta->sta_control); + ml_data->preq.link_bmap |= BIT(sta_control & EHT_PER_STA_CTRL_LINK_ID_MSK); + } + + if (!for_each_element_completed(sub, pos, len)) { + wpa_printf(MSG_DEBUG, + "MLD: ML probe req sub-elements parsing error"); + return false; + } + return true; } --- a/src/common/ieee802_11_common.h +++ b/src/common/ieee802_11_common.h @@ -228,7 +228,8 @@ void ieee802_11_elems_clear_ids(struct i const u8 *ids, size_t num); void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems, const u8 *ids, size_t num); -bool ieee802_11_parse_ml_probe_req(struct wpabuf *mlbuf, u8 *mld_id); +bool ieee802_11_parse_ml_probe_req(struct wpabuf *mlbuf, + struct multi_link_data *ml_data); ParseRes ieee802_11_parse_link_assoc_req(const u8 *start, size_t len, struct ieee802_11_elems *elems, struct wpabuf *mlbuf, --- a/src/common/ieee802_11_defs.h +++ b/src/common/ieee802_11_defs.h @@ -2786,6 +2786,13 @@ struct ieee80211_eht_ml { u8 variable[]; } STRUCT_PACKED; +struct multi_link_data { + struct multi_link_preq_info { + u8 mld_id; + u16 link_bmap; + } preq; +}; + /* Table 9-401c - Optional subelement IDs for Link Info field of the * Multi-Link element */ enum ieee80211_eht_ml_sub_elem {