xref: /openbsd/usr.sbin/tcpdump/print-802_11.c (revision 46e5e1a2)
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