From 7b9070229d828a9d50f110d92bf0b1a4cdd41eb7 Mon Sep 17 00:00:00 2001 From: Shivani Baranwal Date: Wed, 24 May 2023 14:44:55 +0530 Subject: [PATCH] Indicate TID to link mapping changes with QCA vendor interface Add support to indicate TID-to-link mapping changes reported by the QCA vendor interface to the wpa_supplicant control interface. Signed-off-by: Shivani Baranwal --- src/common/wpa_ctrl.h | 2 + src/drivers/driver.h | 33 ++++++++ src/drivers/driver_common.c | 1 + src/drivers/driver_nl80211.c | 20 ++++- src/drivers/driver_nl80211.h | 2 + src/drivers/driver_nl80211_event.c | 131 +++++++++++++++++++++++++++++ wpa_supplicant/events.c | 57 +++++++++++++ 7 files changed, 244 insertions(+), 2 deletions(-) diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h index 4ab2a1b63..57d69ae2e 100644 --- a/src/common/wpa_ctrl.h +++ b/src/common/wpa_ctrl.h @@ -110,6 +110,8 @@ extern "C" { #define WPA_EVENT_DO_ROAM "CTRL-EVENT-DO-ROAM " /** Decision made to skip a within-ESS roam */ #define WPA_EVENT_SKIP_ROAM "CTRL-EVENT-SKIP-ROAM " +/** TID-to-link mapping response event */ +#define WPA_EVENT_T2LM_UPDATE "CTRL-EVENT-T2LM-UPDATE " /** IP subnet status change notification * diff --git a/src/drivers/driver.h b/src/drivers/driver.h index 101f98a72..c68cc415e 100644 --- a/src/drivers/driver.h +++ b/src/drivers/driver.h @@ -430,6 +430,18 @@ struct wpa_driver_scan_ssid { size_t ssid_len; }; +struct t2lm_mapping { + /** + * downlink - Bitmap of TIDs mapped with a link in downlink direction + */ + u8 downlink; + + /** + * uplink - Bitmap of TIDs mapped with a link in uplink direction + */ + u8 uplink; +}; + /** * struct wpa_driver_scan_params - Scan parameters * Data for struct wpa_driver_ops::scan2(). @@ -2911,6 +2923,7 @@ struct weighted_pcl { }; struct driver_sta_mlo_info { + bool default_map; u16 req_links; /* bitmap of requested link IDs */ u16 valid_links; /* bitmap of accepted link IDs */ u8 assoc_link_id; @@ -2919,6 +2932,7 @@ struct driver_sta_mlo_info { u8 addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; unsigned int freq; + struct t2lm_mapping t2lmap; } links[MAX_NUM_MLD_LINKS]; }; @@ -5640,6 +5654,16 @@ enum wpa_event_type { * Described in wpa_event_data.ch_switch. */ EVENT_LINK_CH_SWITCH_STARTED, + + /** + * EVENT_TID_LINK_MAP - MLD event to set TID-to-link mapping + * + * This event is used by the driver to indicate the received TID-to-link + * mapping response from the associated AP MLD. + * + * Described in wpa_event_data.t2l_map_info. + */ + EVENT_TID_LINK_MAP, }; @@ -6564,6 +6588,15 @@ union wpa_event_data { const u8 *td_bitmap; size_t td_bitmap_len; } port_authorized; + + /** + * struct tid_link_map_info - Data for EVENT_TID_LINK_MAP + */ + struct tid_link_map_info { + bool default_map; + u8 valid_links; + struct t2lm_mapping t2lmap[MAX_NUM_MLD_LINKS]; + } t2l_map_info; }; /** diff --git a/src/drivers/driver_common.c b/src/drivers/driver_common.c index bbd1a7cef..4dda51e73 100644 --- a/src/drivers/driver_common.c +++ b/src/drivers/driver_common.c @@ -98,6 +98,7 @@ const char * event_to_string(enum wpa_event_type event) E2S(PASN_AUTH); E2S(LINK_CH_SWITCH); E2S(LINK_CH_SWITCH_STARTED); + E2S(TID_LINK_MAP); } return "UNKNOWN"; diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c index eb25730c5..d4353541c 100644 --- a/src/drivers/driver_nl80211.c +++ b/src/drivers/driver_nl80211.c @@ -279,6 +279,8 @@ void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv) #ifdef CONFIG_DRIVER_NL80211_QCA os_free(drv->pending_roam_data); drv->pending_roam_data = NULL; + os_free(drv->pending_t2lm_data); + drv->pending_t2lm_data = NULL; #endif /* CONFIG_DRIVER_NL80211_QCA */ drv->auth_mld = false; @@ -10592,8 +10594,10 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) struct driver_sta_mlo_info *mlo = &drv->sta_mlo_info; res = os_snprintf(pos, end - pos, - "ap_mld_addr=" MACSTR "\n", - MAC2STR(mlo->ap_mld_addr)); + "ap_mld_addr=" MACSTR "\n" + "default_map=%d\n", + MAC2STR(mlo->ap_mld_addr), + mlo->default_map); if (os_snprintf_error(end - pos, res)) return pos - buf; pos += res; @@ -10612,6 +10616,18 @@ static int wpa_driver_nl80211_status(void *priv, char *buf, size_t buflen) if (os_snprintf_error(end - pos, res)) return pos - buf; pos += res; + + if (!mlo->default_map) { + res = os_snprintf( + pos, end - pos, + "uplink_map[%u]=%x\n" + "downlink_map[%u]=%x\n", + i, mlo->links[i].t2lmap.uplink, + i, mlo->links[i].t2lmap.downlink); + if (os_snprintf_error(end - pos, res)) + return pos - buf; + pos += res; + } } } diff --git a/src/drivers/driver_nl80211.h b/src/drivers/driver_nl80211.h index 38b59ab50..208c8b043 100644 --- a/src/drivers/driver_nl80211.h +++ b/src/drivers/driver_nl80211.h @@ -255,6 +255,8 @@ struct wpa_driver_nl80211_data { bool roam_indication_done; u8 *pending_roam_data; size_t pending_roam_data_len; + u8 *pending_t2lm_data; + size_t pending_t2lm_data_len; #endif /* CONFIG_DRIVER_NL80211_QCA */ }; diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c index a6f8c97ca..bb3622970 100644 --- a/src/drivers/driver_nl80211_event.c +++ b/src/drivers/driver_nl80211_event.c @@ -714,6 +714,126 @@ static void nl80211_parse_mlo_info(struct wpa_driver_nl80211_data *drv, } +#ifdef CONFIG_DRIVER_NL80211_QCA +static void +qca_nl80211_tid_to_link_map_event(struct wpa_driver_nl80211_data *drv, + u8 *data, size_t len) +{ + struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_MAX + 1]; + struct nlattr *tids; + union wpa_event_data event; + u8 *ap_mld; + int i, rem, tidnum = 0; + + os_memset(&event, 0, sizeof(event)); + + if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_MAX, + (struct nlattr *) data, len, NULL) || + !tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR]) + return; + + ap_mld = nla_data(tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_AP_MLD_ADDR]); + + wpa_printf(MSG_DEBUG, "nl80211: AP MLD address " MACSTR + " received in TID to link mapping event", MAC2STR(ap_mld)); + if (!drv->sta_mlo_info.valid_links || + os_memcmp(drv->sta_mlo_info.ap_mld_addr, ap_mld, ETH_ALEN) != 0) { + if (drv->pending_t2lm_data == data) { + wpa_printf(MSG_DEBUG, + "nl80211: Drop pending TID-to-link mapping event since AP MLD not matched even after new connect/roam event"); + os_free(drv->pending_t2lm_data); + drv->pending_t2lm_data = NULL; + return; + } + wpa_printf(MSG_DEBUG, + "nl80211: Cache new TID-to-link map event until the next connect/roam event"); + if (drv->pending_t2lm_data) { + wpa_printf(MSG_DEBUG, + "nl80211: Override old TID-to-link map event data"); + os_free(drv->pending_t2lm_data); + } + drv->pending_t2lm_data = os_memdup(data, len); + if (!drv->pending_t2lm_data) + return; + drv->pending_t2lm_data_len = len; + return; + } + + if (!tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS]) { + wpa_printf(MSG_DEBUG, "nl80211: Default TID-to-link map"); + event.t2l_map_info.default_map = true; + goto out; + } + + event.t2l_map_info.default_map = false; + + nla_for_each_nested(tids, + tb[QCA_WLAN_VENDOR_ATTR_TID_TO_LINK_MAP_STATUS], + rem) { + u16 uplink, downlink; + struct nlattr *tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_MAX + 1]; + + if (nla_parse_nested( + tid, QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_MAX, + tids, NULL)) { + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: nla_parse_nested() failed"); + return; + } + + if (!tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK]) { + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: uplink not present for tid: %d", + tidnum); + return; + } + uplink = nla_get_u16(tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_UPLINK]); + + if (!tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK]) { + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: downlink not present for tid: %d", + tidnum); + return; + } + downlink = nla_get_u16(tid[QCA_WLAN_VENDOR_ATTR_LINK_TID_MAP_STATUS_DOWNLINK]); + + wpa_printf(MSG_DEBUG, + "nl80211: TID-to-link: Received uplink %x downlink %x", + uplink, downlink); + for (i = 0; i < MAX_NUM_MLD_LINKS; i++) { + if (!(drv->sta_mlo_info.valid_links & BIT(i))) + continue; + if (uplink & BIT(i)) + event.t2l_map_info.t2lmap[i].uplink |= + BIT(tidnum); + if (downlink & BIT(i)) + event.t2l_map_info.t2lmap[i].downlink |= + BIT(tidnum); + } + + tidnum++; + } + +out: + drv->sta_mlo_info.default_map = event.t2l_map_info.default_map; + + event.t2l_map_info.valid_links = drv->sta_mlo_info.valid_links; + for (i = 0; i < MAX_NUM_MLD_LINKS && !drv->sta_mlo_info.default_map; + i++) { + if (!(drv->sta_mlo_info.valid_links & BIT(i))) + continue; + + drv->sta_mlo_info.links[i].t2lmap.uplink = + event.t2l_map_info.t2lmap[i].uplink; + drv->sta_mlo_info.links[i].t2lmap.downlink = + event.t2l_map_info.t2lmap[i].downlink; + } + + wpa_supplicant_event(drv->ctx, EVENT_TID_LINK_MAP, &event); +} +#endif /* CONFIG_DRIVER_NL80211_QCA */ + + static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, enum nl80211_commands cmd, bool qca_roam_auth, struct nlattr *status, @@ -913,6 +1033,14 @@ static void mlme_event_connect(struct wpa_driver_nl80211_data *drv, * operation that happened in parallel with the disconnection request. */ drv->ignore_next_local_disconnect = 0; + +#ifdef CONFIG_DRIVER_NL80211_QCA + if (drv->pending_t2lm_data) + qca_nl80211_tid_to_link_map_event(drv, drv->pending_t2lm_data, + drv->pending_t2lm_data_len); + else + drv->sta_mlo_info.default_map = true; +#endif /* CONFIG_DRIVER_NL80211_QCA */ } @@ -2863,6 +2991,9 @@ static void nl80211_vendor_event_qca(struct wpa_driver_nl80211_data *drv, qca_nl80211_pasn_auth(drv, data, len); break; #endif /* CONFIG_PASN */ + case QCA_NL80211_VENDOR_SUBCMD_TID_TO_LINK_MAP: + qca_nl80211_tid_to_link_map_event(drv, data, len); + break; #endif /* CONFIG_DRIVER_NL80211_QCA */ default: wpa_printf(MSG_DEBUG, diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c index 70d65b6fe..4af02c1ec 100644 --- a/wpa_supplicant/events.c +++ b/wpa_supplicant/events.c @@ -5254,6 +5254,59 @@ static void wpas_event_unprot_beacon(struct wpa_supplicant *wpa_s, } +static const char * bitmap_to_str(u8 value, char *buf) +{ + char *pos = buf; + int i, k = 0; + + for (i = 7; i >= 0; i--) + pos[k++] = (value & BIT(i)) ? '1' : '0'; + + pos[8] = '\0'; + return pos; +} + + +static void wpas_tid_link_map(struct wpa_supplicant *wpa_s, + struct tid_link_map_info *info) +{ + char map_info[1000], *pos, *end; + int res, i; + + pos = map_info; + end = pos + sizeof(map_info); + res = os_snprintf(map_info, sizeof(map_info), "default=%d", + info->default_map); + if (os_snprintf_error(end - pos, res)) + return; + pos += res; + + if (!info->default_map) { + for (i = 0; i < MAX_NUM_MLD_LINKS && end > pos; i++) { + char uplink_map_str[9]; + char downlink_map_str[9]; + + if (!(info->valid_links & BIT(i))) + continue; + + bitmap_to_str(info->t2lmap[i].uplink, uplink_map_str); + bitmap_to_str(info->t2lmap[i].downlink, + downlink_map_str); + + res = os_snprintf(pos, end - pos, + " link_id=%d up_link=%s down_link=%s", + i, uplink_map_str, + downlink_map_str); + if (os_snprintf_error(end - pos, res)) + return; + pos += res; + } + } + + wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_T2LM_UPDATE "%s", map_info); +} + + void wpa_supplicant_event(void *ctx, enum wpa_event_type event, union wpa_event_data *data) { @@ -6159,6 +6212,10 @@ void wpa_supplicant_event(void *ctx, enum wpa_event_type event, wpas_dpp_tx_wait_expire(wpa_s); #endif /* CONFIG_DPP */ break; + case EVENT_TID_LINK_MAP: + if (data) + wpas_tid_link_map(wpa_s, &data->t2l_map_info); + break; default: wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event); break;