xref: /openbsd/usr.sbin/tcpdump/print-802_11.c (revision 36fa064c)
1*36fa064cSstsp /*	$OpenBSD: print-802_11.c,v 1.23 2015/07/18 23:35:01 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 
4012a08440Sreyk const char *ieee80211_mgt_subtype_name[] = {
4112a08440Sreyk 	"association request",
4212a08440Sreyk 	"association response",
4312a08440Sreyk 	"reassociation request",
4412a08440Sreyk 	"reassociation response",
4512a08440Sreyk 	"probe request",
4612a08440Sreyk 	"probe response",
4712a08440Sreyk 	"reserved#6",
4812a08440Sreyk 	"reserved#7",
4912a08440Sreyk 	"beacon",
5012a08440Sreyk 	"atim",
5112a08440Sreyk 	"disassociation",
5212a08440Sreyk 	"authentication",
5312a08440Sreyk 	"deauthentication",
54ab7e388eSclaudio 	"action",
55ab7e388eSclaudio 	"action noack",
5612a08440Sreyk 	"reserved#15"
5712a08440Sreyk };
5812a08440Sreyk 
59ab7e388eSclaudio const char *ieee80211_data_subtype_name[] = {
60ab7e388eSclaudio 	"data",
61ab7e388eSclaudio 	"data cf ack",
62ab7e388eSclaudio 	"data cf poll",
63ab7e388eSclaudio 	"data cf poll ack",
64ab7e388eSclaudio 	"no-data",
65ab7e388eSclaudio 	"no-data cf poll",
66ab7e388eSclaudio 	"no-data cf ack",
67ab7e388eSclaudio 	"no-data cf poll ack",
68ab7e388eSclaudio 	"QoS data",
69ab7e388eSclaudio 	"QoS data cf ack",
70ab7e388eSclaudio 	"QoS data cf poll",
71ab7e388eSclaudio 	"QoS data cf poll ack",
72ab7e388eSclaudio 	"QoS no-data",
73ab7e388eSclaudio 	"QoS no-data cf poll",
74ab7e388eSclaudio 	"QoS no-data cf ack",
75ab7e388eSclaudio 	"QoS no-data cf poll ack"
76ab7e388eSclaudio };
77ab7e388eSclaudio 
7812a08440Sreyk int	 ieee80211_hdr(struct ieee80211_frame *);
79b72abdefSreyk int	 ieee80211_data(struct ieee80211_frame *, u_int);
8012a08440Sreyk void	 ieee80211_print_element(u_int8_t *, u_int);
8112a08440Sreyk void	 ieee80211_print_essid(u_int8_t *, u_int);
8277734011Sstsp void	 ieee80211_print_country(u_int8_t *, u_int);
831e3bf20aSstsp void	 ieee80211_print_htcaps(u_int8_t *, u_int);
84*36fa064cSstsp void	 ieee80211_print_htop(u_int8_t *, u_int);
8512a08440Sreyk int	 ieee80211_elements(struct ieee80211_frame *, u_int);
8612a08440Sreyk int	 ieee80211_frame(struct ieee80211_frame *, u_int);
8712a08440Sreyk int	 ieee80211_print(struct ieee80211_frame *, u_int);
8812a08440Sreyk u_int	 ieee80211_any2ieee(u_int, u_int);
8918786664Sclaudio void	 ieee80211_reason(u_int16_t);
9012a08440Sreyk 
9112a08440Sreyk #define TCARR(a)	TCHECK2(*a, sizeof(a))
9212a08440Sreyk 
93c79cf170Sreyk int ieee80211_encap = 0;
94c79cf170Sreyk 
9512a08440Sreyk int
9612a08440Sreyk ieee80211_hdr(struct ieee80211_frame *wh)
9712a08440Sreyk {
9812a08440Sreyk 	struct ieee80211_frame_addr4 *w4;
9912a08440Sreyk 
10012a08440Sreyk 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
10112a08440Sreyk 	case IEEE80211_FC1_DIR_NODS:
10212a08440Sreyk 		TCARR(wh->i_addr2);
10312a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr2));
10412a08440Sreyk 		TCARR(wh->i_addr1);
10512a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr1));
10612a08440Sreyk 		TCARR(wh->i_addr3);
10712a08440Sreyk 		printf(", bssid %s", etheraddr_string(wh->i_addr3));
10812a08440Sreyk 		break;
10912a08440Sreyk 	case IEEE80211_FC1_DIR_TODS:
11012a08440Sreyk 		TCARR(wh->i_addr2);
11112a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr2));
11212a08440Sreyk 		TCARR(wh->i_addr3);
11312a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr3));
11412a08440Sreyk 		TCARR(wh->i_addr1);
11512a08440Sreyk 		printf(", bssid %s, > DS", etheraddr_string(wh->i_addr1));
11612a08440Sreyk 		break;
11712a08440Sreyk 	case IEEE80211_FC1_DIR_FROMDS:
11812a08440Sreyk 		TCARR(wh->i_addr3);
11912a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr3));
12012a08440Sreyk 		TCARR(wh->i_addr1);
12112a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr1));
12212a08440Sreyk 		TCARR(wh->i_addr2);
12312a08440Sreyk 		printf(", bssid %s, DS >", etheraddr_string(wh->i_addr2));
12412a08440Sreyk 		break;
12512a08440Sreyk 	case IEEE80211_FC1_DIR_DSTODS:
12612a08440Sreyk 		w4 = (struct ieee80211_frame_addr4 *) wh;
12712a08440Sreyk 		TCARR(w4->i_addr4);
12812a08440Sreyk 		printf("%s", etheraddr_string(w4->i_addr4));
12912a08440Sreyk 		TCARR(w4->i_addr3);
13012a08440Sreyk 		printf(" > %s", etheraddr_string(w4->i_addr3));
13112a08440Sreyk 		TCARR(w4->i_addr2);
13212a08440Sreyk 		printf(", bssid %s", etheraddr_string(w4->i_addr2));
13312a08440Sreyk 		TCARR(w4->i_addr1);
13412a08440Sreyk 		printf(" > %s, DS > DS", etheraddr_string(w4->i_addr1));
13512a08440Sreyk 		break;
13612a08440Sreyk 	}
13712a08440Sreyk 	if (vflag) {
138cce1ba42Sclaudio 		u_int16_t seq;
13912a08440Sreyk 		TCARR(wh->i_seq);
140cce1ba42Sclaudio 		bcopy(wh->i_seq, &seq, sizeof(u_int16_t));
141cce1ba42Sclaudio 		printf(" (seq %u): ", letoh16(seq));
14212a08440Sreyk 	} else
14312a08440Sreyk 		printf(": ");
14412a08440Sreyk 
14512a08440Sreyk 	return (0);
14612a08440Sreyk 
14712a08440Sreyk  trunc:
14812a08440Sreyk 	/* Truncated elements in frame */
14912a08440Sreyk 	return (1);
15012a08440Sreyk }
15112a08440Sreyk 
152b72abdefSreyk int
153b72abdefSreyk ieee80211_data(struct ieee80211_frame *wh, u_int len)
154b72abdefSreyk {
155b72abdefSreyk 	u_int8_t *t = (u_int8_t *)wh;
156d49cb46eScanacar 	struct ieee80211_frame_addr4 *w4;
157b72abdefSreyk 	u_int datalen;
15893cbfc44Sstsp 	int data = !(wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_NODATA);
159ab7e388eSclaudio 	u_char *esrc = NULL, *edst = NULL;
160b72abdefSreyk 
161d49cb46eScanacar 	TCHECK(*wh);
162b72abdefSreyk 	t += sizeof(struct ieee80211_frame);
163b72abdefSreyk 	datalen = len - sizeof(struct ieee80211_frame);
164b72abdefSreyk 
165b72abdefSreyk 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
166b72abdefSreyk 	case IEEE80211_FC1_DIR_TODS:
167ab7e388eSclaudio 		esrc = wh->i_addr2;
168ab7e388eSclaudio 		edst = wh->i_addr3;
169b72abdefSreyk 		break;
170b72abdefSreyk 	case IEEE80211_FC1_DIR_FROMDS:
171ab7e388eSclaudio 		esrc = wh->i_addr3;
172ab7e388eSclaudio 		edst = wh->i_addr1;
173b72abdefSreyk 		break;
174b72abdefSreyk 	case IEEE80211_FC1_DIR_NODS:
175ab7e388eSclaudio 		esrc = wh->i_addr2;
176ab7e388eSclaudio 		edst = wh->i_addr1;
177d49cb46eScanacar 		break;
178b72abdefSreyk 	case IEEE80211_FC1_DIR_DSTODS:
179d49cb46eScanacar 		w4 = (struct ieee80211_frame_addr4 *) wh;
180d49cb46eScanacar 		TCHECK(*w4);
181d49cb46eScanacar 		t = (u_int8_t *) (w4 + 1);
182d49cb46eScanacar 		datalen = len - sizeof(*w4);
183ab7e388eSclaudio 		esrc = w4->i_addr4;
184ab7e388eSclaudio 		edst = w4->i_addr3;
185b72abdefSreyk 		break;
186b72abdefSreyk 	}
187b72abdefSreyk 
188ab7e388eSclaudio 	if (data && esrc)
189ab7e388eSclaudio 		llc_print(t, datalen, datalen, esrc, edst);
190ab7e388eSclaudio 	else if (eflag && esrc)
191ab7e388eSclaudio 		printf("%s > %s",
192ab7e388eSclaudio 		    etheraddr_string(esrc), etheraddr_string(edst));
193ab7e388eSclaudio 
194b72abdefSreyk 	return (0);
195b72abdefSreyk 
196b72abdefSreyk  trunc:
197b72abdefSreyk 	/* Truncated elements in frame */
198b72abdefSreyk 	return (1);
199b72abdefSreyk }
200b72abdefSreyk 
20112a08440Sreyk /* Caller checks len */
20212a08440Sreyk void
20312a08440Sreyk ieee80211_print_element(u_int8_t *data, u_int len)
20412a08440Sreyk {
20512a08440Sreyk 	u_int8_t *p;
2069cbdb746Sderaadt 	int i;
20712a08440Sreyk 
20812a08440Sreyk 	printf(" 0x");
2099cbdb746Sderaadt 	for (i = 0, p = data; i < len; i++, p++)
21012a08440Sreyk 		printf("%02x", *p);
21112a08440Sreyk }
21212a08440Sreyk 
21312a08440Sreyk /* Caller checks len */
21412a08440Sreyk void
21512a08440Sreyk ieee80211_print_essid(u_int8_t *essid, u_int len)
21612a08440Sreyk {
21712a08440Sreyk 	u_int8_t *p;
2189cbdb746Sderaadt 	int i;
21912a08440Sreyk 
22012a08440Sreyk 	if (len > IEEE80211_NWID_LEN)
22112a08440Sreyk 		len = IEEE80211_NWID_LEN;
22212a08440Sreyk 
22312a08440Sreyk 	/* determine printable or not */
22412a08440Sreyk 	for (i = 0, p = essid; i < len; i++, p++) {
22512a08440Sreyk 		if (*p < ' ' || *p > 0x7e)
22612a08440Sreyk 			break;
22712a08440Sreyk 	}
22812a08440Sreyk 	if (i == len) {
22912a08440Sreyk 		printf(" (");
23012a08440Sreyk 		for (i = 0, p = essid; i < len; i++, p++)
23112a08440Sreyk 			putchar(*p);
23212a08440Sreyk 		putchar(')');
2339cbdb746Sderaadt 	} else
23412a08440Sreyk 		ieee80211_print_element(essid, len);
23512a08440Sreyk }
23612a08440Sreyk 
2371e3bf20aSstsp /* Caller checks len */
2381e3bf20aSstsp void
23977734011Sstsp ieee80211_print_country(u_int8_t *data, u_int len)
24077734011Sstsp {
24177734011Sstsp 	u_int8_t first_chan, nchan, maxpower;
24277734011Sstsp 
24377734011Sstsp 	if (len < 6)
24477734011Sstsp 		return;
24577734011Sstsp 
24677734011Sstsp 	/* country string */
24777734011Sstsp 	printf((isprint(data[0]) ? " '%c" : " '\\%03o"), data[0]);
24877734011Sstsp 	printf((isprint(data[1]) ? "%c" : "\\%03o"), data[1]);
24977734011Sstsp 	printf((isprint(data[2]) ? "%c'" : "\\%03o'"), data[2]);
25077734011Sstsp 
25177734011Sstsp 	len -= 3;
25277734011Sstsp 	data += 3;
25377734011Sstsp 
25477734011Sstsp 	/* channels and corresponding TX power limits */
25577734011Sstsp 	while (len > 3)	{
25677734011Sstsp 		/* no pretty-printing for nonsensical zero values,
25777734011Sstsp 		 * nor for operating extension IDs (values >= 201) */
25877734011Sstsp 		if (data[0] == 0 || data[1] == 0 ||
25977734011Sstsp 		    data[0] >= 201 || data[1] >= 201) {
26077734011Sstsp 			printf(", %d %d %d", data[0], data[1], data[2]);
26177734011Sstsp 			continue;
26277734011Sstsp 		}
26377734011Sstsp 
26477734011Sstsp 		first_chan = data[0];
26577734011Sstsp 		nchan = data[1];
26677734011Sstsp 		maxpower = data[2];
26777734011Sstsp 
26877734011Sstsp 		printf(", channel%s %d", nchan == 1 ? "" : "s", first_chan);
26977734011Sstsp 		if (nchan > 1)
27077734011Sstsp 			printf("-%d", first_chan + nchan - 1);
27177734011Sstsp 		printf(" limit %ddB", maxpower);
27277734011Sstsp 
27377734011Sstsp 		len -= 3;
27477734011Sstsp 		data += 3;
27577734011Sstsp 	}
27677734011Sstsp }
27777734011Sstsp 
27877734011Sstsp /* Caller checks len */
27977734011Sstsp void
2801e3bf20aSstsp ieee80211_print_htcaps(u_int8_t *data, u_int len)
2811e3bf20aSstsp {
2821e3bf20aSstsp 	u_int16_t htcaps;
2831e3bf20aSstsp 	int smps, rxstbc;
2841e3bf20aSstsp 
2851e3bf20aSstsp 	if (len < 2) {
2861e3bf20aSstsp 		ieee80211_print_element(data, len);
2871e3bf20aSstsp 		return;
2881e3bf20aSstsp 	}
2891e3bf20aSstsp 
2901e3bf20aSstsp 	htcaps = (data[0]) | (data[1] << 8);
2911e3bf20aSstsp 	printf("=<");
2921e3bf20aSstsp 
2931e3bf20aSstsp 	/* channel width */
2941e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_CBW20_40)
2951e3bf20aSstsp 		printf("20/40MHz");
2961e3bf20aSstsp 	else
2971e3bf20aSstsp 		printf("20MHz");
2981e3bf20aSstsp 
2991e3bf20aSstsp 	/* LDPC coding */
3001e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_LDPC)
3011e3bf20aSstsp 		printf(",LDPC");
3021e3bf20aSstsp 
3031e3bf20aSstsp 	/* spatial multiplexing power save mode */
3041e3bf20aSstsp 	smps = (htcaps & IEEE80211_HTCAP_SMPS_MASK)
3051e3bf20aSstsp 	    >> IEEE80211_HTCAP_SMPS_SHIFT;
3061e3bf20aSstsp 	if (smps == 0)
3071e3bf20aSstsp 		printf(",SMPS static");
3081e3bf20aSstsp 	else if (smps == 1)
3091e3bf20aSstsp 		printf(",SMPS dynamic");
3101e3bf20aSstsp 
3111e3bf20aSstsp 	/* 11n greenfield mode */
3121e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_GF)
3131e3bf20aSstsp 		printf(",greenfield");
3141e3bf20aSstsp 
3151e3bf20aSstsp 	/* short guard interval */
3161e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_SGI20)
3171e3bf20aSstsp 		printf(",SGI@20MHz");
3181e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_SGI40)
3191e3bf20aSstsp 		printf(",SGI@40MHz");
3201e3bf20aSstsp 
3211e3bf20aSstsp 	/* space-time block coding */
3221e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_TXSTBC)
3231e3bf20aSstsp 		printf(",TXSTBC");
3241e3bf20aSstsp 	rxstbc = (htcaps & IEEE80211_HTCAP_RXSTBC_MASK)
3251e3bf20aSstsp 	    >> IEEE80211_HTCAP_RXSTBC_SHIFT;
3261e3bf20aSstsp 	if (rxstbc > 0 && rxstbc < 4)
3271e3bf20aSstsp 		printf(",RXSTBC %d stream", rxstbc);
3281e3bf20aSstsp 
3291e3bf20aSstsp 	/* delayed block-ack */
3301e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_DELAYEDBA)
3311e3bf20aSstsp 		printf(",delayed BA");
3321e3bf20aSstsp 
3331e3bf20aSstsp 	/* max A-MSDU length */
3341e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_AMSDU7935)
3351e3bf20aSstsp 		printf(",A-MSDU 7935");
3361e3bf20aSstsp 	else
3371e3bf20aSstsp 		printf(",A-MSDU 3839");
3381e3bf20aSstsp 
3391e3bf20aSstsp 	/* DSSS/CCK in 40MHz mode */
3401e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_DSSSCCK40)
3411e3bf20aSstsp 		printf(",DSSS/CCK@40MHz");
3421e3bf20aSstsp 
3431e3bf20aSstsp 	/* 40MHz intolerant */
3441e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_40INTOLERANT)
3451e3bf20aSstsp 		printf(",40MHz intolerant");
3461e3bf20aSstsp 
3471e3bf20aSstsp 	/* L-SIG TXOP protection */
3481e3bf20aSstsp 	if (htcaps & IEEE80211_HTCAP_LSIGTXOPPROT)
3491e3bf20aSstsp 		printf(",L-SIG TXOP prot");
3501e3bf20aSstsp 
3511e3bf20aSstsp 	printf(">");
3521e3bf20aSstsp }
3531e3bf20aSstsp 
354*36fa064cSstsp /* Caller checks len */
355*36fa064cSstsp void
356*36fa064cSstsp ieee80211_print_htop(u_int8_t *data, u_int len)
357*36fa064cSstsp {
358*36fa064cSstsp 	u_int8_t primary_chan;
359*36fa064cSstsp 	u_int8_t htopinfo[5];
360*36fa064cSstsp 	u_int8_t basic_mcs[16];
361*36fa064cSstsp 	int sco, prot, i;
362*36fa064cSstsp 
363*36fa064cSstsp 	if (len < sizeof(primary_chan) + sizeof(htopinfo) + sizeof(basic_mcs)) {
364*36fa064cSstsp 		ieee80211_print_element(data, len);
365*36fa064cSstsp 		return;
366*36fa064cSstsp 	}
367*36fa064cSstsp 
368*36fa064cSstsp 	htopinfo[0] = data[1];
369*36fa064cSstsp 
370*36fa064cSstsp 	printf("=<");
371*36fa064cSstsp 
372*36fa064cSstsp 	/* primary channel and secondary channel offset */
373*36fa064cSstsp 	primary_chan = data[0];
374*36fa064cSstsp 	sco = ((htopinfo[0] & IEEE80211_HTOP0_SCO_MASK)
375*36fa064cSstsp 	    >> IEEE80211_HTOP0_SCO_SHIFT);
376*36fa064cSstsp 	if (sco == 0)
377*36fa064cSstsp 		printf("20MHz chan %d", primary_chan);
378*36fa064cSstsp 	else if (sco == 1)
379*36fa064cSstsp 		printf("40MHz primary chan %d secondary above", primary_chan);
380*36fa064cSstsp 	else if (sco == 3)
381*36fa064cSstsp 		printf("40MHz primary chan %d secondary below", primary_chan);
382*36fa064cSstsp 	else
383*36fa064cSstsp 		printf("chan %d [invalid secondary channel offset %d]",
384*36fa064cSstsp 		    primary_chan, sco);
385*36fa064cSstsp 
386*36fa064cSstsp 	/* STA channel width */
387*36fa064cSstsp 	if ((htopinfo[0] & IEEE80211_HTOP0_CHW) == 0)
388*36fa064cSstsp 		printf(",STA chanw 20MHz");
389*36fa064cSstsp 
390*36fa064cSstsp 	/* reduced interframe space (RIFS) permitted */
391*36fa064cSstsp 	if (htopinfo[0] & IEEE80211_HTOP0_RIFS)
392*36fa064cSstsp 		printf(",RIFS");
393*36fa064cSstsp 
394*36fa064cSstsp 	htopinfo[1] = data[2];
395*36fa064cSstsp 
396*36fa064cSstsp 	/* protection requirements for HT transmissions */
397*36fa064cSstsp 	prot = ((htopinfo[1] & IEEE80211_HTOP1_PROT_MASK)
398*36fa064cSstsp 	    >> IEEE80211_HTOP1_PROT_SHIFT);
399*36fa064cSstsp 	if (prot == 1)
400*36fa064cSstsp 		printf(",protect non-member");
401*36fa064cSstsp 	else if (prot == 2)
402*36fa064cSstsp 		printf(",protect 20MHz");
403*36fa064cSstsp 	else if (prot == 3)
404*36fa064cSstsp 		printf(",protect non-HT");
405*36fa064cSstsp 
406*36fa064cSstsp 	/* non-greenfield STA present */
407*36fa064cSstsp 	if (htopinfo[1] & IEEE80211_HTOP1_NONGF_STA)
408*36fa064cSstsp 		printf(",non-greenfield STA");
409*36fa064cSstsp 
410*36fa064cSstsp 	/* non-HT STA present */
411*36fa064cSstsp 	if (htopinfo[1] & IEEE80211_HTOP1_OBSS_NONHT_STA)
412*36fa064cSstsp 		printf(",non-HT STA");
413*36fa064cSstsp 
414*36fa064cSstsp 	htopinfo[3] = data[4];
415*36fa064cSstsp 
416*36fa064cSstsp 	/* dual-beacon */
417*36fa064cSstsp 	if (htopinfo[3] & IEEE80211_HTOP2_DUALBEACON)
418*36fa064cSstsp 		printf(",dualbeacon");
419*36fa064cSstsp 
420*36fa064cSstsp 	/* dual CTS protection */
421*36fa064cSstsp 	if (htopinfo[3] & IEEE80211_HTOP2_DUALCTSPROT)
422*36fa064cSstsp 		printf(",dualctsprot");
423*36fa064cSstsp 
424*36fa064cSstsp 	htopinfo[4] = data[5];
425*36fa064cSstsp 
426*36fa064cSstsp 	/* space-time block coding (STBC) beacon */
427*36fa064cSstsp 	if ((htopinfo[4] << 8) & IEEE80211_HTOP2_DUALCTSPROT)
428*36fa064cSstsp 		printf(",STBC beacon");
429*36fa064cSstsp 
430*36fa064cSstsp 	/* L-SIG (non-HT signal field) TX opportunity (TXOP) protection */
431*36fa064cSstsp 	if ((htopinfo[4] << 8) & IEEE80211_HTOP2_LSIGTXOP)
432*36fa064cSstsp 		printf(",lsigtxprot");
433*36fa064cSstsp 
434*36fa064cSstsp 	/* phased-coexistence operation (PCO) active */
435*36fa064cSstsp 	if ((htopinfo[4] << 8) & IEEE80211_HTOP2_PCOACTIVE) {
436*36fa064cSstsp 		/* PCO phase */
437*36fa064cSstsp 		if ((htopinfo[4] << 8) & IEEE80211_HTOP2_PCOPHASE40)
438*36fa064cSstsp 			printf(",pco40MHz");
439*36fa064cSstsp 		else
440*36fa064cSstsp 			printf(",pco20MHz");
441*36fa064cSstsp 	}
442*36fa064cSstsp 
443*36fa064cSstsp 	/* basic MCS set */
444*36fa064cSstsp 	memcpy(basic_mcs, &data[6], sizeof(basic_mcs));
445*36fa064cSstsp 	printf(",basic MCS set 0x");
446*36fa064cSstsp 	for (i = 0; i < sizeof(basic_mcs) / sizeof(basic_mcs[0]); i++)
447*36fa064cSstsp 			printf("%x", basic_mcs[i]);
448*36fa064cSstsp 
449*36fa064cSstsp 	printf(">");
450*36fa064cSstsp }
451*36fa064cSstsp 
45212a08440Sreyk int
45312a08440Sreyk ieee80211_elements(struct ieee80211_frame *wh, u_int flen)
45412a08440Sreyk {
45512a08440Sreyk 	u_int8_t *buf, *frm;
456cce1ba42Sclaudio 	u_int64_t tstamp;
457cce1ba42Sclaudio 	u_int16_t bintval, capinfo;
45812a08440Sreyk 	int i;
45912a08440Sreyk 
46012a08440Sreyk 	buf = (u_int8_t *)wh;
46112a08440Sreyk 	frm = (u_int8_t *)&wh[1];
46212a08440Sreyk 
4630a05c5bfSreyk 	TCHECK2(*frm, 8);
464cce1ba42Sclaudio 	bcopy(frm, &tstamp, sizeof(u_int64_t));
46512a08440Sreyk 	frm += 8;
46612a08440Sreyk 
46712a08440Sreyk 	if (vflag > 1)
468cce1ba42Sclaudio 		printf(", timestamp %llu", letoh64(tstamp));
46912a08440Sreyk 
4700a05c5bfSreyk 	TCHECK2(*frm, 2);
471cce1ba42Sclaudio 	bcopy(frm, &bintval, sizeof(u_int16_t));
47212a08440Sreyk 	frm += 2;
47312a08440Sreyk 
47412a08440Sreyk 	if (vflag > 1)
475cce1ba42Sclaudio 		printf(", interval %u", letoh16(bintval));
47612a08440Sreyk 
4770a05c5bfSreyk 	TCHECK2(*frm, 2);
478cce1ba42Sclaudio 	bcopy(frm, &capinfo, sizeof(u_int16_t));
47912a08440Sreyk 	frm += 2;
48012a08440Sreyk 
48112a08440Sreyk 	if (vflag)
482cce1ba42Sclaudio 		printb(", caps", letoh16(capinfo),
48312a08440Sreyk 		    IEEE80211_CAPINFO_BITS);
48412a08440Sreyk 
48512a08440Sreyk 	while (TTEST2(*frm, 2)) {
48612a08440Sreyk 		u_int len = frm[1];
48712a08440Sreyk 		u_int8_t *data = frm + 2;
48812a08440Sreyk 
48912a08440Sreyk 		if (!TTEST2(*data, len))
49012a08440Sreyk 			break;
49112a08440Sreyk 
49212a08440Sreyk #define ELEM_CHECK(l)	if (len != l) break
49312a08440Sreyk 
49412a08440Sreyk 		switch (*frm) {
49512a08440Sreyk 		case IEEE80211_ELEMID_SSID:
49612a08440Sreyk 			printf(", ssid");
49712a08440Sreyk 			ieee80211_print_essid(data, len);
49812a08440Sreyk 			break;
49912a08440Sreyk 		case IEEE80211_ELEMID_RATES:
50012a08440Sreyk 			printf(", rates");
50112a08440Sreyk 			if (!vflag)
50212a08440Sreyk 				break;
50312a08440Sreyk 			for (i = len; i > 0; i--, data++)
50412a08440Sreyk 				printf(" %uM",
50512a08440Sreyk 				    (data[0] & IEEE80211_RATE_VAL) / 2);
50612a08440Sreyk 			break;
50712a08440Sreyk 		case IEEE80211_ELEMID_FHPARMS:
50812a08440Sreyk 			ELEM_CHECK(5);
50912a08440Sreyk 			printf(", fh (dwell %u, chan %u, index %u)",
51012a08440Sreyk 			    (data[1] << 8) | data[0],
51112a08440Sreyk 			    (data[2] - 1) * 80 + data[3],	/* FH_CHAN */
51212a08440Sreyk 			    data[4]);
51312a08440Sreyk 			break;
51412a08440Sreyk 		case IEEE80211_ELEMID_DSPARMS:
51512a08440Sreyk 			ELEM_CHECK(1);
51612a08440Sreyk 			printf(", ds");
51712a08440Sreyk 			if (vflag)
51812a08440Sreyk 				printf(" (chan %u)", data[0]);
51912a08440Sreyk 			break;
52012a08440Sreyk 		case IEEE80211_ELEMID_CFPARMS:
52112a08440Sreyk 			printf(", cf");
52212a08440Sreyk 			if (vflag)
52312a08440Sreyk 				ieee80211_print_element(data, len);
52412a08440Sreyk 			break;
52512a08440Sreyk 		case IEEE80211_ELEMID_TIM:
52612a08440Sreyk 			printf(", tim");
52712a08440Sreyk 			if (vflag)
52812a08440Sreyk 				ieee80211_print_element(data, len);
52912a08440Sreyk 			break;
53012a08440Sreyk 		case IEEE80211_ELEMID_IBSSPARMS:
53112a08440Sreyk 			printf(", ibss");
53212a08440Sreyk 			if (vflag)
53312a08440Sreyk 				ieee80211_print_element(data, len);
53412a08440Sreyk 			break;
53512a08440Sreyk 		case IEEE80211_ELEMID_COUNTRY:
53612a08440Sreyk 			printf(", country");
53777734011Sstsp 			ieee80211_print_country(data, len);
53812a08440Sreyk 			break;
53912a08440Sreyk 		case IEEE80211_ELEMID_CHALLENGE:
54012a08440Sreyk 			printf(", challenge");
54112a08440Sreyk 			if (vflag)
54212a08440Sreyk 				ieee80211_print_element(data, len);
54312a08440Sreyk 			break;
544738acb58Ssthen 		case IEEE80211_ELEMID_CSA:
545958b7e45Ssthen 			ELEM_CHECK(3);
546738acb58Ssthen 			printf(", csa (chan %u count %u%s)", data[1], data[2],
547738acb58Ssthen 			    (data[0] == 1) ? " noTX" : "");
548738acb58Ssthen 			break;
54912a08440Sreyk 		case IEEE80211_ELEMID_ERP:
55012a08440Sreyk 			printf(", erp");
55112a08440Sreyk 			if (vflag)
55212a08440Sreyk 				ieee80211_print_element(data, len);
55312a08440Sreyk 			break;
55412a08440Sreyk 		case IEEE80211_ELEMID_RSN:
55512a08440Sreyk 			printf(", rsn");
55612a08440Sreyk 			if (vflag)
55712a08440Sreyk 				ieee80211_print_element(data, len);
55812a08440Sreyk 			break;
55912a08440Sreyk 		case IEEE80211_ELEMID_XRATES:
56012a08440Sreyk 			printf(", xrates");
56112a08440Sreyk 			if (!vflag)
56212a08440Sreyk 				break;
56312a08440Sreyk 			for (i = len; i > 0; i--, data++)
56412a08440Sreyk 				printf(" %uM",
56512a08440Sreyk 				    (data[0] & IEEE80211_RATE_VAL) / 2);
56612a08440Sreyk 			break;
5678138faddSstsp 		case IEEE80211_ELEMID_TPC_REPORT:
5688138faddSstsp 			printf(", tpcreport");
56912a08440Sreyk 			if (vflag)
57012a08440Sreyk 				ieee80211_print_element(data, len);
57112a08440Sreyk 			break;
5728138faddSstsp 		case IEEE80211_ELEMID_TPC_REQUEST:
5738138faddSstsp 			printf(", tpcrequest");
57412a08440Sreyk 			if (vflag)
57512a08440Sreyk 				ieee80211_print_element(data, len);
57612a08440Sreyk 			break;
5771e3bf20aSstsp 		case IEEE80211_ELEMID_HTCAPS:
5781e3bf20aSstsp 			printf(", htcaps");
5791e3bf20aSstsp 			if (vflag)
5801e3bf20aSstsp 				ieee80211_print_htcaps(data, len);
5811e3bf20aSstsp 			break;
582*36fa064cSstsp 		case IEEE80211_ELEMID_HTOP:
583*36fa064cSstsp 			printf(", htop");
584*36fa064cSstsp 			if (vflag)
585*36fa064cSstsp 				ieee80211_print_htop(data, len);
586*36fa064cSstsp 			break;
58777734011Sstsp 		case IEEE80211_ELEMID_POWER_CONSTRAINT:
58877734011Sstsp 			ELEM_CHECK(1);
58977734011Sstsp 			printf(", power constraint %udB", data[0]);
59077734011Sstsp 			break;
5918f0a8537Sstsp 		case IEEE80211_ELEMID_QBSS_LOAD:
5928f0a8537Sstsp 			ELEM_CHECK(5);
5938f0a8537Sstsp 			printf(", %u stations, %d%% utilization, "
5948f0a8537Sstsp 			    "admission capacity %uus/s",
5958f0a8537Sstsp 			    (data[0] | data[1] << 8),
5968f0a8537Sstsp 			    (data[2] * 100) / 255,
5978f0a8537Sstsp 			    (data[3] | data[4] << 8) / 32);
5988f0a8537Sstsp 			break;
59912a08440Sreyk 		case IEEE80211_ELEMID_VENDOR:
60012a08440Sreyk 			printf(", vendor");
60112a08440Sreyk 			if (vflag)
60212a08440Sreyk 				ieee80211_print_element(data, len);
60312a08440Sreyk 			break;
60412a08440Sreyk 		default:
60512a08440Sreyk 			printf(", %u:%u", (u_int) *frm, len);
60612a08440Sreyk 			if (vflag)
60712a08440Sreyk 				ieee80211_print_element(data, len);
60812a08440Sreyk 			break;
60912a08440Sreyk 		}
61012a08440Sreyk 		frm += len + 2;
61112a08440Sreyk 
61212a08440Sreyk 		if (frm >= snapend)
61312a08440Sreyk 			break;
61412a08440Sreyk 	}
61512a08440Sreyk 
61612a08440Sreyk #undef ELEM_CHECK
61712a08440Sreyk 
61812a08440Sreyk 	return (0);
61912a08440Sreyk 
62012a08440Sreyk  trunc:
62112a08440Sreyk 	/* Truncated elements in frame */
62212a08440Sreyk 	return (1);
62312a08440Sreyk }
62412a08440Sreyk 
62512a08440Sreyk int
62612a08440Sreyk ieee80211_frame(struct ieee80211_frame *wh, u_int len)
62712a08440Sreyk {
62812a08440Sreyk 	u_int8_t subtype, type, *frm;
62912a08440Sreyk 
63012a08440Sreyk 	TCARR(wh->i_fc);
63112a08440Sreyk 
63212a08440Sreyk 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
63312a08440Sreyk 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
63412a08440Sreyk 
63512a08440Sreyk 	frm = (u_int8_t *)&wh[1];
63612a08440Sreyk 
637ab7e388eSclaudio 	if (vflag)
638ab7e388eSclaudio 		printb(" flags", wh->i_fc[1], IEEE80211_FC1_BITS);
639ab7e388eSclaudio 
64012a08440Sreyk 	switch (type) {
64112a08440Sreyk 	case IEEE80211_FC0_TYPE_DATA:
642ab7e388eSclaudio 		printf(": %s: ", ieee80211_data_subtype_name[
643ab7e388eSclaudio 		    subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
644b72abdefSreyk 		ieee80211_data(wh, len);
64512a08440Sreyk 		break;
64612a08440Sreyk 	case IEEE80211_FC0_TYPE_MGT:
64712a08440Sreyk 		printf(": %s", ieee80211_mgt_subtype_name[
64812a08440Sreyk 		    subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
64912a08440Sreyk 		switch (subtype) {
65012a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_BEACON:
65112a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
65212a08440Sreyk 			if (ieee80211_elements(wh, len) != 0)
65312a08440Sreyk 				goto trunc;
65412a08440Sreyk 			break;
65512a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_AUTH:
65612a08440Sreyk 			TCHECK2(*frm, 2);		/* Auth Algorithm */
65712a08440Sreyk 			switch (IEEE80211_AUTH_ALGORITHM(frm)) {
65812a08440Sreyk 			case IEEE80211_AUTH_ALG_OPEN:
65912a08440Sreyk 				TCHECK2(*frm, 4);	/* Auth Transaction */
66012a08440Sreyk 				switch (IEEE80211_AUTH_TRANSACTION(frm)) {
66112a08440Sreyk 				case IEEE80211_AUTH_OPEN_REQUEST:
66212a08440Sreyk 					printf(" request");
66312a08440Sreyk 					break;
66412a08440Sreyk 				case IEEE80211_AUTH_OPEN_RESPONSE:
66512a08440Sreyk 					printf(" response");
66612a08440Sreyk 					break;
66712a08440Sreyk 				}
66812a08440Sreyk 				break;
66912a08440Sreyk 			case IEEE80211_AUTH_ALG_SHARED:
67012a08440Sreyk 				TCHECK2(*frm, 4);	/* Auth Transaction */
67112a08440Sreyk 				switch (IEEE80211_AUTH_TRANSACTION(frm)) {
67212a08440Sreyk 				case IEEE80211_AUTH_SHARED_REQUEST:
67312a08440Sreyk 					printf(" request");
67412a08440Sreyk 					break;
67512a08440Sreyk 				case IEEE80211_AUTH_SHARED_CHALLENGE:
67612a08440Sreyk 					printf(" challenge");
67712a08440Sreyk 					break;
67812a08440Sreyk 				case IEEE80211_AUTH_SHARED_RESPONSE:
67912a08440Sreyk 					printf(" response");
68012a08440Sreyk 					break;
68112a08440Sreyk 				case IEEE80211_AUTH_SHARED_PASS:
68212a08440Sreyk 					printf(" pass");
68312a08440Sreyk 					break;
68412a08440Sreyk 				}
68512a08440Sreyk 				break;
68612a08440Sreyk 			case IEEE80211_AUTH_ALG_LEAP:
68712a08440Sreyk 				printf(" (leap)");
68812a08440Sreyk 				break;
68912a08440Sreyk 			}
69012a08440Sreyk 			break;
69118786664Sclaudio 		case IEEE80211_FC0_SUBTYPE_DEAUTH:
69218786664Sclaudio 		case IEEE80211_FC0_SUBTYPE_DISASSOC:
69318786664Sclaudio 			TCHECK2(*frm, 2);		/* Reason Code */
69418786664Sclaudio 			ieee80211_reason(frm[0] | (frm[1] << 8));
69518786664Sclaudio 			break;
69612a08440Sreyk 		}
69712a08440Sreyk 		break;
69812a08440Sreyk 	default:
69912a08440Sreyk 		printf(": type#%d", type);
70012a08440Sreyk 		break;
70112a08440Sreyk 	}
70212a08440Sreyk 
70312a08440Sreyk 	return (0);
70412a08440Sreyk 
70512a08440Sreyk  trunc:
70612a08440Sreyk 	/* Truncated 802.11 frame */
70712a08440Sreyk 	return (1);
70812a08440Sreyk }
70912a08440Sreyk 
71012a08440Sreyk u_int
71112a08440Sreyk ieee80211_any2ieee(u_int freq, u_int flags)
71212a08440Sreyk {
71312a08440Sreyk 	if (flags & IEEE80211_CHAN_2GHZ) {
71412a08440Sreyk 		if (freq == 2484)
71512a08440Sreyk 			return 14;
71612a08440Sreyk 		if (freq < 2484)
71712a08440Sreyk 			return (freq - 2407) / 5;
71812a08440Sreyk 		else
71912a08440Sreyk 			return 15 + ((freq - 2512) / 20);
72012a08440Sreyk 	} else if (flags & IEEE80211_CHAN_5GHZ) {
72112a08440Sreyk 		return (freq - 5000) / 5;
72212a08440Sreyk 	} else {
72312a08440Sreyk 		/* Assume channel is already an IEEE number */
72412a08440Sreyk 		return (freq);
72512a08440Sreyk 	}
72612a08440Sreyk }
72712a08440Sreyk 
72812a08440Sreyk int
72912a08440Sreyk ieee80211_print(struct ieee80211_frame *wh, u_int len)
73012a08440Sreyk {
73112a08440Sreyk 	if (eflag)
73212a08440Sreyk 		if (ieee80211_hdr(wh))
73312a08440Sreyk 			return (1);
73412a08440Sreyk 
73512a08440Sreyk 	printf("802.11");
73612a08440Sreyk 
73712a08440Sreyk 	return (ieee80211_frame(wh, len));
73812a08440Sreyk }
73912a08440Sreyk 
74012a08440Sreyk void
74112a08440Sreyk ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h,
74212a08440Sreyk     const u_char *p)
74312a08440Sreyk {
74412a08440Sreyk 	struct ieee80211_frame *wh = (struct ieee80211_frame*)p;
74512a08440Sreyk 
746c79cf170Sreyk 	if (!ieee80211_encap)
74712a08440Sreyk 		ts_print(&h->ts);
74812a08440Sreyk 
74912a08440Sreyk 	packetp = p;
75012a08440Sreyk 	snapend = p + h->caplen;
75112a08440Sreyk 
752a0774ae9Smglocker 	if (ieee80211_print(wh, (u_int)h->len) != 0)
75312a08440Sreyk 		printf("[|802.11]");
75412a08440Sreyk 
755c79cf170Sreyk 	if (!ieee80211_encap) {
75612a08440Sreyk 		if (xflag)
757a0774ae9Smglocker 			default_print(p, (u_int)h->len);
75812a08440Sreyk 		putchar('\n');
75912a08440Sreyk 	}
760c79cf170Sreyk }
76112a08440Sreyk 
76212a08440Sreyk void
76312a08440Sreyk ieee802_11_radio_if_print(u_char *user, const struct pcap_pkthdr *h,
76412a08440Sreyk     const u_char *p)
76512a08440Sreyk {
76612a08440Sreyk 	struct ieee80211_radiotap_header *rh =
76712a08440Sreyk 	    (struct ieee80211_radiotap_header*)p;
76812a08440Sreyk 	struct ieee80211_frame *wh;
76912a08440Sreyk 	u_int8_t *t;
77012a08440Sreyk 	u_int32_t present;
77112a08440Sreyk 	u_int len, rh_len;
772cce1ba42Sclaudio 	u_int16_t tmp;
77312a08440Sreyk 
774c79cf170Sreyk 	if (!ieee80211_encap)
77512a08440Sreyk 		ts_print(&h->ts);
77612a08440Sreyk 
77712a08440Sreyk 	packetp = p;
77812a08440Sreyk 	snapend = p + h->caplen;
77912a08440Sreyk 
78012a08440Sreyk 	TCHECK(*rh);
78112a08440Sreyk 
782a0774ae9Smglocker 	len = h->len;
78312a08440Sreyk 	rh_len = letoh16(rh->it_len);
78412a08440Sreyk 	if (rh->it_version != 0) {
785c79cf170Sreyk 		printf("[?radiotap + 802.11 v:%u]", rh->it_version);
78612a08440Sreyk 		goto out;
78712a08440Sreyk 	}
78812a08440Sreyk 
78912a08440Sreyk 	wh = (struct ieee80211_frame *)(p + rh_len);
79012a08440Sreyk 	if (len <= rh_len || ieee80211_print(wh, len - rh_len))
79112a08440Sreyk 		printf("[|802.11]");
79212a08440Sreyk 
79312a08440Sreyk 	t = (u_int8_t*)p + sizeof(struct ieee80211_radiotap_header);
79412a08440Sreyk 
79512a08440Sreyk 	if ((present = letoh32(rh->it_present)) == 0)
79612a08440Sreyk 		goto out;
79712a08440Sreyk 
79812a08440Sreyk 	printf(", <radiotap v%u", rh->it_version);
79912a08440Sreyk 
80012a08440Sreyk #define RADIOTAP(_x)	\
80112a08440Sreyk 	(present & (1 << IEEE80211_RADIOTAP_##_x))
80212a08440Sreyk 
80312a08440Sreyk 	if (RADIOTAP(TSFT)) {
804cce1ba42Sclaudio 		u_int64_t tsf;
805cce1ba42Sclaudio 
80612a08440Sreyk 		TCHECK2(*t, 8);
807cce1ba42Sclaudio 		bcopy(t, &tsf, sizeof(u_int64_t));
80812a08440Sreyk 		if (vflag > 1)
809cce1ba42Sclaudio 			printf(", tsf %llu", letoh64(tsf));
81012a08440Sreyk 		t += 8;
81112a08440Sreyk 	}
81212a08440Sreyk 
81312a08440Sreyk 	if (RADIOTAP(FLAGS)) {
81412a08440Sreyk 		u_int8_t flags = *(u_int8_t*)t;
815026ca542Sderaadt 		TCHECK2(*t, 1);
816026ca542Sderaadt 
81712a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_CFP)
81812a08440Sreyk 			printf(", CFP");
81912a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_SHORTPRE)
82012a08440Sreyk 			printf(", SHORTPRE");
82112a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_WEP)
82212a08440Sreyk 			printf(", WEP");
82312a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_FRAG)
82412a08440Sreyk 			printf(", FRAG");
82512a08440Sreyk 		t += 1;
82612a08440Sreyk 	}
82712a08440Sreyk 
82812a08440Sreyk 	if (RADIOTAP(RATE)) {
82912a08440Sreyk 		TCHECK2(*t, 1);
83012a08440Sreyk 		if (vflag)
83112a08440Sreyk 			printf(", %uMbit/s", (*(u_int8_t*)t) / 2);
83212a08440Sreyk 		t += 1;
83312a08440Sreyk 	}
83412a08440Sreyk 
83512a08440Sreyk 	if (RADIOTAP(CHANNEL)) {
83612a08440Sreyk 		u_int16_t freq, flags;
83712a08440Sreyk 		TCHECK2(*t, 2);
83812a08440Sreyk 
839cce1ba42Sclaudio 		bcopy(t, &freq, sizeof(u_int16_t));
840cce1ba42Sclaudio 		freq = letoh16(freq);
84112a08440Sreyk 		t += 2;
84212a08440Sreyk 		TCHECK2(*t, 2);
843cce1ba42Sclaudio 		bcopy(t, &flags, sizeof(u_int16_t));
844cce1ba42Sclaudio 		flags = letoh16(flags);
84512a08440Sreyk 		t += 2;
84612a08440Sreyk 
84712a08440Sreyk 		printf(", chan %u", ieee80211_any2ieee(freq, flags));
84812a08440Sreyk 
84912a08440Sreyk 		if (flags & IEEE80211_CHAN_DYN &&
85012a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
85112a08440Sreyk 			printf(", 11g");
85212a08440Sreyk 		else if (flags & IEEE80211_CHAN_CCK &&
85312a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
85412a08440Sreyk 			printf(", 11b");
85512a08440Sreyk 		else if (flags & IEEE80211_CHAN_OFDM &&
85612a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
85712a08440Sreyk 			printf(", 11G");
85812a08440Sreyk 		else if (flags & IEEE80211_CHAN_OFDM &&
85912a08440Sreyk 		    flags & IEEE80211_CHAN_5GHZ)
86012a08440Sreyk 			printf(", 11a");
86112a08440Sreyk 
86212a08440Sreyk 		if (flags & IEEE80211_CHAN_TURBO)
86312a08440Sreyk 			printf(", TURBO");
86412a08440Sreyk 		if (flags & IEEE80211_CHAN_XR)
86512a08440Sreyk 			printf(", XR");
86612a08440Sreyk 	}
86712a08440Sreyk 
86812a08440Sreyk 	if (RADIOTAP(FHSS)) {
86912a08440Sreyk 		TCHECK2(*t, 2);
87012a08440Sreyk 		printf(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1);
87112a08440Sreyk 		t += 2;
87212a08440Sreyk 	}
87312a08440Sreyk 
87412a08440Sreyk 	if (RADIOTAP(DBM_ANTSIGNAL)) {
87512a08440Sreyk 		TCHECK(*t);
87612a08440Sreyk 		printf(", sig %ddBm", *(int8_t*)t);
87712a08440Sreyk 		t += 1;
87812a08440Sreyk 	}
87912a08440Sreyk 
88012a08440Sreyk 	if (RADIOTAP(DBM_ANTNOISE)) {
88112a08440Sreyk 		TCHECK(*t);
88212a08440Sreyk 		printf(", noise %ddBm", *(int8_t*)t);
88312a08440Sreyk 		t += 1;
88412a08440Sreyk 	}
88512a08440Sreyk 
88612a08440Sreyk 	if (RADIOTAP(LOCK_QUALITY)) {
88712a08440Sreyk 		TCHECK2(*t, 2);
888cce1ba42Sclaudio 		if (vflag) {
889cce1ba42Sclaudio 			bcopy(t, &tmp, sizeof(u_int16_t));
890cce1ba42Sclaudio 			printf(", quality %u", letoh16(tmp));
891cce1ba42Sclaudio 		}
89212a08440Sreyk 		t += 2;
89312a08440Sreyk 	}
89412a08440Sreyk 
89512a08440Sreyk 	if (RADIOTAP(TX_ATTENUATION)) {
89612a08440Sreyk 		TCHECK2(*t, 2);
897cce1ba42Sclaudio 		if (vflag) {
898cce1ba42Sclaudio 			bcopy(t, &tmp, sizeof(u_int16_t));
899cce1ba42Sclaudio 			printf(", txatt %u", letoh16(tmp));
900cce1ba42Sclaudio 		}
90112a08440Sreyk 		t += 2;
90212a08440Sreyk 	}
90312a08440Sreyk 
90412a08440Sreyk 	if (RADIOTAP(DB_TX_ATTENUATION)) {
90512a08440Sreyk 		TCHECK2(*t, 2);
906cce1ba42Sclaudio 		if (vflag) {
907cce1ba42Sclaudio 			bcopy(t, &tmp, sizeof(u_int16_t));
908cce1ba42Sclaudio 			printf(", txatt %udB", letoh16(tmp));
909cce1ba42Sclaudio 		}
91012a08440Sreyk 		t += 2;
91112a08440Sreyk 	}
91212a08440Sreyk 
91312a08440Sreyk 	if (RADIOTAP(DBM_TX_POWER)) {
91412a08440Sreyk 		TCHECK(*t);
91512a08440Sreyk 		printf(", txpower %ddBm", *(int8_t*)t);
91612a08440Sreyk 		t += 1;
91712a08440Sreyk 	}
91812a08440Sreyk 
91912a08440Sreyk 	if (RADIOTAP(ANTENNA)) {
92012a08440Sreyk 		TCHECK(*t);
92112a08440Sreyk 		if (vflag)
92212a08440Sreyk 			printf(", antenna %u", *(u_int8_t*)t);
92312a08440Sreyk 		t += 1;
92412a08440Sreyk 	}
92512a08440Sreyk 
92612a08440Sreyk 	if (RADIOTAP(DB_ANTSIGNAL)) {
92712a08440Sreyk 		TCHECK(*t);
92812a08440Sreyk 		printf(", signal %udB", *(u_int8_t*)t);
92912a08440Sreyk 		t += 1;
93012a08440Sreyk 	}
93112a08440Sreyk 
93212a08440Sreyk 	if (RADIOTAP(DB_ANTNOISE)) {
93312a08440Sreyk 		TCHECK(*t);
93412a08440Sreyk 		printf(", noise %udB", *(u_int8_t*)t);
93512a08440Sreyk 		t += 1;
93612a08440Sreyk 	}
93712a08440Sreyk 
93812a08440Sreyk 	if (RADIOTAP(FCS)) {
93912a08440Sreyk 		TCHECK2(*t, 4);
940cce1ba42Sclaudio 		if (vflag) {
941cce1ba42Sclaudio 			u_int32_t fcs;
942cce1ba42Sclaudio 			bcopy(t, &fcs, sizeof(u_int32_t));
943cce1ba42Sclaudio 			printf(", fcs %08x", letoh32(fcs));
944cce1ba42Sclaudio 		}
94512a08440Sreyk 		t += 4;
94612a08440Sreyk 	}
94712a08440Sreyk 
9486fc94ee3Sreyk 	if (RADIOTAP(RSSI)) {
9496fc94ee3Sreyk 		u_int8_t rssi, max_rssi;
9506fc94ee3Sreyk 		TCHECK(*t);
9516fc94ee3Sreyk 		rssi = *(u_int8_t*)t;
9526fc94ee3Sreyk 		t += 1;
9536fc94ee3Sreyk 		TCHECK(*t);
9546fc94ee3Sreyk 		max_rssi = *(u_int8_t*)t;
9556fc94ee3Sreyk 		t += 1;
9566fc94ee3Sreyk 
9576fc94ee3Sreyk 		printf(", rssi %u/%u", rssi, max_rssi);
9586fc94ee3Sreyk 	}
9596fc94ee3Sreyk 
96012a08440Sreyk #undef RADIOTAP
96112a08440Sreyk 
96212a08440Sreyk 	putchar('>');
96312a08440Sreyk 	goto out;
96412a08440Sreyk 
96512a08440Sreyk  trunc:
96612a08440Sreyk 	/* Truncated frame */
96712a08440Sreyk 	printf("[|radiotap + 802.11]");
96812a08440Sreyk 
96912a08440Sreyk  out:
970c79cf170Sreyk 	if (!ieee80211_encap) {
97112a08440Sreyk 		if (xflag)
972a0774ae9Smglocker 			default_print(p, h->len);
97312a08440Sreyk 		putchar('\n');
97412a08440Sreyk 	}
975c79cf170Sreyk }
97618786664Sclaudio 
97718786664Sclaudio void
97818786664Sclaudio ieee80211_reason(u_int16_t reason)
97918786664Sclaudio {
98018786664Sclaudio 	if (!vflag)
98118786664Sclaudio 		return;
98218786664Sclaudio 
98318786664Sclaudio 	switch (reason) {
98418786664Sclaudio 	case IEEE80211_REASON_UNSPECIFIED:
98518786664Sclaudio 		printf(", unspecified failure");
98618786664Sclaudio 		break;
98718786664Sclaudio 	case IEEE80211_REASON_AUTH_EXPIRE:
98818786664Sclaudio 		printf(", authentication expired");
98918786664Sclaudio 		break;
99018786664Sclaudio 	case IEEE80211_REASON_AUTH_LEAVE:
99118786664Sclaudio 		printf(", deauth - station left");
99218786664Sclaudio 		break;
99318786664Sclaudio 	case IEEE80211_REASON_ASSOC_EXPIRE:
99418786664Sclaudio 		printf(", association expired");
99518786664Sclaudio 		break;
99618786664Sclaudio 	case IEEE80211_REASON_ASSOC_TOOMANY:
99718786664Sclaudio 		printf(", too many associated stations");
99818786664Sclaudio 		break;
99918786664Sclaudio 	case IEEE80211_REASON_NOT_AUTHED:
100018786664Sclaudio 		printf(", not authenticated");
100118786664Sclaudio 		break;
100218786664Sclaudio 	case IEEE80211_REASON_NOT_ASSOCED:
100318786664Sclaudio 		printf(", not associated");
100418786664Sclaudio 		break;
100518786664Sclaudio 	case IEEE80211_REASON_ASSOC_LEAVE:
100618786664Sclaudio 		printf(", disassociated - station left");
100718786664Sclaudio 		break;
100818786664Sclaudio 	case IEEE80211_REASON_ASSOC_NOT_AUTHED:
100918786664Sclaudio 		printf(", association but not authenticated");
101018786664Sclaudio 		break;
101118786664Sclaudio 	case IEEE80211_REASON_RSN_REQUIRED:
101218786664Sclaudio 		printf(", rsn required");
101318786664Sclaudio 		break;
101418786664Sclaudio 	case IEEE80211_REASON_RSN_INCONSISTENT:
101518786664Sclaudio 		printf(", rsn inconsistent");
101618786664Sclaudio 		break;
101718786664Sclaudio 	case IEEE80211_REASON_IE_INVALID:
101818786664Sclaudio 		printf(", ie invalid");
101918786664Sclaudio 		break;
102018786664Sclaudio 	case IEEE80211_REASON_MIC_FAILURE:
102118786664Sclaudio 		printf(", mic failure");
102218786664Sclaudio 		break;
102318786664Sclaudio 	default:
102418786664Sclaudio 		printf(", unknown reason %u", reason);
102518786664Sclaudio 	}
102618786664Sclaudio }
1027