aboutsummaryrefslogtreecommitdiff
path: root/src/drivers/driver_nl80211_event.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/driver_nl80211_event.c')
-rw-r--r--src/drivers/driver_nl80211_event.c211
1 files changed, 211 insertions, 0 deletions
diff --git a/src/drivers/driver_nl80211_event.c b/src/drivers/driver_nl80211_event.c
index 14d78427..e99afdca 100644
--- a/src/drivers/driver_nl80211_event.c
+++ b/src/drivers/driver_nl80211_event.c
@@ -421,6 +421,78 @@ convert_connect_fail_reason_codes(enum qca_sta_connect_fail_reason_codes
}
+static void qca_nl80211_link_reconfig_event(struct wpa_driver_nl80211_data *drv,
+ u8 *data, size_t len)
+{
+ struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_MAX + 1];
+ u16 removed_links;
+ u8 *ap_mld;
+ int i;
+
+ if (!data)
+ return;
+
+ if (nla_parse(tb, QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_MAX,
+ (struct nlattr *) data, len, NULL) ||
+ !tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR])
+ return;
+
+ ap_mld = nla_data(tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_AP_MLD_ADDR]);
+ wpa_printf(MSG_DEBUG, "nl80211: AP MLD address " MACSTR
+ " received in link reconfig 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_link_reconfig_data == data) {
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Drop pending link reconfig event since AP MLD not matched even after new connect/roam event");
+ os_free(drv->pending_link_reconfig_data);
+ drv->pending_link_reconfig_data = NULL;
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "nl80211: Cache new link reconfig event till next connect/roam event");
+ if (drv->pending_link_reconfig_data) {
+ wpa_printf(MSG_DEBUG, "nl80211: Override old link reconfig event data");
+ os_free(drv->pending_link_reconfig_data);
+ }
+ drv->pending_link_reconfig_data = os_memdup(data, len);
+ if (!drv->pending_link_reconfig_data)
+ return;
+ drv->pending_link_reconfig_data_len = len;
+ return;
+ }
+
+ if (!tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS])
+ return;
+ removed_links = nla_get_u16(
+ tb[QCA_WLAN_VENDOR_ATTR_LINK_RECONFIG_REMOVED_LINKS]);
+
+ drv->sta_mlo_info.valid_links &= ~removed_links;
+
+ /*
+ * Set default BSSID to the BSSID of the lowest link ID of remaining
+ * links when the link used for (re)association is removed.
+ */
+ if (removed_links & BIT(drv->sta_mlo_info.assoc_link_id)) {
+ for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+ if (!(drv->sta_mlo_info.valid_links & BIT(i)))
+ continue;
+
+ os_memcpy(drv->bssid, drv->sta_mlo_info.links[i].bssid,
+ ETH_ALEN);
+ drv->sta_mlo_info.assoc_link_id = i;
+ break;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Removed MLO links bitmap: 0x%x",
+ removed_links);
+
+ wpa_supplicant_event(drv->ctx, EVENT_LINK_RECONFIG, NULL);
+}
+
+
static void
nl80211_parse_qca_vendor_mlo_link_info(struct driver_sta_mlo_info *mlo,
struct nlattr *mlo_links)
@@ -713,6 +785,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,
@@ -912,6 +1104,19 @@ 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;
+
+ if (drv->pending_link_reconfig_data)
+ qca_nl80211_link_reconfig_event(
+ drv, drv->pending_link_reconfig_data,
+ drv->pending_link_reconfig_data_len);
+#endif /* CONFIG_DRIVER_NL80211_QCA */
}
@@ -2861,6 +3066,12 @@ 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;
+ case QCA_NL80211_VENDOR_SUBCMD_LINK_RECONFIG:
+ qca_nl80211_link_reconfig_event(drv, data, len);
+ break;
#endif /* CONFIG_DRIVER_NL80211_QCA */
default:
wpa_printf(MSG_DEBUG,