The branch main has been updated by bz:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=a2a15732eb1db4616aa628ae8bfd4047c40dbaee

commit a2a15732eb1db4616aa628ae8bfd4047c40dbaee
Author:     Bjoern A. Zeeb <b...@freebsd.org>
AuthorDate: 2025-06-02 16:06:50 +0000
Commit:     Bjoern A. Zeeb <b...@freebsd.org>
CommitDate: 2025-06-09 21:44:26 +0000

    ifconfig: 802.11: decode more information elements (IEs)
    
    Start dealing with Element ID Extension present (IE T=255) and start
    parsing elemants from the Element ID Extension set.
    
    Namely (partially) decode HE_CAPA, HE_OPER, MU_EDCA_PARAM_SET,
    and as well as SUP_OP_CLASS.
    
    For length reasons also rename UNKNOWN_ELEMID_%d to ELEMID_%d.
    
    Sponsored by:   The FreeBSD Foundation
    MFC after:      3 days
    Reviewed by:    adrian
    Differential Revision: https://reviews.freebsd.org/D50678
---
 sbin/ifconfig/ifieee80211.c | 229 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 226 insertions(+), 3 deletions(-)

diff --git a/sbin/ifconfig/ifieee80211.c b/sbin/ifconfig/ifieee80211.c
index 2f79f2e92e60..e73dcc2c4f24 100644
--- a/sbin/ifconfig/ifieee80211.c
+++ b/sbin/ifconfig/ifieee80211.c
@@ -2778,6 +2778,177 @@ printwmeinfo(if_ctx *ctx, const char *tag, const 
u_int8_t *ie)
        }
 }
 
