xref: /openbsd/usr.sbin/tcpdump/print-802_11.c (revision 9533a5ea)
1*9533a5eaSstsp /*	$OpenBSD: print-802_11.c,v 1.34 2016/10/08 14:45:11 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);
1046f9acb7aSstsp int	 ieee80211_print_beacon(struct ieee80211_frame *, u_int);
1056f9acb7aSstsp int	 ieee80211_print_assocreq(struct ieee80211_frame *, u_int);
1066f9acb7aSstsp int	 ieee80211_print_elements(uint8_t *);
10712a08440Sreyk int	 ieee80211_frame(struct ieee80211_frame *, u_int);
10812a08440Sreyk int	 ieee80211_print(struct ieee80211_frame *, u_int);
10912a08440Sreyk u_int	 ieee80211_any2ieee(u_int, u_int);
11018786664Sclaudio void	 ieee80211_reason(u_int16_t);
11112a08440Sreyk 
11212a08440Sreyk #define TCARR(a)	TCHECK2(*a, sizeof(a))
11312a08440Sreyk 
114c79cf170Sreyk int ieee80211_encap = 0;
115c79cf170Sreyk 
11612a08440Sreyk int
11712a08440Sreyk ieee80211_hdr(struct ieee80211_frame *wh)
11812a08440Sreyk {
11912a08440Sreyk 	struct ieee80211_frame_addr4 *w4;
12012a08440Sreyk 
12112a08440Sreyk 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
12212a08440Sreyk 	case IEEE80211_FC1_DIR_NODS:
12312a08440Sreyk 		TCARR(wh->i_addr2);
12412a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr2));
12512a08440Sreyk 		TCARR(wh->i_addr1);
12612a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr1));
12712a08440Sreyk 		TCARR(wh->i_addr3);
12812a08440Sreyk 		printf(", bssid %s", etheraddr_string(wh->i_addr3));
12912a08440Sreyk 		break;
13012a08440Sreyk 	case IEEE80211_FC1_DIR_TODS:
13112a08440Sreyk 		TCARR(wh->i_addr2);
13212a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr2));
13312a08440Sreyk 		TCARR(wh->i_addr3);
13412a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr3));
13512a08440Sreyk 		TCARR(wh->i_addr1);
13612a08440Sreyk 		printf(", bssid %s, > DS", etheraddr_string(wh->i_addr1));
13712a08440Sreyk 		break;
13812a08440Sreyk 	case IEEE80211_FC1_DIR_FROMDS:
13912a08440Sreyk 		TCARR(wh->i_addr3);
14012a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr3));
14112a08440Sreyk 		TCARR(wh->i_addr1);
14212a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr1));
14312a08440Sreyk 		TCARR(wh->i_addr2);
14412a08440Sreyk 		printf(", bssid %s, DS >", etheraddr_string(wh->i_addr2));
14512a08440Sreyk 		break;
14612a08440Sreyk 	case IEEE80211_FC1_DIR_DSTODS:
14712a08440Sreyk 		w4 = (struct ieee80211_frame_addr4 *) wh;
14812a08440Sreyk 		TCARR(w4->i_addr4);
14912a08440Sreyk 		printf("%s", etheraddr_string(w4->i_addr4));
15012a08440Sreyk 		TCARR(w4->i_addr3);
15112a08440Sreyk 		printf(" > %s", etheraddr_string(w4->i_addr3));
15212a08440Sreyk 		TCARR(w4->i_addr2);
15312a08440Sreyk 		printf(", bssid %s", etheraddr_string(w4->i_addr2));
15412a08440Sreyk 		TCARR(w4->i_addr1);
15512a08440Sreyk 		printf(" > %s, DS > DS", etheraddr_string(w4->i_addr1));
15612a08440Sreyk 		break;
15712a08440Sreyk 	}
15812a08440Sreyk 	if (vflag) {
159cce1ba42Sclaudio 		u_int16_t seq;
16012a08440Sreyk 		TCARR(wh->i_seq);
161cce1ba42Sclaudio 		bcopy(wh->i_seq, &seq, sizeof(u_int16_t));
162cce1ba42Sclaudio 		printf(" (seq %u): ", letoh16(seq));
16312a08440Sreyk 	} else
16412a08440Sreyk 		printf(": ");
16512a08440Sreyk 
16612a08440Sreyk 	return (0);
16712a08440Sreyk 
16812a08440Sreyk  trunc:
16912a08440Sreyk 	/* Truncated elements in frame */
17012a08440Sreyk 	return (1);
17112a08440Sreyk }
17212a08440Sreyk 
173b72abdefSreyk int
174b72abdefSreyk ieee80211_data(struct ieee80211_frame *wh, u_int len)
175b72abdefSreyk {
176b72abdefSreyk 	u_int8_t *t = (u_int8_t *)wh;
177b72abdefSreyk 	u_int datalen;
17893cbfc44Sstsp 	int data = !(wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_NODATA);
1799d5679eaSstsp 	int hasqos = ((wh->i_fc[0] &
1809d5679eaSstsp 	    (IEEE80211_FC0_TYPE_MASK | IEEE80211_FC0_SUBTYPE_QOS)) ==
1819d5679eaSstsp 	    (IEEE80211_FC0_TYPE_DATA | IEEE80211_FC0_SUBTYPE_QOS));
182ab7e388eSclaudio 	u_char *esrc = NULL, *edst = NULL;
183b72abdefSreyk 
1849d5679eaSstsp 	if (hasqos) {
1859d5679eaSstsp 		struct ieee80211_qosframe *wq;
1869d5679eaSstsp 
1879d5679eaSstsp 		wq = (struct ieee80211_qosframe *) wh;
1889d5679eaSstsp 		TCHECK(*wq);
1899d5679eaSstsp 		t += sizeof(*wq);
1909d5679eaSstsp 		datalen = len - sizeof(*wq);
1919d5679eaSstsp 	} else {
192d49cb46eScanacar 		TCHECK(*wh);
1939d5679eaSstsp 		t += sizeof(*wh);
1949d5679eaSstsp 		datalen = len - sizeof(*wh);
1959d5679eaSstsp 	}
196b72abdefSreyk 
197b72abdefSreyk 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
198b72abdefSreyk 	case IEEE80211_FC1_DIR_TODS:
199ab7e388eSclaudio 		esrc = wh->i_addr2;
200ab7e388eSclaudio 		edst = wh->i_addr3;
201b72abdefSreyk 		break;
202b72abdefSreyk 	case IEEE80211_FC1_DIR_FROMDS:
203ab7e388eSclaudio 		esrc = wh->i_addr3;
204ab7e388eSclaudio 		edst = wh->i_addr1;
205b72abdefSreyk 		break;
206b72abdefSreyk 	case IEEE80211_FC1_DIR_NODS:
207ab7e388eSclaudio 		esrc = wh->i_addr2;
208ab7e388eSclaudio 		edst = wh->i_addr1;
209d49cb46eScanacar 		break;
210b72abdefSreyk 	case IEEE80211_FC1_DIR_DSTODS:
2119d5679eaSstsp 		if (hasqos) {
2129d5679eaSstsp 			struct ieee80211_qosframe_addr4 *w4;
2139d5679eaSstsp 
2149d5679eaSstsp 			w4 = (struct ieee80211_qosframe_addr4 *) wh;
2159d5679eaSstsp 			TCHECK(*w4);
2169d5679eaSstsp 			t = (u_int8_t *) (w4 + 1);
2179d5679eaSstsp 			datalen = len - sizeof(*w4);
2189d5679eaSstsp 			esrc = w4->i_addr4;
2199d5679eaSstsp 			edst = w4->i_addr3;
2209d5679eaSstsp 		} else {
2219d5679eaSstsp 			struct ieee80211_frame_addr4 *w4;
2229d5679eaSstsp 
223d49cb46eScanacar 			w4 = (struct ieee80211_frame_addr4 *) wh;
224d49cb46eScanacar 			TCHECK(*w4);
225d49cb46eScanacar 			t = (u_int8_t *) (w4 + 1);
226d49cb46eScanacar 			datalen = len - sizeof(*w4);
227ab7e388eSclaudio 			esrc = w4->i_addr4;
228ab7e388eSclaudio 			edst = w4->i_addr3;
2299d5679eaSstsp 		}
230b72abdefSreyk 		break;
231b72abdefSreyk 	}
232b72abdefSreyk 
233ab7e388eSclaudio 	if (data && esrc)
234ab7e388eSclaudio 		llc_print(t, datalen, datalen, esrc, edst);
235ab7e388eSclaudio 	else if (eflag && esrc)
236ab7e388eSclaudio 		printf("%s > %s",
237ab7e388eSclaudio 		    etheraddr_string(esrc), etheraddr_string(edst));
238ab7e388eSclaudio 
239b72abdefSreyk 	return (0);
240b72abdefSreyk 
241b72abdefSreyk  trunc:
242b72abdefSreyk 	/* Truncated elements in frame */
243b72abdefSreyk 	return (1);
244b72abdefSreyk }
245b72abdefSreyk 
24612a08440Sreyk /* Caller checks len */
24712a08440Sreyk void
24812a08440Sreyk ieee80211_print_element(u_int8_t *data, u_int len)
24912a08440Sreyk {
25012a08440Sreyk 	u_int8_t *p;
2519cbdb746Sderaadt 	int i;
25212a08440Sreyk 
25312a08440Sreyk 	printf(" 0x");
2549cbdb746Sderaadt 	for (i = 0, p = data; i < len; i++, p++)
25512a08440Sreyk 		printf("%02x", *p);
25612a08440Sreyk }
25712a08440Sreyk 
25812a08440Sreyk /* Caller checks len */
25912a08440Sreyk void
26012a08440Sreyk ieee80211_print_essid(u_int8_t *essid, u_int len)
26112a08440Sreyk {
26212a08440Sreyk 	u_int8_t *p;
2639cbdb746Sderaadt 	int i;
26412a08440Sreyk 
26512a08440Sreyk 	if (len > IEEE80211_NWID_LEN)
26612a08440Sreyk 		len = IEEE80211_NWID_LEN;
26712a08440Sreyk 
26812a08440Sreyk 	/* determine printable or not */
26912a08440Sreyk 	for (i = 0, p = essid; i < len; i++, p++) {
27012a08440Sreyk 		if (*p < ' ' || *p > 0x7e)
27112a08440Sreyk 			break;
27212a08440Sreyk 	}
27312a08440Sreyk 	if (i == len) {
27412a08440Sreyk 		printf(" (");
27512a08440Sreyk 		for (i = 0, p = essid; i < len; i++, p++)
27612a08440Sreyk 			putchar(*p);
27712a08440Sreyk 		putchar(')');
2789cbdb746Sderaadt 	} else
27912a08440Sreyk 		ieee80211_print_element(essid, len);
28012a08440Sreyk }
28112a08440Sreyk 
2821e3bf20aSstsp /* Caller checks len */
2831e3bf20aSstsp void
28477734011Sstsp ieee80211_print_country(u_int8_t *data, u_int len)
28577734011Sstsp {
28677734011Sstsp 	u_int8_t first_chan, nchan, maxpower;
28777734011Sstsp 
28877734011Sstsp 	if (len < 6)
28977734011Sstsp 		return;
29077734011Sstsp 
29177734011Sstsp 	/* country string */
29277734011Sstsp 	printf((isprint(data[0]) ? " '%c" : " '\\%03o"), data[0]);
29377734011Sstsp 	printf((isprint(data[1]) ? "%c" : "\\%03o"), data[1]);
29477734011Sstsp 	printf((isprint(data[2]) ? "%c'" : "\\%03o'"), data[2]);
29577734011Sstsp 
29677734011Sstsp 	len -= 3;
29777734011Sstsp 	data += 3;
29877734011Sstsp 
29977734011Sstsp 	/* channels and corresponding TX power limits */
30075f33b99Sstsp 	while (len >= 3) {
30177734011Sstsp 		/* no pretty-printing for nonsensical zero values,
30277734011Sstsp 		 * nor for operating extension IDs (values >= 201) */
30377734011Sstsp 		if (data[0] == 0 || data[1] == 0 ||
30477734011Sstsp 		    data[0] >= 201 || data[1] >= 201) {
30577734011Sstsp 			printf(", %d %d %d", data[0], data[1], data[2]);
30675f33b99Sstsp 			len -= 3;
30775f33b99Sstsp 			data += 3;
30877734011Sstsp 			continue;
30977734011Sstsp 		}
31077734011Sstsp 
31177734011Sstsp 		first_chan = data[0];
31277734011Sstsp 		nchan = data[1];
31377734011Sstsp 		maxpower = data[2];
31477734011Sstsp 
31577734011Sstsp 		printf(", channel%s %d", nchan == 1 ? "" : "s", first_chan);
31677734011Sstsp 		if (nchan > 1)
31777734011Sstsp 			printf("-%d", first_chan + nchan - 1);
31877734011Sstsp 		printf(" limit %ddB", maxpower);
31977734011Sstsp 
32077734011Sstsp 		len -= 3;
32177734011Sstsp 		data += 3;
32277734011Sstsp 	}
32377734011Sstsp }
32477734011Sstsp 
32577734011Sstsp /* Caller checks len */
32677734011Sstsp void
3271e3bf20aSstsp ieee80211_print_htcaps(u_int8_t *data, u_int len)
3281e3bf20aSstsp {
329537e7cd0Sstsp 	uint16_t htcaps, rxrate;
3301e3bf20aSstsp 	int smps, rxstbc;
331537e7cd0Sstsp 	uint8_t ampdu, txmcs;
332537e7cd0Sstsp 	int i;
333537e7cd0Sstsp 	uint8_t *rxmcs;
3341e3bf20aSstsp 
3351e3bf20aSstsp 	if (len < 2) {
3361e3bf20aSstsp 		ieee80211_print_element(data, len);
3371e3bf20aSstsp 		return;
3381e3bf20aSstsp 	}
3391e3bf20aSstsp 
3401e3bf20aSstsp 	htcaps = (data[0]) | (data[1] << 8);
3411e3bf20aSstsp 	printf("=<");
3421e3bf20aSstsp 
3431e3bf20aSstsp 	/* channel width */
3441e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_CBW20_40)
3451e3bf20aSstsp 		printf("20/40MHz");
3461e3bf20aSstsp 	else
3471e3bf20aSstsp 		printf("20MHz");
3481e3bf20aSstsp 
3491e3bf20aSstsp 	/* LDPC coding */
3501e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_LDPC)
3511e3bf20aSstsp 		printf(",LDPC");
3521e3bf20aSstsp 
3531e3bf20aSstsp 	/* spatial multiplexing power save mode */
3541e3bf20aSstsp 	smps = (htcaps & IEEE80211_HTCAP_SMPS_MASK)
3551e3bf20aSstsp 	    >> IEEE80211_HTCAP_SMPS_SHIFT;
3561e3bf20aSstsp 	if (smps == 0)
3571e3bf20aSstsp 		printf(",SMPS static");
3581e3bf20aSstsp 	else if (smps == 1)
3591e3bf20aSstsp 		printf(",SMPS dynamic");
3601e3bf20aSstsp 
3611e3bf20aSstsp 	/* 11n greenfield mode */
3621e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_GF)
3631e3bf20aSstsp 		printf(",greenfield");
3641e3bf20aSstsp 
3651e3bf20aSstsp 	/* short guard interval */
3661e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_SGI20)
3671e3bf20aSstsp 		printf(",SGI@20MHz");
3681e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_SGI40)
3691e3bf20aSstsp 		printf(",SGI@40MHz");
3701e3bf20aSstsp 
3711e3bf20aSstsp 	/* space-time block coding */
3721e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_TXSTBC)
3731e3bf20aSstsp 		printf(",TXSTBC");
3741e3bf20aSstsp 	rxstbc = (htcaps & IEEE80211_HTCAP_RXSTBC_MASK)
3751e3bf20aSstsp 	    >> IEEE80211_HTCAP_RXSTBC_SHIFT;
3761e3bf20aSstsp 	if (rxstbc > 0 && rxstbc < 4)
3771e3bf20aSstsp 		printf(",RXSTBC %d stream", rxstbc);
3781e3bf20aSstsp 
3791e3bf20aSstsp 	/* delayed block-ack */
3801e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_DELAYEDBA)
3811e3bf20aSstsp 		printf(",delayed BA");
3821e3bf20aSstsp 
3831e3bf20aSstsp 	/* max A-MSDU length */
3841e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_AMSDU7935)
3851e3bf20aSstsp 		printf(",A-MSDU 7935");
3861e3bf20aSstsp 	else
3871e3bf20aSstsp 		printf(",A-MSDU 3839");
3881e3bf20aSstsp 
3891e3bf20aSstsp 	/* DSSS/CCK in 40MHz mode */
3901e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_DSSSCCK40)
3911e3bf20aSstsp 		printf(",DSSS/CCK@40MHz");
3921e3bf20aSstsp 
3931e3bf20aSstsp 	/* 40MHz intolerant */
3941e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_40INTOLERANT)
3951e3bf20aSstsp 		printf(",40MHz intolerant");
3961e3bf20aSstsp 
3971e3bf20aSstsp 	/* L-SIG TXOP protection */
3981e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_LSIGTXOPPROT)
3991e3bf20aSstsp 		printf(",L-SIG TXOP prot");
4001e3bf20aSstsp 
401537e7cd0Sstsp 	if (len < 3) {
402537e7cd0Sstsp 		printf(">");
403537e7cd0Sstsp 		return;
404537e7cd0Sstsp 	}
405537e7cd0Sstsp 
406537e7cd0Sstsp 	/* A-MPDU parameters. */
407537e7cd0Sstsp 	ampdu = data[2];
408537e7cd0Sstsp 
409537e7cd0Sstsp 	/* A-MPDU length exponent */
410537e7cd0Sstsp 	if ((ampdu & IEEE80211_AMPDU_PARAM_LE) >= 0 &&
411537e7cd0Sstsp 	    (ampdu & IEEE80211_AMPDU_PARAM_LE) <= 3)
412537e7cd0Sstsp 		printf(",A-MPDU max %d",
4130b19ae84Sstsp 		    (1 << (13 + (ampdu & IEEE80211_AMPDU_PARAM_LE))) - 1);
414537e7cd0Sstsp 
415537e7cd0Sstsp 	/* A-MPDU start spacing */
416537e7cd0Sstsp 	if (ampdu & IEEE80211_AMPDU_PARAM_SS) {
417537e7cd0Sstsp 		float ss;
418537e7cd0Sstsp 
419537e7cd0Sstsp 		switch ((ampdu & IEEE80211_AMPDU_PARAM_SS) >> 2) {
420537e7cd0Sstsp 		case 1:
421537e7cd0Sstsp 			ss = 0.25;
422537e7cd0Sstsp 			break;
423537e7cd0Sstsp 		case 2:
424537e7cd0Sstsp 			ss = 0.5;
425537e7cd0Sstsp 			break;
426537e7cd0Sstsp 		case 3:
427537e7cd0Sstsp 			ss = 1;
428537e7cd0Sstsp 			break;
429537e7cd0Sstsp 		case 4:
430537e7cd0Sstsp 			ss = 2;
431537e7cd0Sstsp 			break;
432537e7cd0Sstsp 		case 5:
433537e7cd0Sstsp 			ss = 4;
434537e7cd0Sstsp 			break;
435537e7cd0Sstsp 		case 6:
436537e7cd0Sstsp 			ss = 8;
437537e7cd0Sstsp 			break;
438537e7cd0Sstsp 		case 7:
439537e7cd0Sstsp 			ss = 16;
440537e7cd0Sstsp 			break;
441537e7cd0Sstsp 		default:
442537e7cd0Sstsp 			ss = 0;
443537e7cd0Sstsp 			break;
444537e7cd0Sstsp 		}
445537e7cd0Sstsp 		if (ss != 0)
446537e7cd0Sstsp 			printf(",A-MPDU spacing %.2fus", ss);
447537e7cd0Sstsp 	}
448537e7cd0Sstsp 
449537e7cd0Sstsp 	if (len < 21) {
450537e7cd0Sstsp 		printf(">");
451537e7cd0Sstsp 		return;
452537e7cd0Sstsp 	}
453537e7cd0Sstsp 
454537e7cd0Sstsp 	/* Supported MCS set. */
455537e7cd0Sstsp 	printf(",RxMCS 0x");
456537e7cd0Sstsp 	rxmcs = &data[3];
457537e7cd0Sstsp 	for (i = 0; i < 10; i++)
458537e7cd0Sstsp 		printf("%02x", rxmcs[i]);
459537e7cd0Sstsp 
460537e7cd0Sstsp 	/* Max MCS Rx rate (a value of 0 means "not specified"). */
461537e7cd0Sstsp 	rxrate = ((data[13] | (data[14]) << 8) & IEEE80211_MCS_RX_RATE_HIGH);
462537e7cd0Sstsp 	if (rxrate)
463537e7cd0Sstsp 		printf(",RxMaxrate %huMb/s", rxrate);
464537e7cd0Sstsp 
465537e7cd0Sstsp 	/* Tx MCS Set */
466537e7cd0Sstsp 	txmcs = data[15];
467537e7cd0Sstsp 	if (txmcs & IEEE80211_TX_MCS_SET_DEFINED) {
468537e7cd0Sstsp 		if (txmcs & IEEE80211_TX_RX_MCS_NOT_EQUAL) {
469537e7cd0Sstsp 			/* Number of spatial Tx streams. */
470537e7cd0Sstsp 			printf(",%d Tx streams",
471537e7cd0Sstsp 			     1 + ((txmcs & IEEE80211_TX_SPATIAL_STREAMS) >> 2));
472537e7cd0Sstsp 			/* Transmit unequal modulation supported. */
473537e7cd0Sstsp 			if (txmcs & IEEE80211_TX_UNEQUAL_MODULATION)
474537e7cd0Sstsp 				printf(",UEQM");
475537e7cd0Sstsp 		}
476537e7cd0Sstsp 	}
477537e7cd0Sstsp 
4781e3bf20aSstsp 	printf(">");
4791e3bf20aSstsp }
4801e3bf20aSstsp 
48136fa064cSstsp /* Caller checks len */
48236fa064cSstsp void
48336fa064cSstsp ieee80211_print_htop(u_int8_t *data, u_int len)
48436fa064cSstsp {
48536fa064cSstsp 	u_int8_t primary_chan;
48636fa064cSstsp 	u_int8_t htopinfo[5];
48736fa064cSstsp 	u_int8_t basic_mcs[16];
48836fa064cSstsp 	int sco, prot, i;
48936fa064cSstsp 
49036fa064cSstsp 	if (len < sizeof(primary_chan) + sizeof(htopinfo) + sizeof(basic_mcs)) {
49136fa064cSstsp 		ieee80211_print_element(data, len);
49236fa064cSstsp 		return;
49336fa064cSstsp 	}
49436fa064cSstsp 
49536fa064cSstsp 	htopinfo[0] = data[1];
49636fa064cSstsp 
49736fa064cSstsp 	printf("=<");
49836fa064cSstsp 
49936fa064cSstsp 	/* primary channel and secondary channel offset */
50036fa064cSstsp 	primary_chan = data[0];
50136fa064cSstsp 	sco = ((htopinfo[0] & IEEE80211_HTOP0_SCO_MASK)
50236fa064cSstsp 	    >> IEEE80211_HTOP0_SCO_SHIFT);
503b144e175Sstsp 	if (sco == 0) /* no secondary channel */
50436fa064cSstsp 		printf("20MHz chan %d", primary_chan);
505b144e175Sstsp 	else if (sco == 1) { /* secondary channel above */
506b144e175Sstsp 		if (primary_chan >= 1 && primary_chan <= 13) /* 2GHz */
507b144e175Sstsp 			printf("40MHz chan %d:%d", primary_chan,
508b144e175Sstsp 			    primary_chan + 1);
509b144e175Sstsp 		else if (primary_chan >= 34) /* 5GHz */
510b144e175Sstsp 			printf("40MHz chan %d:%d", primary_chan,
511b144e175Sstsp 			    primary_chan + 4);
51236fa064cSstsp 		else
513b144e175Sstsp 			printf("[invalid 40MHz chan %d+]", primary_chan);
514b144e175Sstsp 	} else if (sco == 3) { /* secondary channel below */
515b144e175Sstsp 		if (primary_chan >= 2 && primary_chan <= 14) /* 2GHz */
516b144e175Sstsp 			printf("40MHz chan %d:%d", primary_chan,
517b144e175Sstsp 			    primary_chan - 1);
518b144e175Sstsp 		else if (primary_chan >= 40) /* 5GHz */
519b144e175Sstsp 			printf("40MHz chan %d:%d", primary_chan,
520b144e175Sstsp 			    primary_chan - 4);
521b144e175Sstsp 		else
522b144e175Sstsp 			printf("[invalid 40MHz chan %d-]", primary_chan);
523b144e175Sstsp 	} else
52436fa064cSstsp 		printf("chan %d [invalid secondary channel offset %d]",
52536fa064cSstsp 		    primary_chan, sco);
52636fa064cSstsp 
52736fa064cSstsp 	/* STA channel width */
52836fa064cSstsp 	if ((htopinfo[0] & IEEE80211_HTOP0_CHW) == 0)
52936fa064cSstsp 		printf(",STA chanw 20MHz");
53036fa064cSstsp 
53136fa064cSstsp 	/* reduced interframe space (RIFS) permitted */
53236fa064cSstsp 	if (htopinfo[0] & IEEE80211_HTOP0_RIFS)
53336fa064cSstsp 		printf(",RIFS");
53436fa064cSstsp 
53536fa064cSstsp 	htopinfo[1] = data[2];
53636fa064cSstsp 
53736fa064cSstsp 	/* protection requirements for HT transmissions */
53836fa064cSstsp 	prot = ((htopinfo[1] & IEEE80211_HTOP1_PROT_MASK)
53936fa064cSstsp 	    >> IEEE80211_HTOP1_PROT_SHIFT);
54036fa064cSstsp 	if (prot == 1)
54136fa064cSstsp 		printf(",protect non-member");
54236fa064cSstsp 	else if (prot == 2)
54336fa064cSstsp 		printf(",protect 20MHz");
54436fa064cSstsp 	else if (prot == 3)
54536fa064cSstsp 		printf(",protect non-HT");
54636fa064cSstsp 
54736fa064cSstsp 	/* non-greenfield STA present */
54836fa064cSstsp 	if (htopinfo[1] & IEEE80211_HTOP1_NONGF_STA)
54936fa064cSstsp 		printf(",non-greenfield STA");
55036fa064cSstsp 
55136fa064cSstsp 	/* non-HT STA present */
55236fa064cSstsp 	if (htopinfo[1] & IEEE80211_HTOP1_OBSS_NONHT_STA)
55336fa064cSstsp 		printf(",non-HT STA");
55436fa064cSstsp 
55536fa064cSstsp 	htopinfo[3] = data[4];
55636fa064cSstsp 
55736fa064cSstsp 	/* dual-beacon */
55836fa064cSstsp 	if (htopinfo[3] & IEEE80211_HTOP2_DUALBEACON)
55936fa064cSstsp 		printf(",dualbeacon");
56036fa064cSstsp 
56136fa064cSstsp 	/* dual CTS protection */
56236fa064cSstsp 	if (htopinfo[3] & IEEE80211_HTOP2_DUALCTSPROT)
56336fa064cSstsp 		printf(",dualctsprot");
56436fa064cSstsp 
56536fa064cSstsp 	htopinfo[4] = data[5];
56636fa064cSstsp 
56736fa064cSstsp 	/* space-time block coding (STBC) beacon */
56858089030Sstsp 	if ((htopinfo[4] << 8) & IEEE80211_HTOP2_STBCBEACON)
56936fa064cSstsp 		printf(",STBC beacon");
57036fa064cSstsp 
57136fa064cSstsp 	/* L-SIG (non-HT signal field) TX opportunity (TXOP) protection */
57236fa064cSstsp 	if ((htopinfo[4] << 8) & IEEE80211_HTOP2_LSIGTXOP)
57336fa064cSstsp 		printf(",lsigtxprot");
57436fa064cSstsp 
57536fa064cSstsp 	/* phased-coexistence operation (PCO) active */
57636fa064cSstsp 	if ((htopinfo[4] << 8) & IEEE80211_HTOP2_PCOACTIVE) {
57736fa064cSstsp 		/* PCO phase */
57836fa064cSstsp 		if ((htopinfo[4] << 8) & IEEE80211_HTOP2_PCOPHASE40)
57936fa064cSstsp 			printf(",pco40MHz");
58036fa064cSstsp 		else
58136fa064cSstsp 			printf(",pco20MHz");
58236fa064cSstsp 	}
58336fa064cSstsp 
58436fa064cSstsp 	/* basic MCS set */
58536fa064cSstsp 	memcpy(basic_mcs, &data[6], sizeof(basic_mcs));
58636fa064cSstsp 	printf(",basic MCS set 0x");
58736fa064cSstsp 	for (i = 0; i < sizeof(basic_mcs) / sizeof(basic_mcs[0]); i++)
58836fa064cSstsp 			printf("%x", basic_mcs[i]);
58936fa064cSstsp 
59036fa064cSstsp 	printf(">");
59136fa064cSstsp }
59236fa064cSstsp 
59312a08440Sreyk int
5946f9acb7aSstsp ieee80211_print_beacon(struct ieee80211_frame *wh, u_int len)
59512a08440Sreyk {
5966f9acb7aSstsp 	uint64_t tstamp;
5976f9acb7aSstsp 	uint16_t bintval, capinfo;
5986f9acb7aSstsp 	uint8_t *frm;
59912a08440Sreyk 
6006f9acb7aSstsp 	if (len < sizeof(tstamp) + sizeof(bintval) + sizeof(capinfo))
6016f9acb7aSstsp 		return 1; /* truncated */
6026f9acb7aSstsp 
60312a08440Sreyk 	frm = (u_int8_t *)&wh[1];
60412a08440Sreyk 
605cce1ba42Sclaudio 	bcopy(frm, &tstamp, sizeof(u_int64_t));
60612a08440Sreyk 	frm += 8;
60712a08440Sreyk 	if (vflag > 1)
608cce1ba42Sclaudio 		printf(", timestamp %llu", letoh64(tstamp));
60912a08440Sreyk 
610cce1ba42Sclaudio 	bcopy(frm, &bintval, sizeof(u_int16_t));
61112a08440Sreyk 	frm += 2;
61212a08440Sreyk 	if (vflag > 1)
613cce1ba42Sclaudio 		printf(", interval %u", letoh16(bintval));
61412a08440Sreyk 
615cce1ba42Sclaudio 	bcopy(frm, &capinfo, sizeof(u_int16_t));
61612a08440Sreyk 	frm += 2;
61712a08440Sreyk 	if (vflag)
6186f9acb7aSstsp 		printb(", caps", letoh16(capinfo), IEEE80211_CAPINFO_BITS);
6196f9acb7aSstsp 
6206f9acb7aSstsp 	return ieee80211_print_elements(frm);
6216f9acb7aSstsp }
6226f9acb7aSstsp 
6236f9acb7aSstsp int
6246f9acb7aSstsp ieee80211_print_assocreq(struct ieee80211_frame *wh, u_int len)
6256f9acb7aSstsp {
6266f9acb7aSstsp 	uint8_t subtype;
6276f9acb7aSstsp 	uint16_t capinfo, lintval;
6286f9acb7aSstsp 	uint8_t *frm;
6296f9acb7aSstsp 
6306f9acb7aSstsp 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
6316f9acb7aSstsp 
6326f9acb7aSstsp 	if (len < sizeof(capinfo) + sizeof(lintval) +
6336f9acb7aSstsp 	    (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ ?
6346f9acb7aSstsp 	    IEEE80211_ADDR_LEN : 0))
6356f9acb7aSstsp 		return 1; /* truncated */
6366f9acb7aSstsp 
6376f9acb7aSstsp 	frm = (u_int8_t *)&wh[1];
6386f9acb7aSstsp 
6396f9acb7aSstsp 	bcopy(frm, &capinfo, sizeof(u_int16_t));
6406f9acb7aSstsp 	frm += 2;
6416f9acb7aSstsp 	if (vflag)
6426f9acb7aSstsp 		printb(", caps", letoh16(capinfo), IEEE80211_CAPINFO_BITS);
6436f9acb7aSstsp 
6446f9acb7aSstsp 	bcopy(frm, &lintval, sizeof(u_int16_t));
6456f9acb7aSstsp 	frm += 2;
6466f9acb7aSstsp 	if (vflag > 1)
6476f9acb7aSstsp 		printf(", listen interval %u", letoh16(lintval));
6486f9acb7aSstsp 
6496f9acb7aSstsp 	if (subtype == IEEE80211_FC0_SUBTYPE_REASSOC_REQ) {
6506f9acb7aSstsp 		if (vflag)
6516f9acb7aSstsp 			printf(", AP %s", etheraddr_string(frm));
6526f9acb7aSstsp 		frm += IEEE80211_ADDR_LEN;
6536f9acb7aSstsp 	}
6546f9acb7aSstsp 
6556f9acb7aSstsp 	return ieee80211_print_elements(frm);
6566f9acb7aSstsp }
6576f9acb7aSstsp 
6586f9acb7aSstsp int
6596f9acb7aSstsp ieee80211_print_elements(uint8_t *frm)
6606f9acb7aSstsp {
6616f9acb7aSstsp 	int i;
66212a08440Sreyk 
66312a08440Sreyk 	while (TTEST2(*frm, 2)) {
66412a08440Sreyk 		u_int len = frm[1];
66512a08440Sreyk 		u_int8_t *data = frm + 2;
66612a08440Sreyk 
66712a08440Sreyk 		if (!TTEST2(*data, len))
66812a08440Sreyk 			break;
66912a08440Sreyk 
6706f9acb7aSstsp #define ELEM_CHECK(l)	if (len != l) goto trunc
67112a08440Sreyk 
67212a08440Sreyk 		switch (*frm) {
67312a08440Sreyk 		case IEEE80211_ELEMID_SSID:
67412a08440Sreyk 			printf(", ssid");
67512a08440Sreyk 			ieee80211_print_essid(data, len);
67612a08440Sreyk 			break;
67712a08440Sreyk 		case IEEE80211_ELEMID_RATES:
67812a08440Sreyk 			printf(", rates");
67912a08440Sreyk 			if (!vflag)
68012a08440Sreyk 				break;
68112a08440Sreyk 			for (i = len; i > 0; i--, data++)
68212a08440Sreyk 				printf(" %uM",
68312a08440Sreyk 				    (data[0] & IEEE80211_RATE_VAL) / 2);
68412a08440Sreyk 			break;
68512a08440Sreyk 		case IEEE80211_ELEMID_FHPARMS:
68612a08440Sreyk 			ELEM_CHECK(5);
68712a08440Sreyk 			printf(", fh (dwell %u, chan %u, index %u)",
68812a08440Sreyk 			    (data[1] << 8) | data[0],
68912a08440Sreyk 			    (data[2] - 1) * 80 + data[3],	/* FH_CHAN */
69012a08440Sreyk 			    data[4]);
69112a08440Sreyk 			break;
69212a08440Sreyk 		case IEEE80211_ELEMID_DSPARMS:
69312a08440Sreyk 			ELEM_CHECK(1);
69412a08440Sreyk 			printf(", ds");
69512a08440Sreyk 			if (vflag)
69612a08440Sreyk 				printf(" (chan %u)", data[0]);
69712a08440Sreyk 			break;
69812a08440Sreyk 		case IEEE80211_ELEMID_CFPARMS:
69912a08440Sreyk 			printf(", cf");
70012a08440Sreyk 			if (vflag)
70112a08440Sreyk 				ieee80211_print_element(data, len);
70212a08440Sreyk 			break;
70312a08440Sreyk 		case IEEE80211_ELEMID_TIM:
70412a08440Sreyk 			printf(", tim");
70512a08440Sreyk 			if (vflag)
70612a08440Sreyk 				ieee80211_print_element(data, len);
70712a08440Sreyk 			break;
70812a08440Sreyk 		case IEEE80211_ELEMID_IBSSPARMS:
70912a08440Sreyk 			printf(", ibss");
71012a08440Sreyk 			if (vflag)
71112a08440Sreyk 				ieee80211_print_element(data, len);
71212a08440Sreyk 			break;
71312a08440Sreyk 		case IEEE80211_ELEMID_COUNTRY:
71412a08440Sreyk 			printf(", country");
7157ccd2116Sstsp 			if (vflag)
71677734011Sstsp 				ieee80211_print_country(data, len);
71712a08440Sreyk 			break;
71812a08440Sreyk 		case IEEE80211_ELEMID_CHALLENGE:
71912a08440Sreyk 			printf(", challenge");
72012a08440Sreyk 			if (vflag)
72112a08440Sreyk 				ieee80211_print_element(data, len);
72212a08440Sreyk 			break;
723738acb58Ssthen 		case IEEE80211_ELEMID_CSA:
724958b7e45Ssthen 			ELEM_CHECK(3);
725738acb58Ssthen 			printf(", csa (chan %u count %u%s)", data[1], data[2],
726738acb58Ssthen 			    (data[0] == 1) ? " noTX" : "");
727738acb58Ssthen 			break;
72812a08440Sreyk 		case IEEE80211_ELEMID_ERP:
72912a08440Sreyk 			printf(", erp");
73012a08440Sreyk 			if (vflag)
73112a08440Sreyk 				ieee80211_print_element(data, len);
73212a08440Sreyk 			break;
73312a08440Sreyk 		case IEEE80211_ELEMID_RSN:
73412a08440Sreyk 			printf(", rsn");
73512a08440Sreyk 			if (vflag)
73612a08440Sreyk 				ieee80211_print_element(data, len);
73712a08440Sreyk 			break;
73812a08440Sreyk 		case IEEE80211_ELEMID_XRATES:
73912a08440Sreyk 			printf(", xrates");
74012a08440Sreyk 			if (!vflag)
74112a08440Sreyk 				break;
74212a08440Sreyk 			for (i = len; i > 0; i--, data++)
74312a08440Sreyk 				printf(" %uM",
74412a08440Sreyk 				    (data[0] & IEEE80211_RATE_VAL) / 2);
74512a08440Sreyk 			break;
7468138faddSstsp 		case IEEE80211_ELEMID_TPC_REPORT:
7478138faddSstsp 			printf(", tpcreport");
74812a08440Sreyk 			if (vflag)
74912a08440Sreyk 				ieee80211_print_element(data, len);
75012a08440Sreyk 			break;
7518138faddSstsp 		case IEEE80211_ELEMID_TPC_REQUEST:
7528138faddSstsp 			printf(", tpcrequest");
75312a08440Sreyk 			if (vflag)
75412a08440Sreyk 				ieee80211_print_element(data, len);
75512a08440Sreyk 			break;
7561e3bf20aSstsp 		case IEEE80211_ELEMID_HTCAPS:
7571e3bf20aSstsp 			printf(", htcaps");
7581e3bf20aSstsp 			if (vflag)
7591e3bf20aSstsp 				ieee80211_print_htcaps(data, len);
7601e3bf20aSstsp 			break;
76136fa064cSstsp 		case IEEE80211_ELEMID_HTOP:
76236fa064cSstsp 			printf(", htop");
76336fa064cSstsp 			if (vflag)
76436fa064cSstsp 				ieee80211_print_htop(data, len);
76536fa064cSstsp 			break;
76677734011Sstsp 		case IEEE80211_ELEMID_POWER_CONSTRAINT:
76777734011Sstsp 			ELEM_CHECK(1);
76877734011Sstsp 			printf(", power constraint %udB", data[0]);
76977734011Sstsp 			break;
7708f0a8537Sstsp 		case IEEE80211_ELEMID_QBSS_LOAD:
7718f0a8537Sstsp 			ELEM_CHECK(5);
7728f0a8537Sstsp 			printf(", %u stations, %d%% utilization, "
7738f0a8537Sstsp 			    "admission capacity %uus/s",
7748f0a8537Sstsp 			    (data[0] | data[1] << 8),
7758f0a8537Sstsp 			    (data[2] * 100) / 255,
7768f0a8537Sstsp 			    (data[3] | data[4] << 8) / 32);
7778f0a8537Sstsp 			break;
77812a08440Sreyk 		case IEEE80211_ELEMID_VENDOR:
77912a08440Sreyk 			printf(", vendor");
78012a08440Sreyk 			if (vflag)
78112a08440Sreyk 				ieee80211_print_element(data, len);
78212a08440Sreyk 			break;
78312a08440Sreyk 		default:
78412a08440Sreyk 			printf(", %u:%u", (u_int) *frm, len);
78512a08440Sreyk 			if (vflag)
78612a08440Sreyk 				ieee80211_print_element(data, len);
78712a08440Sreyk 			break;
78812a08440Sreyk 		}
78912a08440Sreyk 		frm += len + 2;
79012a08440Sreyk 
79112a08440Sreyk 		if (frm >= snapend)
79212a08440Sreyk 			break;
79312a08440Sreyk 	}
79412a08440Sreyk 
79512a08440Sreyk #undef ELEM_CHECK
79612a08440Sreyk 
79712a08440Sreyk 	return (0);
79812a08440Sreyk 
79912a08440Sreyk  trunc:
80012a08440Sreyk 	/* Truncated elements in frame */
80112a08440Sreyk 	return (1);
80212a08440Sreyk }
80312a08440Sreyk 
80412a08440Sreyk int
80512a08440Sreyk ieee80211_frame(struct ieee80211_frame *wh, u_int len)
80612a08440Sreyk {
80712a08440Sreyk 	u_int8_t subtype, type, *frm;
80812a08440Sreyk 
80912a08440Sreyk 	TCARR(wh->i_fc);
81012a08440Sreyk 
81112a08440Sreyk 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
81212a08440Sreyk 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
81312a08440Sreyk 
81412a08440Sreyk 	frm = (u_int8_t *)&wh[1];
81512a08440Sreyk 
816ab7e388eSclaudio 	if (vflag)
817ab7e388eSclaudio 		printb(" flags", wh->i_fc[1], IEEE80211_FC1_BITS);
818ab7e388eSclaudio 
81912a08440Sreyk 	switch (type) {
82012a08440Sreyk 	case IEEE80211_FC0_TYPE_DATA:
821ab7e388eSclaudio 		printf(": %s: ", ieee80211_data_subtype_name[
822ab7e388eSclaudio 		    subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
823b72abdefSreyk 		ieee80211_data(wh, len);
82412a08440Sreyk 		break;
82512a08440Sreyk 	case IEEE80211_FC0_TYPE_MGT:
82612a08440Sreyk 		printf(": %s", ieee80211_mgt_subtype_name[
82712a08440Sreyk 		    subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
82812a08440Sreyk 		switch (subtype) {
82912a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_BEACON:
83012a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
8316f9acb7aSstsp 			if (ieee80211_print_beacon(wh, len) != 0)
8326f9acb7aSstsp 				goto trunc;
8336f9acb7aSstsp 			break;
8346f9acb7aSstsp 		case IEEE80211_FC0_SUBTYPE_ASSOC_REQ:
8356f9acb7aSstsp 		case IEEE80211_FC0_SUBTYPE_REASSOC_REQ:
8366f9acb7aSstsp 			if (ieee80211_print_assocreq(wh, len) != 0)
83712a08440Sreyk 				goto trunc;
83812a08440Sreyk 			break;
83912a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_AUTH:
84012a08440Sreyk 			TCHECK2(*frm, 2);		/* Auth Algorithm */
84112a08440Sreyk 			switch (IEEE80211_AUTH_ALGORITHM(frm)) {
84212a08440Sreyk 			case IEEE80211_AUTH_ALG_OPEN:
84312a08440Sreyk 				TCHECK2(*frm, 4);	/* Auth Transaction */
84412a08440Sreyk 				switch (IEEE80211_AUTH_TRANSACTION(frm)) {
84512a08440Sreyk 				case IEEE80211_AUTH_OPEN_REQUEST:
84612a08440Sreyk 					printf(" request");
84712a08440Sreyk 					break;
84812a08440Sreyk 				case IEEE80211_AUTH_OPEN_RESPONSE:
84912a08440Sreyk 					printf(" response");
85012a08440Sreyk 					break;
85112a08440Sreyk 				}
85212a08440Sreyk 				break;
85312a08440Sreyk 			case IEEE80211_AUTH_ALG_SHARED:
85412a08440Sreyk 				TCHECK2(*frm, 4);	/* Auth Transaction */
85512a08440Sreyk 				switch (IEEE80211_AUTH_TRANSACTION(frm)) {
85612a08440Sreyk 				case IEEE80211_AUTH_SHARED_REQUEST:
85712a08440Sreyk 					printf(" request");
85812a08440Sreyk 					break;
85912a08440Sreyk 				case IEEE80211_AUTH_SHARED_CHALLENGE:
86012a08440Sreyk 					printf(" challenge");
86112a08440Sreyk 					break;
86212a08440Sreyk 				case IEEE80211_AUTH_SHARED_RESPONSE:
86312a08440Sreyk 					printf(" response");
86412a08440Sreyk 					break;
86512a08440Sreyk 				case IEEE80211_AUTH_SHARED_PASS:
86612a08440Sreyk 					printf(" pass");
86712a08440Sreyk 					break;
86812a08440Sreyk 				}
86912a08440Sreyk 				break;
87012a08440Sreyk 			case IEEE80211_AUTH_ALG_LEAP:
87112a08440Sreyk 				printf(" (leap)");
87212a08440Sreyk 				break;
87312a08440Sreyk 			}
87412a08440Sreyk 			break;
87518786664Sclaudio 		case IEEE80211_FC0_SUBTYPE_DEAUTH:
87618786664Sclaudio 		case IEEE80211_FC0_SUBTYPE_DISASSOC:
87718786664Sclaudio 			TCHECK2(*frm, 2);		/* Reason Code */
87818786664Sclaudio 			ieee80211_reason(frm[0] | (frm[1] << 8));
87918786664Sclaudio 			break;
88012a08440Sreyk 		}
88112a08440Sreyk 		break;
8828dd9ce3eSstsp 	case IEEE80211_FC0_TYPE_CTL: {
8838dd9ce3eSstsp 		u_int8_t *t = (u_int8_t *) wh;
8848dd9ce3eSstsp 
8858dd9ce3eSstsp 		printf(": %s", ieee80211_ctl_subtype_name[
8868dd9ce3eSstsp 		    subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
8878dd9ce3eSstsp 		if (!vflag)
8888dd9ce3eSstsp 			break;
8898dd9ce3eSstsp 
8908dd9ce3eSstsp 		/* See 802.11 2012 "8.3.1 Control frames". */
8918dd9ce3eSstsp 		t += 2; /* skip Frame Control */
8928dd9ce3eSstsp 		switch (subtype) {
8938dd9ce3eSstsp 		case IEEE80211_FC0_SUBTYPE_RTS:
8948dd9ce3eSstsp 		case IEEE80211_FC0_SUBTYPE_BAR:
8958dd9ce3eSstsp 		case IEEE80211_FC0_SUBTYPE_BA:
8968dd9ce3eSstsp 			TCHECK2(*t, 2); /* Duration */
8978dd9ce3eSstsp 			printf(", duration %dms", (t[0] | t[1] << 8));
8988dd9ce3eSstsp 			t += 2;
8998dd9ce3eSstsp 			TCHECK2(*t, 6); /* RA */
9008dd9ce3eSstsp 			printf(", ra %s", etheraddr_string(t));
9018dd9ce3eSstsp 			t += 6;
9028dd9ce3eSstsp 			TCHECK2(*t, 6); /* TA */
9038dd9ce3eSstsp 			printf(", ta %s", etheraddr_string(t));
9048dd9ce3eSstsp 			if (subtype == IEEE80211_FC0_SUBTYPE_BAR ||
9058dd9ce3eSstsp 			    subtype == IEEE80211_FC0_SUBTYPE_BA) {
9068dd9ce3eSstsp 				u_int16_t ctrl;
9078dd9ce3eSstsp 
9088dd9ce3eSstsp 				t += 6;
9098dd9ce3eSstsp 				TCHECK2(*t, 2); /* BAR/BA control */
9108dd9ce3eSstsp 				ctrl = t[0] | (t[1] << 8);
9118dd9ce3eSstsp 				if (ctrl & IEEE80211_BA_ACK_POLICY)
9128dd9ce3eSstsp 					printf(", no ack");
9138dd9ce3eSstsp 				else
9148dd9ce3eSstsp 					printf(", normal ack");
9158dd9ce3eSstsp 				if ((ctrl & IEEE80211_BA_MULTI_TID) == 0 &&
9168dd9ce3eSstsp 				    (ctrl & IEEE80211_BA_COMPRESSED) == 0)
9178dd9ce3eSstsp 					printf(", basic variant");
9188dd9ce3eSstsp 				else if ((ctrl & IEEE80211_BA_MULTI_TID) &&
9198dd9ce3eSstsp 				    (ctrl & IEEE80211_BA_COMPRESSED))
9208dd9ce3eSstsp 					printf(", multi-tid variant");
9218dd9ce3eSstsp 				else if (ctrl & IEEE80211_BA_COMPRESSED)
9228dd9ce3eSstsp 					printf(", compressed variant");
9238dd9ce3eSstsp 			}
9248dd9ce3eSstsp 			break;
9258dd9ce3eSstsp 		case IEEE80211_FC0_SUBTYPE_CTS:
9268dd9ce3eSstsp 		case IEEE80211_FC0_SUBTYPE_ACK:
9278dd9ce3eSstsp 			TCHECK2(*t, 2); /* Duration */
9288dd9ce3eSstsp 			printf(", duration %dms", (t[0] | t[1] << 8));
9298dd9ce3eSstsp 			t += 2;
9308dd9ce3eSstsp 			TCHECK2(*t, 6); /* RA */
9318dd9ce3eSstsp 			printf(", ra %s", etheraddr_string(t));
9328dd9ce3eSstsp 			break;
9338dd9ce3eSstsp 		case IEEE80211_FC0_SUBTYPE_PS_POLL:
9348dd9ce3eSstsp 			TCHECK2(*t, 2); /* AID */
9358dd9ce3eSstsp 			printf(", aid 0x%x", (t[0] | t[1] << 8));
9368dd9ce3eSstsp 			t += 2;
9378dd9ce3eSstsp 			TCHECK2(*t, 6); /* BSSID(RA) */
9388dd9ce3eSstsp 			printf(", ra %s", etheraddr_string(t));
9398dd9ce3eSstsp 			t += 6;
9408dd9ce3eSstsp 			TCHECK2(*t, 6); /* TA */
9418dd9ce3eSstsp 			printf(", ta %s", etheraddr_string(t));
9428dd9ce3eSstsp 			break;
9438dd9ce3eSstsp 		}
9448dd9ce3eSstsp 		break;
9458dd9ce3eSstsp 	}
94612a08440Sreyk 	default:
94712a08440Sreyk 		printf(": type#%d", type);
94812a08440Sreyk 		break;
94912a08440Sreyk 	}
95012a08440Sreyk 
95112a08440Sreyk 	return (0);
95212a08440Sreyk 
95312a08440Sreyk  trunc:
95412a08440Sreyk 	/* Truncated 802.11 frame */
95512a08440Sreyk 	return (1);
95612a08440Sreyk }
95712a08440Sreyk 
95812a08440Sreyk u_int
95912a08440Sreyk ieee80211_any2ieee(u_int freq, u_int flags)
96012a08440Sreyk {
96112a08440Sreyk 	if (flags & IEEE80211_CHAN_2GHZ) {
96212a08440Sreyk 		if (freq == 2484)
96312a08440Sreyk 			return 14;
96412a08440Sreyk 		if (freq < 2484)
96512a08440Sreyk 			return (freq - 2407) / 5;
96612a08440Sreyk 		else
96712a08440Sreyk 			return 15 + ((freq - 2512) / 20);
96812a08440Sreyk 	} else if (flags & IEEE80211_CHAN_5GHZ) {
96912a08440Sreyk 		return (freq - 5000) / 5;
97012a08440Sreyk 	} else {
97112a08440Sreyk 		/* Assume channel is already an IEEE number */
97212a08440Sreyk 		return (freq);
97312a08440Sreyk 	}
97412a08440Sreyk }
97512a08440Sreyk 
97612a08440Sreyk int
97712a08440Sreyk ieee80211_print(struct ieee80211_frame *wh, u_int len)
97812a08440Sreyk {
97912a08440Sreyk 	if (eflag)
98012a08440Sreyk 		if (ieee80211_hdr(wh))
98112a08440Sreyk 			return (1);
98212a08440Sreyk 
98312a08440Sreyk 	printf("802.11");
98412a08440Sreyk 
98512a08440Sreyk 	return (ieee80211_frame(wh, len));
98612a08440Sreyk }
98712a08440Sreyk 
98812a08440Sreyk void
98912a08440Sreyk ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h,
99012a08440Sreyk     const u_char *p)
99112a08440Sreyk {
99212a08440Sreyk 	struct ieee80211_frame *wh = (struct ieee80211_frame*)p;
99312a08440Sreyk 
994c79cf170Sreyk 	if (!ieee80211_encap)
99512a08440Sreyk 		ts_print(&h->ts);
99612a08440Sreyk 
99712a08440Sreyk 	packetp = p;
99812a08440Sreyk 	snapend = p + h->caplen;
99912a08440Sreyk 
1000a0774ae9Smglocker 	if (ieee80211_print(wh, (u_int)h->len) != 0)
100112a08440Sreyk 		printf("[|802.11]");
100212a08440Sreyk 
1003c79cf170Sreyk 	if (!ieee80211_encap) {
100412a08440Sreyk 		if (xflag)
1005a0774ae9Smglocker 			default_print(p, (u_int)h->len);
100612a08440Sreyk 		putchar('\n');
100712a08440Sreyk 	}
1008c79cf170Sreyk }
100912a08440Sreyk 
101012a08440Sreyk void
101112a08440Sreyk ieee802_11_radio_if_print(u_char *user, const struct pcap_pkthdr *h,
101212a08440Sreyk     const u_char *p)
101312a08440Sreyk {
101412a08440Sreyk 	struct ieee80211_radiotap_header *rh =
101512a08440Sreyk 	    (struct ieee80211_radiotap_header*)p;
101612a08440Sreyk 	struct ieee80211_frame *wh;
101712a08440Sreyk 	u_int8_t *t;
101812a08440Sreyk 	u_int32_t present;
101912a08440Sreyk 	u_int len, rh_len;
1020cce1ba42Sclaudio 	u_int16_t tmp;
102112a08440Sreyk 
1022c79cf170Sreyk 	if (!ieee80211_encap)
102312a08440Sreyk 		ts_print(&h->ts);
102412a08440Sreyk 
102512a08440Sreyk 	packetp = p;
102612a08440Sreyk 	snapend = p + h->caplen;
102712a08440Sreyk 
102812a08440Sreyk 	TCHECK(*rh);
102912a08440Sreyk 
1030a0774ae9Smglocker 	len = h->len;
103112a08440Sreyk 	rh_len = letoh16(rh->it_len);
103212a08440Sreyk 	if (rh->it_version != 0) {
1033c79cf170Sreyk 		printf("[?radiotap + 802.11 v:%u]", rh->it_version);
103412a08440Sreyk 		goto out;
103512a08440Sreyk 	}
103612a08440Sreyk 
103712a08440Sreyk 	wh = (struct ieee80211_frame *)(p + rh_len);
103812a08440Sreyk 	if (len <= rh_len || ieee80211_print(wh, len - rh_len))
103912a08440Sreyk 		printf("[|802.11]");
104012a08440Sreyk 
104112a08440Sreyk 	t = (u_int8_t*)p + sizeof(struct ieee80211_radiotap_header);
104212a08440Sreyk 
104312a08440Sreyk 	if ((present = letoh32(rh->it_present)) == 0)
104412a08440Sreyk 		goto out;
104512a08440Sreyk 
104612a08440Sreyk 	printf(", <radiotap v%u", rh->it_version);
104712a08440Sreyk 
104812a08440Sreyk #define RADIOTAP(_x)	\
104912a08440Sreyk 	(present & (1 << IEEE80211_RADIOTAP_##_x))
105012a08440Sreyk 
105112a08440Sreyk 	if (RADIOTAP(TSFT)) {
1052cce1ba42Sclaudio 		u_int64_t tsf;
1053cce1ba42Sclaudio 
105412a08440Sreyk 		TCHECK2(*t, 8);
1055cce1ba42Sclaudio 		bcopy(t, &tsf, sizeof(u_int64_t));
105612a08440Sreyk 		if (vflag > 1)
1057cce1ba42Sclaudio 			printf(", tsf %llu", letoh64(tsf));
105812a08440Sreyk 		t += 8;
105912a08440Sreyk 	}
106012a08440Sreyk 
106112a08440Sreyk 	if (RADIOTAP(FLAGS)) {
106212a08440Sreyk 		u_int8_t flags = *(u_int8_t*)t;
1063026ca542Sderaadt 		TCHECK2(*t, 1);
1064026ca542Sderaadt 
106512a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_CFP)
106612a08440Sreyk 			printf(", CFP");
106712a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_SHORTPRE)
106812a08440Sreyk 			printf(", SHORTPRE");
106912a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_WEP)
107012a08440Sreyk 			printf(", WEP");
107112a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_FRAG)
107212a08440Sreyk 			printf(", FRAG");
107312a08440Sreyk 		t += 1;
107412a08440Sreyk 	}
107512a08440Sreyk 
107612a08440Sreyk 	if (RADIOTAP(RATE)) {
107712a08440Sreyk 		TCHECK2(*t, 1);
1078*9533a5eaSstsp 		if (vflag) {
1079*9533a5eaSstsp 			uint8_t rate = *(u_int8_t*)t;
1080*9533a5eaSstsp 			if (rate & 0x80)
1081*9533a5eaSstsp 				printf(", MCS %u", rate & 0x7f);
1082*9533a5eaSstsp 			else
1083*9533a5eaSstsp 				printf(", %uMbit/s", rate / 2);
1084*9533a5eaSstsp 		}
108512a08440Sreyk 		t += 1;
108612a08440Sreyk 	}
108712a08440Sreyk 
108812a08440Sreyk 	if (RADIOTAP(CHANNEL)) {
108912a08440Sreyk 		u_int16_t freq, flags;
109012a08440Sreyk 		TCHECK2(*t, 2);
109112a08440Sreyk 
1092cce1ba42Sclaudio 		bcopy(t, &freq, sizeof(u_int16_t));
1093cce1ba42Sclaudio 		freq = letoh16(freq);
109412a08440Sreyk 		t += 2;
109512a08440Sreyk 		TCHECK2(*t, 2);
1096cce1ba42Sclaudio 		bcopy(t, &flags, sizeof(u_int16_t));
1097cce1ba42Sclaudio 		flags = letoh16(flags);
109812a08440Sreyk 		t += 2;
109912a08440Sreyk 
110012a08440Sreyk 		printf(", chan %u", ieee80211_any2ieee(freq, flags));
110112a08440Sreyk 
110212a08440Sreyk 		if (flags & IEEE80211_CHAN_DYN &&
110312a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
110412a08440Sreyk 			printf(", 11g");
110512a08440Sreyk 		else if (flags & IEEE80211_CHAN_CCK &&
110612a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
110712a08440Sreyk 			printf(", 11b");
110812a08440Sreyk 		else if (flags & IEEE80211_CHAN_OFDM &&
110912a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
111012a08440Sreyk 			printf(", 11G");
111112a08440Sreyk 		else if (flags & IEEE80211_CHAN_OFDM &&
111212a08440Sreyk 		    flags & IEEE80211_CHAN_5GHZ)
111312a08440Sreyk 			printf(", 11a");
111412a08440Sreyk 
111512a08440Sreyk 		if (flags & IEEE80211_CHAN_XR)
111612a08440Sreyk 			printf(", XR");
111712a08440Sreyk 	}
111812a08440Sreyk 
111912a08440Sreyk 	if (RADIOTAP(FHSS)) {
112012a08440Sreyk 		TCHECK2(*t, 2);
112112a08440Sreyk 		printf(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1);
112212a08440Sreyk 		t += 2;
112312a08440Sreyk 	}
112412a08440Sreyk 
112512a08440Sreyk 	if (RADIOTAP(DBM_ANTSIGNAL)) {
112612a08440Sreyk 		TCHECK(*t);
112712a08440Sreyk 		printf(", sig %ddBm", *(int8_t*)t);
112812a08440Sreyk 		t += 1;
112912a08440Sreyk 	}
113012a08440Sreyk 
113112a08440Sreyk 	if (RADIOTAP(DBM_ANTNOISE)) {
113212a08440Sreyk 		TCHECK(*t);
113312a08440Sreyk 		printf(", noise %ddBm", *(int8_t*)t);
113412a08440Sreyk 		t += 1;
113512a08440Sreyk 	}
113612a08440Sreyk 
113712a08440Sreyk 	if (RADIOTAP(LOCK_QUALITY)) {
113812a08440Sreyk 		TCHECK2(*t, 2);
1139cce1ba42Sclaudio 		if (vflag) {
1140cce1ba42Sclaudio 			bcopy(t, &tmp, sizeof(u_int16_t));
1141cce1ba42Sclaudio 			printf(", quality %u", letoh16(tmp));
1142cce1ba42Sclaudio 		}
114312a08440Sreyk 		t += 2;
114412a08440Sreyk 	}
114512a08440Sreyk 
114612a08440Sreyk 	if (RADIOTAP(TX_ATTENUATION)) {
114712a08440Sreyk 		TCHECK2(*t, 2);
1148cce1ba42Sclaudio 		if (vflag) {
1149cce1ba42Sclaudio 			bcopy(t, &tmp, sizeof(u_int16_t));
1150cce1ba42Sclaudio 			printf(", txatt %u", letoh16(tmp));
1151cce1ba42Sclaudio 		}
115212a08440Sreyk 		t += 2;
115312a08440Sreyk 	}
115412a08440Sreyk 
115512a08440Sreyk 	if (RADIOTAP(DB_TX_ATTENUATION)) {
115612a08440Sreyk 		TCHECK2(*t, 2);
1157cce1ba42Sclaudio 		if (vflag) {
1158cce1ba42Sclaudio 			bcopy(t, &tmp, sizeof(u_int16_t));
1159cce1ba42Sclaudio 			printf(", txatt %udB", letoh16(tmp));
1160cce1ba42Sclaudio 		}
116112a08440Sreyk 		t += 2;
116212a08440Sreyk 	}
116312a08440Sreyk 
116412a08440Sreyk 	if (RADIOTAP(DBM_TX_POWER)) {
116512a08440Sreyk 		TCHECK(*t);
116612a08440Sreyk 		printf(", txpower %ddBm", *(int8_t*)t);
116712a08440Sreyk 		t += 1;
116812a08440Sreyk 	}
116912a08440Sreyk 
117012a08440Sreyk 	if (RADIOTAP(ANTENNA)) {
117112a08440Sreyk 		TCHECK(*t);
117212a08440Sreyk 		if (vflag)
117312a08440Sreyk 			printf(", antenna %u", *(u_int8_t*)t);
117412a08440Sreyk 		t += 1;
117512a08440Sreyk 	}
117612a08440Sreyk 
117712a08440Sreyk 	if (RADIOTAP(DB_ANTSIGNAL)) {
117812a08440Sreyk 		TCHECK(*t);
117912a08440Sreyk 		printf(", signal %udB", *(u_int8_t*)t);
118012a08440Sreyk 		t += 1;
118112a08440Sreyk 	}
118212a08440Sreyk 
118312a08440Sreyk 	if (RADIOTAP(DB_ANTNOISE)) {
118412a08440Sreyk 		TCHECK(*t);
118512a08440Sreyk 		printf(", noise %udB", *(u_int8_t*)t);
118612a08440Sreyk 		t += 1;
118712a08440Sreyk 	}
118812a08440Sreyk 
118912a08440Sreyk 	if (RADIOTAP(FCS)) {
119012a08440Sreyk 		TCHECK2(*t, 4);
1191cce1ba42Sclaudio 		if (vflag) {
1192cce1ba42Sclaudio 			u_int32_t fcs;
1193cce1ba42Sclaudio 			bcopy(t, &fcs, sizeof(u_int32_t));
1194cce1ba42Sclaudio 			printf(", fcs %08x", letoh32(fcs));
1195cce1ba42Sclaudio 		}
119612a08440Sreyk 		t += 4;
119712a08440Sreyk 	}
119812a08440Sreyk 
11996fc94ee3Sreyk 	if (RADIOTAP(RSSI)) {
12006fc94ee3Sreyk 		u_int8_t rssi, max_rssi;
12016fc94ee3Sreyk 		TCHECK(*t);
12026fc94ee3Sreyk 		rssi = *(u_int8_t*)t;
12036fc94ee3Sreyk 		t += 1;
12046fc94ee3Sreyk 		TCHECK(*t);
12056fc94ee3Sreyk 		max_rssi = *(u_int8_t*)t;
12066fc94ee3Sreyk 		t += 1;
12076fc94ee3Sreyk 
12086fc94ee3Sreyk 		printf(", rssi %u/%u", rssi, max_rssi);
12096fc94ee3Sreyk 	}
12106fc94ee3Sreyk 
121112a08440Sreyk #undef RADIOTAP
121212a08440Sreyk 
121312a08440Sreyk 	putchar('>');
121412a08440Sreyk 	goto out;
121512a08440Sreyk 
121612a08440Sreyk  trunc:
121712a08440Sreyk 	/* Truncated frame */
121812a08440Sreyk 	printf("[|radiotap + 802.11]");
121912a08440Sreyk 
122012a08440Sreyk  out:
1221c79cf170Sreyk 	if (!ieee80211_encap) {
122212a08440Sreyk 		if (xflag)
1223a0774ae9Smglocker 			default_print(p, h->len);
122412a08440Sreyk 		putchar('\n');
122512a08440Sreyk 	}
1226c79cf170Sreyk }
122718786664Sclaudio 
122818786664Sclaudio void
122918786664Sclaudio ieee80211_reason(u_int16_t reason)
123018786664Sclaudio {
123118786664Sclaudio 	if (!vflag)
123218786664Sclaudio 		return;
123318786664Sclaudio 
123418786664Sclaudio 	switch (reason) {
123518786664Sclaudio 	case IEEE80211_REASON_UNSPECIFIED:
123618786664Sclaudio 		printf(", unspecified failure");
123718786664Sclaudio 		break;
123818786664Sclaudio 	case IEEE80211_REASON_AUTH_EXPIRE:
123918786664Sclaudio 		printf(", authentication expired");
124018786664Sclaudio 		break;
124118786664Sclaudio 	case IEEE80211_REASON_AUTH_LEAVE:
124218786664Sclaudio 		printf(", deauth - station left");
124318786664Sclaudio 		break;
124418786664Sclaudio 	case IEEE80211_REASON_ASSOC_EXPIRE:
124518786664Sclaudio 		printf(", association expired");
124618786664Sclaudio 		break;
124718786664Sclaudio 	case IEEE80211_REASON_ASSOC_TOOMANY:
124818786664Sclaudio 		printf(", too many associated stations");
124918786664Sclaudio 		break;
125018786664Sclaudio 	case IEEE80211_REASON_NOT_AUTHED:
125118786664Sclaudio 		printf(", not authenticated");
125218786664Sclaudio 		break;
125318786664Sclaudio 	case IEEE80211_REASON_NOT_ASSOCED:
125418786664Sclaudio 		printf(", not associated");
125518786664Sclaudio 		break;
125618786664Sclaudio 	case IEEE80211_REASON_ASSOC_LEAVE:
125718786664Sclaudio 		printf(", disassociated - station left");
125818786664Sclaudio 		break;
125918786664Sclaudio 	case IEEE80211_REASON_ASSOC_NOT_AUTHED:
126018786664Sclaudio 		printf(", association but not authenticated");
126118786664Sclaudio 		break;
126218786664Sclaudio 	case IEEE80211_REASON_RSN_REQUIRED:
126318786664Sclaudio 		printf(", rsn required");
126418786664Sclaudio 		break;
126518786664Sclaudio 	case IEEE80211_REASON_RSN_INCONSISTENT:
126618786664Sclaudio 		printf(", rsn inconsistent");
126718786664Sclaudio 		break;
126818786664Sclaudio 	case IEEE80211_REASON_IE_INVALID:
126918786664Sclaudio 		printf(", ie invalid");
127018786664Sclaudio 		break;
127118786664Sclaudio 	case IEEE80211_REASON_MIC_FAILURE:
127218786664Sclaudio 		printf(", mic failure");
127318786664Sclaudio 		break;
127418786664Sclaudio 	default:
127518786664Sclaudio 		printf(", unknown reason %u", reason);
127618786664Sclaudio 	}
127718786664Sclaudio }
1278