[PATCH] supplicant: Fix MLD related IE parsing.

Ben Greear greearb at candelatech.com
Sat Oct 28 16:26:52 PDT 2023


On 10/28/23 10:01 AM, Jouni Malinen wrote:
> On Sat, Oct 28, 2023 at 08:32:29AM -0700, Ben Greear wrote:
>> Is it worth posting the changes to debugging as separate patch, or do you
>> not want those at all?
> 
> I did not go through the details for those once I realized that the
> patch was too complex to figure out what all was happening and what was
> part of the fix and what was something else.. But at least the part
> about dumping all IEs at ERROR verbosity would certainly be something
> that I would not want. As far as changing MLD related items to use
> wpa_dbg() is concerned, that would also seem a bit odd for more normal
> use cases, so it might be easier to skip those as well. If there were
> other types of debugging changes, I don't have an easy answer for those
> before the changes were identified in an easier to review form.
>   
> 

Here's a diff -w of the v2 patch.  There are two new loops, so whitespace
changes makes it look more complicated than it is:

[greearb at v-f36-64 hostap]$ git diff -w HEAD~1
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 8ccb24d22..e4516f8f1 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -2498,6 +2498,34 @@ const u8 * get_ie(const u8 *ies, size_t len, u8 eid)
         return NULL;
  }