+static void
+printhecap(if_ctx *ctx, const char *tag, const uint8_t *ie)
+{
+       const struct ieee80211_he_cap_elem *hecap;
+       const struct ieee80211_he_mcs_nss_supp *mcsnss;
+       unsigned int i;
+       uint8_t chw;
+
+       printf("%s", tag);
+       if (!ctx->args->verbose)
+               return;
+
+       /* Check that the right size. */
+       if (ie[1] < 1 + sizeof(*hecap) + 4) {
+               printf("<err: he_cap inval. length %#0x>", ie[1]);
+               return;
+       }
+       /* Skip Element ID, Length, EID Extension. */
+       hecap = (const struct ieee80211_he_cap_elem *)(ie + 3);
+
+       /* XXX-BZ we need to somehow decode each field? */
+       printf("<mac_cap");
+       for (i = 0; i < nitems(hecap->mac_cap_info); i++)
+               printf(" %#04x", hecap->mac_cap_info[i]);
+       printf(" phy_cap");
+       for (i = 0; i < nitems(hecap->phy_cap_info); i++)
+               printf(" %#04x", hecap->phy_cap_info[i]);
+
+       chw = hecap->phy_cap_info[0];
+       ie = (const uint8_t *)(const void *)(hecap + 1);
+       mcsnss = (const struct ieee80211_he_mcs_nss_supp *)ie;
+       /* Cannot use <=  as < is a delimiter. */
+       printf(" rx/tx_he_mcs map: loweq80 %#06x/%#06x",
+           mcsnss->rx_mcs_80, mcsnss->tx_mcs_80);
+       ie += 2;
+       if ((chw & (1<<2)) != 0) {
+               printf(" 160 %#06x/%#06x",
+                   mcsnss->rx_mcs_160, mcsnss->tx_mcs_160);
+               ie += 2;
+       }
+       if ((chw & (1<<3)) != 0) {
+               printf(" 80+80 %#06x/%#06x",
+                   mcsnss->rx_mcs_80p80, mcsnss->tx_mcs_80p80);
+               ie += 2;
+       }
+       /* TODO: ppet = (struct ... *)ie; */
+
+       printf(">");
+}
+
+static void
+printheoper(if_ctx *ctx, const char *tag, const uint8_t *ie)
+{
+       printf("%s", tag);
+       if (ctx->args->verbose) {
+               const struct ieee80211_he_operation *heoper;
+               uint32_t params;
+
+               /* Check that the right size. */
+               if (ie[1] < 1 + sizeof(*heoper)) {
+                       printf("<err: he_oper inval. length %#0x>", ie[1]);
+                       return;
+               }
+               /* Skip Element ID, Length, EID Extension. */
+               heoper = (const struct ieee80211_he_operation *)(ie + 3);
+
+               /* XXX-BZ we need to somehow decode each field? */
+               params = heoper->he_oper_params & 0x00ffffff;
+               printf("<params %#08x", params);
+               printf(" bss_col %#04x", (heoper->he_oper_params & 0xff000000) 
>> 24);
+               printf(" mcs_nss %#06x", heoper->he_mcs_nss_set);
+               if ((params & (1 << 14)) != 0) {
+                       printf(" vht_op 0-3");
+               }
+               if ((params & (1 << 15)) != 0) {
+                       printf(" max_coh_bssid 0-1");
+               }
+               if ((params & (1 << 17)) != 0) {
+                       printf(" 6ghz_op 0-5");
+               }
+               printf(">");
+       }
+}
+
+static void
+printmuedcaparamset(if_ctx *ctx, const char *tag, const uint8_t *ie)
+{
+       static const char *acnames[] = { "BE", "BK", "VO", "VI" };
+       const struct ieee80211_mu_edca_param_set *mu_edca;
+       int i;
+
+       printf("%s", tag);
+       if (!ctx->args->verbose)
+               return;
+
+       /* Check that the right size. */
+       if (ie[1] != 1 + sizeof(*mu_edca)) {
+               printf("<err: mu_edca inval. length %#04x>", ie[1]);
+               return;
+       }
+       /* Skip Element ID, Length, EID Extension. */
+       mu_edca = (const struct ieee80211_mu_edca_param_set *)(ie + 3);
+
+       printf("<qosinfo 0x%x", mu_edca->mu_qos_info);
+       ie++;
+       for (i = 0; i < WME_NUM_AC; i++) {
+               const struct ieee80211_he_mu_edca_param_ac_rec *ac =
+                   &mu_edca->param_ac_recs[i];
+
+               printf(" %s[aifsn %u ecwmin %u ecwmax %u timer %u]", acnames[i],
+                   ac->aifsn,
+                   _IEEE80211_MASKSHIFT(ac->ecw_min_max, WME_PARAM_LOGCWMIN),
+                   _IEEE80211_MASKSHIFT(ac->ecw_min_max, WME_PARAM_LOGCWMAX),
+                   ac->mu_edca_timer);
+       }
+       printf(">");
+}
+
+static void
+printsupopclass(if_ctx *ctx, const char *tag, const u_int8_t *ie)
+{
+       uint8_t len, i;
+
+       printf("%s", tag);
+       if (!ctx->args->verbose)
+               return;
+
+       /* Check that the right size. */
+       len = ie[1];
+       if (len < 2) {
+               printf("<err: sup_op_class inval. length %#04x>", ie[1]);
+               return;
+       }
+
+       ie += 2;
+       i = 0;
+       printf("<cur op class %u", *ie);
+       i++;
+       if (i < len && *(ie + i) != 130)
+               printf(" op classes");
+       while (i < len && *(ie + i) != 130) {
+               printf(" %u", *(ie + i));
+               i++;
+       }
+       if (i > 1 && i < len && *(ie + i) != 130) {
+               printf(" parsing error at %#0x>", i);
+               return;
+       }
+       /* Skip OneHundredAndThirty Delimiter. */
+       i++;
+       if (i < len && *(ie + i) != 0)
+               printf(" ext seq");
+       while (i < len && *(ie + i) != 0) {
+               printf(" %u", *(ie + i));
+               i++;
+       }
+       if (i > 1 && i < len && *(ie + i) != 0) {
+               printf(" parsing error at %#0x>", i);
+               return;
+       }
+       /* Skip Zero Delimiter. */
+       i++;
+       if ((i + 1) < len)
+               printf(" duple seq");
+       while ((i + 1) < len) {
+               printf(" %u/%u", *(ie + i), *(ie + i + 1));
+               i += 2;
+       }
+       printf(">");
+}
+
 static void
 printvhtcap(if_ctx *ctx, const char *tag, const u_int8_t *ie)
 {
@@ -3616,7 +3787,22 @@ iswpsoui(const uint8_t *frm)
 }
 
 static const char *
