]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
iw: backport WiFi 7 (EHT) scan support 18741/head
authorAleksander Jan Bajkowski <olek2@wp.pl>
Sat, 29 Mar 2025 22:39:19 +0000 (23:39 +0100)
committerRobert Marko <robimarko@gmail.com>
Sun, 11 May 2025 11:09:31 +0000 (13:09 +0200)
Backport patches to support scans of WiFi 7 APs.

Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
Link: https://github.com/openwrt/openwrt/pull/18741
Signed-off-by: Robert Marko <robimarko@gmail.com>
package/network/utils/iw/Makefile
package/network/utils/iw/patches/103-iw-scan-add-enum-for-element-IDs.patch [new file with mode: 0644]
package/network/utils/iw/patches/104-iw-scan-replace-passed-ie-buffer-with-ie-context.patch [new file with mode: 0644]
package/network/utils/iw/patches/105-iw-util-update-and-clean-up-eht-capa-printing.patch [new file with mode: 0644]
package/network/utils/iw/patches/106-iw-scan-add-eht-capability-parsing.patch [new file with mode: 0644]
package/network/utils/iw/patches/107-iw-fix-EHT-capabilities-on-Big-Endian-platforms.patch [new file with mode: 0644]
package/network/utils/iw/patches/108-iw-scan-Add-printing-of-EHT-Operation-Element.patch [new file with mode: 0644]
package/network/utils/iw/patches/200-reduce_size.patch

index c59adbaab58d4a389d813cfaeff8b9eb655c4762..17340624716385b5509337a30b87dc0660db5ac2 100644 (file)
@@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
 
 PKG_NAME:=iw
 PKG_VERSION:=6.9
-PKG_RELEASE:=3
+PKG_RELEASE:=4
  
 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
 PKG_SOURCE_URL:=@KERNEL/software/network/iw
