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 <quic_shivbara@quicinc.com>
This commit is contained in:
Shivani Baranwal 2023-05-24 14:44:55 +05:30 committed by Jouni Malinen
parent 95c3f0d1e4
commit 7b9070229d
7 changed files with 244 additions and 2 deletions

View file

@ -110,6 +110,8 @@ extern "C" {
#define WPA_EVENT_DO_ROAM "CTRL-EVENT-DO-ROAM " #define WPA_EVENT_DO_ROAM "CTRL-EVENT-DO-ROAM "
/** Decision made to skip a within-ESS roam */ /** Decision made to skip a within-ESS roam */
#define WPA_EVENT_SKIP_ROAM "CTRL-EVENT-SKIP-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 /** IP subnet status change notification
* *

View file

@ -430,6 +430,18 @@ struct wpa_driver_scan_ssid {
size_t ssid_len; 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 * struct wpa_driver_scan_params - Scan parameters
* Data for struct wpa_driver_ops::scan2(). * Data for struct wpa_driver_ops::scan2().
@ -2911,6 +2923,7 @@ struct weighted_pcl {
}; };
struct driver_sta_mlo_info { struct driver_sta_mlo_info {
bool default_map;
u16 req_links; /* bitmap of requested link IDs */ u16 req_links; /* bitmap of requested link IDs */
u16 valid_links; /* bitmap of accepted link IDs */ u16 valid_links; /* bitmap of accepted link IDs */
u8 assoc_link_id; u8 assoc_link_id;
@ -2919,6 +2932,7 @@ struct driver_sta_mlo_info {
u8 addr[ETH_ALEN]; u8 addr[ETH_ALEN];
u8 bssid[ETH_ALEN]; u8 bssid[ETH_ALEN];
unsigned int freq; unsigned int freq;
struct t2lm_mapping t2lmap;
} links[MAX_NUM_MLD_LINKS]; } links[MAX_NUM_MLD_LINKS];
}; };
@ -5640,6 +5654,16 @@ enum wpa_event_type {
* Described in wpa_event_data.ch_switch. * Described in wpa_event_data.ch_switch.
*/ */
EVENT_LINK_CH_SWITCH_STARTED, 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; const u8 *td_bitmap;
size_t td_bitmap_len; size_t td_bitmap_len;
} port_authorized; } 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;
}; };
/** /**

View file

@ -98,6 +98,7 @@ const char * event_to_string(enum wpa_event_type event)
E2S(PASN_AUTH); E2S(PASN_AUTH);
E2S(LINK_CH_SWITCH); E2S(LINK_CH_SWITCH);
E2S(LINK_CH_SWITCH_STARTED); E2S(LINK_CH_SWITCH_STARTED);
E2S(TID_LINK_MAP);
} }
return "UNKNOWN"; return "UNKNOWN";

View file

@ -279,6 +279,8 @@ void nl80211_mark_disconnected(struct wpa_driver_nl80211_data *drv)
#ifdef CONFIG_DRIVER_NL80211_QCA #ifdef CONFIG_DRIVER_NL80211_QCA
os_free(drv->pending_roam_data); os_free(drv->pending_roam_data);
drv->pending_roam_data = NULL; drv->pending_roam_data = NULL;
os_free(drv->pending_t2lm_data);
drv->pending_t2lm_data = NULL;
#endif /* CONFIG_DRIVER_NL80211_QCA */ #endif /* CONFIG_DRIVER_NL80211_QCA */
drv->auth_mld = false; 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; struct driver_sta_mlo_info *mlo = &drv->sta_mlo_info;
res = os_snprintf(pos, end - pos, res = os_snprintf(pos, end - pos,
"ap_mld_addr=" MACSTR "\n", "ap_mld_addr=" MACSTR "\n"
MAC2STR(mlo->ap_mld_addr)); "default_map=%d\n",
MAC2STR(mlo->ap_mld_addr),
mlo->default_map);
if (os_snprintf_error(end - pos, res)) if (os_snprintf_error(end - pos, res))
return pos - buf; return pos - buf;
pos += res; 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)) if (os_snprintf_error(end - pos, res))
return pos - buf; return pos - buf;
pos += res; 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;
}
} }
} }

View file

@ -255,6 +255,8 @@ struct wpa_driver_nl80211_data {
bool roam_indication_done; bool roam_indication_done;
u8 *pending_roam_data; u8 *pending_roam_data;
size_t pending_roam_data_len; size_t pending_roam_data_len;
u8 *pending_t2lm_data;
size_t pending_t2lm_data_len;
#endif /* CONFIG_DRIVER_NL80211_QCA */ #endif /* CONFIG_DRIVER_NL80211_QCA */
}; };

View file

@ -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, static void mlme_event_connect(struct wpa_driver_nl80211_data *drv,
enum nl80211_commands cmd, bool qca_roam_auth, enum nl80211_commands cmd, bool qca_roam_auth,
struct nlattr *status, 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. * operation that happened in parallel with the disconnection request.
*/ */
drv->ignore_next_local_disconnect = 0; 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); qca_nl80211_pasn_auth(drv, data, len);
break; break;
#endif /* CONFIG_PASN */ #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 */ #endif /* CONFIG_DRIVER_NL80211_QCA */
default: default:
wpa_printf(MSG_DEBUG, wpa_printf(MSG_DEBUG,

View file

@ -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, void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
union wpa_event_data *data) 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); wpas_dpp_tx_wait_expire(wpa_s);
#endif /* CONFIG_DPP */ #endif /* CONFIG_DPP */
break; break;
case EVENT_TID_LINK_MAP:
if (data)
wpas_tid_link_map(wpa_s, &data->t2l_map_info);
break;
default: default:
wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event); wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
break; break;