-iename(int elemid)
+ie_ext_name(uint8_t ext_elemid)
+{
+       static char iename_buf[32];
+
+       switch (ext_elemid) {
+       case IEEE80211_ELEMID_EXT_HE_CAPA:              return " HECAP";
+       case IEEE80211_ELEMID_EXT_HE_OPER:              return " HEOPER";
+       case IEEE80211_ELEMID_EXT_MU_EDCA_PARAM_SET:    return " 
MU_EDCA_PARAM_SET";
+       }
+       snprintf(iename_buf, sizeof(iename_buf), " ELEMID_EXT_%d",
+           ext_elemid & 0xff);
+       return (const char *) iename_buf;
+}
+
+static const char *
+iename(uint8_t elemid, const u_int8_t *vp)
 {
        static char iename_buf[64];
        switch (elemid) {
@@ -3638,6 +3824,8 @@ iename(int elemid)
        case IEEE80211_ELEMID_IBSSDFS:  return " IBSSDFS";
        case IEEE80211_ELEMID_RESERVED_47:
                                        return " RESERVED_47";
+       case IEEE80211_ELEMID_SUP_OP_CLASS:
+                                       return " SUP_OP_CLASS";
        case IEEE80211_ELEMID_MOBILITY_DOMAIN:
                                        return " MOBILITY_DOMAIN";
        case IEEE80211_ELEMID_RRM_ENACAPS:
@@ -3648,12 +3836,41 @@ iename(int elemid)
        case IEEE80211_ELEMID_CCKM:     return " CCKM";
        case IEEE80211_ELEMID_EXTCAP:   return " EXTCAP";
        case IEEE80211_ELEMID_RSN_EXT:  return " RSNXE";
+       case IEEE80211_ELEMID_EXTFIELD:
+               if (vp[1] >= 1)
+                       return ie_ext_name(vp[2]);
+               break;
        }
-       snprintf(iename_buf, sizeof(iename_buf), " UNKNOWN_ELEMID_%d",
+       snprintf(iename_buf, sizeof(iename_buf), " ELEMID_%d",
            elemid);
        return (const char *) iename_buf;
 }
 
+static void
+printexties(if_ctx *ctx, const u_int8_t *vp, unsigned int maxcols)
+{
+       const int verbose = ctx->args->verbose;
+
+       if (vp[1] < 1)
+               return;
+
+       switch (vp[2]) {
+       case IEEE80211_ELEMID_EXT_HE_CAPA:
+               printhecap(ctx, " HECAP", vp);
+               break;
+       case IEEE80211_ELEMID_EXT_HE_OPER:
+               printheoper(ctx, " HEOPER", vp);
+               break;
+       case IEEE80211_ELEMID_EXT_MU_EDCA_PARAM_SET:
+               printmuedcaparamset(ctx, " MU_EDCA_PARAM_SET", vp);
+               break;
+       default:
+               if (verbose)
+                       printie(ctx, iename(vp[0], vp), vp, 2+vp[1], maxcols);
+               break;
+       }
+}
+
 static void
 printies(if_ctx *ctx, const u_int8_t *vp, int ielen, unsigned int maxcols)
 {
@@ -3705,6 +3922,9 @@ printies(if_ctx *ctx, const u_int8_t *vp, int ielen, 
unsigned int maxcols)
                case IEEE80211_ELEMID_HTCAP:
                        printhtcap(ctx, " HTCAP", vp);
                        break;
+               case IEEE80211_ELEMID_SUP_OP_CLASS:
+                       printsupopclass(ctx, " SUP_OP_CLASS", vp);
+                       break;
                case IEEE80211_ELEMID_HTINFO:
                        if (verbose)
                                printhtinfo(ctx, " HTINFO", vp);
@@ -3734,9 +3954,12 @@ printies(if_ctx *ctx, const u_int8_t *vp, int ielen, 
unsigned int maxcols)
                case IEEE80211_ELEMID_RSN_EXT:
                        printrsnxe(ctx, " RSNXE", vp, 2+vp[1]);
                        break;
+               case IEEE80211_ELEMID_EXTFIELD:
+                       printexties(ctx, vp, maxcols);
+                       break;
                default:
                        if (verbose)
-                               printie(ctx, iename(vp[0]), vp, 2+vp[1], 
maxcols);
+                               printie(ctx, iename(vp[0], vp), vp, 2+vp[1], 
maxcols);
                        break;
                }
                ielen -= 2+vp[1];

Reply via email to