diff --git a/package/network/utils/iw/patches/103-iw-scan-add-enum-for-element-IDs.patch b/package/network/utils/iw/patches/103-iw-scan-add-enum-for-element-IDs.patch
new file mode 100644 (file)
index 0000000..abf699f
--- /dev/null
@@ -0,0 +1,170 @@
+From 966c590bc4dcbd9a69fdf8fe9f41cec00e72e376 Mon Sep 17 00:00:00 2001
+From: Dylan Eskew <dylan.eskew@candelatech.com>
+Date: Mon, 30 Sep 2024 11:11:43 -0700
+Subject: [PATCH] iw: scan: add enum for element IDs
+
+Formerly, element IDs were hardcoded. Improve readability by using
+element ID names.
+
+Signed-off-by: Dylan Eskew <dylan.eskew@candelatech.com>
+Link: https://patch.msgid.link/20240930181145.1043048-2-dylan.eskew@candelatech.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+ ieee80211.h | 43 +++++++++++++++++++++++++++
+ scan.c      | 86 +++++++++++++++++++++++++++++++----------------------
+ 2 files changed, 93 insertions(+), 36 deletions(-)
+
+--- a/ieee80211.h
++++ b/ieee80211.h
+@@ -58,6 +58,49 @@ struct ieee80211_vht_cap {
+       struct ieee80211_vht_mcs_info mcs;
+ } __attribute__ ((packed));
++enum elem_id {
++      EID_SSID                        = 0,
++      EID_SUPP_RATES                  = 1,
++      EID_DS_PARAMS                   = 3,
++      EID_TIM                         = 5,
++      EID_IBSS_TIM_PARAMS             = 6,
++      EID_COUNTRY                     = 7,
++      EID_BSS_LOAD                    = 11,
++      EID_POWER_CONSTRAINT            = 32,
++      EID_TPC_REPORT                  = 35,
++      EID_ERP_INFO                    = 42,
++      EID_HT_CAPABILITY               = 45,
++      EID_ERP_D4_0                    = 47,
++      EID_RSN                         = 48,
++      EID_EXT_SUPP_RATES              = 50,
++      EID_AP_CHAN_REPORT              = 51,
++      EID_SUPP_OP_CLASSES             = 59,
++      EID_HT_OPERATION                = 61,
++      EID_SECONDARY_CH_OFFSET         = 62,
++      EID_MEASUREMENT_PILOT_TX        = 66,
++      EID_RM_ENABLED_CAPABILITIES     = 70,
++      EID_OVERLAP_BSS_SCAN_PARAM      = 74,
++      EID_INTERWORKING                = 107,
++      EID_ADVERTISEMENT               = 108,
++      EID_ROAMING_CONSORTIUM          = 111,
++      EID_MESH_CONFIG                 = 113,
++      EID_MESH_ID                     = 114,
++      EID_EXT_CAPABILITY              = 127,
++      EID_VHT_CAPABILITY              = 191,
++      EID_VHT_OPERATION               = 192,
++      EID_TRANSMIT_POWER_ENVELOPE     = 195,
++      EID_SHORT_BEACON_INTERVAL       = 214,
++      EID_S1G_CAPABILITY              = 217,
++      EID_VENDOR                      = 221,
++      EID_S1G_OPERATION               = 232,
++      EID_EXTENSION                   = 255,
++};
++
++enum elem_id_ext {
++      EID_EXT_HE_CAPABILITY           = 35,
++      EID_EXT_HE_OPERATION            = 36,
++};
++
+ #define SUITE(oui, id)  (((oui) << 8) | (id))
+ /* cipher suite selectors */
+--- a/scan.c
++++ b/scan.c
+@@ -1816,40 +1816,54 @@ static void print_ie(const struct ie_pri
+ }
+ static const struct ie_print ieprinters[] = {
+-      [0] = { "SSID", print_ssid, 0, 32,
+-               BIT(PRINT_SCAN) | BIT(PRINT_LINK) | BIT(PRINT_LINK_MLO_MLD), },
+-      [1] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
+-      [3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
+-      [5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
+-      [6] = { "IBSS ATIM window", print_ibssatim, 2, 2, BIT(PRINT_SCAN), },
+-      [7] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), },
+-      [11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
+-      [32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), },
+-      [35] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), },
+-      [42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
+-      [45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
+-      [47] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), },
+-      [51] = { "AP Channel Report", print_ap_channel_report, 1, 255, BIT(PRINT_SCAN), },
+-      [59] = { "Supported operating classes", print_supp_op_classes, 1, 255, BIT(PRINT_SCAN), },
+-      [66] = { "Measurement Pilot Transmission", print_measurement_pilot_tx, 1, 255, BIT(PRINT_SCAN), },
+-      [74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
+-      [61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
+-      [62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
+-      [191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
+-      [192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
+-      [48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
+-      [50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
+-      [70] = { "RM enabled capabilities", print_rm_enabled_capabilities, 5, 5, BIT(PRINT_SCAN), },
+-      [113] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), },
+-      [114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
+-      [127] = { "Extended capabilities", print_capabilities, 0, 255, BIT(PRINT_SCAN), },
+-      [107] = { "802.11u Interworking", print_interworking, 0, 255, BIT(PRINT_SCAN), },
+-      [108] = { "802.11u Advertisement", print_11u_advert, 0, 255, BIT(PRINT_SCAN), },
+-      [111] = { "802.11u Roaming Consortium", print_11u_rcon, 2, 255, BIT(PRINT_SCAN), },
+-      [195] = { "Transmit Power Envelope", print_tx_power_envelope, 2, 5, BIT(PRINT_SCAN), },
+-      [214] = { "Short beacon interval", print_short_beacon_int, 2, 2, BIT(PRINT_SCAN), },
+-      [217] = { "S1G capabilities", print_s1g_capa, 15, 15, BIT(PRINT_SCAN), },
+-      [232] = { "S1G operation", print_s1g_oper, 6, 6, BIT(PRINT_SCAN), },
++      [EID_SSID] = { "SSID", print_ssid, 0, 32,
++                     BIT(PRINT_SCAN) | BIT(PRINT_LINK) | BIT(PRINT_LINK_MLO_MLD), },
++      [EID_SUPP_RATES] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
++      [EID_DS_PARAMS] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
++      [EID_TIM] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
++      [EID_IBSS_TIM_PARAMS] = { "IBSS ATIM window", print_ibssatim, 2, 2, BIT(PRINT_SCAN), },
++      [EID_COUNTRY] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), },
++      [EID_BSS_LOAD] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
++      [EID_POWER_CONSTRAINT] = { "Power constraint", print_powerconstraint,
++                                 1, 1, BIT(PRINT_SCAN), },
++      [EID_TPC_REPORT] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), },
++      [EID_ERP_INFO] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
++      [EID_HT_CAPABILITY] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
++      [EID_ERP_D4_0] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), },
++      [EID_AP_CHAN_REPORT] = { "AP Channel Report", print_ap_channel_report,
++                               1, 255, BIT(PRINT_SCAN), },
++      [EID_SUPP_OP_CLASSES] = { "Supported operating classes",
++                                print_supp_op_classes, 1, 255, BIT(PRINT_SCAN), },
++      [EID_MEASUREMENT_PILOT_TX] = { "Measurement Pilot Transmission",
++                                     print_measurement_pilot_tx, 1, 255, BIT(PRINT_SCAN), },
++      [EID_OVERLAP_BSS_SCAN_PARAM] = { "Overlapping BSS scan params",
++                                       print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
++      [EID_HT_OPERATION] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
++      [EID_SECONDARY_CH_OFFSET] = { "Secondary Channel Offset",
++                                    print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
++      [EID_VHT_CAPABILITY] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
++      [EID_VHT_OPERATION] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
++      [EID_RSN] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
++      [EID_EXT_SUPP_RATES] = { "Extended supported rates", print_supprates,
++                               0, 255, BIT(PRINT_SCAN), },
++      [EID_RM_ENABLED_CAPABILITIES] = { "RM enabled capabilities",
++                                        print_rm_enabled_capabilities, 5, 5, BIT(PRINT_SCAN), },
++      [EID_MESH_CONFIG] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), },
++      [EID_MESH_ID] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
++      [EID_EXT_CAPABILITY] = { "Extended capabilities", print_capabilities,
++                               0, 255, BIT(PRINT_SCAN), },
++      [EID_INTERWORKING] = { "802.11u Interworking", print_interworking,
++                             0, 255, BIT(PRINT_SCAN), },
++      [EID_ADVERTISEMENT] = { "802.11u Advertisement", print_11u_advert,
++                              0, 255, BIT(PRINT_SCAN), },
++      [EID_ROAMING_CONSORTIUM] = { "802.11u Roaming Consortium",
++                                   print_11u_rcon, 2, 255, BIT(PRINT_SCAN), },
++      [EID_TRANSMIT_POWER_ENVELOPE] = { "Transmit Power Envelope",
++                                        print_tx_power_envelope, 2, 5, BIT(PRINT_SCAN), },
++      [EID_SHORT_BEACON_INTERVAL] = { "Short beacon interval",
++                                      print_short_beacon_int, 2, 2, BIT(PRINT_SCAN), },
++      [EID_S1G_CAPABILITY] = { "S1G capabilities", print_s1g_capa, 15, 15, BIT(PRINT_SCAN), },
++      [EID_S1G_OPERATION] = { "S1G operation", print_s1g_oper, 6, 6, BIT(PRINT_SCAN), },
+ };
+ static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data,
+@@ -2392,8 +2406,8 @@ static void print_he_oper(const uint8_t
+ }
+ static const struct ie_print ext_printers[] = {
+-      [35] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), },
+-      [36] = { "HE Operation", print_he_oper, 6, 15, BIT(PRINT_SCAN), },
++      [EID_EXT_HE_CAPABILITY] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), },
++      [EID_EXT_HE_OPERATION] = { "HE Operation", print_he_oper, 6, 15, BIT(PRINT_SCAN), },
+ };
+ static void print_extension(unsigned char len, unsigned char *ie,
diff --git a/package/network/utils/iw/patches/104-iw-scan-replace-passed-ie-buffer-with-ie-context.patch b/package/network/utils/iw/patches/104-iw-scan-replace-passed-ie-buffer-with-ie-context.patch
new file mode 100644 (file)
index 0000000..aa8b8b1
--- /dev/null
@@ -0,0 +1,482 @@
+From a0a7ddef29fc412cee7e3ca027905218b145a40f Mon Sep 17 00:00:00 2001
+From: Dylan Eskew <dylan.eskew@candelatech.com>
+Date: Fri, 22 Nov 2024 08:18:51 -0800
+Subject: [PATCH] iw: scan: replace passed ie buffer with ie context
+
+Since some ies require references to other ies, parse
+the ie list once before to create a context and prevent
+parsing more than the two times required.
+
+Signed-off-by: Dylan Eskew <dylan.eskew@candelatech.com>
+Link: https://patch.msgid.link/20241122161851.647214-1-dylan.eskew@candelatech.com
+[cleanups]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+ scan.c | 141 +++++++++++++++++++++++++++++++--------------------------
+ 1 file changed, 76 insertions(+), 65 deletions(-)
+
+--- a/scan.c
++++ b/scan.c
+@@ -554,13 +554,12 @@ static void tab_on_first(bool *first)
+               *first = false;
+ }
+-struct print_ies_data {
+-      unsigned char *ie;
+-      int ielen;
++struct ie_context {
++      bool is_vht_cap;
+ };
+ static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data,
+-                     const struct print_ies_data *ie_buffer)
++                     const struct ie_context *ctx)
+ {
+       printf(" ");
+       print_ssid_escaped(len, data);
+@@ -572,7 +571,7 @@ static void print_ssid(const uint8_t typ
+ static void print_supprates(const uint8_t type, uint8_t len,
+                           const uint8_t *data,
+-                          const struct print_ies_data *ie_buffer)
++                          const struct ie_context *ctx)
+ {
+       int i;
+@@ -595,7 +594,7 @@ static void print_supprates(const uint8_
+ static void print_rm_enabled_capabilities(const uint8_t type, uint8_t len,
+                           const uint8_t *data,
+-                          const struct print_ies_data *ie_buffer)
++                          const struct ie_context *ctx)
+ {
+       __u64 capa = ((__u64) data[0]) |
+                    ((__u64) data[1]) << 8 |
+@@ -649,7 +648,7 @@ static void print_rm_enabled_capabilitie
+ }
+ static void print_ds(const uint8_t type, uint8_t len, const uint8_t *data,
+-                   const struct print_ies_data *ie_buffer)
++                   const struct ie_context *ctx)
+ {
+       printf(" channel %d\n", data[0]);
+ }
+@@ -669,7 +668,7 @@ static const char *country_env_str(char
+ }
+ static void print_country(const uint8_t type, uint8_t len, const uint8_t *data,
+-                        const struct print_ies_data *ie_buffer)
++                        const struct ie_context *ctx)
+ {
+       printf(" %.*s", 2, data);
+@@ -716,21 +715,21 @@ static void print_country(const uint8_t
+ static void print_powerconstraint(const uint8_t type, uint8_t len,
+                                 const uint8_t *data,
+-                                const struct print_ies_data *ie_buffer)
++                                const struct ie_context *ctx)
+ {
+       printf(" %d dB\n", data[0]);
+ }
+ static void print_tpcreport(const uint8_t type, uint8_t len,
+                           const uint8_t *data,
+-                          const struct print_ies_data *ie_buffer)
++                          const struct ie_context *ctx)
+ {
+       printf(" TX power: %d dBm\n", data[0]);
+       /* printf(" Link Margin (%d dB) is reserved in Beacons\n", data[1]); */
+ }
+ static void print_erp(const uint8_t type, uint8_t len, const uint8_t *data,
+-                    const struct print_ies_data *ie_buffer)
++                    const struct ie_context *ctx)
+ {
+       if (data[0] == 0x00)
+               printf(" <no flags>");
+@@ -744,7 +743,7 @@ static void print_erp(const uint8_t type
+ }
+ static void print_ap_channel_report(const uint8_t type, uint8_t len, const uint8_t *data,
+-                                  const struct print_ies_data *ie_buffer)
++                                  const struct ie_context *ctx)
+ {
+       uint8_t oper_class = data[0];
+       int i;
+@@ -1084,13 +1083,13 @@ static void print_osen_ie(const char *de
+ }
+ static void print_rsn(const uint8_t type, uint8_t len, const uint8_t *data,
+-                    const struct print_ies_data *ie_buffer)
++                    const struct ie_context *ctx)
+ {
+       print_rsn_ie("CCMP", "IEEE 802.1X", len, data);
+ }
+ static void print_ht_capa(const uint8_t type, uint8_t len, const uint8_t *data,
+-                        const struct print_ies_data *ie_buffer)
++                        const struct ie_context *ctx)
+ {
+       printf("\n");
+       print_ht_capability(data[0] | (data[1] << 8));
+@@ -1135,7 +1134,7 @@ static const char* vgroup_11u(uint8_t t)
+ static void print_interworking(const uint8_t type, uint8_t len,
+                              const uint8_t *data,
+-                             const struct print_ies_data *ie_buffer)
++                             const struct ie_context *ctx)
+ {
+       /* See Section 7.3.2.92 in the 802.11u spec. */
+       printf("\n");
+@@ -1168,7 +1167,7 @@ static void print_interworking(const uin
+ static void print_11u_advert(const uint8_t type, uint8_t len,
+                            const uint8_t *data,
+-                           const struct print_ies_data *ie_buffer)
++                           const struct ie_context *ctx)
+ {
+       /* See Section 7.3.2.93 in the 802.11u spec. */
+       /* TODO: This code below does not decode private protocol IDs */
+@@ -1201,7 +1200,7 @@ static void print_11u_advert(const uint8
+ }
+ static void print_11u_rcon(const uint8_t type, uint8_t len, const uint8_t *data,
+-                         const struct print_ies_data *ie_buffer)
++                         const struct ie_context *ctx)
+ {
+       /* See Section 7.3.2.96 in the 802.11u spec. */
+       int idx = 0;
+@@ -1254,7 +1253,7 @@ static void print_11u_rcon(const uint8_t
+ static void print_tx_power_envelope(const uint8_t type, uint8_t len,
+                                   const uint8_t *data,
+-                                  const struct print_ies_data *ie_buffer)
++                                  const struct ie_context *ctx)
+ {
+       const uint8_t local_max_tx_power_count = data[0] & 7;
+       const uint8_t local_max_tx_power_unit_interp = (data[0] >> 3) & 7;
+@@ -1290,7 +1289,7 @@ static const char *ht_secondary_offset[4
+ };
+ static void print_ht_op(const uint8_t type, uint8_t len, const uint8_t *data,
+-                      const struct print_ies_data *ie_buffer)
++                      const struct ie_context *ctx)
+ {
+       static const char *protection[4] = {
+               "no",
+@@ -1322,21 +1321,10 @@ static void print_ht_op(const uint8_t ty
+ static void print_capabilities(const uint8_t type, uint8_t len,
+                              const uint8_t *data,
+-                             const struct print_ies_data *ie_buffer)
++                             const struct ie_context *ctx)
+ {
+       int i, base, bit, si_duration = 0, max_amsdu = 0;
+-      bool s_psmp_support = false, is_vht_cap = false;
+-      unsigned char *ie = ie_buffer->ie;
+-      int ielen = ie_buffer->ielen;
+-
+-      while (ielen >= 2 && ielen >= ie[1]) {
+-              if (ie[0] == 191) {
+-                      is_vht_cap = true;
+-                      break;
+-              }
+-              ielen -= ie[1] + 2;
+-              ie += ie[1] + 2;
+-      }
++      bool s_psmp_support = false;
+       for (i = 0; i < len; i++) {
+               base = i * 8;
+@@ -1432,8 +1420,8 @@ static void print_capabilities(const uin
+                       CAPA(61, "TDLS Wider Bandwidth");
+                       CAPA(62, "Operating Mode Notification");
+-                      ADD_BIT_VAL(63, is_vht_cap, max_amsdu, 1);
+-                      ADD_BIT_VAL(64, is_vht_cap, max_amsdu, 2);
++                      ADD_BIT_VAL(63, ctx->is_vht_cap, max_amsdu, 1);
++                      ADD_BIT_VAL(64, ctx->is_vht_cap, max_amsdu, 2);
+                       CAPA(65, "Channel Schedule Management");
+                       CAPA(66, "Geodatabase Inband Enabling Signal");
+@@ -1462,7 +1450,7 @@ static void print_capabilities(const uin
+               printf("\n\t\t * Service Interval Granularity is %d ms",
+                      (si_duration + 1) * 5);
+-      if (is_vht_cap) {
++      if (ctx->is_vht_cap) {
+               printf("\n\t\t * Max Number Of MSDUs In A-MSDU is ");
+               switch (max_amsdu) {
+               case 0:
+@@ -1486,7 +1474,7 @@ static void print_capabilities(const uin
+ }
+ static void print_tim(const uint8_t type, uint8_t len, const uint8_t *data,
+-                    const struct print_ies_data *ie_buffer)
++                    const struct ie_context *ctx)
+ {
+       printf(" DTIM Count %u DTIM Period %u Bitmap Control 0x%x "
+              "Bitmap[0] 0x%x",
+@@ -1497,13 +1485,13 @@ static void print_tim(const uint8_t type
+ }
+ static void print_ibssatim(const uint8_t type, uint8_t len, const uint8_t *data,
+-                         const struct print_ies_data *ie_buffer)
++                         const struct ie_context *ctx)
+ {
+       printf(" %d TUs\n", (data[1] << 8) + data[0]);
+ }
+ static void print_vht_capa(const uint8_t type, uint8_t len, const uint8_t *data,
+-                         const struct print_ies_data *ie_buffer)
++                         const struct ie_context *ctx)
+ {
+       printf("\n");
+       print_vht_info((__u32) data[0] | ((__u32)data[1] << 8) |
+@@ -1512,7 +1500,7 @@ static void print_vht_capa(const uint8_t
+ }
+ static void print_vht_oper(const uint8_t type, uint8_t len, const uint8_t *data,
+-                         const struct print_ies_data *ie_buffer)
++                         const struct ie_context *ctx)
+ {
+       const char *chandwidths[] = {
+               [0] = "20 or 40 MHz",
+@@ -1531,7 +1519,7 @@ static void print_vht_oper(const uint8_t
+ static void print_supp_op_classes(const uint8_t type, uint8_t len,
+                                 const uint8_t *data,
+-                                const struct print_ies_data *ie_buffer)
++                                const struct ie_context *ctx)
+ {
+       uint8_t *p = (uint8_t*) data;
+       const uint8_t *next_data = p + len;
+@@ -1565,7 +1553,7 @@ static void print_supp_op_classes(const
+ static void print_measurement_pilot_tx(const uint8_t type, uint8_t len,
+                                      const uint8_t *data,
+-                                     const struct print_ies_data *ie_buffer)
++                                     const struct ie_context *ctx)
+ {
+       uint8_t *p, len_remaining;
+@@ -1614,7 +1602,7 @@ static void print_measurement_pilot_tx(c
+ static void print_obss_scan_params(const uint8_t type, uint8_t len,
+                                  const uint8_t *data,
+-                                 const struct print_ies_data *ie_buffer)
++                                 const struct ie_context *ctx)
+ {
+       printf("\n");
+       printf("\t\t * passive dwell: %d TUs\n", (data[1] << 8) | data[0]);
+@@ -1629,7 +1617,7 @@ static void print_obss_scan_params(const
+ static void print_secchan_offs(const uint8_t type, uint8_t len,
+                              const uint8_t *data,
+-                             const struct print_ies_data *ie_buffer)
++                             const struct ie_context *ctx)
+ {
+       if (data[0] < ARRAY_SIZE(ht_secondary_offset))
+               printf(" %s (%d)\n", ht_secondary_offset[data[0]], data[0]);
+@@ -1638,7 +1626,7 @@ static void print_secchan_offs(const uin
+ }
+ static void print_bss_load(const uint8_t type, uint8_t len, const uint8_t *data,
+-                         const struct print_ies_data *ie_buffer)
++                         const struct ie_context *ctx)
+ {
+       printf("\n");
+       printf("\t\t * station count: %d\n", (data[1] << 8) | data[0]);
+@@ -1648,7 +1636,7 @@ static void print_bss_load(const uint8_t
+ static void print_mesh_conf(const uint8_t type, uint8_t len,
+                           const uint8_t *data,
+-                          const struct print_ies_data *ie_buffer)
++                          const struct ie_context *ctx)
+ {
+       printf("\n");
+       printf("\t\t * Active Path Selection Protocol ID: %d\n", data[0]);
+@@ -1681,7 +1669,7 @@ static void print_mesh_conf(const uint8_
+ static void print_s1g_capa(const uint8_t type, uint8_t len,
+                           const uint8_t *data,
+-                          const struct print_ies_data *ie_buffer)
++                          const struct ie_context *ctx)
+ {
+       printf("\n");
+       print_s1g_capability(data);
+@@ -1689,14 +1677,14 @@ static void print_s1g_capa(const uint8_t
+ static void print_short_beacon_int(const uint8_t type, uint8_t len,
+                           const uint8_t *data,
+-                          const struct print_ies_data *ie_buffer)
++                          const struct ie_context *ctx)
+ {
+       printf(" %d\n", (data[1] << 8) | data[0]);
+ }
+ static void print_s1g_oper(const uint8_t type, uint8_t len,
+                           const uint8_t *data,
+-                          const struct print_ies_data *ie_buffer)
++                          const struct ie_context *ctx)
+ {
+       int oper_ch_width, prim_ch_width;
+       int prim_ch_width_subfield = data[0] & 0x1;
+@@ -1777,14 +1765,14 @@ static void print_s1g_oper(const uint8_t
+ struct ie_print {
+       const char *name;
+       void (*print)(const uint8_t type, uint8_t len, const uint8_t *data,
+-                    const struct print_ies_data *ie_buffer);
++                    const struct ie_context *ctx);
+       uint8_t minlen, maxlen;
+       uint8_t flags;
+ };
+ static void print_ie(const struct ie_print *p, const uint8_t type, uint8_t len,
+                    const uint8_t *data,
+-                   const struct print_ies_data *ie_buffer)
++                   const struct ie_context *ctx)
+ {
+       int i;
+@@ -1805,7 +1793,7 @@ static void print_ie(const struct ie_pri
+               return;
+       }
+-      p->print(type, len, data, ie_buffer);
++      p->print(type, len, data, ctx);
+ }
+ #define PRINT_IGN {           \
+@@ -1867,14 +1855,14 @@ static const struct ie_print ieprinters[
+ };
+ static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data,
+-                         const struct print_ies_data *ie_buffer)
++                         const struct ie_context *ctx)
+ {
+       print_rsn_ie("TKIP", "IEEE 802.1X", len, data);
+ }
+ static void print_wifi_osen(const uint8_t type, uint8_t len,
+                           const uint8_t *data,
+-                          const struct print_ies_data *ie_buffer)
++                          const struct ie_context *ctx)
+ {
+       print_osen_ie("OSEN", "OSEN", len, data);
+ }
+@@ -1922,7 +1910,7 @@ static bool print_wifi_wmm_param(const u
+ }
+ static void print_wifi_wmm(const uint8_t type, uint8_t len, const uint8_t *data,
+-                         const struct print_ies_data *ie_buffer)
++                         const struct ie_context *ctx)
+ {
+       int i;
+@@ -1965,7 +1953,7 @@ static const char * wifi_wps_dev_passwd_
+ }
+ static void print_wifi_wps(const uint8_t type, uint8_t len, const uint8_t *data,
+-                         const struct print_ies_data *ie_buffer)
++                         const struct ie_context *ctx)
+ {
+       bool first = true;
+       __u16 subtype, sublen;
+@@ -2205,7 +2193,7 @@ static const struct ie_print wifiprinter
+ static inline void print_p2p(const uint8_t type, uint8_t len,
+                            const uint8_t *data,
+-                           const struct print_ies_data *ie_buffer)
++                           const struct ie_context *ctx)
+ {
+       bool first = true;
+       __u8 subtype;
+@@ -2287,7 +2275,7 @@ static inline void print_p2p(const uint8
+ static inline void print_hs20_ind(const uint8_t type, uint8_t len,
+                                 const uint8_t *data,
+-                                const struct print_ies_data *ie_buffer)
++                                const struct ie_context *ctx)
+ {
+       /* I can't find the spec for this...just going off what wireshark uses. */
+       printf("\n");
+@@ -2299,7 +2287,7 @@ static inline void print_hs20_ind(const
+ static void print_wifi_owe_tarns(const uint8_t type, uint8_t len,
+                                const uint8_t *data,
+-                               const struct print_ies_data *ie_buffer)
++                               const struct ie_context *ctx)
+ {
+       char mac_addr[20];
+       int ssid_len;
+@@ -2392,14 +2380,14 @@ static void print_vendor(unsigned char l
+ }
+ static void print_he_capa(const uint8_t type, uint8_t len, const uint8_t *data,
+-                        const struct print_ies_data *ie_buffer)
++                        const struct ie_context *ctx)
+ {
+       printf("\n");
+       print_he_capability(data, len);
+ }
+ static void print_he_oper(const uint8_t type, uint8_t len, const uint8_t *data,
+-                        const struct print_ies_data *ie_buffer)
++                        const struct ie_context *ctx)
+ {
+       printf("\n");
+       print_he_operation(data, len);
+@@ -2437,23 +2425,46 @@ static void print_extension(unsigned cha
+       }
+ }
++static void init_context(struct ie_context *ctx,
++                       unsigned char *ie, int ielen)
++{
++      unsigned char *pos = ie;
++      int remaining = ielen;
++
++      memset(ctx, 0, sizeof(*ctx));
++
++      if (!ie || !ielen)
++              return;
++
++      while (remaining >= 2 && remaining - 2 >= pos[1]) {
++              switch (pos[0]) {
++              case EID_VHT_CAPABILITY:
++                      ctx->is_vht_cap = true;
++                      break;
++              }
++
++              remaining -= pos[1] + 2;
++              pos += pos[1] + 2;
++      }
++}
++
+ void print_ies(unsigned char *ie, int ielen, bool unknown,
+              enum print_ie_type ptype)
+ {
+-      struct print_ies_data ie_buffer = {
+-              .ie = ie,
+-              .ielen = ielen };
++      struct ie_context ctx;
+-      if (ie == NULL || ielen < 0)
++      if (!ie)
+               return;
++      init_context(&ctx, ie, ielen);
++
+       while (ielen >= 2 && ielen - 2 >= ie[1]) {
+               if (ie[0] < ARRAY_SIZE(ieprinters) &&
+                   ieprinters[ie[0]].name &&
+                   ieprinters[ie[0]].flags & BIT(ptype) &&
+                           ie[1] > 0) {
+                       print_ie(&ieprinters[ie[0]],
+-                               ie[0], ie[1], ie + 2, &ie_buffer);
++                               ie[0], ie[1], ie + 2, &ctx);
+               } else if (ie[0] == 221 /* vendor */) {
+                       print_vendor(ie[1], ie + 2, unknown, ptype);
+               } else if (ie[0] == 255 /* extension */) {
diff --git a/package/network/utils/iw/patches/105-iw-util-update-and-clean-up-eht-capa-printing.patch b/package/network/utils/iw/patches/105-iw-util-update-and-clean-up-eht-capa-printing.patch
new file mode 100644 (file)
index 0000000..3970677
--- /dev/null
@@ -0,0 +1,207 @@
+From 4c859917316b69e66ba241d85b4da6ee01292a11 Mon Sep 17 00:00:00 2001
+From: Dylan Eskew <dylan.eskew@candelatech.com>
+Date: Wed, 19 Mar 2025 11:39:17 -0700
+Subject: [PATCH] iw: util: update and clean up eht capa printing
+
+A number of fields were either missing or incorrect, so
+update to more aligned with 802.11be spec. Also clean up
+printout formatting.
+
+Signed-off-by: Dylan Eskew <dylan.eskew@candelatech.com>
+Link: https://patch.msgid.link/20250319183918.1215853-2-dylan.eskew@candelatech.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+ iw.h   |   2 +
+ util.c | 124 ++++++++++++++++++++++++++++++++++++++++++++-------------
+ 2 files changed, 99 insertions(+), 27 deletions(-)
+
+--- a/iw.h
++++ b/iw.h
+@@ -224,6 +224,8 @@ void print_vht_info(__u32 capa, const __
+ void print_he_capability(const uint8_t *ie, int len);
+ void print_he_operation(const uint8_t *ie, int len);
+ void print_he_info(struct nlattr *nl_iftype);
++void print_eht_capability(const uint8_t *ie, int len, const uint8_t *he_cap,
++                        bool from_ap);
+ void print_eht_info(struct nlattr *nl_iftype, int band);
+ void print_s1g_capability(const uint8_t *caps);
+--- a/util.c
++++ b/util.c
+@@ -1515,11 +1515,11 @@ static void __print_eht_capa(int band,
+                            const __u8 *mcs_set, size_t mcs_len,
+                            const __u8 *ppet, size_t ppet_len,
+                            const __u16 *he_phy_cap,
++                           bool from_ap,
+                            bool indent)
+ {
+       unsigned int i;
+       const char *pre = indent ? "\t" : "";
+-      const char *mcs[] = { "0-7", "8-9", "10-11", "12-13"};
+       #define PRINT_EHT_CAP(_var, _idx, _bit, _str) \
+       do { \
+@@ -1534,6 +1534,7 @@ static void __print_eht_capa(int band,
+       } while (0)
+       #define PRINT_EHT_MAC_CAP(...) PRINT_EHT_CAP(mac_cap, __VA_ARGS__)
++      #define PRINT_EHT_MAC_CAP_MASK(...) PRINT_EHT_CAP_MASK(mac_cap, __VA_ARGS__)
+       #define PRINT_EHT_PHY_CAP(...) PRINT_EHT_CAP(phy_cap, __VA_ARGS__)
+       #define PRINT_EHT_PHY_CAP_MASK(...) PRINT_EHT_CAP_MASK(phy_cap, __VA_ARGS__)
+@@ -1542,13 +1543,22 @@ static void __print_eht_capa(int band,
+               printf("%02x", mac_cap[i]);
+       printf("):\n");
+-      PRINT_EHT_MAC_CAP(0, 0, "NSEP priority access Supported");
++      PRINT_EHT_MAC_CAP(0, 0, "EPCS Priority Access Supported");
+       PRINT_EHT_MAC_CAP(0, 1, "EHT OM Control Supported");
+-      PRINT_EHT_MAC_CAP(0, 2, "Triggered TXOP Sharing Supported");
+-      PRINT_EHT_MAC_CAP(0, 3, "ARR Supported");
++      PRINT_EHT_MAC_CAP(0, 2, "Triggered TXOP Sharing Mode 1 Supported");
++      PRINT_EHT_MAC_CAP(0, 3, "Triggered TXOP Sharing Mode 2 Supported");
++      PRINT_EHT_MAC_CAP(0, 4, "Restricted TWP Supported");
++      PRINT_EHT_MAC_CAP(0, 5, "SCS Traffic Description Supported");
++      PRINT_EHT_MAC_CAP_MASK(0, 6, 0x3, "Maximum MPDU Length");
++
++      PRINT_EHT_MAC_CAP(1, 1, "Maximum A_MPDU Length Exponent Extension");
++      PRINT_EHT_MAC_CAP(1, 2, "EHT TRS Supported");
++      PRINT_EHT_MAC_CAP(1, 3, "TXOP Return In TXOP Sharing Mode 2 Supported");
++      PRINT_EHT_MAC_CAP(1, 4, "Two BQRs Supported");
++      PRINT_EHT_MAC_CAP_MASK(1, 5, 0x3, "EHT Link Adaptation Supported");
+-      printf("%s\t\tEHT PHY Capabilities: (0x", pre);
+-      for (i = 0; i < 8; i++)
++      printf("%s\t\tEHT PHY Capabilities (0x", pre);
++      for (i = 0; i < 9; i++)
+               printf("%02x", ((__u8 *)phy_cap)[i]);
+       printf("):\n");
+@@ -1594,39 +1604,77 @@ static void __print_eht_capa(int band,
+       PRINT_EHT_PHY_CAP(1, 28, "MU Beamformer (80MHz)");
+       PRINT_EHT_PHY_CAP(1, 29, "MU Beamformer (160MHz)");
+       PRINT_EHT_PHY_CAP(1, 30, "MU Beamformer (320MHz)");
++      PRINT_EHT_PHY_CAP(1, 31, "TB Sounding Feedback Rate Limit");
+-      printf("%s\t\tEHT MCS/NSS: (0x", pre);
+-      for (i = 0; i < mcs_len; i++)
+-              printf("%02x", ((__u8 *)mcs_set)[i]);
+-      printf("):\n");
++      PRINT_EHT_PHY_CAP(2, 0, "Rx 1024-QAM In Wider Bandwidth DL OFDMA Supported");
++      PRINT_EHT_PHY_CAP(2, 1, "Rx 4096-QAM In Wider Bandwidth DL OFDMA Supported");
+-      if (!(he_phy_cap[0] & ((BIT(2) | BIT(3) | BIT(4)) << 8))){
+-              for (i = 0; i < 4; i++)
+-                      printf("%s\t\tEHT bw=20 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n",
+-                             pre, mcs[i],
+-                             mcs_set[i] & 0xf, mcs_set[i] >> 4);
++      if (!from_ap &&
++          !(he_phy_cap[0] & ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8))) {
++              static const char * const mcs[] = { "0-7", "8-9", "10-11", "12-13" };
++
++              printf("%s\t\tEHT-MCS Map (20 Mhz Non-AP STA) (0x", pre);
++              for (i = 0; i < mcs_len; i++)
++                      printf("%02x", ((__u8 *)mcs_set)[i]);
++              printf("):\n");
++
++              for (i = 0; i < 4; i++) {
++                      printf("%s\t\t\tRx Max NSS for MCS %s: %u\n",
++                             pre, mcs[i], mcs_set[i] & 0xf);
++                      printf("%s\t\t\tTx Max NSS for MCS %s: %u\n",
++                             pre, mcs[i], mcs_set[i] >> 4);
++              }
+       } else {
+-              if (he_phy_cap[0] & (BIT(2) << 8)) {
++              static const char * const mcs[] = { "0-9", "10-11", "12-13"};
++
++              /* Bit 1 corresponds to 2.4Ghz 40Mhz support
++               * Bit 2 corresponds to 5/6Ghz 40 and 80Mhz support
++               * If no Channel Width bits are set, but we are an AP, we use
++               * this MCS logic also.
++               */
++              if (he_phy_cap[0] & ((BIT(1) | BIT(2)) << 8) ||
++                  (from_ap && !(he_phy_cap[0] & ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8)))) {
++                      printf("%s\t\tEHT-MCS Map (BW <= 80) (0x", pre);
+                       for (i = 0; i < 3; i++)
+-                              printf("%s\t\tEHT bw <= 80 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n",
+-                                     pre, mcs[i + 1],
+-                                     mcs_set[i] & 0xf, mcs_set[i] >> 4);
++                              printf("%02x", ((__u8 *)mcs_set)[i]);
++                      printf("):\n");
++
++                      for (i = 0; i < 3; i++) {
++                              printf("%s\t\t\tRx Max NSS for MCS %s: %u\n",
++                                     pre, mcs[i], mcs_set[i] & 0xf);
++                              printf("%s\t\t\tTx Max NSS for MCS %s: %u\n",
++                                     pre, mcs[i], mcs_set[i] >> 4);
++                      }
+               }
+               mcs_set += 3;
+               if (he_phy_cap[0] & (BIT(3) << 8)) {
++                      printf("%s\t\tEHT-MCS Map (BW = 160) (0x", pre);
+                       for (i = 0; i < 3; i++)
+-                              printf("%s\t\tEHT bw=160 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n",
+-                                     pre, mcs[i + 1],
+-                                     mcs_set[i] & 0xf, mcs_set[i] >> 4);
++                              printf("%02x", ((__u8 *)mcs_set)[i]);
++                      printf("):\n");
++
++                      for (i = 0; i < 3; i++) {
++                              printf("%s\t\t\tRx Max NSS for MCS %s: %u\n",
++                                     pre, mcs[i], mcs_set[i] & 0xf);
++                              printf("%s\t\t\tTx Max NSS for MCS %s: %u\n",
++                                     pre, mcs[i], mcs_set[i] >> 4);
++                      }
+               }
+               mcs_set += 3;
+               if (band == NL80211_BAND_6GHZ && (phy_cap[0] & BIT(1))) {
++                      printf("%s\t\tEHT-MCS Map (BW = 320) (0x", pre);
+                       for (i = 0; i < 3; i++)
+-                              printf("%s\t\tEHT bw=320 MHz, max NSS for MCS %s: Rx=%u, Tx=%u\n",
+-                                     pre, mcs[i + 1],
+-                                     mcs_set[i] & 0xf, mcs_set[i] >> 4);
++                              printf("%02x", ((__u8 *)mcs_set)[i]);
++                      printf("):\n");
++
++                      for (i = 0; i < 3; i++) {
++                              printf("%s\t\t\tRx Max NSS for MCS %s: %u\n",
++                                     pre, mcs[i], mcs_set[i] & 0xf);
++                              printf("%s\t\t\tTx Max NSS for MCS %s: %u\n",
++                                     pre, mcs[i], mcs_set[i] >> 4);
++                      }
+               }
+       }
+@@ -1713,7 +1761,29 @@ void print_eht_info(struct nlattr *nl_if
+       }
+       __print_eht_capa(band, mac_cap, phy_cap, mcs_set, mcs_len, ppet, ppet_len,
+-                       he_phy_cap, true);
++                       he_phy_cap, false, true);
++}
++
++void print_eht_capability(const uint8_t *ie, int len, const uint8_t *he_cap,
++                        bool from_ap)
++{
++      const void *mac_cap, *phy_cap, *mcs_set, *he_phy_cap;
++      int mcs_len;
++      int i = 0;
++
++      mac_cap = &ie[i];
++      i += 2;
++
++      phy_cap = &ie[i];
++      i += 9;
++
++      mcs_set = &ie[i];
++      mcs_len = len - i;
++
++      he_phy_cap = &he_cap[6];
++
++      __print_eht_capa(NL80211_BAND_6GHZ, mac_cap, phy_cap, mcs_set, mcs_len,
++                       NULL, 0, he_phy_cap - 1, from_ap, false);
+ }
+ void print_he_capability(const uint8_t *ie, int len)
diff --git a/package/network/utils/iw/patches/106-iw-scan-add-eht-capability-parsing.patch b/package/network/utils/iw/patches/106-iw-scan-add-eht-capability-parsing.patch
new file mode 100644 (file)
index 0000000..ff8a323
--- /dev/null
@@ -0,0 +1,175 @@
+From a6ad3f11ead18d1812c7d3759991dc22b20d90da Mon Sep 17 00:00:00 2001
+From: Dylan Eskew <dylan.eskew@candelatech.com>
+Date: Wed, 19 Mar 2025 11:39:18 -0700
+Subject: [PATCH] iw: scan: add eht capability parsing
+
+Add ability to print out EHT capabilities from
+AP beacons.
+
+Signed-off-by: Dylan Eskew <dylan.eskew@candelatech.com>
+Link: https://patch.msgid.link/20250319183918.1215853-3-dylan.eskew@candelatech.com
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+ ieee80211.h |  1 +
+ iw.h        |  2 +-
+ link.c      |  5 +++--
+ scan.c      | 34 +++++++++++++++++++++++++++-------
+ 4 files changed, 32 insertions(+), 10 deletions(-)
+
+--- a/ieee80211.h
++++ b/ieee80211.h
+@@ -99,6 +99,7 @@ enum elem_id {
+ enum elem_id_ext {
+       EID_EXT_HE_CAPABILITY           = 35,
+       EID_EXT_HE_OPERATION            = 36,
++      EID_EXT_EHT_CAPABILITY          = 108,
+ };
+ #define SUITE(oui, id)  (((oui) << 8) | (id))
+--- a/iw.h
++++ b/iw.h
+@@ -256,7 +256,7 @@ enum print_ie_type {
+ #define BIT(x) (1ULL<<(x))
+ void print_ies(unsigned char *ie, int ielen, bool unknown,
+-             enum print_ie_type ptype);
++             enum print_ie_type ptype, bool from_ap);
+ void parse_bitrate(struct nlattr *bitrate_attr, char *buf, int buflen);
+ void iw_hexdump(const char *prefix, const __u8 *data, size_t len);
+--- a/link.c
++++ b/link.c
+@@ -93,7 +93,7 @@ static int link_bss_handler(struct nl_ms
+                       if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
+                               print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
+                                         nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
+-                                        false, PRINT_LINK_MLO_MLD);
++                                        false, PRINT_LINK_MLO_MLD, false);
+               }
+       } else {
+               memcpy(result->sta_addr, nla_data(bss[NL80211_BSS_BSSID]), 6);
+@@ -121,7 +121,8 @@ static int link_bss_handler(struct nl_ms
+       if (bss[NL80211_BSS_INFORMATION_ELEMENTS])
+               print_ies(nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
+                         nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]),
+-                        false, result->mld ? PRINT_LINK_MLO_LINK : PRINT_LINK);
++                        false, result->mld ? PRINT_LINK_MLO_LINK : PRINT_LINK,
++                        false);
+       if (bss[NL80211_BSS_FREQUENCY_OFFSET])
+               freq_offset = nla_get_u32(bss[NL80211_BSS_FREQUENCY_OFFSET]);
+--- a/scan.c
++++ b/scan.c
+@@ -555,7 +555,9 @@ static void tab_on_first(bool *first)
+ }
+ struct ie_context {
++      bool from_ap;
+       bool is_vht_cap;
++      const uint8_t *he_cap;
+ };
+ static void print_ssid(const uint8_t type, uint8_t len, const uint8_t *data,
+@@ -2393,12 +2395,21 @@ static void print_he_oper(const uint8_t
+       print_he_operation(data, len);
+ }
++static void print_eht_capa(const uint8_t type, uint8_t len,
++                         const uint8_t *data, const struct ie_context *ctx)
++{
++      printf("\n");
++      print_eht_capability(data, len, ctx->he_cap, ctx->from_ap);
++}
++
+ static const struct ie_print ext_printers[] = {
+       [EID_EXT_HE_CAPABILITY] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), },
+       [EID_EXT_HE_OPERATION] = { "HE Operation", print_he_oper, 6, 15, BIT(PRINT_SCAN), },
++      [EID_EXT_EHT_CAPABILITY] = { "EHT capabilities", print_eht_capa, 13, 30, BIT(PRINT_SCAN), },
+ };
+ static void print_extension(unsigned char len, unsigned char *ie,
++                          const struct ie_context *ctx,
+                           bool unknown, enum print_ie_type ptype)
+ {
+       unsigned char tag;
+@@ -2411,7 +2422,7 @@ static void print_extension(unsigned cha
+       tag = ie[0];
+       if (tag < ARRAY_SIZE(ext_printers) && ext_printers[tag].name &&
+           ext_printers[tag].flags & BIT(ptype)) {
+-              print_ie(&ext_printers[tag], tag, len - 1, ie + 1, NULL);
++              print_ie(&ext_printers[tag], tag, len - 1, ie + 1, ctx);
+               return;
+       }
+@@ -2426,7 +2437,7 @@ static void print_extension(unsigned cha
+ }
+ static void init_context(struct ie_context *ctx,
+-                       unsigned char *ie, int ielen)
++                       unsigned char *ie, int ielen, bool from_ap)
+ {
+       unsigned char *pos = ie;
+       int remaining = ielen;
+@@ -2436,11 +2447,20 @@ static void init_context(struct ie_conte
+       if (!ie || !ielen)
+               return;
++      ctx->from_ap = from_ap;
++
+       while (remaining >= 2 && remaining - 2 >= pos[1]) {
+               switch (pos[0]) {
+               case EID_VHT_CAPABILITY:
+                       ctx->is_vht_cap = true;
+                       break;
++              case EID_EXTENSION:
++                      switch (pos[2]) {
++                      case EID_EXT_HE_CAPABILITY:
++                              ctx->he_cap = pos + 3;
++                              break;
++                      }
++                      break;
+               }
+               remaining -= pos[1] + 2;
+@@ -2449,14 +2469,14 @@ static void init_context(struct ie_conte
+ }
+ void print_ies(unsigned char *ie, int ielen, bool unknown,
+-             enum print_ie_type ptype)
++             enum print_ie_type ptype, bool from_ap)
+ {
+       struct ie_context ctx;
+       if (!ie)
+               return;
+-      init_context(&ctx, ie, ielen);
++      init_context(&ctx, ie, ielen, from_ap);
+       while (ielen >= 2 && ielen - 2 >= ie[1]) {
+               if (ie[0] < ARRAY_SIZE(ieprinters) &&
+@@ -2468,7 +2488,7 @@ void print_ies(unsigned char *ie, int ie
+               } else if (ie[0] == 221 /* vendor */) {
+                       print_vendor(ie[1], ie + 2, unknown, ptype);
+               } else if (ie[0] == 255 /* extension */) {
+-                      print_extension(ie[1], ie + 2, unknown, ptype);
++                      print_extension(ie[1], ie + 2, &ctx, unknown, ptype);
+               } else if (unknown) {
+                       int i;
+@@ -2673,13 +2693,13 @@ static int print_bss_handler(struct nl_m
+                       printf("\tInformation elements from Probe Response "
+                              "frame:\n");
+               print_ies(nla_data(ies), nla_len(ies),
+-                        params->unknown, params->type);
++                        params->unknown, params->type, true);
+       }
+       if (bss[NL80211_BSS_BEACON_IES] && show--) {
+               printf("\tInformation elements from Beacon frame:\n");
+               print_ies(nla_data(bss[NL80211_BSS_BEACON_IES]),
+                         nla_len(bss[NL80211_BSS_BEACON_IES]),
+-                        params->unknown, params->type);
++                        params->unknown, params->type, true);
+       }
+       return NL_SKIP;
diff --git a/package/network/utils/iw/patches/107-iw-fix-EHT-capabilities-on-Big-Endian-platforms.patch b/package/network/utils/iw/patches/107-iw-fix-EHT-capabilities-on-Big-Endian-platforms.patch
new file mode 100644 (file)
index 0000000..d0f15ea
--- /dev/null
@@ -0,0 +1,107 @@
+From 59660a349cf35903e951f99bdd8a74df063c912e Mon Sep 17 00:00:00 2001
+From: Aleksander Jan Bajkowski <olek2@wp.pl>
+Date: Fri, 2 May 2025 21:44:05 +0200
+Subject: [PATCH] iw: fix EHT capabilities on Big Endian platforms
+
+IE fields are encoded in Little Endian and are not correctly
+printed on Big Endian platforms.
+
+Fixes: 5a71b722270c ("iw: Print local EHT capabilities")
+Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
+Link: https://patch.msgid.link/20250502194405.3489240-1-olek2@wp.pl
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+ util.c | 40 +++++++++++++++++++++++++---------------
+ 1 file changed, 25 insertions(+), 15 deletions(-)
+
+--- a/util.c
++++ b/util.c
+@@ -1521,22 +1521,31 @@ static void __print_eht_capa(int band,
+       unsigned int i;
+       const char *pre = indent ? "\t" : "";
+-      #define PRINT_EHT_CAP(_var, _idx, _bit, _str) \
++      #define PRINT_EHT_MAC_CAP(_idx, _bit, _str) \
+       do { \
+-              if (_var[_idx] & BIT(_bit)) \
++              if (mac_cap[_idx] & BIT(_bit)) \
+                       printf("%s\t\t\t" _str "\n", pre); \
+       } while (0)
+-      #define PRINT_EHT_CAP_MASK(_var, _idx, _shift, _mask, _str) \
++      #define PRINT_EHT_MAC_CAP_MASK(_idx, _shift, _mask, _str) \
+       do { \
+-              if ((_var[_idx] >> _shift) & _mask) \
+-                      printf("%s\t\t\t" _str ": %d\n", pre, (_var[_idx] >> _shift) & _mask); \
++              if ((mac_cap[_idx] >> _shift) & _mask) \
++                      printf("%s\t\t\t" _str ": %d\n", pre, \
++                             (mac_cap[_idx] >> _shift) & _mask); \
+       } while (0)
+-      #define PRINT_EHT_MAC_CAP(...) PRINT_EHT_CAP(mac_cap, __VA_ARGS__)
+-      #define PRINT_EHT_MAC_CAP_MASK(...) PRINT_EHT_CAP_MASK(mac_cap, __VA_ARGS__)
+-      #define PRINT_EHT_PHY_CAP(...) PRINT_EHT_CAP(phy_cap, __VA_ARGS__)
+-      #define PRINT_EHT_PHY_CAP_MASK(...) PRINT_EHT_CAP_MASK(phy_cap, __VA_ARGS__)
++      #define PRINT_EHT_PHY_CAP(_idx, _bit, _str) \
++      do { \
++              if (le32toh(phy_cap[_idx]) & BIT(_bit)) \
++                      printf("%s\t\t\t" _str "\n", pre); \
++      } while (0)
++
++      #define PRINT_EHT_PHY_CAP_MASK(_idx, _shift, _mask, _str) \
++      do { \
++              if ((le32toh(phy_cap[_idx]) >> _shift) & _mask) \
++                      printf("%s\t\t\t" _str ": %d\n", pre, \
++                             (le32toh(phy_cap[_idx]) >> _shift) & _mask); \
++      } while (0)
+       printf("%s\t\tEHT MAC Capabilities (0x", pre);
+       for (i = 0; i < 2; i++)
+@@ -1610,7 +1619,7 @@ static void __print_eht_capa(int band,
+       PRINT_EHT_PHY_CAP(2, 1, "Rx 4096-QAM In Wider Bandwidth DL OFDMA Supported");
+       if (!from_ap &&
+-          !(he_phy_cap[0] & ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8))) {
++          !(le16toh(he_phy_cap[0]) & ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8))) {
+               static const char * const mcs[] = { "0-7", "8-9", "10-11", "12-13" };
+               printf("%s\t\tEHT-MCS Map (20 Mhz Non-AP STA) (0x", pre);
+@@ -1632,8 +1641,9 @@ static void __print_eht_capa(int band,
+                * If no Channel Width bits are set, but we are an AP, we use
+                * this MCS logic also.
+                */
+-              if (he_phy_cap[0] & ((BIT(1) | BIT(2)) << 8) ||
+-                  (from_ap && !(he_phy_cap[0] & ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8)))) {
++              if (le16toh(he_phy_cap[0]) & ((BIT(1) | BIT(2)) << 8) ||
++                  (from_ap && !(le16toh(he_phy_cap[0]) &
++                  ((BIT(1) | BIT(2) | BIT(3) | BIT(4)) << 8)))) {
+                       printf("%s\t\tEHT-MCS Map (BW <= 80) (0x", pre);
+                       for (i = 0; i < 3; i++)
+                               printf("%02x", ((__u8 *)mcs_set)[i]);
+@@ -1648,7 +1658,7 @@ static void __print_eht_capa(int band,
+               }
+               mcs_set += 3;
+-              if (he_phy_cap[0] & (BIT(3) << 8)) {
++              if (le16toh(he_phy_cap[0]) & (BIT(3) << 8)) {
+                       printf("%s\t\tEHT-MCS Map (BW = 160) (0x", pre);
+                       for (i = 0; i < 3; i++)
+                               printf("%02x", ((__u8 *)mcs_set)[i]);
+@@ -1663,7 +1673,7 @@ static void __print_eht_capa(int band,
+               }
+               mcs_set += 3;
+-              if (band == NL80211_BAND_6GHZ && (phy_cap[0] & BIT(1))) {
++              if (band == NL80211_BAND_6GHZ && (le32toh(phy_cap[0]) & BIT(1))) {
+                       printf("%s\t\tEHT-MCS Map (BW = 320) (0x", pre);
+                       for (i = 0; i < 3; i++)
+                               printf("%02x", ((__u8 *)mcs_set)[i]);
+@@ -1678,7 +1688,7 @@ static void __print_eht_capa(int band,
+               }
+       }
+-      if (ppet && ppet_len && (phy_cap[1] & BIT(11))) {
++      if (ppet && ppet_len && (le32toh(phy_cap[1]) & BIT(11))) {
+               printf("%s\t\tEHT PPE Thresholds ", pre);
+               for (i = 0; i < ppet_len; i++)
+                       if (ppet[i])
diff --git a/package/network/utils/iw/patches/108-iw-scan-Add-printing-of-EHT-Operation-Element.patch b/package/network/utils/iw/patches/108-iw-scan-Add-printing-of-EHT-Operation-Element.patch
new file mode 100644 (file)
index 0000000..81b1def
--- /dev/null
@@ -0,0 +1,131 @@
+From 8ea80d378ce5f727e69493533a666278c6a568a7 Mon Sep 17 00:00:00 2001
+From: Aleksander Jan Bajkowski <olek2@wp.pl>
+Date: Fri, 2 May 2025 12:03:53 +0200
+Subject: [PATCH] iw: scan: Add printing of EHT Operation Element
+
+Add ability to print out EHT capabilities from AP beacons.
+
+Signed-off-by: Aleksander Jan Bajkowski <olek2@wp.pl>
+Link: https://patch.msgid.link/20250502100353.3149470-1-olek2@wp.pl
+[add default case to bandwidth switch]
+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+---
+ ieee80211.h |  1 +
+ iw.h        |  1 +
+ scan.c      |  8 +++++++
+ util.c      | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 73 insertions(+)
+
+--- a/ieee80211.h
++++ b/ieee80211.h
+@@ -99,6 +99,7 @@ enum elem_id {
+ enum elem_id_ext {
+       EID_EXT_HE_CAPABILITY           = 35,
+       EID_EXT_HE_OPERATION            = 36,
++      EID_EXT_EHT_OPERATION           = 106,
+       EID_EXT_EHT_CAPABILITY          = 108,
+ };
+--- a/iw.h
++++ b/iw.h
+@@ -226,6 +226,7 @@ void print_he_operation(const uint8_t *i
+ void print_he_info(struct nlattr *nl_iftype);
+ void print_eht_capability(const uint8_t *ie, int len, const uint8_t *he_cap,
+                         bool from_ap);
++void print_eht_operation(const uint8_t *ie, int len);
+ void print_eht_info(struct nlattr *nl_iftype, int band);
+ void print_s1g_capability(const uint8_t *caps);
+--- a/scan.c
++++ b/scan.c
+@@ -2402,10 +2402,18 @@ static void print_eht_capa(const uint8_t
+       print_eht_capability(data, len, ctx->he_cap, ctx->from_ap);
+ }
++static void print_eht_oper(const uint8_t type, uint8_t len, const uint8_t *data,
++                         const struct ie_context *ctx)
++{
++      printf("\n");
++      print_eht_operation(data, len);
++}
++
+ static const struct ie_print ext_printers[] = {
+       [EID_EXT_HE_CAPABILITY] = { "HE capabilities", print_he_capa, 21, 54, BIT(PRINT_SCAN), },
+       [EID_EXT_HE_OPERATION] = { "HE Operation", print_he_oper, 6, 15, BIT(PRINT_SCAN), },
+       [EID_EXT_EHT_CAPABILITY] = { "EHT capabilities", print_eht_capa, 13, 30, BIT(PRINT_SCAN), },
++      [EID_EXT_EHT_OPERATION] = { "EHT Operation", print_eht_oper, 5, 10, BIT(PRINT_SCAN), },
+ };
+ static void print_extension(unsigned char len, unsigned char *ie,
+--- a/util.c
++++ b/util.c
+@@ -1917,6 +1917,69 @@ void print_he_operation(const uint8_t *i
+       }
+ }
++void print_eht_operation(const uint8_t *ie, int len)
++{
++      uint8_t oper_parameters = ie[0];
++      uint8_t disabled_subchannel_info_present = oper_parameters & 0x02;
++      uint8_t eht_operation_info_present = oper_parameters & 0x01;
++
++      printf("\t\tEHT Operation Parameters: (0x%02x)\n",
++             oper_parameters);
++
++      if (oper_parameters & 0x04)
++              printf("\t\t\tEHT Default PE Duration\n");
++
++      if (oper_parameters & 0x08)
++              printf("\t\t\tGroup Addressed BU Indication Limit\n");
++
++      printf("\t\t\tGroup Addressed BU Indication Exponent: 0x%01x\n",
++             (oper_parameters >> 4 & 3));
++
++      printf("\t\tBasic EHT-MCS And Nss Set: 0x");
++      for (uint8_t i = 0; i < 4; i++)
++              printf("%02x", ie[1 + i]);
++
++      printf("\n");
++
++      if (eht_operation_info_present) {
++              uint8_t offset = 5;
++              const uint8_t control = ie[offset];
++              uint8_t eht_operation_info_len = 3;
++
++              if (disabled_subchannel_info_present)
++                      eht_operation_info_len += 2;
++
++              if (len - offset < eht_operation_info_len) {
++                      printf("\t\tEHT Operation Info: Invalid\n");
++                      return;
++              }
++
++              printf("\t\tEHT Operation Info: 0x");
++              for (uint8_t i = 0; i < eht_operation_info_len; i++)
++                      printf("%02x", ie[offset + i]);
++
++              printf("\n");
++              printf("\t\t\tChannel Width: ");
++              switch (control & 0x7) {
++              case 0: printf("20 MHz\n"); break;
++              case 1: printf("40 MHz\n"); break;
++              case 2: printf("80 MHz\n"); break;
++              case 3: printf("160 MHz\n"); break;
++              case 4: printf("320 MHz\n"); break;
++              default: printf("invalid bandwidth (%d)\n", control & 0x7); break;
++              }
++
++              printf("\t\t\tCenter Frequency Segment 0: %hhu\n",
++                     ie[offset + 1]);
++              printf("\t\t\tCenter Frequency Segment 1: %hhu\n",
++                     ie[offset + 2]);
++
++              if (disabled_subchannel_info_present)
++                      printf("\t\t\tDisabled Subchannel Bitmap: 0x%02x%02x\n",
++                             ie[offset + 3], ie[offset + 4]);
++      }
++}
++
+ void iw_hexdump(const char *prefix, const __u8 *buf, size_t size)
+ {
+       size_t i;
index dc1cce99a2bc5ecab750779ba6b3f07d94059c25..40ca57209de8f0c167a6e2bbab37db5d231a72cc 100644 (file)
  {
 --- a/scan.c
 +++ b/scan.c
-@@ -1308,6 +1308,9 @@ static void print_ht_op(const uint8_t ty
+@@ -1309,6 +1309,9 @@ static void print_ht_op(const uint8_t ty
        printf("\t\t * secondary channel offset: %s\n",
                ht_secondary_offset[data[1] & 0x3]);
        printf("\t\t * STA channel width: %s\n", sta_chan_width[(data[1] & 0x4)>>2]);
        printf("\t\t * RIFS: %d\n", (data[1] & 0x8)>>3);
        printf("\t\t * HT protection: %s\n", protection[data[2] & 0x3]);
        printf("\t\t * non-GF present: %d\n", (data[2] & 0x4) >> 2);
-@@ -1818,30 +1821,31 @@ static void print_ie(const struct ie_pri
+@@ -1808,17 +1811,25 @@ static void print_ie(const struct ie_pri
  static const struct ie_print ieprinters[] = {
-       [0] = { "SSID", print_ssid, 0, 32,
-                BIT(PRINT_SCAN) | BIT(PRINT_LINK) | BIT(PRINT_LINK_MLO_MLD), },
-+      [11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
-+      [45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
-+      [48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
-+      [61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
-+      [62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
-+      [114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
-+      [191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
-+      [192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
+       [EID_SSID] = { "SSID", print_ssid, 0, 32,
+                      BIT(PRINT_SCAN) | BIT(PRINT_LINK) | BIT(PRINT_LINK_MLO_MLD), },
++      [EID_BSS_LOAD] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
++      [EID_HT_CAPABILITY] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
++      [EID_RSN] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
++      [EID_HT_OPERATION] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
++      [EID_SECONDARY_CH_OFFSET] = { "Secondary Channel Offset",
++                                    print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
++      [EID_MESH_ID] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
++      [EID_VHT_CAPABILITY] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
++      [EID_VHT_OPERATION] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
 +#ifdef IW_FULL
-       [1] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
-       [3] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
-       [5] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
-       [6] = { "IBSS ATIM window", print_ibssatim, 2, 2, BIT(PRINT_SCAN), },
-       [7] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), },
--      [11] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
-       [32] = { "Power constraint", print_powerconstraint, 1, 1, BIT(PRINT_SCAN), },
-       [35] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), },
-       [42] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
--      [45] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
-       [47] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), },
-       [51] = { "AP Channel Report", print_ap_channel_report, 1, 255, BIT(PRINT_SCAN), },
-       [59] = { "Supported operating classes", print_supp_op_classes, 1, 255, BIT(PRINT_SCAN), },
-       [66] = { "Measurement Pilot Transmission", print_measurement_pilot_tx, 1, 255, BIT(PRINT_SCAN), },
-       [74] = { "Overlapping BSS scan params", print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
--      [61] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
--      [62] = { "Secondary Channel Offset", print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
--      [191] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
--      [192] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
--      [48] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
-       [50] = { "Extended supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
-       [70] = { "RM enabled capabilities", print_rm_enabled_capabilities, 5, 5, BIT(PRINT_SCAN), },
-       [113] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), },
--      [114] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
-       [127] = { "Extended capabilities", print_capabilities, 0, 255, BIT(PRINT_SCAN), },
-       [107] = { "802.11u Interworking", print_interworking, 0, 255, BIT(PRINT_SCAN), },
-       [108] = { "802.11u Advertisement", print_11u_advert, 0, 255, BIT(PRINT_SCAN), },
-@@ -1850,6 +1854,7 @@ static const struct ie_print ieprinters[
-       [214] = { "Short beacon interval", print_short_beacon_int, 2, 2, BIT(PRINT_SCAN), },
-       [217] = { "S1G capabilities", print_s1g_capa, 15, 15, BIT(PRINT_SCAN), },
-       [232] = { "S1G operation", print_s1g_oper, 6, 6, BIT(PRINT_SCAN), },
+       [EID_SUPP_RATES] = { "Supported rates", print_supprates, 0, 255, BIT(PRINT_SCAN), },
+       [EID_DS_PARAMS] = { "DS Parameter set", print_ds, 1, 1, BIT(PRINT_SCAN), },
+       [EID_TIM] = { "TIM", print_tim, 4, 255, BIT(PRINT_SCAN), },
+       [EID_IBSS_TIM_PARAMS] = { "IBSS ATIM window", print_ibssatim, 2, 2, BIT(PRINT_SCAN), },
+       [EID_COUNTRY] = { "Country", print_country, 3, 255, BIT(PRINT_SCAN), },
+-      [EID_BSS_LOAD] = { "BSS Load", print_bss_load, 5, 5, BIT(PRINT_SCAN), },
+       [EID_POWER_CONSTRAINT] = { "Power constraint", print_powerconstraint,
+                                  1, 1, BIT(PRINT_SCAN), },
+       [EID_TPC_REPORT] = { "TPC report", print_tpcreport, 2, 2, BIT(PRINT_SCAN), },
+       [EID_ERP_INFO] = { "ERP", print_erp, 1, 255, BIT(PRINT_SCAN), },
+-      [EID_HT_CAPABILITY] = { "HT capabilities", print_ht_capa, 26, 26, BIT(PRINT_SCAN), },
+       [EID_ERP_D4_0] = { "ERP D4.0", print_erp, 1, 255, BIT(PRINT_SCAN), },
+       [EID_AP_CHAN_REPORT] = { "AP Channel Report", print_ap_channel_report,
+                                1, 255, BIT(PRINT_SCAN), },
+@@ -1828,18 +1839,11 @@ static const struct ie_print ieprinters[
+                                      print_measurement_pilot_tx, 1, 255, BIT(PRINT_SCAN), },
+       [EID_OVERLAP_BSS_SCAN_PARAM] = { "Overlapping BSS scan params",
+                                        print_obss_scan_params, 14, 255, BIT(PRINT_SCAN), },
+-      [EID_HT_OPERATION] = { "HT operation", print_ht_op, 22, 22, BIT(PRINT_SCAN), },
+-      [EID_SECONDARY_CH_OFFSET] = { "Secondary Channel Offset",
+-                                    print_secchan_offs, 1, 1, BIT(PRINT_SCAN), },
+-      [EID_VHT_CAPABILITY] = { "VHT capabilities", print_vht_capa, 12, 255, BIT(PRINT_SCAN), },
+-      [EID_VHT_OPERATION] = { "VHT operation", print_vht_oper, 5, 255, BIT(PRINT_SCAN), },
+-      [EID_RSN] = { "RSN", print_rsn, 2, 255, BIT(PRINT_SCAN), },
+       [EID_EXT_SUPP_RATES] = { "Extended supported rates", print_supprates,
+                                0, 255, BIT(PRINT_SCAN), },
+       [EID_RM_ENABLED_CAPABILITIES] = { "RM enabled capabilities",
+                                         print_rm_enabled_capabilities, 5, 5, BIT(PRINT_SCAN), },
+       [EID_MESH_CONFIG] = { "MESH Configuration", print_mesh_conf, 7, 7, BIT(PRINT_SCAN), },
+-      [EID_MESH_ID] = { "MESH ID", print_ssid, 0, 32, BIT(PRINT_SCAN) | BIT(PRINT_LINK), },
+       [EID_EXT_CAPABILITY] = { "Extended capabilities", print_capabilities,
+                                0, 255, BIT(PRINT_SCAN), },
+       [EID_INTERWORKING] = { "802.11u Interworking", print_interworking,
+@@ -1854,6 +1858,7 @@ static const struct ie_print ieprinters[
+                                       print_short_beacon_int, 2, 2, BIT(PRINT_SCAN), },
+       [EID_S1G_CAPABILITY] = { "S1G capabilities", print_s1g_capa, 15, 15, BIT(PRINT_SCAN), },
+       [EID_S1G_OPERATION] = { "S1G operation", print_s1g_oper, 6, 6, BIT(PRINT_SCAN), },
 +#endif
  };
  
  static void print_wifi_wpa(const uint8_t type, uint8_t len, const uint8_t *data,
-@@ -2185,8 +2190,10 @@ static void print_wifi_wps(const uint8_t
+@@ -2189,8 +2194,10 @@ static void print_wifi_wps(const uint8_t
  
  static const struct ie_print wifiprinters[] = {
        [1] = { "WPA", print_wifi_wpa, 2, 255, BIT(PRINT_SCAN), },
  };
  
  static inline void print_p2p(const uint8_t type, uint8_t len,
-@@ -2349,6 +2356,10 @@ static void print_vendor(unsigned char l
+@@ -2353,6 +2360,10 @@ static void print_vendor(unsigned char l
                return;
        }
  
        if (len >= 4 && memcmp(data, wfa_oui, 3) == 0) {
                if (data[3] < ARRAY_SIZE(wfa_printers) &&
                    wfa_printers[data[3]].name &&
-@@ -2491,6 +2502,7 @@ static void print_capa_non_dmg(__u16 cap
+@@ -2544,6 +2555,7 @@ static void print_capa_non_dmg(__u16 cap
                printf(" ESS");
        if (capa & WLAN_CAPABILITY_IBSS)
                printf(" IBSS");
        if (capa & WLAN_CAPABILITY_CF_POLLABLE)
                printf(" CfPollable");
        if (capa & WLAN_CAPABILITY_CF_POLL_REQUEST)
-@@ -2519,6 +2531,7 @@ static void print_capa_non_dmg(__u16 cap
+@@ -2572,6 +2584,7 @@ static void print_capa_non_dmg(__u16 cap
                printf(" DelayedBACK");
        if (capa & WLAN_CAPABILITY_IMM_BACK)
                printf(" ImmediateBACK");
  }
  
  static int print_bss_handler(struct nl_msg *msg, void *arg)
-@@ -2609,8 +2622,10 @@ static int print_bss_handler(struct nl_m
+@@ -2662,8 +2675,10 @@ static int print_bss_handler(struct nl_m
                else
                        printf("\tfreq: %d\n", freq);
  
        }
        if (bss[NL80211_BSS_BEACON_INTERVAL])
                printf("\tbeacon interval: %d TUs\n",
-@@ -2804,6 +2819,7 @@ static int handle_stop_sched_scan(struct
+@@ -2857,6 +2872,7 @@ static int handle_stop_sched_scan(struct
        return 0;
  }
  
  COMMAND(scan, sched_start,
        SCHED_SCAN_OPTIONS,
        NL80211_CMD_START_SCHED_SCAN, 0, CIB_NETDEV, handle_start_sched_scan,
-@@ -2814,3 +2830,4 @@ COMMAND(scan, sched_start,
+@@ -2867,3 +2883,4 @@ COMMAND(scan, sched_start,
  COMMAND(scan, sched_stop, "",
        NL80211_CMD_STOP_SCHED_SCAN, 0, CIB_NETDEV, handle_stop_sched_scan,
        "Stop an ongoing scheduled scan.");