1*46e5e1a2Sstsp /* $OpenBSD: print-802_11.c,v 1.44 2022/07/22 20:37:56 stsp Exp $ */
212a08440Sreyk
312a08440Sreyk /*
42c56d0d6Sreyk * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org>
512a08440Sreyk *
612a08440Sreyk * Permission to use, copy, modify, and distribute this software for any
712a08440Sreyk * purpose with or without fee is hereby granted, provided that the above
812a08440Sreyk * copyright notice and this permission notice appear in all copies.
912a08440Sreyk *
1012a08440Sreyk * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1112a08440Sreyk * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1212a08440Sreyk * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1312a08440Sreyk * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1412a08440Sreyk * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1512a08440Sreyk * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1612a08440Sreyk * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1712a08440Sreyk */
1812a08440Sreyk
1912a08440Sreyk #include <sys/time.h>
2012a08440Sreyk #include <sys/socket.h>
2112a08440Sreyk #include <sys/file.h>
2212a08440Sreyk #include <sys/ioctl.h>
2312a08440Sreyk
2412a08440Sreyk #include <net/if.h>
2512a08440Sreyk
2612a08440Sreyk #include <netinet/in.h>
2712a08440Sreyk #include <netinet/if_ether.h>
2812a08440Sreyk
2912a08440Sreyk #include <net80211/ieee80211.h>
3012a08440Sreyk #include <net80211/ieee80211_radiotap.h>
3112a08440Sreyk
3277734011Sstsp #include <ctype.h>
3312a08440Sreyk #include <pcap.h>
3412a08440Sreyk #include <stdio.h>
3512a08440Sreyk #include <string.h>
3612a08440Sreyk
3712a08440Sreyk #include "addrtoname.h"
3812a08440Sreyk #include "interface.h"
3912a08440Sreyk
408dd9ce3eSstsp const char *ieee80211_ctl_subtype_name[] = {
418dd9ce3eSstsp "reserved#0",
428dd9ce3eSstsp "reserved#1",
438dd9ce3eSstsp "reserved#2",
448dd9ce3eSstsp "reserved#3",
458dd9ce3eSstsp "reserved#4",
468dd9ce3eSstsp "reserved#5",
478dd9ce3eSstsp "reserved#6",
488dd9ce3eSstsp "wrapper",
498dd9ce3eSstsp "block ack request",
508dd9ce3eSstsp "block ack",
518dd9ce3eSstsp "ps poll",
528dd9ce3eSstsp "rts",
538dd9ce3eSstsp "cts",
548dd9ce3eSstsp "ack",
558dd9ce3eSstsp "cf-end",
568dd9ce3eSstsp "cf-end-ack",
578dd9ce3eSstsp };
588dd9ce3eSstsp
5912a08440Sreyk const char *ieee80211_mgt_subtype_name[] = {
6012a08440Sreyk "association request",
6112a08440Sreyk "association response",
6212a08440Sreyk "reassociation request",
6312a08440Sreyk "reassociation response",
6412a08440Sreyk "probe request",
6512a08440Sreyk "probe response",
6612a08440Sreyk "reserved#6",
6712a08440Sreyk "reserved#7",
6812a08440Sreyk "beacon",
6912a08440Sreyk "atim",
7012a08440Sreyk "disassociation",
7112a08440Sreyk "authentication",
7212a08440Sreyk "deauthentication",
73ab7e388eSclaudio "action",
74ab7e388eSclaudio "action noack",
7512a08440Sreyk "reserved#15"
7612a08440Sreyk };
7712a08440Sreyk
78ab7e388eSclaudio const char *ieee80211_data_subtype_name[] = {
79ab7e388eSclaudio "data",
80ab7e388eSclaudio "data cf ack",
81ab7e388eSclaudio "data cf poll",
82ab7e388eSclaudio "data cf poll ack",
83ab7e388eSclaudio "no-data",
84ab7e388eSclaudio "no-data cf poll",
85ab7e388eSclaudio "no-data cf ack",
86ab7e388eSclaudio "no-data cf poll ack",
87ab7e388eSclaudio "QoS data",
88ab7e388eSclaudio "QoS data cf ack",
89ab7e388eSclaudio "QoS data cf poll",
90ab7e388eSclaudio "QoS data cf poll ack",
91ab7e388eSclaudio "QoS no-data",
92ab7e388eSclaudio "QoS no-data cf poll",
93ab7e388eSclaudio "QoS no-data cf ack",
94ab7e388eSclaudio "QoS no-data cf poll ack"
95ab7e388eSclaudio };
96ab7e388eSclaudio
9712a08440Sreyk int ieee80211_hdr(struct ieee80211_frame *);
98b72abdefSreyk int ieee80211_data(struct ieee80211_frame *, u_int);
9912a08440Sreyk void ieee80211_print_element(u_int8_t *, u_int);
10012a08440Sreyk void ieee80211_print_essid(u_int8_t *, u_int);
10177734011Sstsp void ieee80211_print_country(u_int8_t *, u_int);
1021e3bf20aSstsp void ieee80211_print_htcaps(u_int8_t *, u_int);
10336fa064cSstsp void ieee80211_print_htop(u_int8_t *, u_int);
104986f6204Sstsp void ieee80211_print_vhtcaps(u_int8_t *, u_int);
105986f6204Sstsp void ieee80211_print_vhtop(u_int8_t *, u_int);
10674bd9b91Sstsp void ieee80211_print_rsncipher(u_int8_t []);
10774bd9b91Sstsp void ieee80211_print_akm(u_int8_t []);
10874bd9b91Sstsp void ieee80211_print_rsn(u_int8_t *, u_int);
1096f9acb7aSstsp int ieee80211_print_beacon(struct ieee80211_frame *, u_int);
1106f9acb7aSstsp int ieee80211_print_assocreq(struct ieee80211_frame *, u_int);
1116f9acb7aSstsp int ieee80211_print_elements(uint8_t *);
11212a08440Sreyk int ieee80211_frame(struct ieee80211_frame *, u_int);
11312a08440Sreyk int ieee80211_print(struct ieee80211_frame *, u_int);
11412a08440Sreyk u_int ieee80211_any2ieee(u_int, u_int);
11518786664Sclaudio void ieee80211_reason(u_int16_t);
11612a08440Sreyk
11712a08440Sreyk #define TCARR(a) TCHECK2(*a, sizeof(a))
11812a08440Sreyk
119c79cf170Sreyk int ieee80211_encap = 0;
120c79cf170Sreyk
12112a08440Sreyk int
ieee80211_hdr(struct ieee80211_frame * wh)12212a08440Sreyk ieee80211_hdr(struct ieee80211_frame *wh)
12312a08440Sreyk {
12412a08440Sreyk struct ieee80211_frame_addr4 *w4;
12512a08440Sreyk
12612a08440Sreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
12712a08440Sreyk case IEEE80211_FC1_DIR_NODS:
12812a08440Sreyk TCARR(wh->i_addr2);
12912a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2));
13012a08440Sreyk TCARR(wh->i_addr1);
13112a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1));
13212a08440Sreyk TCARR(wh->i_addr3);
13312a08440Sreyk printf(", bssid %s", etheraddr_string(wh->i_addr3));
13412a08440Sreyk break;
13512a08440Sreyk case IEEE80211_FC1_DIR_TODS:
13612a08440Sreyk TCARR(wh->i_addr2);
13712a08440Sreyk printf("%s", etheraddr_string(wh->i_addr2));
13812a08440Sreyk TCARR(wh->i_addr3);
13912a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr3));
14012a08440Sreyk TCARR(wh->i_addr1);
14112a08440Sreyk printf(", bssid %s, > DS", etheraddr_string(wh->i_addr1));
14212a08440Sreyk break;
14312a08440Sreyk case IEEE80211_FC1_DIR_FROMDS:
14412a08440Sreyk TCARR(wh->i_addr3);
14512a08440Sreyk printf("%s", etheraddr_string(wh->i_addr3));
14612a08440Sreyk TCARR(wh->i_addr1);
14712a08440Sreyk printf(" > %s", etheraddr_string(wh->i_addr1));
14812a08440Sreyk TCARR(wh->i_addr2);
14912a08440Sreyk printf(", bssid %s, DS >", etheraddr_string(wh->i_addr2));
15012a08440Sreyk break;
15112a08440Sreyk case IEEE80211_FC1_DIR_DSTODS:
15212a08440Sreyk w4 = (struct ieee80211_frame_addr4 *) wh;
15312a08440Sreyk TCARR(w4->i_addr4);
15412a08440Sreyk printf("%s", etheraddr_string(w4->i_addr4));
15512a08440Sreyk TCARR(w4->i_addr3);
15612a08440Sreyk printf(" > %s", etheraddr_string(w4->i_addr3));
15712a08440Sreyk TCARR(w4->i_addr2);
15812a08440Sreyk printf(", bssid %s", etheraddr_string(w4->i_addr2));
15912a08440Sreyk TCARR(w4->i_addr1);
16012a08440Sreyk printf(" > %s, DS > DS", etheraddr_string(w4->i_addr1));
16112a08440Sreyk break;
16212a08440Sreyk }
16312a08440Sreyk if (vflag) {
164cce1ba42Sclaudio u_int16_t seq;
16512a08440Sreyk TCARR(wh->i_seq);
166cce1ba42Sclaudio bcopy(wh->i_seq, &seq, sizeof(u_int16_t));
167474994bdSstsp printf(" (seq %u frag %u): ",
168474994bdSstsp letoh16(seq) >> IEEE80211_SEQ_SEQ_SHIFT,
169474994bdSstsp letoh16(seq) & IEEE80211_SEQ_FRAG_MASK);
17012a08440Sreyk } else
17112a08440Sreyk printf(": ");
17212a08440Sreyk
17312a08440Sreyk return (0);
17412a08440Sreyk
17512a08440Sreyk trunc:
17612a08440Sreyk /* Truncated elements in frame */
17712a08440Sreyk return (1);
17812a08440Sreyk }
17912a08440Sreyk
180b72abdefSreyk int
ieee80211_data(struct ieee80211_frame * wh,u_int len)181b72abdefSreyk ieee80211_data(struct ieee80211_frame *wh, u_int len)
182b72abdefSreyk {
183b72abdefSreyk u_int8_t *t = (u_int8_t *)wh;
184b72abdefSreyk u_int datalen;
18593cbfc44Sstsp int data = !(wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_NODATA);
1869d5679eaSstsp int hasqos = ((wh->i_fc[0] &
1879d5679eaSstsp (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) ==
1889d5679eaSstsp (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS));
189ab7e388eSclaudio u_char *esrc = NULL, *edst = NULL;
190b72abdefSreyk
1919d5679eaSstsp if (hasqos) {
1929d5679eaSstsp struct ieee80211_qosframe *wq;
1939d5679eaSstsp
1949d5679eaSstsp wq = (struct ieee80211_qosframe *) wh;
1959d5679eaSstsp TCHECK(*wq);
1969d5679eaSstsp t += sizeof(*wq);
1979d5679eaSstsp datalen = len - sizeof(*wq);
1989d5679eaSstsp } else {
199d49cb46eScanacar TCHECK(*wh);
2009d5679eaSstsp t += sizeof(*wh);
2019d5679eaSstsp datalen = len - sizeof(*wh);
2029d5679eaSstsp }
203b72abdefSreyk
204b72abdefSreyk switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
205b72abdefSreyk case IEEE80211_FC1_DIR_TODS:
206ab7e388eSclaudio esrc = wh->i_addr2;
207ab7e388eSclaudio edst = wh->i_addr3;
208b72abdefSreyk break;
209b72abdefSreyk case IEEE80211_FC1_DIR_FROMDS:
210ab7e388eSclaudio esrc = wh->i_addr3;
211ab7e388eSclaudio edst = wh->i_addr1;
212b72abdefSreyk break;
213b72abdefSreyk case IEEE80211_FC1_DIR_NODS:
214ab7e388eSclaudio esrc = wh->i_addr2;
215ab7e388eSclaudio edst = wh->i_addr1;
216d49cb46eScanacar break;
217b72abdefSreyk case IEEE80211_FC1_DIR_DSTODS:
2189d5679eaSstsp if (hasqos) {
2199d5679eaSstsp struct ieee80211_qosframe_addr4 *w4;
2209d5679eaSstsp
2219d5679eaSstsp w4 = (struct ieee80211_qosframe_addr4 *) wh;
2229d5679eaSstsp TCHECK(*w4);
2239d5679eaSstsp t = (u_int8_t *) (w4 + 1);
2249d5679eaSstsp datalen = len - sizeof(*w4);
2259d5679eaSstsp esrc = w4->i_addr4;
2269d5679eaSstsp edst = w4->i_addr3;
2279d5679eaSstsp } else {
2289d5679eaSstsp struct ieee80211_frame_addr4 *w4;
2299d5679eaSstsp
230d49cb46eScanacar w4 = (struct ieee80211_frame_addr4 *) wh;
231d49cb46eScanacar TCHECK(*w4);
232d49cb46eScanacar t = (u_int8_t *) (w4 + 1);
233d49cb46eScanacar datalen = len - sizeof(*w4);
234ab7e388eSclaudio esrc = w4->i_addr4;
235ab7e388eSclaudio edst = w4->i_addr3;
2369d5679eaSstsp }
237b72abdefSreyk break;
238b72abdefSreyk }
239b72abdefSreyk
240ab7e388eSclaudio if (data && esrc)
241ab7e388eSclaudio llc_print(t, datalen, datalen, esrc, edst);
242ab7e388eSclaudio else if (eflag && esrc)
243ab7e388eSclaudio printf("%s > %s",
244ab7e388eSclaudio etheraddr_string(esrc), etheraddr_string(edst));
245ab7e388eSclaudio
246b72abdefSreyk return (0);
247b72abdefSreyk
248b72abdefSreyk trunc:
249b72abdefSreyk /* Truncated elements in frame */
250b72abdefSreyk return (1);
251b72abdefSreyk }
252b72abdefSreyk
25312a08440Sreyk /* Caller checks len */
25412a08440Sreyk void
ieee80211_print_element(u_int8_t * data,u_int len)25512a08440Sreyk ieee80211_print_element(u_int8_t *data, u_int len)
25612a08440Sreyk {
25712a08440Sreyk u_int8_t *p;
2589cbdb746Sderaadt int i;
25912a08440Sreyk
26012a08440Sreyk printf(" 0x");
2619cbdb746Sderaadt for (i = 0, p = data; i < len; i++, p++)
26212a08440Sreyk printf("%02x", *p);
26312a08440Sreyk }
26412a08440Sreyk
26512a08440Sreyk /* Caller checks len */
26612a08440Sreyk void
ieee80211_print_essid(u_int8_t * essid,u_int len)26712a08440Sreyk ieee80211_print_essid(u_int8_t *essid, u_int len)
26812a08440Sreyk {
26912a08440Sreyk u_int8_t *p;
2709cbdb746Sderaadt int i;
27112a08440Sreyk
27212a08440Sreyk if (len > IEEE80211_NWID_LEN)
27312a08440Sreyk len = IEEE80211_NWID_LEN;
27412a08440Sreyk
27512a08440Sreyk /* determine printable or not */
27612a08440Sreyk for (i = 0, p = essid; i < len; i++, p++) {
27712a08440Sreyk if (*p < ' ' || *p > 0x7e)
27812a08440Sreyk break;
27912a08440Sreyk }
28012a08440Sreyk if (i == len) {
28112a08440Sreyk printf(" (");
28212a08440Sreyk for (i = 0, p = essid; i < len; i++, p++)
28312a08440Sreyk putchar(*p);
28412a08440Sreyk putchar(')');
2859cbdb746Sderaadt } else
28612a08440Sreyk ieee80211_print_element(essid, len);
28712a08440Sreyk }
28812a08440Sreyk
2891e3bf20aSstsp /* Caller checks len */
2901e3bf20aSstsp void
ieee80211_print_country(u_int8_t * data,u_int len)29177734011Sstsp ieee80211_print_country(u_int8_t *data, u_int len)
29277734011Sstsp {
29377734011Sstsp u_int8_t first_chan, nchan, maxpower;
29477734011Sstsp
29577734011Sstsp if (len < 6)
29677734011Sstsp return;
29777734011Sstsp
29877734011Sstsp /* country string */
29977734011Sstsp printf((isprint(data[0]) ? " '%c" : " '\\%03o"), data[0]);
30077734011Sstsp printf((isprint(data[1]) ? "%c" : "\\%03o"), data[1]);
30177734011Sstsp printf((isprint(data[2]) ? "%c'" : "\\%03o'"), data[2]);
30277734011Sstsp
30377734011Sstsp len -= 3;
30477734011Sstsp data += 3;
30577734011Sstsp
30677734011Sstsp /* channels and corresponding TX power limits */
30775f33b99Sstsp while (len >= 3) {
30877734011Sstsp /* no pretty-printing for nonsensical zero values,
30977734011Sstsp * nor for operating extension IDs (values >= 201) */
31077734011Sstsp if (data[0] == 0 || data[1] == 0 ||
31177734011Sstsp data[0] >= 201 || data[1] >= 201) {
31277734011Sstsp printf(", %d %d %d", data[0], data[1], data[2]);
31375f33b99Sstsp len -= 3;
31475f33b99Sstsp data += 3;
31577734011Sstsp continue;
31677734011Sstsp }
31777734011Sstsp
31877734011Sstsp first_chan = data[0];
31977734011Sstsp nchan = data[1];
32077734011Sstsp maxpower = data[2];
32177734011Sstsp
32277734011Sstsp printf(", channel%s %d", nchan == 1 ? "" : "s", first_chan);
32377734011Sstsp if (nchan > 1)
32477734011Sstsp printf("-%d", first_chan + nchan - 1);
32577734011Sstsp printf(" limit %ddB", maxpower);
32677734011Sstsp
32777734011Sstsp len -= 3;
32877734011Sstsp data += 3;
32977734011Sstsp }
33077734011Sstsp }
33177734011Sstsp
33277734011Sstsp /* Caller checks len */
33377734011Sstsp void
ieee80211_print_htcaps(u_int8_t * data,u_int len)3341e3bf20aSstsp ieee80211_print_htcaps(u_int8_t *data, u_int len)
3351e3bf20aSstsp {
336537e7cd0Sstsp uint16_t htcaps, rxrate;
3371e3bf20aSstsp int smps, rxstbc;
338537e7cd0Sstsp uint8_t ampdu, txmcs;
339537e7cd0Sstsp int i;
340537e7cd0Sstsp uint8_t *rxmcs;
3411e3bf20aSstsp
3421e3bf20aSstsp if (len < 2) {
3431e3bf20aSstsp ieee80211_print_element(data, len);
3441e3bf20aSstsp return;
3451e3bf20aSstsp }
3461e3bf20aSstsp
3471e3bf20aSstsp htcaps = (data[0]) | (data[1] << 8);
3481e3bf20aSstsp printf("=<");
3491e3bf20aSstsp
3501e3bf20aSstsp /* channel width */
3511e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_CBW20_40)
3521e3bf20aSstsp printf("20/40MHz");
3531e3bf20aSstsp else
3541e3bf20aSstsp printf("20MHz");
3551e3bf20aSstsp
3561e3bf20aSstsp /* LDPC coding */
3571e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_LDPC)
3581e3bf20aSstsp printf(",LDPC");
3591e3bf20aSstsp
3601e3bf20aSstsp /* spatial multiplexing power save mode */
3611e3bf20aSstsp smps = (htcaps & IEEE80211_HTCAP_SMPS_MASK)
3621e3bf20aSstsp >> IEEE80211_HTCAP_SMPS_SHIFT;
3631e3bf20aSstsp if (smps == 0)
3641e3bf20aSstsp printf(",SMPS static");
3651e3bf20aSstsp else if (smps == 1)
3661e3bf20aSstsp printf(",SMPS dynamic");
3671e3bf20aSstsp
3681e3bf20aSstsp /* 11n greenfield mode */
3691e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_GF)
3701e3bf20aSstsp printf(",greenfield");
3711e3bf20aSstsp
3721e3bf20aSstsp /* short guard interval */
3731e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_SGI20)
3741e3bf20aSstsp printf(",SGI@20MHz");
3751e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_SGI40)
3761e3bf20aSstsp printf(",SGI@40MHz");
3771e3bf20aSstsp
3781e3bf20aSstsp /* space-time block coding */
3791e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_TXSTBC)
3801e3bf20aSstsp printf(",TXSTBC");
3811e3bf20aSstsp rxstbc = (htcaps & IEEE80211_HTCAP_RXSTBC_MASK)
3821e3bf20aSstsp >> IEEE80211_HTCAP_RXSTBC_SHIFT;
3831e3bf20aSstsp if (rxstbc > 0 && rxstbc < 4)
3841e3bf20aSstsp printf(",RXSTBC %d stream", rxstbc);
3851e3bf20aSstsp
3861e3bf20aSstsp /* delayed block-ack */
3871e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_DELAYEDBA)
3881e3bf20aSstsp printf(",delayed BA");
3891e3bf20aSstsp
3901e3bf20aSstsp /* max A-MSDU length */
3911e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_AMSDU7935)
3921e3bf20aSstsp printf(",A-MSDU 7935");
3931e3bf20aSstsp else
3941e3bf20aSstsp printf(",A-MSDU 3839");
3951e3bf20aSstsp
3961e3bf20aSstsp /* DSSS/CCK in 40MHz mode */
3971e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_DSSSCCK40)
3981e3bf20aSstsp printf(",DSSS/CCK@40MHz");
3991e3bf20aSstsp
4001e3bf20aSstsp /* 40MHz intolerant */
4011e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_40INTOLERANT)
4021e3bf20aSstsp printf(",40MHz intolerant");
4031e3bf20aSstsp
4041e3bf20aSstsp /* L-SIG TXOP protection */
4051e3bf20aSstsp if (htcaps & IEEE80211_HTCAP_LSIGTXOPPROT)
4061e3bf20aSstsp printf(",L-SIG TXOP prot");
4071e3bf20aSstsp
408537e7cd0Sstsp if (len < 3) {
409537e7cd0Sstsp printf(">");
410537e7cd0Sstsp return;
411537e7cd0Sstsp }
412537e7cd0Sstsp
413537e7cd0Sstsp /* A-MPDU parameters. */
414537e7cd0Sstsp ampdu = data[2];
415537e7cd0Sstsp
416537e7cd0Sstsp /* A-MPDU length exponent */
417537e7cd0Sstsp if ((ampdu & IEEE80211_AMPDU_PARAM_LE) >= 0 &&
418537e7cd0Sstsp (ampdu & IEEE80211_AMPDU_PARAM_LE) <= 3)
419537e7cd0Sstsp printf(",A-MPDU max %d",
4200b19ae84Sstsp (1 << (13 + (ampdu & IEEE80211_AMPDU_PARAM_LE))) - 1);
421537e7cd0Sstsp
422537e7cd0Sstsp /* A-MPDU start spacing */
423537e7cd0Sstsp if (ampdu & IEEE80211_AMPDU_PARAM_SS) {
424537e7cd0Sstsp float ss;
425537e7cd0Sstsp
426537e7cd0Sstsp switch ((ampdu & IEEE80211_AMPDU_PARAM_SS) >> 2) {
427537e7cd0Sstsp case 1:
428537e7cd0Sstsp ss = 0.25;
429537e7cd0Sstsp break;
430537e7cd0Sstsp case 2:
431537e7cd0Sstsp ss = 0.5;
432537e7cd0Sstsp break;
433537e7cd0Sstsp case 3:
434537e7cd0Sstsp ss = 1;
435537e7cd0Sstsp break;
436537e7cd0Sstsp case 4:
437537e7cd0Sstsp ss = 2;
438537e7cd0Sstsp break;
439537e7cd0Sstsp case 5:
440537e7cd0Sstsp ss = 4;
441537e7cd0Sstsp break;
442537e7cd0Sstsp case 6:
443537e7cd0Sstsp ss = 8;
444537e7cd0Sstsp break;
445537e7cd0Sstsp case 7:
446537e7cd0Sstsp ss = 16;
447537e7cd0Sstsp break;
448537e7cd0Sstsp default:
449537e7cd0Sstsp ss = 0;
450537e7cd0Sstsp break;
451537e7cd0Sstsp }
452537e7cd0Sstsp if (ss != 0)
453537e7cd0Sstsp printf(",A-MPDU spacing %.2fus", ss);
454537e7cd0Sstsp }
455537e7cd0Sstsp
456537e7cd0Sstsp if (len < 21) {
457537e7cd0Sstsp printf(">");
458537e7cd0Sstsp return;
459537e7cd0Sstsp }
460537e7cd0Sstsp
461537e7cd0Sstsp /* Supported MCS set. */
462537e7cd0Sstsp printf(",RxMCS 0x");
463537e7cd0Sstsp rxmcs = &data[3];
464537e7cd0Sstsp for (i = 0; i < 10; i++)
465537e7cd0Sstsp printf("%02x", rxmcs[i]);
466537e7cd0Sstsp
467537e7cd0Sstsp /* Max MCS Rx rate (a value of 0 means "not specified"). */
468537e7cd0Sstsp rxrate = ((data[13] | (data[14]) << 8) & IEEE80211_MCS_RX_RATE_HIGH);
469537e7cd0Sstsp if (rxrate)
470537e7cd0Sstsp printf(",RxMaxrate %huMb/s", rxrate);
471537e7cd0Sstsp
472537e7cd0Sstsp /* Tx MCS Set */
473537e7cd0Sstsp txmcs = data[15];
474537e7cd0Sstsp if (txmcs & IEEE80211_TX_MCS_SET_DEFINED) {
475537e7cd0Sstsp if (txmcs & IEEE80211_TX_RX_MCS_NOT_EQUAL) {
476537e7cd0Sstsp /* Number of spatial Tx streams. */
477537e7cd0Sstsp printf(",%d Tx streams",
478537e7cd0Sstsp 1 + ((txmcs & IEEE80211_TX_SPATIAL_STREAMS) >> 2));
479537e7cd0Sstsp /* Transmit unequal modulation supported. */
480537e7cd0Sstsp if (txmcs & IEEE80211_TX_UNEQUAL_MODULATION)
481537e7cd0Sstsp printf(",UEQM");
482537e7cd0Sstsp }
483537e7cd0Sstsp }
484537e7cd0Sstsp
4851e3bf20aSstsp printf(">");
4861e3bf20aSstsp }
4871e3bf20aSstsp
48836fa064cSstsp /* Caller checks len */
48936fa064cSstsp void
ieee80211_print_htop(u_int8_t * data,u_int len)49036fa064cSstsp ieee80211_print_htop(u_int8_t *data, u_int len)
49136fa064cSstsp {
49236fa064cSstsp u_int8_t primary_chan;
49336fa064cSstsp u_int8_t htopinfo[5];
49436fa064cSstsp u_int8_t basic_mcs[16];
4952f166cedSstsp int sco, htprot, i;
49636fa064cSstsp
49736fa064cSstsp if (len < sizeof(primary_chan) + sizeof(htopinfo) + sizeof(basic_mcs)) {
49836fa064cSstsp ieee80211_print_element(data, len);
49936fa064cSstsp return;
50036fa064cSstsp }
50136fa064cSstsp
50236fa064cSstsp htopinfo[0] = data[1];
50336fa064cSstsp
50436fa064cSstsp printf("=<");
50536fa064cSstsp
50636fa064cSstsp /* primary channel and secondary channel offset */
50736fa064cSstsp primary_chan = data[0];
50836fa064cSstsp sco = ((htopinfo[0] & IEEE80211_HTOP0_SCO_MASK)
50936fa064cSstsp >> IEEE80211_HTOP0_SCO_SHIFT);
510b144e175Sstsp if (sco == 0) /* no secondary channel */
51136fa064cSstsp printf("20MHz chan %d", primary_chan);
512b144e175Sstsp else if (sco == 1) { /* secondary channel above */
513b144e175Sstsp if (primary_chan >= 1 && primary_chan <= 13) /* 2GHz */
514b144e175Sstsp printf("40MHz chan %d:%d", primary_chan,
515b144e175Sstsp primary_chan + 1);
516b144e175Sstsp else if (primary_chan >= 34) /* 5GHz */
517b144e175Sstsp printf("40MHz chan %d:%d", primary_chan,
518b144e175Sstsp primary_chan + 4);
51936fa064cSstsp else
520b144e175Sstsp printf("[invalid 40MHz chan %d+]", primary_chan);
521b144e175Sstsp } else if (sco == 3) { /* secondary channel below */
522b144e175Sstsp if (primary_chan >= 2 && primary_chan <= 14) /* 2GHz */
523b144e175Sstsp printf("40MHz chan %d:%d", primary_chan,
524b144e175Sstsp primary_chan - 1);
525b144e175Sstsp else if (primary_chan >= 40) /* 5GHz */
526b144e175Sstsp printf("40MHz chan %d:%d", primary_chan,
527b144e175Sstsp primary_chan - 4);
528b144e175Sstsp else
529b144e175Sstsp printf("[invalid 40MHz chan %d-]", primary_chan);
530b144e175Sstsp } else
53136fa064cSstsp printf("chan %d [invalid secondary channel offset %d]",
53236fa064cSstsp primary_chan, sco);
53336fa064cSstsp
53436fa064cSstsp /* STA channel width */
53536fa064cSstsp if ((htopinfo[0] & IEEE80211_HTOP0_CHW) == 0)
53636fa064cSstsp printf(",STA chanw 20MHz");
53736fa064cSstsp
53836fa064cSstsp /* reduced interframe space (RIFS) permitted */
53936fa064cSstsp if (htopinfo[0] & IEEE80211_HTOP0_RIFS)
54036fa064cSstsp printf(",RIFS");
54136fa064cSstsp
54236fa064cSstsp htopinfo[1] = data[2];
54336fa064cSstsp
54436fa064cSstsp /* protection requirements for HT transmissions */
5452f166cedSstsp htprot = ((htopinfo[1] & IEEE80211_HTOP1_PROT_MASK)
54636fa064cSstsp >> IEEE80211_HTOP1_PROT_SHIFT);
5472f166cedSstsp switch (htprot) {
5482f166cedSstsp case IEEE80211_HTPROT_NONE:
5492f166cedSstsp printf(",htprot none");
5502f166cedSstsp break;
5512f166cedSstsp case IEEE80211_HTPROT_NONMEMBER:
5522f166cedSstsp printf(",htprot non-member");
5532f166cedSstsp break;
5542f166cedSstsp case IEEE80211_HTPROT_20MHZ:
5552f166cedSstsp printf(",htprot 20MHz");
5562f166cedSstsp break;
5572f166cedSstsp case IEEE80211_HTPROT_NONHT_MIXED:
5582f166cedSstsp printf(",htprot non-HT-mixed");
5592f166cedSstsp break;
5602f166cedSstsp default:
5612f166cedSstsp printf(",htprot %d", htprot);
5622f166cedSstsp break;
5632f166cedSstsp }
56436fa064cSstsp
56536fa064cSstsp /* non-greenfield STA present */
56636fa064cSstsp if (htopinfo[1] & IEEE80211_HTOP1_NONGF_STA)
56736fa064cSstsp printf(",non-greenfield STA");
56836fa064cSstsp
56936fa064cSstsp /* non-HT STA present */
57036fa064cSstsp if (htopinfo[1] & IEEE80211_HTOP1_OBSS_NONHT_STA)
57136fa064cSstsp printf(",non-HT STA");
57236fa064cSstsp
57336fa064cSstsp htopinfo[3] = data[4];
57436fa064cSstsp
57536fa064cSstsp /* dual-beacon */
57636fa064cSstsp if (htopinfo[3] & IEEE80211_HTOP2_DUALBEACON)
57736fa064cSstsp printf(",dualbeacon");
57836fa064cSstsp
57936fa064cSstsp /* dual CTS protection */
58036fa064cSstsp if (htopinfo[3] & IEEE80211_HTOP2_DUALCTSPROT)
58136fa064cSstsp printf(",dualctsprot");
58236fa064cSstsp
58336fa064cSstsp htopinfo[4] = data[5];
58436fa064cSstsp
58536fa064cSstsp /* space-time block coding (STBC) beacon */
58658089030Sstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_STBCBEACON)
58736fa064cSstsp printf(",STBC beacon");
58836fa064cSstsp
58936fa064cSstsp /* L-SIG (non-HT signal field) TX opportunity (TXOP) protection */
59036fa064cSstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_LSIGTXOP)
59136fa064cSstsp printf(",lsigtxprot");
59236fa064cSstsp
59336fa064cSstsp /* phased-coexistence operation (PCO) active */
59436fa064cSstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_PCOACTIVE) {
59536fa064cSstsp /* PCO phase */
59636fa064cSstsp if ((htopinfo[4] << 8) & IEEE80211_HTOP2_PCOPHASE40)
59736fa064cSstsp printf(",pco40MHz");
59836fa064cSstsp else
59936fa064cSstsp printf(",pco20MHz");
60036fa064cSstsp }
60136fa064cSstsp
60236fa064cSstsp /* basic MCS set */
60336fa064cSstsp memcpy(basic_mcs, &data[6], sizeof(basic_mcs));
60436fa064cSstsp printf(",basic MCS set 0x");
60536fa064cSstsp for (i = 0; i < sizeof(basic_mcs) / sizeof(basic_mcs[0]); i++)
60636fa064cSstsp printf("%x", basic_mcs[i]);
60736fa064cSstsp
60836fa064cSstsp printf(">");
60936fa064cSstsp }
61036fa064cSstsp
61174bd9b91Sstsp void
print_vht_mcsmap(uint16_t mcsmap)612986f6204Sstsp print_vht_mcsmap(uint16_t mcsmap)
613986f6204Sstsp {
614986f6204Sstsp int nss, mcs;
615986f6204Sstsp
616986f6204Sstsp for (nss = 1; nss < IEEE80211_VHT_NUM_SS; nss++) {
617986f6204Sstsp mcs = (mcsmap & IEEE80211_VHT_MCS_FOR_SS_MASK(nss)) >>
618986f6204Sstsp IEEE80211_VHT_MCS_FOR_SS_SHIFT(nss);
619986f6204Sstsp switch (mcs) {
620986f6204Sstsp case IEEE80211_VHT_MCS_0_9:
621986f6204Sstsp printf(" 0-9@%uSS", nss);
622986f6204Sstsp break;
623986f6204Sstsp case IEEE80211_VHT_MCS_0_8:
624986f6204Sstsp printf(" 0-8@%uSS", nss);
625986f6204Sstsp break;
626986f6204Sstsp case IEEE80211_VHT_MCS_0_7:
627986f6204Sstsp printf(" 0-7@%uSS", nss);
628986f6204Sstsp break;
629986f6204Sstsp case IEEE80211_VHT_MCS_SS_NOT_SUPP:
630986f6204Sstsp default:
631986f6204Sstsp break;
632986f6204Sstsp }
633986f6204Sstsp }
634986f6204Sstsp }
635986f6204Sstsp
636986f6204Sstsp /* Caller checks len */
637986f6204Sstsp void
ieee80211_print_vhtcaps(u_int8_t * data,u_int len)638986f6204Sstsp ieee80211_print_vhtcaps(u_int8_t *data, u_int len)
639986f6204Sstsp {
640986f6204Sstsp uint32_t vhtcaps;
641986f6204Sstsp uint16_t rxmcs, txmcs, max_lgi;
642986f6204Sstsp uint32_t rxstbc, num_sts, max_ampdu, link_adapt;
643986f6204Sstsp
644986f6204Sstsp if (len < 12) {
645986f6204Sstsp ieee80211_print_element(data, len);
646986f6204Sstsp return;
647986f6204Sstsp }
648986f6204Sstsp
649986f6204Sstsp vhtcaps = (data[0] | (data[1] << 8) | data[2] << 16 |
650986f6204Sstsp data[3] << 24);
651986f6204Sstsp printf("=<");
652986f6204Sstsp
653986f6204Sstsp /* max MPDU length */
654986f6204Sstsp switch (vhtcaps & IEEE80211_VHTCAP_MAX_MPDU_LENGTH_MASK) {
655986f6204Sstsp case IEEE80211_VHTCAP_MAX_MPDU_LENGTH_11454:
656986f6204Sstsp printf("max MPDU 11454");
657986f6204Sstsp break;
658986f6204Sstsp case IEEE80211_VHTCAP_MAX_MPDU_LENGTH_7991:
659986f6204Sstsp printf("max MPDU 7991");
660986f6204Sstsp break;
661986f6204Sstsp case IEEE80211_VHTCAP_MAX_MPDU_LENGTH_3895:
662986f6204Sstsp default:
663986f6204Sstsp printf("max MPDU 3895");
664986f6204Sstsp break;
665986f6204Sstsp }
666986f6204Sstsp
667986f6204Sstsp /* supported channel widths */
668986f6204Sstsp switch ((vhtcaps & IEEE80211_VHTCAP_CHAN_WIDTH_MASK) <<
669986f6204Sstsp IEEE80211_VHTCAP_CHAN_WIDTH_SHIFT) {
670986f6204Sstsp case IEEE80211_VHTCAP_CHAN_WIDTH_160_8080:
671986f6204Sstsp printf(",80+80MHz");
672986f6204Sstsp /* fallthrough */
673986f6204Sstsp case IEEE80211_VHTCAP_CHAN_WIDTH_160:
674986f6204Sstsp printf(",160MHz");
675986f6204Sstsp /* fallthrough */
676986f6204Sstsp case IEEE80211_VHTCAP_CHAN_WIDTH_80:
677986f6204Sstsp default:
678986f6204Sstsp printf(",80MHz");
679986f6204Sstsp break;
680986f6204Sstsp }
681986f6204Sstsp
682986f6204Sstsp /* LDPC coding */
683986f6204Sstsp if (vhtcaps & IEEE80211_VHTCAP_RX_LDPC)
684986f6204Sstsp printf(",LDPC");
685986f6204Sstsp
686986f6204Sstsp /* short guard interval */
687986f6204Sstsp if (vhtcaps & IEEE80211_VHTCAP_SGI80)
688986f6204Sstsp printf(",SGI@80MHz");
689986f6204Sstsp if (vhtcaps & IEEE80211_VHTCAP_SGI160)
690986f6204Sstsp printf(",SGI@160MHz");
691986f6204Sstsp
692986f6204Sstsp /* space-time block coding */
693986f6204Sstsp if (vhtcaps & IEEE80211_VHTCAP_TX_STBC)
694986f6204Sstsp printf(",TxSTBC");
695986f6204Sstsp rxstbc = (vhtcaps & IEEE80211_VHTCAP_RX_STBC_SS_MASK)
696986f6204Sstsp >> IEEE80211_VHTCAP_RX_STBC_SS_SHIFT;
697986f6204Sstsp if (rxstbc > 0 && rxstbc <= 7)
698986f6204Sstsp printf(",RxSTBC %d stream", rxstbc);
699986f6204Sstsp
700986f6204Sstsp /* beamforming */
701986f6204Sstsp if (vhtcaps & IEEE80211_VHTCAP_SU_BEAMFORMER) {
702986f6204Sstsp printf(",beamformer");
703986f6204Sstsp num_sts = ((vhtcaps & IEEE80211_VHTCAP_NUM_STS_MASK) >>
704986f6204Sstsp IEEE80211_VHTCAP_NUM_STS_SHIFT);
705986f6204Sstsp if (num_sts)
706986f6204Sstsp printf(" STS %u", num_sts);
707986f6204Sstsp }
708986f6204Sstsp if (vhtcaps & IEEE80211_VHTCAP_SU_BEAMFORMEE) {
709986f6204Sstsp printf(",beamformee");
710986f6204Sstsp num_sts = ((vhtcaps & IEEE80211_VHTCAP_BEAMFORMEE_STS_MASK) >>
711986f6204Sstsp IEEE80211_VHTCAP_BEAMFORMEE_STS_SHIFT);
712986f6204Sstsp if (num_sts)
713986f6204Sstsp printf(" STS %u", num_sts);
714986f6204Sstsp }
715986f6204Sstsp
716986f6204Sstsp if (vhtcaps & IEEE80211_VHTCAP_TXOP_PS)
717986f6204Sstsp printf(",TXOP PS");
718986f6204Sstsp if (vhtcaps & IEEE80211_VHTCAP_HTC_VHT)
719986f6204Sstsp printf(",+HTC VHT");
720986f6204Sstsp
721986f6204Sstsp /* max A-MPDU length */
722986f6204Sstsp max_ampdu = ((vhtcaps & IEEE80211_VHTCAP_MAX_AMPDU_LEN_MASK) >>
723986f6204Sstsp IEEE80211_VHTCAP_MAX_AMPDU_LEN_SHIFT);
724986f6204Sstsp if (max_ampdu >= IEEE80211_VHTCAP_MAX_AMPDU_LEN_8K &&
725986f6204Sstsp max_ampdu <= IEEE80211_VHTCAP_MAX_AMPDU_LEN_1024K)
726986f6204Sstsp printf(",max A-MPDU %uK", (1 << (max_ampdu + 3)));
727986f6204Sstsp
728986f6204Sstsp link_adapt = ((vhtcaps & IEEE80211_VHTCAP_LINK_ADAPT_MASK) >>
729986f6204Sstsp IEEE80211_VHTCAP_LINK_ADAPT_SHIFT);
730986f6204Sstsp if (link_adapt == IEEE80211_VHTCAP_LINK_ADAPT_UNSOL_MFB)
731986f6204Sstsp printf(",linkadapt unsolicited MFB");
732986f6204Sstsp else if (link_adapt == IEEE80211_VHTCAP_LINK_ADAPT_MRQ_MFB)
733986f6204Sstsp printf(",linkadapt MRQ MFB");
734986f6204Sstsp
735986f6204Sstsp if (vhtcaps & IEEE80211_VHTCAP_RX_ANT_PATTERN)
736986f6204Sstsp printf(",Rx ant pattern consistent");
737986f6204Sstsp if (vhtcaps & IEEE80211_VHTCAP_TX_ANT_PATTERN)
738986f6204Sstsp printf(",Tx ant pattern consistent");
739986f6204Sstsp
740986f6204Sstsp /* Supported MCS set. */
741986f6204Sstsp rxmcs = (data[4] | (data[5] << 8));
742986f6204Sstsp printf(",RxMCS");
743986f6204Sstsp print_vht_mcsmap(rxmcs);
744986f6204Sstsp max_lgi = ((data[6] | (data[7] << 8)) &
745986f6204Sstsp IEEE80211_VHT_MAX_LGI_MBIT_S_MASK);
746986f6204Sstsp if (max_lgi)
747986f6204Sstsp printf(",Rx max LGI rate %uMbit/s", max_lgi);
748986f6204Sstsp txmcs = (data[8] | (data[9] << 8));
749986f6204Sstsp printf(",TxMCS");
750986f6204Sstsp print_vht_mcsmap(txmcs);
751986f6204Sstsp max_lgi = ((data[6] | (data[7] << 8)) &
752986f6204Sstsp IEEE80211_VHT_MAX_LGI_MBIT_S_MASK);
753986f6204Sstsp if (max_lgi)
754986f6204Sstsp printf(",Tx max LGI rate %uMbit/s", max_lgi);
755986f6204Sstsp
756986f6204Sstsp printf(">");
757986f6204Sstsp }
758986f6204Sstsp
759986f6204Sstsp /* Caller checks len */
760986f6204Sstsp void
ieee80211_print_vhtop(u_int8_t * data,u_int len)761986f6204Sstsp ieee80211_print_vhtop(u_int8_t *data, u_int len)
762986f6204Sstsp {
763986f6204Sstsp u_int8_t chan_width, freq_idx0, freq_idx1;
764986f6204Sstsp uint16_t basic_mcs;
765986f6204Sstsp
766986f6204Sstsp if (len < 5) {
767986f6204Sstsp ieee80211_print_element(data, len);
768986f6204Sstsp return;
769986f6204Sstsp }
770986f6204Sstsp
771986f6204Sstsp chan_width = data[0];
772986f6204Sstsp printf("=<");
773986f6204Sstsp
774986f6204Sstsp switch (chan_width) {
775986f6204Sstsp case IEEE80211_VHTOP0_CHAN_WIDTH_8080:
776986f6204Sstsp printf("80+80MHz chan");
777986f6204Sstsp break;
778986f6204Sstsp case IEEE80211_VHTOP0_CHAN_WIDTH_160:
779986f6204Sstsp printf("160MHz chan");
780986f6204Sstsp break;
781986f6204Sstsp case IEEE80211_VHTOP0_CHAN_WIDTH_80:
782986f6204Sstsp printf("80MHz chan");
783986f6204Sstsp break;
784986f6204Sstsp case IEEE80211_VHTOP0_CHAN_WIDTH_HT:
785986f6204Sstsp default:
786986f6204Sstsp printf("using HT chan width");
787986f6204Sstsp break;
788986f6204Sstsp }
789986f6204Sstsp
790986f6204Sstsp freq_idx0 = data[1];
791986f6204Sstsp if (freq_idx0)
792986f6204Sstsp printf(",center chan %u", freq_idx0);
793986f6204Sstsp freq_idx1 = data[2];
794986f6204Sstsp if (freq_idx1)
795986f6204Sstsp printf(",second center chan %u", freq_idx1);
796986f6204Sstsp
797986f6204Sstsp basic_mcs = (data[3] | data[4] << 8);
798986f6204Sstsp printf(",basic MCS set");
799986f6204Sstsp print_vht_mcsmap(basic_mcs);
800986f6204Sstsp
801986f6204Sstsp printf(">");
802986f6204Sstsp }
803986f6204Sstsp
804986f6204Sstsp void
ieee80211_print_rsncipher(uint8_t selector[4])80574bd9b91Sstsp ieee80211_print_rsncipher(uint8_t selector[4])
80674bd9b91Sstsp {
80774bd9b91Sstsp if (memcmp(selector, MICROSOFT_OUI, 3) != 0 &&
80874bd9b91Sstsp memcmp(selector, IEEE80211_OUI, 3) != 0) {
80974bd9b91Sstsp printf("0x%x%x%x%x", selector[0], selector[1], selector[2],
81074bd9b91Sstsp selector[3]);
81174bd9b91Sstsp return;
81274bd9b91Sstsp }
81374bd9b91Sstsp
81474bd9b91Sstsp /* See 802.11-2012 Table 8-99 */
81574bd9b91Sstsp switch (selector[3]) {
81674bd9b91Sstsp case 0: /* use group data cipher suite */
81774bd9b91Sstsp printf("usegroup");
81874bd9b91Sstsp break;
81974bd9b91Sstsp case 1: /* WEP-40 */
82074bd9b91Sstsp printf("wep40");
82174bd9b91Sstsp break;
82274bd9b91Sstsp case 2: /* TKIP */
82374bd9b91Sstsp printf("tkip");
82474bd9b91Sstsp break;
82574bd9b91Sstsp case 4: /* CCMP (RSNA default) */
82674bd9b91Sstsp printf("ccmp");
82774bd9b91Sstsp break;
82874bd9b91Sstsp case 5: /* WEP-104 */
82974bd9b91Sstsp printf("wep104");
83074bd9b91Sstsp break;
83174bd9b91Sstsp case 6: /* BIP */
83274bd9b91Sstsp printf("bip");
83374bd9b91Sstsp break;
83474bd9b91Sstsp default:
83574bd9b91Sstsp printf("%d", selector[3]);
83674bd9b91Sstsp break;
83774bd9b91Sstsp }
83874bd9b91Sstsp }
83974bd9b91Sstsp
84074bd9b91Sstsp void
ieee80211_print_akm(uint8_t selector[4])84174bd9b91Sstsp ieee80211_print_akm(uint8_t selector[4])
84274bd9b91Sstsp {
84374bd9b91Sstsp if (memcmp(selector, MICROSOFT_OUI, 3) != 0 &&
84474bd9b91Sstsp memcmp(selector, IEEE80211_OUI, 3) != 0) {
84574bd9b91Sstsp printf("0x%x%x%x%x", selector[0], selector[1], selector[2],
84674bd9b91Sstsp selector[3]);
84774bd9b91Sstsp return;
84874bd9b91Sstsp }
84974bd9b91Sstsp
85074bd9b91Sstsp switch (selector[3]) {
85174bd9b91Sstsp case 1:
85274bd9b91Sstsp printf("802.1x");
85374bd9b91Sstsp break;
85474bd9b91Sstsp case 2:
85574bd9b91Sstsp printf("PSK");
85674bd9b91Sstsp break;
85774bd9b91Sstsp case 5:
85874bd9b91Sstsp printf("SHA256-802.1x");
85974bd9b91Sstsp break;
86074bd9b91Sstsp case 6:
86174bd9b91Sstsp printf("SHA256-PSK");
86274bd9b91Sstsp break;
8633cfb4572Sstsp case 8:
8643cfb4572Sstsp printf("SAE");
8653cfb4572Sstsp break;
86674bd9b91Sstsp default:
86774bd9b91Sstsp printf("%d", selector[3]);
86874bd9b91Sstsp break;
86974bd9b91Sstsp }
87074bd9b91Sstsp }
87174bd9b91Sstsp
87274bd9b91Sstsp /* Caller checks len */
87374bd9b91Sstsp void
ieee80211_print_rsn(u_int8_t * data,u_int len)87474bd9b91Sstsp ieee80211_print_rsn(u_int8_t *data, u_int len)
87574bd9b91Sstsp {
87674bd9b91Sstsp uint16_t version, nciphers, nakms, rsncap, npmk;
87774bd9b91Sstsp int i, j;
87874bd9b91Sstsp uint8_t selector[4];
87974bd9b91Sstsp
88074bd9b91Sstsp if (len < 2) {
88174bd9b91Sstsp ieee80211_print_element(data, len);
88274bd9b91Sstsp return;
88374bd9b91Sstsp }
88474bd9b91Sstsp
88574bd9b91Sstsp version = (data[0]) | (data[1] << 8);
88674bd9b91Sstsp printf("=<version %d", version);
88774bd9b91Sstsp
88874bd9b91Sstsp if (len < 6) {
88974bd9b91Sstsp printf(">");
89074bd9b91Sstsp return;
89174bd9b91Sstsp }
89274bd9b91Sstsp
89374bd9b91Sstsp data += 2;
89474bd9b91Sstsp printf(",groupcipher ");
89574bd9b91Sstsp for (i = 0; i < 4; i++)
89674bd9b91Sstsp selector[i] = data[i];
89774bd9b91Sstsp ieee80211_print_rsncipher(selector);
89874bd9b91Sstsp
89974bd9b91Sstsp if (len < 8) {
90074bd9b91Sstsp printf(">");
90174bd9b91Sstsp return;
90274bd9b91Sstsp }
90374bd9b91Sstsp
90474bd9b91Sstsp data += 4;
90574bd9b91Sstsp nciphers = (data[0]) | ((data[1]) << 8);
90674bd9b91Sstsp data += 2;
90774bd9b91Sstsp
90874bd9b91Sstsp if (len < 8 + (nciphers * 4)) {
90974bd9b91Sstsp printf(">");
91074bd9b91Sstsp return;
91174bd9b91Sstsp }
91274bd9b91Sstsp
91374bd9b91Sstsp printf(",cipher%s ", nciphers > 1 ? "s" : "");
91474bd9b91Sstsp for (i = 0; i < nciphers; i++) {
91574bd9b91Sstsp for (j = 0; j < 4; j++)
9163cfb4572Sstsp selector[j] = data[j];
91774bd9b91Sstsp ieee80211_print_rsncipher(selector);
91874bd9b91Sstsp if (i < nciphers - 1)
91974bd9b91Sstsp printf(" ");
92074bd9b91Sstsp data += 4;
92174bd9b91Sstsp }
92274bd9b91Sstsp
92374bd9b91Sstsp if (len < 8 + (nciphers * 4) + 2) {
92474bd9b91Sstsp printf(">");
92574bd9b91Sstsp return;
92674bd9b91Sstsp }
92774bd9b91Sstsp
92874bd9b91Sstsp nakms = (data[0]) | ((data[1]) << 8);
92974bd9b91Sstsp data += 2;
93074bd9b91Sstsp
93174bd9b91Sstsp if (len < 8 + (nciphers * 4) + 2 + (nakms * 4)) {
93274bd9b91Sstsp printf(">");
93374bd9b91Sstsp return;
93474bd9b91Sstsp }
93574bd9b91Sstsp
93674bd9b91Sstsp printf(",akm%s ", nakms > 1 ? "s" : "");
9373cfb4572Sstsp for (i = 0; i < nakms; i++) {
93874bd9b91Sstsp for (j = 0; j < 4; j++)
9393cfb4572Sstsp selector[j] = data[j];
94074bd9b91Sstsp ieee80211_print_akm(selector);
9413cfb4572Sstsp if (i < nakms - 1)
94274bd9b91Sstsp printf(" ");
94374bd9b91Sstsp data += 4;
94474bd9b91Sstsp }
94574bd9b91Sstsp
94674bd9b91Sstsp if (len < 8 + (nciphers * 4) + 2 + (nakms * 4) + 2) {
94774bd9b91Sstsp printf(">");
94874bd9b91Sstsp return;
94974bd9b91Sstsp }
95074bd9b91Sstsp
95174bd9b91Sstsp rsncap = (data[0]) | ((data[1]) << 8);
95274bd9b91Sstsp printf(",rsncap 0x%x", rsncap);
95374bd9b91Sstsp data += 2;
95474bd9b91Sstsp
95574bd9b91Sstsp if (len < 8 + (nciphers * 4) + 2 + (nakms * 4) + 2 + 2) {
95674bd9b91Sstsp printf(">");
95774bd9b91Sstsp return;
95874bd9b91Sstsp }
95974bd9b91Sstsp
96074bd9b91Sstsp npmk = (data[0]) | ((data[1]) << 8);
96174bd9b91Sstsp data += 2;
96274bd9b91Sstsp
96374bd9b91Sstsp if (len < 8 + (nciphers * 4) + 2 + (nakms * 4) + 2 + 2 +
96474bd9b91Sstsp (npmk * IEEE80211_PMKID_LEN)) {
96574bd9b91Sstsp printf(">");
96674bd9b91Sstsp return;
96774bd9b91Sstsp }
96874bd9b91Sstsp
96974bd9b91Sstsp if (npmk >= 1)
97074bd9b91Sstsp printf(",pmkid%s ", npmk > 1 ? "s" : "");
97174bd9b91Sstsp for (i = 0; i < npmk; i++) {
97274bd9b91Sstsp printf("0x");
97374bd9b91Sstsp for (j = 0; j < IEEE80211_PMKID_LEN; j++)
974*46e5e1a2Sstsp printf("%x", data[j]);
97574bd9b91Sstsp if (i < npmk - 1)
97674bd9b91Sstsp printf(" ");
97774bd9b91Sstsp data += IEEE80211_PMKID_LEN;
97874bd9b91Sstsp }
97974bd9b91Sstsp
98074bd9b91Sstsp if (len < 8 + (nciphers * 4) + 2 + (nakms * 4) + 2 + 2 +
98174bd9b91Sstsp (npmk * IEEE80211_PMKID_LEN) + 4) {
98274bd9b91Sstsp printf(">");
98374bd9b91Sstsp return;
98474bd9b91Sstsp }
98574bd9b91Sstsp
98674bd9b91Sstsp printf(",integrity-groupcipher ");
98774bd9b91Sstsp for (i = 0; i < 4; i++)
98874bd9b91Sstsp selector[i] = data[i];
98974bd9b91Sstsp ieee80211_print_rsncipher(selector);
99074bd9b91Sstsp
99174bd9b91Sstsp printf(">");
99274bd9b91Sstsp }
99374bd9b91Sstsp
99412a08440Sreyk int
ieee80211_print_beacon(struct ieee80211_frame * wh,u_int len)9956f9acb7aSstsp ieee80211_print_beacon(struct ieee80211_frame *wh, u_int len)
99612a08440Sreyk {
9976f9acb7aSstsp uint64_t tstamp;
9986f9acb7aSstsp uint16_t bintval, capinfo;
9996f9acb7aSstsp uint8_t *frm;
100012a08440Sreyk
10016f9acb7aSstsp if (len < sizeof(tstamp) + sizeof(bintval) + sizeof(capinfo))
10026f9acb7aSstsp return 1; /* truncated */
10036f9acb7aSstsp
100412a08440Sreyk frm = (u_int8_t *)&wh[1];
100512a08440Sreyk
1006cce1ba42Sclaudio bcopy(frm, &tstamp, sizeof(u_int64_t));
100712a08440Sreyk frm += 8;
100812a08440Sreyk if (vflag > 1)
1009cce1ba42Sclaudio printf(", timestamp %llu", letoh64(tstamp));
101012a08440Sreyk
1011cce1ba42Sclaudio bcopy(frm, &bintval, sizeof(u_int16_t));
101212a08440Sreyk frm += 2;
101312a08440Sreyk if (vflag > 1)
1014cce1ba42Sclaudio printf(", interval %u", letoh16(bintval));
101512a08440Sreyk
1016cce1ba42Sclaudio bcopy(frm, &capinfo, sizeof(u_int16_t));
101712a08440Sreyk frm += 2;
101812a08440Sreyk if (vflag)
10196f9acb7aSstsp printb(", caps", letoh16(capinfo), IEEE80211_CAPINFO_BITS);
10206f9acb7aSstsp
10216f9acb7aSstsp return ieee80211_print_elements(frm);
10226f9acb7aSstsp }
10236f9acb7aSstsp
10246f9acb7aSstsp int
ieee80211_print_assocreq(struct ieee80211_frame * wh,u_int len)10256f9acb7aSstsp ieee80211_print_assocreq(struct ieee80211_frame *wh, u_int len)
10266f9acb7aSstsp {
10276f9acb7aSstsp uint8_t subtype;
10286f9acb7aSstsp uint16_t capinfo, lintval;
10296f9acb7aSstsp uint8_t *frm;
10306f9acb7aSstsp
10316f9acb7aSstsp subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
10326f9acb7aSstsp
10336f9acb7aSstsp if (len < sizeof(capinfo) + sizeof(lintval) +
10346f9acb7aSstsp (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ ?
10356f9acb7aSstsp IEEE80211_ADDR_LEN : 0))
10366f9acb7aSstsp return 1; /* truncated */
10376f9acb7aSstsp
10386f9acb7aSstsp frm = (u_int8_t *)&wh[1];
10396f9acb7aSstsp
10406f9acb7aSstsp bcopy(frm, &capinfo, sizeof(u_int16_t));
10416f9acb7aSstsp frm += 2;
10426f9acb7aSstsp if (vflag)
10436f9acb7aSstsp printb(", caps", letoh16(capinfo), IEEE80211_CAPINFO_BITS);
10446f9acb7aSstsp
10456f9acb7aSstsp bcopy(frm, &lintval, sizeof(u_int16_t));
10466f9acb7aSstsp frm += 2;
10476f9acb7aSstsp if (vflag > 1)
10486f9acb7aSstsp printf(", listen interval %u", letoh16(lintval));
10496f9acb7aSstsp
10506f9acb7aSstsp if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
10516f9acb7aSstsp if (vflag)
10526f9acb7aSstsp printf(", AP %s", etheraddr_string(frm));
10536f9acb7aSstsp frm += IEEE80211_ADDR_LEN;
10546f9acb7aSstsp }
10556f9acb7aSstsp
10566f9acb7aSstsp return ieee80211_print_elements(frm);
10576f9acb7aSstsp }
10586f9acb7aSstsp
10596f9acb7aSstsp int
ieee80211_print_elements(uint8_t * frm)10606f9acb7aSstsp ieee80211_print_elements(uint8_t *frm)
10616f9acb7aSstsp {
10626f9acb7aSstsp int i;
106312a08440Sreyk
106412a08440Sreyk while (TTEST2(*frm, 2)) {
106512a08440Sreyk u_int len = frm[1];
106612a08440Sreyk u_int8_t *data = frm + 2;
106712a08440Sreyk
106812a08440Sreyk if (!TTEST2(*data, len))
106912a08440Sreyk break;
107012a08440Sreyk
10716f9acb7aSstsp #define ELEM_CHECK(l) if (len != l) goto trunc
107212a08440Sreyk
107312a08440Sreyk switch (*frm) {
107412a08440Sreyk case IEEE80211_ELEMID_SSID:
107512a08440Sreyk printf(", ssid");
107612a08440Sreyk ieee80211_print_essid(data, len);
107712a08440Sreyk break;
107812a08440Sreyk case IEEE80211_ELEMID_RATES:
107912a08440Sreyk printf(", rates");
108012a08440Sreyk if (!vflag)
108112a08440Sreyk break;
108212a08440Sreyk for (i = len; i > 0; i--, data++)
1083feb1bebcSstsp printf(" %uM%s",
1084feb1bebcSstsp (data[0] & IEEE80211_RATE_VAL) / 2,
1085feb1bebcSstsp (data[0] & IEEE80211_RATE_BASIC
1086feb1bebcSstsp ? "*" : ""));
108712a08440Sreyk break;
108812a08440Sreyk case IEEE80211_ELEMID_FHPARMS:
108912a08440Sreyk ELEM_CHECK(5);
109012a08440Sreyk printf(", fh (dwell %u, chan %u, index %u)",
109112a08440Sreyk (data[1] << 8) | data[0],
109212a08440Sreyk (data[2] - 1) * 80 + data[3], /* FH_CHAN */
109312a08440Sreyk data[4]);
109412a08440Sreyk break;
109512a08440Sreyk case IEEE80211_ELEMID_DSPARMS:
109612a08440Sreyk ELEM_CHECK(1);
109712a08440Sreyk printf(", ds");
109812a08440Sreyk if (vflag)
109912a08440Sreyk printf(" (chan %u)", data[0]);
110012a08440Sreyk break;
110112a08440Sreyk case IEEE80211_ELEMID_CFPARMS:
110212a08440Sreyk printf(", cf");
110312a08440Sreyk if (vflag)
110412a08440Sreyk ieee80211_print_element(data, len);
110512a08440Sreyk break;
110612a08440Sreyk case IEEE80211_ELEMID_TIM:
110712a08440Sreyk printf(", tim");
110812a08440Sreyk if (vflag)
110912a08440Sreyk ieee80211_print_element(data, len);
111012a08440Sreyk break;
111112a08440Sreyk case IEEE80211_ELEMID_IBSSPARMS:
111212a08440Sreyk printf(", ibss");
111312a08440Sreyk if (vflag)
111412a08440Sreyk ieee80211_print_element(data, len);
111512a08440Sreyk break;
111612a08440Sreyk case IEEE80211_ELEMID_COUNTRY:
111712a08440Sreyk printf(", country");
11187ccd2116Sstsp if (vflag)
111977734011Sstsp ieee80211_print_country(data, len);
112012a08440Sreyk break;
112112a08440Sreyk case IEEE80211_ELEMID_CHALLENGE:
112212a08440Sreyk printf(", challenge");
112312a08440Sreyk if (vflag)
112412a08440Sreyk ieee80211_print_element(data, len);
112512a08440Sreyk break;
1126738acb58Ssthen case IEEE80211_ELEMID_CSA:
1127958b7e45Ssthen ELEM_CHECK(3);
1128738acb58Ssthen printf(", csa (chan %u count %u%s)", data[1], data[2],
1129738acb58Ssthen (data[0] == 1) ? " noTX" : "");
1130738acb58Ssthen break;
113112a08440Sreyk case IEEE80211_ELEMID_ERP:
113212a08440Sreyk printf(", erp");
113312a08440Sreyk if (vflag)
113412a08440Sreyk ieee80211_print_element(data, len);
113512a08440Sreyk break;
113612a08440Sreyk case IEEE80211_ELEMID_RSN:
113712a08440Sreyk printf(", rsn");
113812a08440Sreyk if (vflag)
113974bd9b91Sstsp ieee80211_print_rsn(data, len);
114012a08440Sreyk break;
114112a08440Sreyk case IEEE80211_ELEMID_XRATES:
114212a08440Sreyk printf(", xrates");
114312a08440Sreyk if (!vflag)
114412a08440Sreyk break;
114512a08440Sreyk for (i = len; i > 0; i--, data++)
114612a08440Sreyk printf(" %uM",
114712a08440Sreyk (data[0] & IEEE80211_RATE_VAL) / 2);
114812a08440Sreyk break;
11498138faddSstsp case IEEE80211_ELEMID_TPC_REPORT:
11508138faddSstsp printf(", tpcreport");
115112a08440Sreyk if (vflag)
115212a08440Sreyk ieee80211_print_element(data, len);
115312a08440Sreyk break;
11548138faddSstsp case IEEE80211_ELEMID_TPC_REQUEST:
11558138faddSstsp printf(", tpcrequest");
115612a08440Sreyk if (vflag)
115712a08440Sreyk ieee80211_print_element(data, len);
115812a08440Sreyk break;
11591e3bf20aSstsp case IEEE80211_ELEMID_HTCAPS:
11601e3bf20aSstsp printf(", htcaps");
11611e3bf20aSstsp if (vflag)
11621e3bf20aSstsp ieee80211_print_htcaps(data, len);
11631e3bf20aSstsp break;
116436fa064cSstsp case IEEE80211_ELEMID_HTOP:
116536fa064cSstsp printf(", htop");
116636fa064cSstsp if (vflag)
116736fa064cSstsp ieee80211_print_htop(data, len);
116836fa064cSstsp break;
1169986f6204Sstsp case IEEE80211_ELEMID_VHTCAPS:
1170986f6204Sstsp printf(", vhtcaps");
1171986f6204Sstsp if (vflag)
1172986f6204Sstsp ieee80211_print_vhtcaps(data, len);
1173986f6204Sstsp break;
1174986f6204Sstsp case IEEE80211_ELEMID_VHTOP:
1175986f6204Sstsp printf(", vhtop");
1176986f6204Sstsp if (vflag)
1177986f6204Sstsp ieee80211_print_vhtop(data, len);
1178986f6204Sstsp break;
117977734011Sstsp case IEEE80211_ELEMID_POWER_CONSTRAINT:
118077734011Sstsp ELEM_CHECK(1);
118177734011Sstsp printf(", power constraint %udB", data[0]);
118277734011Sstsp break;
11838f0a8537Sstsp case IEEE80211_ELEMID_QBSS_LOAD:
11848f0a8537Sstsp ELEM_CHECK(5);
11858f0a8537Sstsp printf(", %u stations, %d%% utilization, "
11868f0a8537Sstsp "admission capacity %uus/s",
11878f0a8537Sstsp (data[0] | data[1] << 8),
11888f0a8537Sstsp (data[2] * 100) / 255,
11898f0a8537Sstsp (data[3] | data[4] << 8) / 32);
11908f0a8537Sstsp break;
119112a08440Sreyk case IEEE80211_ELEMID_VENDOR:
119212a08440Sreyk printf(", vendor");
119312a08440Sreyk if (vflag)
119412a08440Sreyk ieee80211_print_element(data, len);
119512a08440Sreyk break;
119612a08440Sreyk default:
119712a08440Sreyk printf(", %u:%u", (u_int) *frm, len);
119812a08440Sreyk if (vflag)
119912a08440Sreyk ieee80211_print_element(data, len);
120012a08440Sreyk break;
120112a08440Sreyk }
120212a08440Sreyk frm += len + 2;
120312a08440Sreyk
120412a08440Sreyk if (frm >= snapend)
120512a08440Sreyk break;
120612a08440Sreyk }
120712a08440Sreyk
120812a08440Sreyk #undef ELEM_CHECK
120912a08440Sreyk
121012a08440Sreyk return (0);
121112a08440Sreyk
121212a08440Sreyk trunc:
121312a08440Sreyk /* Truncated elements in frame */
121412a08440Sreyk return (1);
121512a08440Sreyk }
121612a08440Sreyk
121712a08440Sreyk int
ieee80211_frame(struct ieee80211_frame * wh,u_int len)121812a08440Sreyk ieee80211_frame(struct ieee80211_frame *wh, u_int len)
121912a08440Sreyk {
122012a08440Sreyk u_int8_t subtype, type, *frm;
122112a08440Sreyk
122212a08440Sreyk TCARR(wh->i_fc);
122312a08440Sreyk
122412a08440Sreyk type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
122512a08440Sreyk subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
122612a08440Sreyk
122712a08440Sreyk frm = (u_int8_t *)&wh[1];
122812a08440Sreyk
1229ab7e388eSclaudio if (vflag)
1230ab7e388eSclaudio printb(" flags", wh->i_fc[1], IEEE80211_FC1_BITS);
1231ab7e388eSclaudio
123212a08440Sreyk switch (type) {
123312a08440Sreyk case IEEE80211_FC0_TYPE_DATA:
1234ab7e388eSclaudio printf(": %s: ", ieee80211_data_subtype_name[
1235ab7e388eSclaudio subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
1236b72abdefSreyk ieee80211_data(wh, len);
123712a08440Sreyk break;
123812a08440Sreyk case IEEE80211_FC0_TYPE_MGT:
123912a08440Sreyk printf(": %s", ieee80211_mgt_subtype_name[
124012a08440Sreyk subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
124112a08440Sreyk switch (subtype) {
124212a08440Sreyk case IEEE80211_FC0_SUBTYPE_BEACON:
124312a08440Sreyk case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
12446f9acb7aSstsp if (ieee80211_print_beacon(wh, len) != 0)
12456f9acb7aSstsp goto trunc;
12466f9acb7aSstsp break;
12476f9acb7aSstsp case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
12486f9acb7aSstsp case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
12496f9acb7aSstsp if (ieee80211_print_assocreq(wh, len) != 0)
125012a08440Sreyk goto trunc;
125112a08440Sreyk break;
125212a08440Sreyk case IEEE80211_FC0_SUBTYPE_AUTH:
125312a08440Sreyk TCHECK2(*frm, 2); /* Auth Algorithm */
125412a08440Sreyk switch (IEEE80211_AUTH_ALGORITHM(frm)) {
125512a08440Sreyk case IEEE80211_AUTH_ALG_OPEN:
125612a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */
125712a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) {
125812a08440Sreyk case IEEE80211_AUTH_OPEN_REQUEST:
125912a08440Sreyk printf(" request");
126012a08440Sreyk break;
126112a08440Sreyk case IEEE80211_AUTH_OPEN_RESPONSE:
126212a08440Sreyk printf(" response");
126312a08440Sreyk break;
126412a08440Sreyk }
126512a08440Sreyk break;
126612a08440Sreyk case IEEE80211_AUTH_ALG_SHARED:
126712a08440Sreyk TCHECK2(*frm, 4); /* Auth Transaction */
126812a08440Sreyk switch (IEEE80211_AUTH_TRANSACTION(frm)) {
126912a08440Sreyk case IEEE80211_AUTH_SHARED_REQUEST:
127012a08440Sreyk printf(" request");
127112a08440Sreyk break;
127212a08440Sreyk case IEEE80211_AUTH_SHARED_CHALLENGE:
127312a08440Sreyk printf(" challenge");
127412a08440Sreyk break;
127512a08440Sreyk case IEEE80211_AUTH_SHARED_RESPONSE:
127612a08440Sreyk printf(" response");
127712a08440Sreyk break;
127812a08440Sreyk case IEEE80211_AUTH_SHARED_PASS:
127912a08440Sreyk printf(" pass");
128012a08440Sreyk break;
128112a08440Sreyk }
128212a08440Sreyk break;
128312a08440Sreyk case IEEE80211_AUTH_ALG_LEAP:
128412a08440Sreyk printf(" (leap)");
128512a08440Sreyk break;
128612a08440Sreyk }
128712a08440Sreyk break;
128818786664Sclaudio case IEEE80211_FC0_SUBTYPE_DEAUTH:
128918786664Sclaudio case IEEE80211_FC0_SUBTYPE_DISASSOC:
129018786664Sclaudio TCHECK2(*frm, 2); /* Reason Code */
129118786664Sclaudio ieee80211_reason(frm[0] | (frm[1] << 8));
129218786664Sclaudio break;
129312a08440Sreyk }
129412a08440Sreyk break;
12958dd9ce3eSstsp case IEEE80211_FC0_TYPE_CTL: {
12968dd9ce3eSstsp u_int8_t *t = (u_int8_t *) wh;
12978dd9ce3eSstsp
12988dd9ce3eSstsp printf(": %s", ieee80211_ctl_subtype_name[
12998dd9ce3eSstsp subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
13008dd9ce3eSstsp if (!vflag)
13018dd9ce3eSstsp break;
13028dd9ce3eSstsp
13038dd9ce3eSstsp /* See 802.11 2012 "8.3.1 Control frames". */
13048dd9ce3eSstsp t += 2; /* skip Frame Control */
13058dd9ce3eSstsp switch (subtype) {
13068dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_RTS:
13078dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_BAR:
13088dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_BA:
13098dd9ce3eSstsp TCHECK2(*t, 2); /* Duration */
13101e43aa30Sstsp printf(", duration %dus", (t[0] | t[1] << 8));
13118dd9ce3eSstsp t += 2;
13128dd9ce3eSstsp TCHECK2(*t, 6); /* RA */
13138dd9ce3eSstsp printf(", ra %s", etheraddr_string(t));
13148dd9ce3eSstsp t += 6;
13158dd9ce3eSstsp TCHECK2(*t, 6); /* TA */
13168dd9ce3eSstsp printf(", ta %s", etheraddr_string(t));
13178dd9ce3eSstsp if (subtype == IEEE80211_FC0_SUBTYPE_BAR ||
13188dd9ce3eSstsp subtype == IEEE80211_FC0_SUBTYPE_BA) {
13198dd9ce3eSstsp u_int16_t ctrl;
13208dd9ce3eSstsp
13218dd9ce3eSstsp t += 6;
13228dd9ce3eSstsp TCHECK2(*t, 2); /* BAR/BA control */
13238dd9ce3eSstsp ctrl = t[0] | (t[1] << 8);
13248dd9ce3eSstsp if (ctrl & IEEE80211_BA_ACK_POLICY)
13258dd9ce3eSstsp printf(", no ack");
13268dd9ce3eSstsp else
13278dd9ce3eSstsp printf(", normal ack");
13288dd9ce3eSstsp if ((ctrl & IEEE80211_BA_MULTI_TID) == 0 &&
13298dd9ce3eSstsp (ctrl & IEEE80211_BA_COMPRESSED) == 0)
13308dd9ce3eSstsp printf(", basic variant");
13318dd9ce3eSstsp else if ((ctrl & IEEE80211_BA_MULTI_TID) &&
13328dd9ce3eSstsp (ctrl & IEEE80211_BA_COMPRESSED))
13338dd9ce3eSstsp printf(", multi-tid variant");
13348dd9ce3eSstsp else if (ctrl & IEEE80211_BA_COMPRESSED)
13358dd9ce3eSstsp printf(", compressed variant");
13368dd9ce3eSstsp }
13378dd9ce3eSstsp break;
13388dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_CTS:
13398dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_ACK:
13408dd9ce3eSstsp TCHECK2(*t, 2); /* Duration */
13411e43aa30Sstsp printf(", duration %dus", (t[0] | t[1] << 8));
13428dd9ce3eSstsp t += 2;
13438dd9ce3eSstsp TCHECK2(*t, 6); /* RA */
13448dd9ce3eSstsp printf(", ra %s", etheraddr_string(t));
13458dd9ce3eSstsp break;
13468dd9ce3eSstsp case IEEE80211_FC0_SUBTYPE_PS_POLL:
13478dd9ce3eSstsp TCHECK2(*t, 2); /* AID */
13488dd9ce3eSstsp printf(", aid 0x%x", (t[0] | t[1] << 8));
13498dd9ce3eSstsp t += 2;
13508dd9ce3eSstsp TCHECK2(*t, 6); /* BSSID(RA) */
13518dd9ce3eSstsp printf(", ra %s", etheraddr_string(t));
13528dd9ce3eSstsp t += 6;
13538dd9ce3eSstsp TCHECK2(*t, 6); /* TA */
13548dd9ce3eSstsp printf(", ta %s", etheraddr_string(t));
13558dd9ce3eSstsp break;
13568dd9ce3eSstsp }
13578dd9ce3eSstsp break;
13588dd9ce3eSstsp }
135912a08440Sreyk default:
136012a08440Sreyk printf(": type#%d", type);
136112a08440Sreyk break;
136212a08440Sreyk }
136312a08440Sreyk
136412a08440Sreyk return (0);
136512a08440Sreyk
136612a08440Sreyk trunc:
136712a08440Sreyk /* Truncated 802.11 frame */
136812a08440Sreyk return (1);
136912a08440Sreyk }
137012a08440Sreyk
137112a08440Sreyk u_int
ieee80211_any2ieee(u_int freq,u_int flags)137212a08440Sreyk ieee80211_any2ieee(u_int freq, u_int flags)
137312a08440Sreyk {
137412a08440Sreyk if (flags & IEEE80211_CHAN_2GHZ) {
137512a08440Sreyk if (freq == 2484)
137612a08440Sreyk return 14;
137712a08440Sreyk if (freq < 2484)
137812a08440Sreyk return (freq - 2407) / 5;
137912a08440Sreyk else
138012a08440Sreyk return 15 + ((freq - 2512) / 20);
138112a08440Sreyk } else if (flags & IEEE80211_CHAN_5GHZ) {
138212a08440Sreyk return (freq - 5000) / 5;
138312a08440Sreyk } else {
138412a08440Sreyk /* Assume channel is already an IEEE number */
138512a08440Sreyk return (freq);
138612a08440Sreyk }
138712a08440Sreyk }
138812a08440Sreyk
138912a08440Sreyk int
ieee80211_print(struct ieee80211_frame * wh,u_int len)139012a08440Sreyk ieee80211_print(struct ieee80211_frame *wh, u_int len)
139112a08440Sreyk {
139212a08440Sreyk if (eflag)
139312a08440Sreyk if (ieee80211_hdr(wh))
139412a08440Sreyk return (1);
139512a08440Sreyk
139612a08440Sreyk printf("802.11");
139712a08440Sreyk
139812a08440Sreyk return (ieee80211_frame(wh, len));
139912a08440Sreyk }
140012a08440Sreyk
140112a08440Sreyk void
ieee802_11_if_print(u_char * user,const struct pcap_pkthdr * h,const u_char * p)140212a08440Sreyk ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h,
140312a08440Sreyk const u_char *p)
140412a08440Sreyk {
140512a08440Sreyk struct ieee80211_frame *wh = (struct ieee80211_frame*)p;
140612a08440Sreyk
1407c79cf170Sreyk if (!ieee80211_encap)
140812a08440Sreyk ts_print(&h->ts);
140912a08440Sreyk
141012a08440Sreyk packetp = p;
141112a08440Sreyk snapend = p + h->caplen;
141212a08440Sreyk
1413a0774ae9Smglocker if (ieee80211_print(wh, (u_int)h->len) != 0)
141412a08440Sreyk printf("[|802.11]");
141512a08440Sreyk
1416c79cf170Sreyk if (!ieee80211_encap) {
141712a08440Sreyk if (xflag)
1418a0774ae9Smglocker default_print(p, (u_int)h->len);
141912a08440Sreyk putchar('\n');
142012a08440Sreyk }
1421c79cf170Sreyk }
142212a08440Sreyk
142312a08440Sreyk void
ieee802_11_radio_if_print(u_char * user,const struct pcap_pkthdr * h,const u_char * p)142412a08440Sreyk ieee802_11_radio_if_print(u_char *user, const struct pcap_pkthdr *h,
142512a08440Sreyk const u_char *p)
142612a08440Sreyk {
142712a08440Sreyk struct ieee80211_radiotap_header *rh =
142812a08440Sreyk (struct ieee80211_radiotap_header*)p;
142912a08440Sreyk struct ieee80211_frame *wh;
143012a08440Sreyk u_int8_t *t;
143112a08440Sreyk u_int32_t present;
143212a08440Sreyk u_int len, rh_len;
1433cce1ba42Sclaudio u_int16_t tmp;
143412a08440Sreyk
1435c79cf170Sreyk if (!ieee80211_encap)
143612a08440Sreyk ts_print(&h->ts);
143712a08440Sreyk
143812a08440Sreyk packetp = p;
143912a08440Sreyk snapend = p + h->caplen;
144012a08440Sreyk
144112a08440Sreyk TCHECK(*rh);
144212a08440Sreyk
1443a0774ae9Smglocker len = h->len;
144412a08440Sreyk rh_len = letoh16(rh->it_len);
144512a08440Sreyk if (rh->it_version != 0) {
1446c79cf170Sreyk printf("[?radiotap + 802.11 v:%u]", rh->it_version);
144712a08440Sreyk goto out;
144812a08440Sreyk }
144912a08440Sreyk
145012a08440Sreyk wh = (struct ieee80211_frame *)(p + rh_len);
145112a08440Sreyk if (len <= rh_len || ieee80211_print(wh, len - rh_len))
145212a08440Sreyk printf("[|802.11]");
145312a08440Sreyk
145412a08440Sreyk t = (u_int8_t*)p + sizeof(struct ieee80211_radiotap_header);
145512a08440Sreyk
145612a08440Sreyk if ((present = letoh32(rh->it_present)) == 0)
145712a08440Sreyk goto out;
145812a08440Sreyk
145912a08440Sreyk printf(", <radiotap v%u", rh->it_version);
146012a08440Sreyk
146112a08440Sreyk #define RADIOTAP(_x) \
146212a08440Sreyk (present & (1 << IEEE80211_RADIOTAP_##_x))
146312a08440Sreyk
146412a08440Sreyk if (RADIOTAP(TSFT)) {
1465cce1ba42Sclaudio u_int64_t tsf;
1466cce1ba42Sclaudio
146712a08440Sreyk TCHECK2(*t, 8);
1468cce1ba42Sclaudio bcopy(t, &tsf, sizeof(u_int64_t));
146912a08440Sreyk if (vflag > 1)
1470cce1ba42Sclaudio printf(", tsf %llu", letoh64(tsf));
147112a08440Sreyk t += 8;
147212a08440Sreyk }
147312a08440Sreyk
147412a08440Sreyk if (RADIOTAP(FLAGS)) {
147512a08440Sreyk u_int8_t flags = *(u_int8_t*)t;
1476026ca542Sderaadt TCHECK2(*t, 1);
1477026ca542Sderaadt
147812a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_CFP)
147912a08440Sreyk printf(", CFP");
148012a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_SHORTPRE)
148112a08440Sreyk printf(", SHORTPRE");
148212a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_WEP)
148312a08440Sreyk printf(", WEP");
148412a08440Sreyk if (flags & IEEE80211_RADIOTAP_F_FRAG)
148512a08440Sreyk printf(", FRAG");
148612a08440Sreyk t += 1;
148712a08440Sreyk }
148812a08440Sreyk
148912a08440Sreyk if (RADIOTAP(RATE)) {
149012a08440Sreyk TCHECK2(*t, 1);
14919533a5eaSstsp if (vflag) {
14929533a5eaSstsp uint8_t rate = *(u_int8_t*)t;
14939533a5eaSstsp if (rate & 0x80)
14949533a5eaSstsp printf(", MCS %u", rate & 0x7f);
14959533a5eaSstsp else
14969533a5eaSstsp printf(", %uMbit/s", rate / 2);
14979533a5eaSstsp }
149812a08440Sreyk t += 1;
149912a08440Sreyk }
150012a08440Sreyk
150112a08440Sreyk if (RADIOTAP(CHANNEL)) {
150212a08440Sreyk u_int16_t freq, flags;
150312a08440Sreyk TCHECK2(*t, 2);
150412a08440Sreyk
1505cce1ba42Sclaudio bcopy(t, &freq, sizeof(u_int16_t));
1506cce1ba42Sclaudio freq = letoh16(freq);
150712a08440Sreyk t += 2;
150812a08440Sreyk TCHECK2(*t, 2);
1509cce1ba42Sclaudio bcopy(t, &flags, sizeof(u_int16_t));
1510cce1ba42Sclaudio flags = letoh16(flags);
151112a08440Sreyk t += 2;
151212a08440Sreyk
151312a08440Sreyk printf(", chan %u", ieee80211_any2ieee(freq, flags));
151412a08440Sreyk
1515cc3040aaSstsp if (flags & IEEE80211_CHAN_HT)
1516cc3040aaSstsp printf(", 11n");
1517cc3040aaSstsp else if (flags & IEEE80211_CHAN_DYN &&
1518cc3040aaSstsp flags & IEEE80211_CHAN_2GHZ)
1519cc3040aaSstsp printf(", 11g");
152012a08440Sreyk else if (flags & IEEE80211_CHAN_CCK &&
152112a08440Sreyk flags & IEEE80211_CHAN_2GHZ)
152212a08440Sreyk printf(", 11b");
152312a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM &&
152412a08440Sreyk flags & IEEE80211_CHAN_2GHZ)
152512a08440Sreyk printf(", 11G");
152612a08440Sreyk else if (flags & IEEE80211_CHAN_OFDM &&
152712a08440Sreyk flags & IEEE80211_CHAN_5GHZ)
152812a08440Sreyk printf(", 11a");
152912a08440Sreyk
153012a08440Sreyk if (flags & IEEE80211_CHAN_XR)
153112a08440Sreyk printf(", XR");
153212a08440Sreyk }
153312a08440Sreyk
153412a08440Sreyk if (RADIOTAP(FHSS)) {
153512a08440Sreyk TCHECK2(*t, 2);
153612a08440Sreyk printf(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1);
153712a08440Sreyk t += 2;
153812a08440Sreyk }
153912a08440Sreyk
154012a08440Sreyk if (RADIOTAP(DBM_ANTSIGNAL)) {
154112a08440Sreyk TCHECK(*t);
154212a08440Sreyk printf(", sig %ddBm", *(int8_t*)t);
154312a08440Sreyk t += 1;
154412a08440Sreyk }
154512a08440Sreyk
154612a08440Sreyk if (RADIOTAP(DBM_ANTNOISE)) {
154712a08440Sreyk TCHECK(*t);
154812a08440Sreyk printf(", noise %ddBm", *(int8_t*)t);
154912a08440Sreyk t += 1;
155012a08440Sreyk }
155112a08440Sreyk
155212a08440Sreyk if (RADIOTAP(LOCK_QUALITY)) {
155312a08440Sreyk TCHECK2(*t, 2);
1554cce1ba42Sclaudio if (vflag) {
1555cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t));
1556cce1ba42Sclaudio printf(", quality %u", letoh16(tmp));
1557cce1ba42Sclaudio }
155812a08440Sreyk t += 2;
155912a08440Sreyk }
156012a08440Sreyk
156112a08440Sreyk if (RADIOTAP(TX_ATTENUATION)) {
156212a08440Sreyk TCHECK2(*t, 2);
1563cce1ba42Sclaudio if (vflag) {
1564cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t));
1565cce1ba42Sclaudio printf(", txatt %u", letoh16(tmp));
1566cce1ba42Sclaudio }
156712a08440Sreyk t += 2;
156812a08440Sreyk }
156912a08440Sreyk
157012a08440Sreyk if (RADIOTAP(DB_TX_ATTENUATION)) {
157112a08440Sreyk TCHECK2(*t, 2);
1572cce1ba42Sclaudio if (vflag) {
1573cce1ba42Sclaudio bcopy(t, &tmp, sizeof(u_int16_t));
1574cce1ba42Sclaudio printf(", txatt %udB", letoh16(tmp));
1575cce1ba42Sclaudio }
157612a08440Sreyk t += 2;
157712a08440Sreyk }
157812a08440Sreyk
157912a08440Sreyk if (RADIOTAP(DBM_TX_POWER)) {
158012a08440Sreyk TCHECK(*t);
158112a08440Sreyk printf(", txpower %ddBm", *(int8_t*)t);
158212a08440Sreyk t += 1;
158312a08440Sreyk }
158412a08440Sreyk
158512a08440Sreyk if (RADIOTAP(ANTENNA)) {
158612a08440Sreyk TCHECK(*t);
158712a08440Sreyk if (vflag)
158812a08440Sreyk printf(", antenna %u", *(u_int8_t*)t);
158912a08440Sreyk t += 1;
159012a08440Sreyk }
159112a08440Sreyk
159212a08440Sreyk if (RADIOTAP(DB_ANTSIGNAL)) {
159312a08440Sreyk TCHECK(*t);
159412a08440Sreyk printf(", signal %udB", *(u_int8_t*)t);
159512a08440Sreyk t += 1;
159612a08440Sreyk }
159712a08440Sreyk
159812a08440Sreyk if (RADIOTAP(DB_ANTNOISE)) {
159912a08440Sreyk TCHECK(*t);
160012a08440Sreyk printf(", noise %udB", *(u_int8_t*)t);
160112a08440Sreyk t += 1;
160212a08440Sreyk }
160312a08440Sreyk
160412a08440Sreyk if (RADIOTAP(FCS)) {
160512a08440Sreyk TCHECK2(*t, 4);
1606cce1ba42Sclaudio if (vflag) {
1607cce1ba42Sclaudio u_int32_t fcs;
1608cce1ba42Sclaudio bcopy(t, &fcs, sizeof(u_int32_t));
1609cce1ba42Sclaudio printf(", fcs %08x", letoh32(fcs));
1610cce1ba42Sclaudio }
161112a08440Sreyk t += 4;
161212a08440Sreyk }
161312a08440Sreyk
16146fc94ee3Sreyk if (RADIOTAP(RSSI)) {
16156fc94ee3Sreyk u_int8_t rssi, max_rssi;
16166fc94ee3Sreyk TCHECK(*t);
16176fc94ee3Sreyk rssi = *(u_int8_t*)t;
16186fc94ee3Sreyk t += 1;
16196fc94ee3Sreyk TCHECK(*t);
16206fc94ee3Sreyk max_rssi = *(u_int8_t*)t;
16216fc94ee3Sreyk t += 1;
16226fc94ee3Sreyk
16236fc94ee3Sreyk printf(", rssi %u/%u", rssi, max_rssi);
16246fc94ee3Sreyk }
16256fc94ee3Sreyk
162612a08440Sreyk #undef RADIOTAP
162712a08440Sreyk
162812a08440Sreyk putchar('>');
162912a08440Sreyk goto out;
163012a08440Sreyk
163112a08440Sreyk trunc:
163212a08440Sreyk /* Truncated frame */
163312a08440Sreyk printf("[|radiotap + 802.11]");
163412a08440Sreyk
163512a08440Sreyk out:
1636c79cf170Sreyk if (!ieee80211_encap) {
163712a08440Sreyk if (xflag)
1638a0774ae9Smglocker default_print(p, h->len);
163912a08440Sreyk putchar('\n');
164012a08440Sreyk }
1641c79cf170Sreyk }
164218786664Sclaudio
164318786664Sclaudio void
ieee80211_reason(u_int16_t reason)164418786664Sclaudio ieee80211_reason(u_int16_t reason)
164518786664Sclaudio {
164618786664Sclaudio if (!vflag)
164718786664Sclaudio return;
164818786664Sclaudio
164918786664Sclaudio switch (reason) {
165018786664Sclaudio case IEEE80211_REASON_UNSPECIFIED:
165118786664Sclaudio printf(", unspecified failure");
165218786664Sclaudio break;
165318786664Sclaudio case IEEE80211_REASON_AUTH_EXPIRE:
165418786664Sclaudio printf(", authentication expired");
165518786664Sclaudio break;
165618786664Sclaudio case IEEE80211_REASON_AUTH_LEAVE:
165718786664Sclaudio printf(", deauth - station left");
165818786664Sclaudio break;
165918786664Sclaudio case IEEE80211_REASON_ASSOC_EXPIRE:
166018786664Sclaudio printf(", association expired");
166118786664Sclaudio break;
166218786664Sclaudio case IEEE80211_REASON_ASSOC_TOOMANY:
166318786664Sclaudio printf(", too many associated stations");
166418786664Sclaudio break;
166518786664Sclaudio case IEEE80211_REASON_NOT_AUTHED:
166618786664Sclaudio printf(", not authenticated");
166718786664Sclaudio break;
166818786664Sclaudio case IEEE80211_REASON_NOT_ASSOCED:
166918786664Sclaudio printf(", not associated");
167018786664Sclaudio break;
167118786664Sclaudio case IEEE80211_REASON_ASSOC_LEAVE:
167218786664Sclaudio printf(", disassociated - station left");
167318786664Sclaudio break;
167418786664Sclaudio case IEEE80211_REASON_ASSOC_NOT_AUTHED:
167518786664Sclaudio printf(", association but not authenticated");
167618786664Sclaudio break;
167718786664Sclaudio case IEEE80211_REASON_RSN_REQUIRED:
167818786664Sclaudio printf(", rsn required");
167918786664Sclaudio break;
168018786664Sclaudio case IEEE80211_REASON_RSN_INCONSISTENT:
168118786664Sclaudio printf(", rsn inconsistent");
168218786664Sclaudio break;
168318786664Sclaudio case IEEE80211_REASON_IE_INVALID:
168418786664Sclaudio printf(", ie invalid");
168518786664Sclaudio break;
168618786664Sclaudio case IEEE80211_REASON_MIC_FAILURE:
168718786664Sclaudio printf(", mic failure");
168818786664Sclaudio break;
168918786664Sclaudio default:
169018786664Sclaudio printf(", unknown reason %u", reason);
169118786664Sclaudio }
169218786664Sclaudio }
1693