+/**
+ * get_ie - Fetch a specified information element from IEs buffer
+ * @ies: Information elements buffer
+ * @len: Information elements buffer length
+ * @eid: Information element identifier (WLAN_EID_*)
+ * @nth: Return the nth element of the requested type (2 returns the second)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the nth matching information element in the IEs
+ * buffer or %NULL in case the element is not found.
+ */
+const u8 * get_ie_nth(const u8 *ies, size_t len, u8 eid, int nth)
+{
+       const struct element *elem;
+       int sofar = 0;
+
+       if (!ies)
+               return NULL;
+
+       for_each_element_id(elem, eid, ies, len) {
+               if ((sofar + 1) == nth)
+                       return &elem->id;
+               sofar++;
+       }
+
+       return NULL;
+}
+

  /**
   * get_ie_ext - Fetch a specified extended information element from IEs buffer
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index ef95c3591..b35ce777b 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -262,6 +262,7 @@ extern const struct oper_class_map global_op_class[];
  extern size_t global_op_class_size;

  const u8 * get_ie(const u8 *ies, size_t len, u8 eid);
+const u8 * get_ie_nth(const u8 *ies, size_t len, u8 eid, int nth);
  const u8 * get_ie_ext(const u8 *ies, size_t len, u8 ext);
  const u8 * get_vendor_ie(const u8 *ies, size_t len, u32 vendor_type);

diff --git a/wpa_supplicant/bss.c b/wpa_supplicant/bss.c
index 3b1646dd2..0162c142d 100644
--- a/wpa_supplicant/bss.c
+++ b/wpa_supplicant/bss.c
@@ -1194,6 +1194,21 @@ const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
         return get_ie(wpa_bss_ie_ptr(bss), bss->ie_len, ie);
  }

+/**
+ * wpa_bss_get_ie_nth - Fetch a specified information element from a BSS entry
+ * @bss: BSS table entry
+ * @ie: Information element identitifier (WLAN_EID_*)
+ * @nth: Return the nth element of the requested type (2 returns the second)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the nth matching information element in the BSS
+ * entry.
+ */
+const u8 * wpa_bss_get_ie_nth(const struct wpa_bss *bss, u8 ie, int nth)
+{
+       return get_ie_nth(wpa_bss_ie_ptr(bss), bss->ie_len, ie, nth);
+}
+

  /**
   * wpa_bss_get_ie_ext - Fetch a specified extended IE from a BSS entry
diff --git a/wpa_supplicant/bss.h b/wpa_supplicant/bss.h
index 611da8844..4580e7981 100644
--- a/wpa_supplicant/bss.h
+++ b/wpa_supplicant/bss.h
@@ -160,6 +160,7 @@ struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
  struct wpa_bss * wpa_bss_get_id_range(struct wpa_supplicant *wpa_s,
                                       unsigned int idf, unsigned int idl);
  const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
+const u8 * wpa_bss_get_ie_nth(const struct wpa_bss *bss, u8 ie, int nth);
  const u8 * wpa_bss_get_ie_ext(const struct wpa_bss *bss, u8 ext);
  const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
  const u8 * wpa_bss_get_vendor_ie_beacon(const struct wpa_bss *bss,
diff --git a/wpa_supplicant/sme.c b/wpa_supplicant/sme.c
index acb6981d9..c595014c5 100644
--- a/wpa_supplicant/sme.c
+++ b/wpa_supplicant/sme.c
@@ -400,6 +400,7 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                              BASIC_MULTI_LINK_CTRL_PRES_BSS_PARAM_CH_COUNT |
                              BASIC_MULTI_LINK_CTRL_PRES_MLD_CAPA);
         bool ret = false;
+       int rnr_idx = 0;

         if (!(wpa_s->drv_flags2 & WPA_DRIVER_FLAGS2_MLO))
                 return false;
@@ -468,12 +469,17 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,

         wpa_s->valid_links = BIT(wpa_s->mlo_assoc_link_id);

-       rnr_ie = wpa_bss_get_ie(bss, WLAN_EID_REDUCED_NEIGHBOR_REPORT);
+       /* Search for multiple neigh report IEs. */
+       while (true) {
+               rnr_ie = wpa_bss_get_ie_nth(bss, WLAN_EID_REDUCED_NEIGHBOR_REPORT, ++rnr_idx);
                 if (!rnr_ie) {
-               wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RNR element");
                         ret = true;
+                       if (rnr_idx == 0) {
+                               wpa_dbg(wpa_s, MSG_DEBUG, "MLD: No RNR element");
                                 goto out;
                         }
+                       break;
+               }

                 rnr_ie_len = rnr_ie[1];
                 pos = rnr_ie + 2;
@@ -481,12 +487,14 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                 while (rnr_ie_len > sizeof(struct ieee80211_neighbor_ap_info)) {
                         const struct ieee80211_neighbor_ap_info *ap_info =
                                 (const struct ieee80211_neighbor_ap_info *) pos;
-               const u8 *data = ap_info->data;
-               size_t len = sizeof(struct ieee80211_neighbor_ap_info) +
-                       ap_info->tbtt_info_len;
+                       const u8 *data = ap_info->data; /* start of tbtt elements */
+                       const u8 tbtt_count = ap_info->tbtt_info_hdr >> 4;
+                       size_t len = ap_info->tbtt_info_len * (tbtt_count + 1) +
+                               sizeof(struct ieee80211_neighbor_ap_info);
+                       int tbti;

-               wpa_printf(MSG_DEBUG, "MLD: op_class=%u, channel=%u",
-                          ap_info->op_class, ap_info->channel);
+                       wpa_dbg(wpa_s, MSG_DEBUG, "MLD: rnr-idx: %d op_class=%u, channel=%u\n",
+                               rnr_idx - 1, ap_info->op_class, ap_info->channel);

                         if (len > rnr_ie_len)
                                 break;
@@ -497,26 +505,36 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                                 continue;
                         }

-               data += 13;
+                       for (tbti = 0; tbti <= tbtt_count; tbti++) {
+                               const u8* bssid = data + 1; /* one byte into the tbtt object */

-               wpa_printf(MSG_DEBUG, "MLD: mld ID=%u, link ID=%u",
-                          *data, *(data + 1) & 0xF);
+                               data += 13; /* advance to mld parameters */
+
+                               wpa_dbg(wpa_s, MSG_DEBUG, "MLD: tbtt idx: %d mld ID=%u, link ID=%u  data: 0x%lx bssid=" MACSTR,
+                                       tbti, *data, *(data + 1) & 0xF, (unsigned long)data,
+                                       MAC2STR(bssid));

                                 if (*data) {
                                         wpa_printf(MSG_DEBUG,
                                                    "MLD: Reported link not part of MLD");
                                 } else {
                                         struct wpa_bss *neigh_bss =
-                               wpa_bss_get_bssid(wpa_s, ap_info->data + 1);
+                                               wpa_bss_get_bssid(wpa_s, bssid);
                                         u8 link_id = *(data + 1) & 0xF;

+                                       /* Intel radios won't scan 6e at first.  Would need to force
+                                        * the radio to scan multiple times to fix that limitations.
+                                        */
                                         if (neigh_bss) {
-                               if (wpa_scan_res_match(wpa_s, 0, neigh_bss,
+                                               u8 bss_params = *(data + (1 + 6 + 4 - 13));
+                                               if (((bss_params & 0x2) /* same ssid */
+                                                    && (bss_params & (1<<6))) || /* co-located AP */
+                                                   wpa_scan_res_match(wpa_s, 0, neigh_bss,
                                                                        wpa_s->current_ssid,
                                                                        1, 0)) {
                                                         wpa_s->valid_links |= BIT(link_id);
                                                         os_memcpy(wpa_s->links[link_id].bssid,
-                                                 ap_info->data + 1, ETH_ALEN);
+                                                                 bssid, ETH_ALEN);
                                                         wpa_s->links[link_id].freq =
                                                                 neigh_bss->freq;
                                                 } else {
@@ -528,10 +546,13 @@ static bool wpas_ml_element(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
                                                            "MLD: Neighbor not found in scan");
                                         }
                                 }
+                               data += (ap_info->tbtt_info_len - 13); /* consume rest of tbtt */
+                       }/* for all tbtt */

                         rnr_ie_len -= len;
                         pos += len;
-       }
+               }/* while more neigh info */
+       }/* for all neigh report IEs */

         wpa_printf(MSG_DEBUG, "MLD: valid_links=0x%x", wpa_s->valid_links);

[greearb at v-f36-64 hostap]$



-- 
Ben Greear <greearb at candelatech.com>
Candela Technologies Inc  http://www.candelatech.com



More information about the Hostap mailing list