]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
common: Support parsing link specific association request
authorIlan Peer <ilan.peer@intel.com>
Wed, 15 Feb 2023 23:08:29 +0000 (01:08 +0200)
committerJouni Malinen <j@w1.fi>
Tue, 7 Mar 2023 20:03:40 +0000 (22:03 +0200)
An association request in the context of an MLO connection can
contain an ML element that holds the per station profile for
the additional links negotiated. To support this, add a function
to parse the per station profile.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
src/common/ieee802_11_common.c
src/common/ieee802_11_common.h

index fbc84654e4d8b52ee04acb8db2471d9526bd35df..22f65affa876d440a7a14421fd87dced5a754a07 100644 (file)
@@ -944,6 +944,153 @@ void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems,
 }
 
 
+ParseRes ieee802_11_parse_link_assoc_req(const u8 *start, size_t len,
+                                        struct ieee802_11_elems *elems,
+                                        struct wpabuf *mlbuf,
+                                        u8 link_id, bool show_errors)
+{
+       const struct ieee80211_eht_ml *ml;
+       const u8 *pos;
+       ParseRes res = ParseFailed;
+
+       pos = wpabuf_head(mlbuf);
+       len = wpabuf_len(mlbuf);
+
+       /* Must have control and common info length */
+       if (len < sizeof(*ml) + 1 || len < sizeof(*ml) + pos[sizeof(*ml)])
+               goto out;
+
+       ml = (const struct ieee80211_eht_ml *) pos;
+
+       /* As we are interested with the Per-STA profile, ignore other types */
+       if ((le_to_host16(ml->ml_control) & MULTI_LINK_CONTROL_TYPE_MASK) !=
+            MULTI_LINK_CONTROL_TYPE_BASIC)
+               goto out;
+
+       /* Skip the common info */
+       len -= sizeof(*ml) + pos[sizeof(*ml)];
+       pos += sizeof(*ml) + pos[sizeof(*ml)];
+
+       while (len > 2) {
+               size_t sub_elem_len = *(pos + 1);
+               size_t sta_info_len;
+               u16 link_info_control;
+               const u8 *non_inherit;
+
+               wpa_printf(MSG_DEBUG,
+                          "MLD: sub element: len=%zu, sub_elem_len=%zu",
+                          len, sub_elem_len);
+
+               if (2 + sub_elem_len > len) {
+                       if (show_errors)
+                               wpa_printf(MSG_DEBUG,
+                                          "MLD: error: len=%zu, sub_elem_len=%zu",
+                                          len, sub_elem_len);
+                       goto out;
+               }
+
+               if (*pos != 0) {
+                       pos += 2 + sub_elem_len;
+                       len -= 2 + sub_elem_len;
+                       continue;
+               }
+
+               if (sub_elem_len < 3) {
+                       if (show_errors)
+                               wpa_printf(MSG_DEBUG,
+                                          "MLD: error: sub_elem_len=%zu < 5",
+                                          sub_elem_len);
+                       goto out;
+               }
+
+               link_info_control = WPA_GET_LE16(pos + 2);
+               if ((link_info_control & BASIC_MLE_STA_CTRL_LINK_ID_MASK) !=
+                   link_id) {
+                       pos += 2 + sub_elem_len;
+                       len -= 2 + sub_elem_len;
+                       continue;
+               }
+
+               sta_info_len = *(pos + 4);
+               if (sub_elem_len < sta_info_len + 3 || sta_info_len < 1) {
+                       if (show_errors)
+                               wpa_printf(MSG_DEBUG,
+                                          "MLD: error: sub_elem_len=%zu, sta_info_len=%zu",
+                                          sub_elem_len, sta_info_len);
+                       goto out;
+               }
+
+               pos += sta_info_len + 4;
+               sub_elem_len -= sta_info_len + 2;
+
+               if (sub_elem_len < 2) {
+                       if (show_errors)
+                               wpa_printf(MSG_DEBUG,
+                                          "MLD: missing capability info");
+                       goto out;
+               }
+
+               pos += 2;
+               sub_elem_len -= 2;
+
+               /* Handle non-inheritance */
+               non_inherit = get_ie_ext(pos, sub_elem_len,
+                                        WLAN_EID_EXT_NON_INHERITANCE);
+               if (non_inherit && non_inherit[1] > 1) {
+                       u8 non_inherit_len = non_inherit[1] - 1;
+
+                       /*
+                        * Do not include the Non-Inheritance element when
+                        * parsing below. It should be the last element in the
+                        * subelement.
+                        */
+                       if (3U + non_inherit_len > sub_elem_len)
+                               goto out;
+                       sub_elem_len -= 3 + non_inherit_len;
+
+                       /* Skip the ID, length and extension ID */
+                       non_inherit += 3;
+
+                       if (non_inherit_len < 1UL + non_inherit[0]) {
+                               if (show_errors)
+                                       wpa_printf(MSG_DEBUG,
+                                                  "MLD: Invalid inheritance");
+                               goto out;
+                       }
+
+                       ieee802_11_elems_clear_ids(elems, &non_inherit[1],
+                                                  non_inherit[0]);
+
+                       non_inherit_len -= 1 + non_inherit[0];
+                       non_inherit += 1 + non_inherit[0];
+
+                       if (non_inherit_len < 1UL + non_inherit[0]) {
+                               if (show_errors)
+                                       wpa_printf(MSG_DEBUG,
+                                                  "MLD: Invalid inheritance");
+                               goto out;
+                       }
+
+                       ieee802_11_elems_clear_ext_ids(elems, &non_inherit[1],
+                                                      non_inherit[0]);
+               }
+
+               wpa_printf(MSG_DEBUG, "MLD: link: sub_elem_len=%zu",
+                          sub_elem_len);
+
+               if (sub_elem_len)
+                       res = __ieee802_11_parse_elems(pos, sub_elem_len,
+                                                      elems, show_errors);
+               else
+                       res = ParseOK;
+               break;
+       }
+
+out:
+       return res;
+}
+
+
 int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
 {
        const struct element *elem;
index f4b17a55fb3f4e7d7011c95aedb0b0d706d7ad4d..8e730440af2a5e319db0364091cc149da8a69a73 100644 (file)
@@ -190,6 +190,10 @@ void ieee802_11_elems_clear_ids(struct ieee802_11_elems *elems,
                                const u8 *ids, size_t num);
 void ieee802_11_elems_clear_ext_ids(struct ieee802_11_elems *elems,
                                    const u8 *ids, size_t num);
+ParseRes ieee802_11_parse_link_assoc_req(const u8 *start, size_t len,
+                                        struct ieee802_11_elems *elems,
+                                        struct wpabuf *mlbuf,
+                                        u8 link_id, bool show_errors);
 int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
 struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
                                            u32 oui_type);