]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
TDLS: Learn MLD link ID from TDLS Discovery Response
authorKiran Kumar Lokere <quic_klokere@quicinc.com>
Thu, 9 Feb 2023 08:25:30 +0000 (00:25 -0800)
committerJouni Malinen <j@w1.fi>
Fri, 8 Sep 2023 10:13:24 +0000 (13:13 +0300)
This is needed to be able to determine which link is used for TDLS setup
when the current association is with an AP MLD.

Signed-off-by: Jouni Malinen <quic_klokere@quicinc.com>
src/rsn_supp/tdls.c
src/rsn_supp/wpa.h
wpa_supplicant/events.c

index 8eb74ac226b2e52cd563b7788eeb2cf11149b405..5f7607b46fac11f9c9db4beabf611d8bbf4c31ca 100644 (file)
@@ -159,6 +159,8 @@ struct wpa_tdls_peer {
 
        /* channel switch currently enabled */
        int chan_switch_enabled;
+
+       int mld_link_id;
 };
 
 
@@ -737,6 +739,7 @@ static void wpa_tdls_peer_clear(struct wpa_sm *sm, struct wpa_tdls_peer *peer)
        os_memset(&peer->tpk, 0, sizeof(peer->tpk));
        os_memset(peer->inonce, 0, WPA_NONCE_LEN);
        os_memset(peer->rnonce, 0, WPA_NONCE_LEN);
+       peer->mld_link_id = -1;
 }
 
 
@@ -1075,6 +1078,7 @@ wpa_tdls_add_peer(struct wpa_sm *sm, const u8 *addr, int *existing)
                return NULL;
 
        os_memcpy(peer->addr, addr, ETH_ALEN);
+       peer->mld_link_id = -1;
        peer->next = sm->tdls;
        sm->tdls = peer;
 
@@ -1544,6 +1548,38 @@ skip_ies:
 }
 
 
+static bool wpa_tdls_is_lnkid_bss_valid(struct wpa_sm *sm,
+                                       const struct wpa_tdls_lnkid *lnkid,
+                                       int *link_id)
+{
+       *link_id = -1;
+
+       if (!sm->mlo.valid_links) {
+               if (os_memcmp(sm->bssid, lnkid->bssid, ETH_ALEN) != 0)
+                       return false;
+       } else {
+               int i;
+
+               for (i = 0; i < MAX_NUM_MLD_LINKS; i++) {
+                       if ((sm->mlo.valid_links & BIT(i)) &&
+                           os_memcmp(lnkid->bssid, sm->mlo.links[i].bssid,
+                                     ETH_ALEN) == 0) {
+                               *link_id = i;
+                               break;
+                       }
+               }
+               if (*link_id < 0) {
+                       wpa_printf(MSG_DEBUG,
+                                  "TDLS: MLD link not found for linkid BSS "
+                                  MACSTR, MAC2STR(lnkid->bssid));
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+
 static int
 wpa_tdls_process_discovery_request(struct wpa_sm *sm, const u8 *addr,
                                   const u8 *buf, size_t len)
@@ -3120,6 +3156,63 @@ int wpa_tdls_is_external_setup(struct wpa_sm *sm)
 }
 
 
+int wpa_tdls_process_discovery_response(struct wpa_sm *sm, const u8 *addr,
+                                       const u8 *buf, size_t len)
+{
+       struct ieee802_11_elems elems;
+       struct wpa_tdls_lnkid lnkid;
+       struct wpa_tdls_peer *peer;
+       size_t min_req_len = 1 /* Dialog Token */ + 2 /* Capability */ +
+               sizeof(struct wpa_tdls_lnkid);
+       int link_id = -1;
+
+       wpa_printf(MSG_DEBUG, "TDLS: Process Discovery Response from " MACSTR,
+                  MAC2STR(addr));
+
+       if (len < min_req_len) {
+               wpa_printf(MSG_DEBUG, "TDLS Discovery Resp is too short: %zu",
+                          len);
+               return -1;
+       }
+
+       /* Elements start after the three octets of fixed field (one octet for
+        * the Dialog Token field and two octets for the Capability field. */
+       if (ieee802_11_parse_elems(buf + 3, len - 3, &elems, 1) ==
+           ParseFailed) {
+               wpa_printf(MSG_DEBUG,
+                          "TDLS: Failed to parse IEs in Discovery Response");
+               return -1;
+       }
+
+       if (!elems.link_id) {
+               wpa_printf(MSG_DEBUG,
+                          "TDLS: Link Identifier element not found in Discovery Response");
+               return -1;
+       }
+
+       os_memcpy(&lnkid.bssid[0], elems.link_id, sizeof(lnkid) - 2);
+
+       if (!wpa_tdls_is_lnkid_bss_valid(sm, &lnkid, &link_id)) {
+               wpa_printf(MSG_DEBUG,
+                          "TDLS: Discovery Response from different BSS "
+                          MACSTR, MAC2STR(lnkid.bssid));
+               return -1;
+       }
+
+       peer = wpa_tdls_add_peer(sm, addr, NULL);
+       if (!peer) {
+               wpa_printf(MSG_DEBUG, "TDLS: Could not add peer entry");
+               return -1;
+       }
+
+       peer->mld_link_id = link_id;
+       wpa_printf(MSG_DEBUG, "TDLS: Link identifier BSS: " MACSTR
+                  " , link id: %u", MAC2STR(lnkid.bssid), link_id);
+
+       return 0;
+}
+
+
 int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
                                u8 oper_class,
                                struct hostapd_freq_params *freq_params)
index 36ddab3fe09c48a0d30ebcac8f0b1dd483aca84b..dfcc3aa02d9c25ccf18fa01a8217b295120bb8b3 100644 (file)
@@ -574,6 +574,8 @@ int wpa_tdls_enable_chan_switch(struct wpa_sm *sm, const u8 *addr,
                                u8 oper_class,
                                struct hostapd_freq_params *freq_params);
 int wpa_tdls_disable_chan_switch(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_process_discovery_response(struct wpa_sm *sm, const u8 *addr,
+                                       const u8 *buf, size_t len);
 #ifdef CONFIG_TDLS_TESTING
 extern unsigned int tdls_testing;
 #endif /* CONFIG_TDLS_TESTING */
index 41e25f0771ecefa2879c9b90fd78cac13be78e56..32cf24c795534eba674f16bfcd590b3b709f0589 100644 (file)
@@ -4771,6 +4771,12 @@ static void wpas_event_rx_mgmt_action(struct wpa_supplicant *wpa_s,
                wpa_dbg(wpa_s, MSG_DEBUG,
                        "TDLS: Received Discovery Response from " MACSTR,
                        MAC2STR(mgmt->sa));
+               if (wpa_s->valid_links &&
+                   wpa_tdls_process_discovery_response(wpa_s->wpa, mgmt->sa,
+                                                       &payload[1], plen - 1))
+                       wpa_dbg(wpa_s, MSG_ERROR,
+                               "TDLS: Discovery Response process failed for "
+                               MACSTR, MAC2STR(mgmt->sa));
                return;
        }
 #endif /* CONFIG_TDLS */