Make tcpdump(8) show 802.11ac VHT capability and operation IEs in -v mode.
authorstsp <stsp@openbsd.org>
Thu, 17 Mar 2022 14:00:53 +0000 (14:00 +0000)
committerstsp <stsp@openbsd.org>
Thu, 17 Mar 2022 14:00:53 +0000 (14:00 +0000)
ok sthen@

usr.sbin/tcpdump/print-802_11.c

index 4af7bdb..b0641a2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: print-802_11.c,v 1.41 2021/06/28 14:35:42 stsp Exp $  */
+/*     $OpenBSD: print-802_11.c,v 1.42 2022/03/17 14:00:53 stsp Exp $  */
 
 /*
  * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org>
@@ -101,6 +101,8 @@ void         ieee80211_print_essid(u_int8_t *, u_int);
 void    ieee80211_print_country(u_int8_t *, u_int);
 void    ieee80211_print_htcaps(u_int8_t *, u_int);
 void    ieee80211_print_htop(u_int8_t *, u_int);
+void    ieee80211_print_vhtcaps(u_int8_t *, u_int);
+void    ieee80211_print_vhtop(u_int8_t *, u_int);
 void    ieee80211_print_rsncipher(u_int8_t []);
 void    ieee80211_print_akm(u_int8_t []);
 void    ieee80211_print_rsn(u_int8_t *, u_int);
@@ -606,6 +608,199 @@ ieee80211_print_htop(u_int8_t *data, u_int len)
        printf(">");
 }
 
+void
+print_vht_mcsmap(uint16_t mcsmap)
+{
+       int nss, mcs;
+
+       for (nss = 1; nss < IEEE80211_VHT_NUM_SS; nss++) {
+               mcs = (mcsmap & IEEE80211_VHT_MCS_FOR_SS_MASK(nss)) >>
+                   IEEE80211_VHT_MCS_FOR_SS_SHIFT(nss);
+               switch (mcs) {
+               case IEEE80211_VHT_MCS_0_9:
+                       printf(" 0-9@%uSS", nss);
+                       break;
+               case IEEE80211_VHT_MCS_0_8:
+                       printf(" 0-8@%uSS", nss);
+                       break;
+               case IEEE80211_VHT_MCS_0_7:
+                       printf(" 0-7@%uSS", nss);
+                       break;
+               case IEEE80211_VHT_MCS_SS_NOT_SUPP:
+               default:
+                       break;
+               }
+       }
+}
+
+/* Caller checks len */
+void
+ieee80211_print_vhtcaps(u_int8_t *data, u_int len)
+{
+       uint32_t vhtcaps;
+       uint16_t rxmcs, txmcs, max_lgi;
+       uint32_t rxstbc, num_sts, max_ampdu, link_adapt;
+
+       if (len < 12) {
+               ieee80211_print_element(data, len);
+               return;
+       }
+
+       vhtcaps = (data[0] | (data[1] << 8) | data[2] << 16 |
+           data[3] << 24);
+       printf("=<");
+
+       /* max MPDU length */
+       switch (vhtcaps & IEEE80211_VHTCAP_MAX_MPDU_LENGTH_MASK) {
+       case IEEE80211_VHTCAP_MAX_MPDU_LENGTH_11454:
+               printf("max MPDU 11454");
+               break;
+       case IEEE80211_VHTCAP_MAX_MPDU_LENGTH_7991:
+               printf("max MPDU 7991");
+               break;
+       case IEEE80211_VHTCAP_MAX_MPDU_LENGTH_3895:
+       default:
+               printf("max MPDU 3895");
+               break;
+       }
+
+       /* supported channel widths */
+       switch ((vhtcaps & IEEE80211_VHTCAP_CHAN_WIDTH_MASK) <<
+           IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT) {
+       case IEEE80211_VHTCAP_CHAN_WIDTH_160_8080:
+               printf(",80+80MHz");
+               /* fallthrough */
+       case IEEE80211_VHTCAP_CHAN_WIDTH_160:
+               printf(",160MHz");
+               /* fallthrough */
+       case IEEE80211_VHTCAP_CHAN_WIDTH_80:
+       default:
+               printf(",80MHz");
+               break;
+       }
+
+       /* LDPC coding */
+       if (vhtcaps & IEEE80211_VHTCAP_RX_LDPC)
+               printf(",LDPC");
+
+       /* short guard interval */
+       if (vhtcaps & IEEE80211_VHTCAP_SGI80)
+               printf(",SGI@80MHz");
+       if (vhtcaps & IEEE80211_VHTCAP_SGI160)
+               printf(",SGI@160MHz");
+
+       /* space-time block coding */
+       if (vhtcaps & IEEE80211_VHTCAP_TX_STBC)
+               printf(",TxSTBC");
+       rxstbc = (vhtcaps & IEEE80211_VHTCAP_RX_STBC_SS_MASK)
+           >> IEEE80211_VHTCAP_RX_STBC_SS_SHIFT;
+       if (rxstbc > 0 && rxstbc <= 7)
+               printf(",RxSTBC %d stream", rxstbc);
+
+       /* beamforming */
+       if (vhtcaps & IEEE80211_VHTCAP_SU_BEAMFORMER) {
+               printf(",beamformer");
+               num_sts = ((vhtcaps & IEEE80211_VHTCAP_NUM_STS_MASK) >>
+                   IEEE80211_VHTCAP_NUM_STS_SHIFT);
+               if (num_sts)
+                       printf(" STS %u", num_sts);
+       }
+       if (vhtcaps & IEEE80211_VHTCAP_SU_BEAMFORMEE) {
+               printf(",beamformee");
+               num_sts = ((vhtcaps & IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK) >>
+                   IEEE80211_VHTCAP_BEAMFORMEE_STS_SHIFT);
+               if (num_sts)
+                       printf(" STS %u", num_sts);
+       }
+
+       if (vhtcaps & IEEE80211_VHTCAP_TXOP_PS)
+               printf(",TXOP PS");
+       if (vhtcaps & IEEE80211_VHTCAP_HTC_VHT)
+               printf(",+HTC VHT");
+
+       /* max A-MPDU length */
+       max_ampdu = ((vhtcaps & IEEE80211_VHTCAP_MAX_AMPDU_LEN_MASK) >>
+           IEEE80211_VHTCAP_MAX_AMPDU_LEN_SHIFT);
+       if (max_ampdu >= IEEE80211_VHTCAP_MAX_AMPDU_LEN_8K &&
+           max_ampdu <= IEEE80211_VHTCAP_MAX_AMPDU_LEN_1024K)
+               printf(",max A-MPDU %uK", (1 << (max_ampdu + 3)));
+
+       link_adapt = ((vhtcaps & IEEE80211_VHTCAP_LINK_ADAPT_MASK) >>
+           IEEE80211_VHTCAP_LINK_ADAPT_SHIFT);
+       if (link_adapt == IEEE80211_VHTCAP_LINK_ADAPT_UNSOL_MFB)
+               printf(",linkadapt unsolicited MFB");
+       else if (link_adapt == IEEE80211_VHTCAP_LINK_ADAPT_MRQ_MFB)
+               printf(",linkadapt MRQ MFB");
+
+       if (vhtcaps & IEEE80211_VHTCAP_RX_ANT_PATTERN)
+               printf(",Rx ant pattern consistent");
+       if (vhtcaps & IEEE80211_VHTCAP_TX_ANT_PATTERN)
+               printf(",Tx ant pattern consistent");
+
+       /* Supported MCS set. */
+       rxmcs = (data[4] | (data[5] << 8));
+       printf(",RxMCS");
+       print_vht_mcsmap(rxmcs);        
+       max_lgi = ((data[6] | (data[7] << 8)) &
+           IEEE80211_VHT_MAX_LGI_MBIT_S_MASK);
+       if (max_lgi)
+               printf(",Rx max LGI rate %uMbit/s", max_lgi);
+       txmcs = (data[8] | (data[9] << 8));
+       printf(",TxMCS");
+       print_vht_mcsmap(txmcs);        
+       max_lgi = ((data[6] | (data[7] << 8)) &
+           IEEE80211_VHT_MAX_LGI_MBIT_S_MASK);
+       if (max_lgi)
+               printf(",Tx max LGI rate %uMbit/s", max_lgi);
+
+       printf(">");
+}
+
+/* Caller checks len */
+void
+ieee80211_print_vhtop(u_int8_t *data, u_int len)
+{
+       u_int8_t chan_width, freq_idx0, freq_idx1;
+       uint16_t basic_mcs;
+
+       if (len < 5) {
+               ieee80211_print_element(data, len);
+               return;
+       }
+
+       chan_width = data[0];
+       printf("=<");
+
+       switch (chan_width) {
+       case IEEE80211_VHTOP0_CHAN_WIDTH_8080:
+               printf("80+80MHz chan");
+               break;
+       case IEEE80211_VHTOP0_CHAN_WIDTH_160:
+               printf("160MHz chan");
+               break;
+       case IEEE80211_VHTOP0_CHAN_WIDTH_80:
+               printf("80MHz chan");
+               break;
+       case IEEE80211_VHTOP0_CHAN_WIDTH_HT:
+       default:
+               printf("using HT chan width");
+               break;
+       }
+
+       freq_idx0 = data[1];
+       if (freq_idx0)
+               printf(",center chan %u", freq_idx0);
+       freq_idx1 = data[2];
+       if (freq_idx1)
+               printf(",second center chan %u", freq_idx1);
+
+       basic_mcs = (data[3] | data[4] << 8);
+       printf(",basic MCS set");
+       print_vht_mcsmap(basic_mcs);
+
+       printf(">");
+}
+
 void
 ieee80211_print_rsncipher(uint8_t selector[4])
 {
@@ -968,6 +1163,16 @@ ieee80211_print_elements(uint8_t *frm)
                        if (vflag)
                                ieee80211_print_htop(data, len);
                        break;
+               case IEEE80211_ELEMID_VHTCAPS:
+                       printf(", vhtcaps");
+                       if (vflag)
+                               ieee80211_print_vhtcaps(data, len);
+                       break;
+               case IEEE80211_ELEMID_VHTOP:
+                       printf(", vhtop");
+                       if (vflag)
+                               ieee80211_print_vhtop(data, len);
+                       break;
                case IEEE80211_ELEMID_POWER_CONSTRAINT:
                        ELEM_CHECK(1);
                        printf(", power constraint %udB", data[0]);