]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
Indicate TID to link mapping changes with QCA vendor interface
authorShivani Baranwal <quic_shivbara@quicinc.com>
Wed, 24 May 2023 09:14:55 +0000 (14:44 +0530)
committerJouni Malinen <j@w1.fi>
Thu, 1 Jun 2023 15:12:03 +0000 (18:12 +0300)
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>
src/common/wpa_ctrl.h
src/drivers/driver.h
src/drivers/driver_common.c
src/drivers/driver_nl80211.c
src/drivers/driver_nl80211.h
src/drivers/driver_nl80211_event.c
wpa_supplicant/events.c

index 4ab2a1b634ccf6c849efd2b76166b8190d806df9..57d69ae2eea487925b97e9810b9a2d938d91c1d6 100644 (file)
@@ -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
  *
index 101f98a72d602ff5c890b28fbc898772a00f1427..c68cc415e665db7e7afb5b9fadfcafa93affeb9f 100644 (file)
@@ -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;
 };
 
 /**
index bbd1a7cef517a0eec3bad613d24ed97ad80e3b23..4dda51e7337b46a7ffcd6829c6a4548c9ad97e89 100644 (file)
@@ -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";
index eb25730c56d8720ab6e09e79cbf2fd46b5d32ba3..d4353541c7c068d88d0e1a52aa9f29991d37e3eb 100644 (file)
@@ -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;
+                       }
                }
        }
 
index 38b59ab5059d37639ae1cb6a7f2219bb33da0144..208c8b0434df8435fd97bc39674166cc9d4108f3 100644 (file)
@@ -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 */
 };
 
index a6f8c97ca276b0d824530608aec4f20a4a27ff20..bb3622970ee54241e5a2272fe80e46c9eaf217c3 100644 (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,
                               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,
index 70d65b6fec372933e60c2b6f434e573f285a3bab..4af02c1ec0cd3511ebc6e07aa4705a54b5e6f9f9 100644 (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,
                          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;