xref: /openbsd/usr.sbin/tcpdump/print-802_11.c (revision d49cb46e)
1*d49cb46eScanacar /*	$OpenBSD: print-802_11.c,v 1.11 2007/07/02 22:09:01 canacar 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/param.h>
2012a08440Sreyk #include <sys/time.h>
2112a08440Sreyk #include <sys/socket.h>
2212a08440Sreyk #include <sys/file.h>
2312a08440Sreyk #include <sys/ioctl.h>
2412a08440Sreyk 
2512a08440Sreyk #include <net/if.h>
2612a08440Sreyk 
2712a08440Sreyk #include <netinet/in.h>
2812a08440Sreyk #include <netinet/in_systm.h>
2912a08440Sreyk #include <netinet/if_ether.h>
3012a08440Sreyk 
3112a08440Sreyk #include <net80211/ieee80211.h>
3212a08440Sreyk #include <net80211/ieee80211_radiotap.h>
3312a08440Sreyk 
3412a08440Sreyk #include <pcap.h>
3512a08440Sreyk #include <stdio.h>
3612a08440Sreyk #include <string.h>
3712a08440Sreyk 
3812a08440Sreyk #include "addrtoname.h"
3912a08440Sreyk #include "interface.h"
4012a08440Sreyk 
4112a08440Sreyk const char *ieee80211_mgt_subtype_name[] = {
4212a08440Sreyk 	"association request",
4312a08440Sreyk 	"association response",
4412a08440Sreyk 	"reassociation request",
4512a08440Sreyk 	"reassociation response",
4612a08440Sreyk 	"probe request",
4712a08440Sreyk 	"probe response",
4812a08440Sreyk 	"reserved#6",
4912a08440Sreyk 	"reserved#7",
5012a08440Sreyk 	"beacon",
5112a08440Sreyk 	"atim",
5212a08440Sreyk 	"disassociation",
5312a08440Sreyk 	"authentication",
5412a08440Sreyk 	"deauthentication",
5512a08440Sreyk 	"reserved#13",
5612a08440Sreyk 	"reserved#14",
5712a08440Sreyk 	"reserved#15"
5812a08440Sreyk };
5912a08440Sreyk 
6012a08440Sreyk int	 ieee80211_hdr(struct ieee80211_frame *);
61b72abdefSreyk int	 ieee80211_data(struct ieee80211_frame *, u_int);
6212a08440Sreyk void	 ieee80211_print_element(u_int8_t *, u_int);
6312a08440Sreyk void	 ieee80211_print_essid(u_int8_t *, u_int);
6412a08440Sreyk int	 ieee80211_elements(struct ieee80211_frame *, u_int);
6512a08440Sreyk int	 ieee80211_frame(struct ieee80211_frame *, u_int);
6612a08440Sreyk int	 ieee80211_print(struct ieee80211_frame *, u_int);
6712a08440Sreyk u_int	 ieee80211_any2ieee(u_int, u_int);
6818786664Sclaudio void	 ieee80211_reason(u_int16_t);
6912a08440Sreyk 
7012a08440Sreyk #define TCARR(a)	TCHECK2(*a, sizeof(a))
7112a08440Sreyk 
72c79cf170Sreyk int ieee80211_encap = 0;
73c79cf170Sreyk 
7412a08440Sreyk int
7512a08440Sreyk ieee80211_hdr(struct ieee80211_frame *wh)
7612a08440Sreyk {
7712a08440Sreyk 	struct ieee80211_frame_addr4 *w4;
7812a08440Sreyk 
7912a08440Sreyk 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
8012a08440Sreyk 	case IEEE80211_FC1_DIR_NODS:
8112a08440Sreyk 		TCARR(wh->i_addr2);
8212a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr2));
8312a08440Sreyk 		TCARR(wh->i_addr1);
8412a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr1));
8512a08440Sreyk 		TCARR(wh->i_addr3);
8612a08440Sreyk 		printf(", bssid %s", etheraddr_string(wh->i_addr3));
8712a08440Sreyk 		break;
8812a08440Sreyk 	case IEEE80211_FC1_DIR_TODS:
8912a08440Sreyk 		TCARR(wh->i_addr2);
9012a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr2));
9112a08440Sreyk 		TCARR(wh->i_addr3);
9212a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr3));
9312a08440Sreyk 		TCARR(wh->i_addr1);
9412a08440Sreyk 		printf(", bssid %s, > DS", etheraddr_string(wh->i_addr1));
9512a08440Sreyk 		break;
9612a08440Sreyk 	case IEEE80211_FC1_DIR_FROMDS:
9712a08440Sreyk 		TCARR(wh->i_addr3);
9812a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr3));
9912a08440Sreyk 		TCARR(wh->i_addr1);
10012a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr1));
10112a08440Sreyk 		TCARR(wh->i_addr2);
10212a08440Sreyk 		printf(", bssid %s, DS >", etheraddr_string(wh->i_addr2));
10312a08440Sreyk 		break;
10412a08440Sreyk 	case IEEE80211_FC1_DIR_DSTODS:
10512a08440Sreyk 		w4 = (struct ieee80211_frame_addr4 *) wh;
10612a08440Sreyk 		TCARR(w4->i_addr4);
10712a08440Sreyk 		printf("%s", etheraddr_string(w4->i_addr4));
10812a08440Sreyk 		TCARR(w4->i_addr3);
10912a08440Sreyk 		printf(" > %s", etheraddr_string(w4->i_addr3));
11012a08440Sreyk 		TCARR(w4->i_addr2);
11112a08440Sreyk 		printf(", bssid %s", etheraddr_string(w4->i_addr2));
11212a08440Sreyk 		TCARR(w4->i_addr1);
11312a08440Sreyk 		printf(" > %s, DS > DS", etheraddr_string(w4->i_addr1));
11412a08440Sreyk 		break;
11512a08440Sreyk 	}
11612a08440Sreyk 	if (vflag) {
117cce1ba42Sclaudio 		u_int16_t seq;
11812a08440Sreyk 		TCARR(wh->i_seq);
119cce1ba42Sclaudio 		bcopy(wh->i_seq, &seq, sizeof(u_int16_t));
120cce1ba42Sclaudio 		printf(" (seq %u): ", letoh16(seq));
12112a08440Sreyk 	} else
12212a08440Sreyk 		printf(": ");
12312a08440Sreyk 
12412a08440Sreyk 	return (0);
12512a08440Sreyk 
12612a08440Sreyk  trunc:
12712a08440Sreyk 	/* Truncated elements in frame */
12812a08440Sreyk 	return (1);
12912a08440Sreyk }
13012a08440Sreyk 
131b72abdefSreyk int
132b72abdefSreyk ieee80211_data(struct ieee80211_frame *wh, u_int len)
133b72abdefSreyk {
134b72abdefSreyk 	u_int8_t *t = (u_int8_t *)wh;
135*d49cb46eScanacar 	struct ieee80211_frame_addr4 *w4;
136b72abdefSreyk 	u_int datalen;
137b72abdefSreyk 
138*d49cb46eScanacar 	TCHECK(*wh);
139b72abdefSreyk 	t += sizeof(struct ieee80211_frame);
140b72abdefSreyk 	datalen = len - sizeof(struct ieee80211_frame);
141b72abdefSreyk 
142b72abdefSreyk 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
143b72abdefSreyk 	case IEEE80211_FC1_DIR_TODS:
144b72abdefSreyk 		llc_print(t, datalen, datalen, wh->i_addr2, wh->i_addr3);
145b72abdefSreyk 		break;
146b72abdefSreyk 	case IEEE80211_FC1_DIR_FROMDS:
147b72abdefSreyk 		llc_print(t, datalen, datalen, wh->i_addr3, wh->i_addr1);
148b72abdefSreyk 		break;
149b72abdefSreyk 	case IEEE80211_FC1_DIR_NODS:
150*d49cb46eScanacar 		llc_print(t, datalen, datalen, wh->i_addr2, wh->i_addr1);
151*d49cb46eScanacar 		break;
152b72abdefSreyk 	case IEEE80211_FC1_DIR_DSTODS:
153*d49cb46eScanacar 		w4 = (struct ieee80211_frame_addr4 *) wh;
154*d49cb46eScanacar 		TCHECK(*w4);
155*d49cb46eScanacar 		t = (u_int8_t *) (w4 + 1);
156*d49cb46eScanacar 		datalen = len - sizeof(*w4);
157*d49cb46eScanacar 		llc_print(t, datalen, datalen, w4->i_addr4, w4->i_addr3);
158b72abdefSreyk 		break;
159b72abdefSreyk 	}
160b72abdefSreyk 
161b72abdefSreyk 	return (0);
162b72abdefSreyk 
163b72abdefSreyk  trunc:
164b72abdefSreyk 	/* Truncated elements in frame */
165b72abdefSreyk 	return (1);
166b72abdefSreyk }
167b72abdefSreyk 
16812a08440Sreyk /* Caller checks len */
16912a08440Sreyk void
17012a08440Sreyk ieee80211_print_element(u_int8_t *data, u_int len)
17112a08440Sreyk {
17212a08440Sreyk 	u_int8_t *p;
1739cbdb746Sderaadt 	int i;
17412a08440Sreyk 
17512a08440Sreyk 	printf(" 0x");
1769cbdb746Sderaadt 	for (i = 0, p = data; i < len; i++, p++)
17712a08440Sreyk 		printf("%02x", *p);
17812a08440Sreyk }
17912a08440Sreyk 
18012a08440Sreyk /* Caller checks len */
18112a08440Sreyk void
18212a08440Sreyk ieee80211_print_essid(u_int8_t *essid, u_int len)
18312a08440Sreyk {
18412a08440Sreyk 	u_int8_t *p;
1859cbdb746Sderaadt 	int i;
18612a08440Sreyk 
18712a08440Sreyk 	if (len > IEEE80211_NWID_LEN)
18812a08440Sreyk 		len = IEEE80211_NWID_LEN;
18912a08440Sreyk 
19012a08440Sreyk 	/* determine printable or not */
19112a08440Sreyk 	for (i = 0, p = essid; i < len; i++, p++) {
19212a08440Sreyk 		if (*p < ' ' || *p > 0x7e)
19312a08440Sreyk 			break;
19412a08440Sreyk 	}
19512a08440Sreyk 	if (i == len) {
19612a08440Sreyk 		printf(" (");
19712a08440Sreyk 		for (i = 0, p = essid; i < len; i++, p++)
19812a08440Sreyk 			putchar(*p);
19912a08440Sreyk 		putchar(')');
2009cbdb746Sderaadt 	} else
20112a08440Sreyk 		ieee80211_print_element(essid, len);
20212a08440Sreyk }
20312a08440Sreyk 
20412a08440Sreyk int
20512a08440Sreyk ieee80211_elements(struct ieee80211_frame *wh, u_int flen)
20612a08440Sreyk {
20712a08440Sreyk 	u_int8_t *buf, *frm;
208cce1ba42Sclaudio 	u_int64_t tstamp;
209cce1ba42Sclaudio 	u_int16_t bintval, capinfo;
21012a08440Sreyk 	int i;
21112a08440Sreyk 
21212a08440Sreyk 	buf = (u_int8_t *)wh;
21312a08440Sreyk 	frm = (u_int8_t *)&wh[1];
21412a08440Sreyk 
2150a05c5bfSreyk 	TCHECK2(*frm, 8);
216cce1ba42Sclaudio 	bcopy(frm, &tstamp, sizeof(u_int64_t));
21712a08440Sreyk 	frm += 8;
21812a08440Sreyk 
21912a08440Sreyk 	if (vflag > 1)
220cce1ba42Sclaudio 		printf(", timestamp %llu", letoh64(tstamp));
22112a08440Sreyk 
2220a05c5bfSreyk 	TCHECK2(*frm, 2);
223cce1ba42Sclaudio 	bcopy(frm, &bintval, sizeof(u_int16_t));
22412a08440Sreyk 	frm += 2;
22512a08440Sreyk 
22612a08440Sreyk 	if (vflag > 1)
227cce1ba42Sclaudio 		printf(", interval %u", letoh16(bintval));
22812a08440Sreyk 
2290a05c5bfSreyk 	TCHECK2(*frm, 2);
230cce1ba42Sclaudio 	bcopy(frm, &capinfo, sizeof(u_int16_t));
23112a08440Sreyk 	frm += 2;
23212a08440Sreyk 
23312a08440Sreyk 	if (vflag)
234cce1ba42Sclaudio 		printb(", caps", letoh16(capinfo),
23512a08440Sreyk 		    IEEE80211_CAPINFO_BITS);
23612a08440Sreyk 
23712a08440Sreyk 	while (TTEST2(*frm, 2)) {
23812a08440Sreyk 		u_int len = frm[1];
23912a08440Sreyk 		u_int8_t *data = frm + 2;
24012a08440Sreyk 
24112a08440Sreyk 		if (!TTEST2(*data, len))
24212a08440Sreyk 			break;
24312a08440Sreyk 
24412a08440Sreyk #define ELEM_CHECK(l)	if (len != l) break
24512a08440Sreyk 
24612a08440Sreyk 		switch (*frm) {
24712a08440Sreyk 		case IEEE80211_ELEMID_SSID:
24812a08440Sreyk 			printf(", ssid");
24912a08440Sreyk 			ieee80211_print_essid(data, len);
25012a08440Sreyk 			break;
25112a08440Sreyk 		case IEEE80211_ELEMID_RATES:
25212a08440Sreyk 			printf(", rates");
25312a08440Sreyk 			if (!vflag)
25412a08440Sreyk 				break;
25512a08440Sreyk 			for (i = len; i > 0; i--, data++)
25612a08440Sreyk 				printf(" %uM",
25712a08440Sreyk 				    (data[0] & IEEE80211_RATE_VAL) / 2);
25812a08440Sreyk 			break;
25912a08440Sreyk 		case IEEE80211_ELEMID_FHPARMS:
26012a08440Sreyk 			ELEM_CHECK(5);
26112a08440Sreyk 			printf(", fh (dwell %u, chan %u, index %u)",
26212a08440Sreyk 			    (data[1] << 8) | data[0],
26312a08440Sreyk 			    (data[2] - 1) * 80 + data[3],	/* FH_CHAN */
26412a08440Sreyk 			    data[4]);
26512a08440Sreyk 			break;
26612a08440Sreyk 		case IEEE80211_ELEMID_DSPARMS:
26712a08440Sreyk 			ELEM_CHECK(1);
26812a08440Sreyk 			printf(", ds");
26912a08440Sreyk 			if (vflag)
27012a08440Sreyk 				printf(" (chan %u)", data[0]);
27112a08440Sreyk 			break;
27212a08440Sreyk 		case IEEE80211_ELEMID_CFPARMS:
27312a08440Sreyk 			printf(", cf");
27412a08440Sreyk 			if (vflag)
27512a08440Sreyk 				ieee80211_print_element(data, len);
27612a08440Sreyk 			break;
27712a08440Sreyk 		case IEEE80211_ELEMID_TIM:
27812a08440Sreyk 			printf(", tim");
27912a08440Sreyk 			if (vflag)
28012a08440Sreyk 				ieee80211_print_element(data, len);
28112a08440Sreyk 			break;
28212a08440Sreyk 		case IEEE80211_ELEMID_IBSSPARMS:
28312a08440Sreyk 			printf(", ibss");
28412a08440Sreyk 			if (vflag)
28512a08440Sreyk 				ieee80211_print_element(data, len);
28612a08440Sreyk 			break;
28712a08440Sreyk 		case IEEE80211_ELEMID_COUNTRY:
28812a08440Sreyk 			printf(", country");
28912a08440Sreyk 			for (i = len; i > 0; i--, data++)
29012a08440Sreyk 				printf(" %u", data[0]);
29112a08440Sreyk 			break;
29212a08440Sreyk 		case IEEE80211_ELEMID_CHALLENGE:
29312a08440Sreyk 			printf(", challenge");
29412a08440Sreyk 			if (vflag)
29512a08440Sreyk 				ieee80211_print_element(data, len);
29612a08440Sreyk 			break;
29712a08440Sreyk 		case IEEE80211_ELEMID_ERP:
29812a08440Sreyk 			printf(", erp");
29912a08440Sreyk 			if (vflag)
30012a08440Sreyk 				ieee80211_print_element(data, len);
30112a08440Sreyk 			break;
30212a08440Sreyk 		case IEEE80211_ELEMID_RSN:
30312a08440Sreyk 			printf(", rsn");
30412a08440Sreyk 			if (vflag)
30512a08440Sreyk 				ieee80211_print_element(data, len);
30612a08440Sreyk 			break;
30712a08440Sreyk 		case IEEE80211_ELEMID_XRATES:
30812a08440Sreyk 			printf(", xrates");
30912a08440Sreyk 			if (!vflag)
31012a08440Sreyk 				break;
31112a08440Sreyk 			for (i = len; i > 0; i--, data++)
31212a08440Sreyk 				printf(" %uM",
31312a08440Sreyk 				    (data[0] & IEEE80211_RATE_VAL) / 2);
31412a08440Sreyk 			break;
31512a08440Sreyk 		case IEEE80211_ELEMID_TPC:
31612a08440Sreyk 			printf(", tpc");
31712a08440Sreyk 			if (vflag)
31812a08440Sreyk 				ieee80211_print_element(data, len);
31912a08440Sreyk 			break;
32012a08440Sreyk 		case IEEE80211_ELEMID_CCKM:
32112a08440Sreyk 			printf(", cckm");
32212a08440Sreyk 			if (vflag)
32312a08440Sreyk 				ieee80211_print_element(data, len);
32412a08440Sreyk 			break;
32512a08440Sreyk 		case IEEE80211_ELEMID_VENDOR:
32612a08440Sreyk 			printf(", vendor");
32712a08440Sreyk 			if (vflag)
32812a08440Sreyk 				ieee80211_print_element(data, len);
32912a08440Sreyk 			break;
33012a08440Sreyk 		default:
33112a08440Sreyk 			printf(", %u:%u", (u_int) *frm, len);
33212a08440Sreyk 			if (vflag)
33312a08440Sreyk 				ieee80211_print_element(data, len);
33412a08440Sreyk 			break;
33512a08440Sreyk 		}
33612a08440Sreyk 		frm += len + 2;
33712a08440Sreyk 
33812a08440Sreyk 		if (frm >= snapend)
33912a08440Sreyk 			break;
34012a08440Sreyk 	}
34112a08440Sreyk 
34212a08440Sreyk #undef ELEM_CHECK
34312a08440Sreyk 
34412a08440Sreyk 	return (0);
34512a08440Sreyk 
34612a08440Sreyk  trunc:
34712a08440Sreyk 	/* Truncated elements in frame */
34812a08440Sreyk 	return (1);
34912a08440Sreyk }
35012a08440Sreyk 
35112a08440Sreyk int
35212a08440Sreyk ieee80211_frame(struct ieee80211_frame *wh, u_int len)
35312a08440Sreyk {
35412a08440Sreyk 	u_int8_t subtype, type, *frm;
35512a08440Sreyk 
35612a08440Sreyk 	TCARR(wh->i_fc);
35712a08440Sreyk 
35812a08440Sreyk 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
35912a08440Sreyk 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
36012a08440Sreyk 
36112a08440Sreyk 	frm = (u_int8_t *)&wh[1];
36212a08440Sreyk 
36312a08440Sreyk 	switch (type) {
36412a08440Sreyk 	case IEEE80211_FC0_TYPE_DATA:
365b72abdefSreyk 		printf(": data: ");
366b72abdefSreyk 		ieee80211_data(wh, len);
36712a08440Sreyk 		break;
36812a08440Sreyk 	case IEEE80211_FC0_TYPE_MGT:
36912a08440Sreyk 		printf(": %s", ieee80211_mgt_subtype_name[
37012a08440Sreyk 		    subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
37112a08440Sreyk 		switch (subtype) {
37212a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_BEACON:
37312a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
37412a08440Sreyk 			if (ieee80211_elements(wh, len) != 0)
37512a08440Sreyk 				goto trunc;
37612a08440Sreyk 			break;
37712a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_AUTH:
37812a08440Sreyk 			TCHECK2(*frm, 2);		/* Auth Algorithm */
37912a08440Sreyk 			switch (IEEE80211_AUTH_ALGORITHM(frm)) {
38012a08440Sreyk 			case IEEE80211_AUTH_ALG_OPEN:
38112a08440Sreyk 				TCHECK2(*frm, 4);	/* Auth Transaction */
38212a08440Sreyk 				switch (IEEE80211_AUTH_TRANSACTION(frm)) {
38312a08440Sreyk 				case IEEE80211_AUTH_OPEN_REQUEST:
38412a08440Sreyk 					printf(" request");
38512a08440Sreyk 					break;
38612a08440Sreyk 				case IEEE80211_AUTH_OPEN_RESPONSE:
38712a08440Sreyk 					printf(" response");
38812a08440Sreyk 					break;
38912a08440Sreyk 				}
39012a08440Sreyk 				break;
39112a08440Sreyk 			case IEEE80211_AUTH_ALG_SHARED:
39212a08440Sreyk 				TCHECK2(*frm, 4);	/* Auth Transaction */
39312a08440Sreyk 				switch (IEEE80211_AUTH_TRANSACTION(frm)) {
39412a08440Sreyk 				case IEEE80211_AUTH_SHARED_REQUEST:
39512a08440Sreyk 					printf(" request");
39612a08440Sreyk 					break;
39712a08440Sreyk 				case IEEE80211_AUTH_SHARED_CHALLENGE:
39812a08440Sreyk 					printf(" challenge");
39912a08440Sreyk 					break;
40012a08440Sreyk 				case IEEE80211_AUTH_SHARED_RESPONSE:
40112a08440Sreyk 					printf(" response");
40212a08440Sreyk 					break;
40312a08440Sreyk 				case IEEE80211_AUTH_SHARED_PASS:
40412a08440Sreyk 					printf(" pass");
40512a08440Sreyk 					break;
40612a08440Sreyk 				}
40712a08440Sreyk 				break;
40812a08440Sreyk 			case IEEE80211_AUTH_ALG_LEAP:
40912a08440Sreyk 				printf(" (leap)");
41012a08440Sreyk 				break;
41112a08440Sreyk 			}
41212a08440Sreyk 			break;
41318786664Sclaudio 		case IEEE80211_FC0_SUBTYPE_DEAUTH:
41418786664Sclaudio 		case IEEE80211_FC0_SUBTYPE_DISASSOC:
41518786664Sclaudio 			TCHECK2(*frm, 2);		/* Reason Code */
41618786664Sclaudio 			ieee80211_reason(frm[0] | (frm[1] << 8));
41718786664Sclaudio 			break;
41812a08440Sreyk 		}
41912a08440Sreyk 		break;
42012a08440Sreyk 	default:
42112a08440Sreyk 		printf(": type#%d", type);
42212a08440Sreyk 		break;
42312a08440Sreyk 	}
42412a08440Sreyk 
42512a08440Sreyk 	if (wh->i_fc[1] & IEEE80211_FC1_WEP)
42612a08440Sreyk 		printf(", WEP");
42712a08440Sreyk 
42812a08440Sreyk 	return (0);
42912a08440Sreyk 
43012a08440Sreyk  trunc:
43112a08440Sreyk 	/* Truncated 802.11 frame */
43212a08440Sreyk 	return (1);
43312a08440Sreyk }
43412a08440Sreyk 
43512a08440Sreyk u_int
43612a08440Sreyk ieee80211_any2ieee(u_int freq, u_int flags)
43712a08440Sreyk {
43812a08440Sreyk 	if (flags & IEEE80211_CHAN_2GHZ) {
43912a08440Sreyk 		if (freq == 2484)
44012a08440Sreyk 			return 14;
44112a08440Sreyk 		if (freq < 2484)
44212a08440Sreyk 			return (freq - 2407) / 5;
44312a08440Sreyk 		else
44412a08440Sreyk 			return 15 + ((freq - 2512) / 20);
44512a08440Sreyk 	} else if (flags & IEEE80211_CHAN_5GHZ) {
44612a08440Sreyk 		return (freq - 5000) / 5;
44712a08440Sreyk 	} else {
44812a08440Sreyk 		/* Assume channel is already an IEEE number */
44912a08440Sreyk 		return (freq);
45012a08440Sreyk 	}
45112a08440Sreyk }
45212a08440Sreyk 
45312a08440Sreyk int
45412a08440Sreyk ieee80211_print(struct ieee80211_frame *wh, u_int len)
45512a08440Sreyk {
45612a08440Sreyk 	if (eflag)
45712a08440Sreyk 		if (ieee80211_hdr(wh))
45812a08440Sreyk 			return (1);
45912a08440Sreyk 
46012a08440Sreyk 	printf("802.11");
46112a08440Sreyk 
46212a08440Sreyk 	return (ieee80211_frame(wh, len));
46312a08440Sreyk }
46412a08440Sreyk 
46512a08440Sreyk void
46612a08440Sreyk ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h,
46712a08440Sreyk     const u_char *p)
46812a08440Sreyk {
46912a08440Sreyk 	struct ieee80211_frame *wh = (struct ieee80211_frame*)p;
47012a08440Sreyk 
471c79cf170Sreyk 	if (!ieee80211_encap)
47212a08440Sreyk 		ts_print(&h->ts);
47312a08440Sreyk 
47412a08440Sreyk 	packetp = p;
47512a08440Sreyk 	snapend = p + h->caplen;
47612a08440Sreyk 
47712a08440Sreyk 	if (ieee80211_print(wh, (u_int)h->caplen) != 0)
47812a08440Sreyk 		printf("[|802.11]");
47912a08440Sreyk 
480c79cf170Sreyk 	if (!ieee80211_encap) {
48112a08440Sreyk 		if (xflag)
48212a08440Sreyk 			default_print(p, (u_int)h->caplen);
48312a08440Sreyk 		putchar('\n');
48412a08440Sreyk 	}
485c79cf170Sreyk }
48612a08440Sreyk 
48712a08440Sreyk void
48812a08440Sreyk ieee802_11_radio_if_print(u_char *user, const struct pcap_pkthdr *h,
48912a08440Sreyk     const u_char *p)
49012a08440Sreyk {
49112a08440Sreyk 	struct ieee80211_radiotap_header *rh =
49212a08440Sreyk 	    (struct ieee80211_radiotap_header*)p;
49312a08440Sreyk 	struct ieee80211_frame *wh;
49412a08440Sreyk 	u_int8_t *t;
49512a08440Sreyk 	u_int32_t present;
49612a08440Sreyk 	u_int len, rh_len;
497cce1ba42Sclaudio 	u_int16_t tmp;
49812a08440Sreyk 
499c79cf170Sreyk 	if (!ieee80211_encap)
50012a08440Sreyk 		ts_print(&h->ts);
50112a08440Sreyk 
50212a08440Sreyk 	packetp = p;
50312a08440Sreyk 	snapend = p + h->caplen;
50412a08440Sreyk 
50512a08440Sreyk 	TCHECK(*rh);
50612a08440Sreyk 
50712a08440Sreyk 	len = h->caplen;
50812a08440Sreyk 	rh_len = letoh16(rh->it_len);
50912a08440Sreyk 	if (rh->it_version != 0) {
510c79cf170Sreyk 		printf("[?radiotap + 802.11 v:%u]", rh->it_version);
51112a08440Sreyk 		goto out;
51212a08440Sreyk 	}
51312a08440Sreyk 
51412a08440Sreyk 	wh = (struct ieee80211_frame *)(p + rh_len);
51512a08440Sreyk 	if (len <= rh_len || ieee80211_print(wh, len - rh_len))
51612a08440Sreyk 		printf("[|802.11]");
51712a08440Sreyk 
51812a08440Sreyk 	t = (u_int8_t*)p + sizeof(struct ieee80211_radiotap_header);
51912a08440Sreyk 
52012a08440Sreyk 	if ((present = letoh32(rh->it_present)) == 0)
52112a08440Sreyk 		goto out;
52212a08440Sreyk 
52312a08440Sreyk 	printf(", <radiotap v%u", rh->it_version);
52412a08440Sreyk 
52512a08440Sreyk #define RADIOTAP(_x)	\
52612a08440Sreyk 	(present & (1 << IEEE80211_RADIOTAP_##_x))
52712a08440Sreyk 
52812a08440Sreyk 	if (RADIOTAP(TSFT)) {
529cce1ba42Sclaudio 		u_int64_t tsf;
530cce1ba42Sclaudio 
53112a08440Sreyk 		TCHECK2(*t, 8);
532cce1ba42Sclaudio 		bcopy(t, &tsf, sizeof(u_int64_t));
53312a08440Sreyk 		if (vflag > 1)
534cce1ba42Sclaudio 			printf(", tsf %llu", letoh64(tsf));
53512a08440Sreyk 		t += 8;
53612a08440Sreyk 	}
53712a08440Sreyk 
53812a08440Sreyk 	if (RADIOTAP(FLAGS)) {
53912a08440Sreyk 		u_int8_t flags = *(u_int8_t*)t;
540026ca542Sderaadt 		TCHECK2(*t, 1);
541026ca542Sderaadt 
54212a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_CFP)
54312a08440Sreyk 			printf(", CFP");
54412a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_SHORTPRE)
54512a08440Sreyk 			printf(", SHORTPRE");
54612a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_WEP)
54712a08440Sreyk 			printf(", WEP");
54812a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_FRAG)
54912a08440Sreyk 			printf(", FRAG");
55012a08440Sreyk 		t += 1;
55112a08440Sreyk 	}
55212a08440Sreyk 
55312a08440Sreyk 	if (RADIOTAP(RATE)) {
55412a08440Sreyk 		TCHECK2(*t, 1);
55512a08440Sreyk 		if (vflag)
55612a08440Sreyk 			printf(", %uMbit/s", (*(u_int8_t*)t) / 2);
55712a08440Sreyk 		t += 1;
55812a08440Sreyk 	}
55912a08440Sreyk 
56012a08440Sreyk 	if (RADIOTAP(CHANNEL)) {
56112a08440Sreyk 		u_int16_t freq, flags;
56212a08440Sreyk 		TCHECK2(*t, 2);
56312a08440Sreyk 
564cce1ba42Sclaudio 		bcopy(t, &freq, sizeof(u_int16_t));
565cce1ba42Sclaudio 		freq = letoh16(freq);
56612a08440Sreyk 		t += 2;
56712a08440Sreyk 		TCHECK2(*t, 2);
568cce1ba42Sclaudio 		bcopy(t, &flags, sizeof(u_int16_t));
569cce1ba42Sclaudio 		flags = letoh16(flags);
57012a08440Sreyk 		t += 2;
57112a08440Sreyk 
57212a08440Sreyk 		printf(", chan %u", ieee80211_any2ieee(freq, flags));
57312a08440Sreyk 
57412a08440Sreyk 		if (flags & IEEE80211_CHAN_DYN &&
57512a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
57612a08440Sreyk 			printf(", 11g");
57712a08440Sreyk 		else if (flags & IEEE80211_CHAN_CCK &&
57812a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
57912a08440Sreyk 			printf(", 11b");
58012a08440Sreyk 		else if (flags & IEEE80211_CHAN_OFDM &&
58112a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
58212a08440Sreyk 			printf(", 11G");
58312a08440Sreyk 		else if (flags & IEEE80211_CHAN_OFDM &&
58412a08440Sreyk 		    flags & IEEE80211_CHAN_5GHZ)
58512a08440Sreyk 			printf(", 11a");
58612a08440Sreyk 
58712a08440Sreyk 		if (flags & IEEE80211_CHAN_TURBO)
58812a08440Sreyk 			printf(", TURBO");
58912a08440Sreyk 		if (flags & IEEE80211_CHAN_XR)
59012a08440Sreyk 			printf(", XR");
59112a08440Sreyk 	}
59212a08440Sreyk 
59312a08440Sreyk 	if (RADIOTAP(FHSS)) {
59412a08440Sreyk 		TCHECK2(*t, 2);
59512a08440Sreyk 		printf(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1);
59612a08440Sreyk 		t += 2;
59712a08440Sreyk 	}
59812a08440Sreyk 
59912a08440Sreyk 	if (RADIOTAP(DBM_ANTSIGNAL)) {
60012a08440Sreyk 		TCHECK(*t);
60112a08440Sreyk 		printf(", sig %ddBm", *(int8_t*)t);
60212a08440Sreyk 		t += 1;
60312a08440Sreyk 	}
60412a08440Sreyk 
60512a08440Sreyk 	if (RADIOTAP(DBM_ANTNOISE)) {
60612a08440Sreyk 		TCHECK(*t);
60712a08440Sreyk 		printf(", noise %ddBm", *(int8_t*)t);
60812a08440Sreyk 		t += 1;
60912a08440Sreyk 	}
61012a08440Sreyk 
61112a08440Sreyk 	if (RADIOTAP(LOCK_QUALITY)) {
61212a08440Sreyk 		TCHECK2(*t, 2);
613cce1ba42Sclaudio 		if (vflag) {
614cce1ba42Sclaudio 			bcopy(t, &tmp, sizeof(u_int16_t));
615cce1ba42Sclaudio 			printf(", quality %u", letoh16(tmp));
616cce1ba42Sclaudio 		}
61712a08440Sreyk 		t += 2;
61812a08440Sreyk 	}
61912a08440Sreyk 
62012a08440Sreyk 	if (RADIOTAP(TX_ATTENUATION)) {
62112a08440Sreyk 		TCHECK2(*t, 2);
622cce1ba42Sclaudio 		if (vflag) {
623cce1ba42Sclaudio 			bcopy(t, &tmp, sizeof(u_int16_t));
624cce1ba42Sclaudio 			printf(", txatt %u", letoh16(tmp));
625cce1ba42Sclaudio 		}
62612a08440Sreyk 		t += 2;
62712a08440Sreyk 	}
62812a08440Sreyk 
62912a08440Sreyk 	if (RADIOTAP(DB_TX_ATTENUATION)) {
63012a08440Sreyk 		TCHECK2(*t, 2);
631cce1ba42Sclaudio 		if (vflag) {
632cce1ba42Sclaudio 			bcopy(t, &tmp, sizeof(u_int16_t));
633cce1ba42Sclaudio 			printf(", txatt %udB", letoh16(tmp));
634cce1ba42Sclaudio 		}
63512a08440Sreyk 		t += 2;
63612a08440Sreyk 	}
63712a08440Sreyk 
63812a08440Sreyk 	if (RADIOTAP(DBM_TX_POWER)) {
63912a08440Sreyk 		TCHECK(*t);
64012a08440Sreyk 		printf(", txpower %ddBm", *(int8_t*)t);
64112a08440Sreyk 		t += 1;
64212a08440Sreyk 	}
64312a08440Sreyk 
64412a08440Sreyk 	if (RADIOTAP(ANTENNA)) {
64512a08440Sreyk 		TCHECK(*t);
64612a08440Sreyk 		if (vflag)
64712a08440Sreyk 			printf(", antenna %u", *(u_int8_t*)t);
64812a08440Sreyk 		t += 1;
64912a08440Sreyk 	}
65012a08440Sreyk 
65112a08440Sreyk 	if (RADIOTAP(DB_ANTSIGNAL)) {
65212a08440Sreyk 		TCHECK(*t);
65312a08440Sreyk 		printf(", signal %udB", *(u_int8_t*)t);
65412a08440Sreyk 		t += 1;
65512a08440Sreyk 	}
65612a08440Sreyk 
65712a08440Sreyk 	if (RADIOTAP(DB_ANTNOISE)) {
65812a08440Sreyk 		TCHECK(*t);
65912a08440Sreyk 		printf(", noise %udB", *(u_int8_t*)t);
66012a08440Sreyk 		t += 1;
66112a08440Sreyk 	}
66212a08440Sreyk 
66312a08440Sreyk 	if (RADIOTAP(FCS)) {
66412a08440Sreyk 		TCHECK2(*t, 4);
665cce1ba42Sclaudio 		if (vflag) {
666cce1ba42Sclaudio 			u_int32_t fcs;
667cce1ba42Sclaudio 			bcopy(t, &fcs, sizeof(u_int32_t));
668cce1ba42Sclaudio 			printf(", fcs %08x", letoh32(fcs));
669cce1ba42Sclaudio 		}
67012a08440Sreyk 		t += 4;
67112a08440Sreyk 	}
67212a08440Sreyk 
6736fc94ee3Sreyk 	if (RADIOTAP(RSSI)) {
6746fc94ee3Sreyk 		u_int8_t rssi, max_rssi;
6756fc94ee3Sreyk 		TCHECK(*t);
6766fc94ee3Sreyk 		rssi = *(u_int8_t*)t;
6776fc94ee3Sreyk 		t += 1;
6786fc94ee3Sreyk 		TCHECK(*t);
6796fc94ee3Sreyk 		max_rssi = *(u_int8_t*)t;
6806fc94ee3Sreyk 		t += 1;
6816fc94ee3Sreyk 
6826fc94ee3Sreyk 		printf(", rssi %u/%u", rssi, max_rssi);
6836fc94ee3Sreyk 	}
6846fc94ee3Sreyk 
68512a08440Sreyk #undef RADIOTAP
68612a08440Sreyk 
68712a08440Sreyk 	putchar('>');
68812a08440Sreyk 	goto out;
68912a08440Sreyk 
69012a08440Sreyk  trunc:
69112a08440Sreyk 	/* Truncated frame */
69212a08440Sreyk 	printf("[|radiotap + 802.11]");
69312a08440Sreyk 
69412a08440Sreyk  out:
695c79cf170Sreyk 	if (!ieee80211_encap) {
69612a08440Sreyk 		if (xflag)
69712a08440Sreyk 			default_print(p, h->caplen);
69812a08440Sreyk 		putchar('\n');
69912a08440Sreyk 	}
700c79cf170Sreyk }
70118786664Sclaudio 
70218786664Sclaudio void
70318786664Sclaudio ieee80211_reason(u_int16_t reason)
70418786664Sclaudio {
70518786664Sclaudio 	if (!vflag)
70618786664Sclaudio 		return;
70718786664Sclaudio 
70818786664Sclaudio 	switch (reason) {
70918786664Sclaudio 	case IEEE80211_REASON_UNSPECIFIED:
71018786664Sclaudio 		printf(", unspecified failure");
71118786664Sclaudio 		break;
71218786664Sclaudio 	case IEEE80211_REASON_AUTH_EXPIRE:
71318786664Sclaudio 		printf(", authentication expired");
71418786664Sclaudio 		break;
71518786664Sclaudio 	case IEEE80211_REASON_AUTH_LEAVE:
71618786664Sclaudio 		printf(", deauth - station left");
71718786664Sclaudio 		break;
71818786664Sclaudio 	case IEEE80211_REASON_ASSOC_EXPIRE:
71918786664Sclaudio 		printf(", association expired");
72018786664Sclaudio 		break;
72118786664Sclaudio 	case IEEE80211_REASON_ASSOC_TOOMANY:
72218786664Sclaudio 		printf(", too many associated stations");
72318786664Sclaudio 		break;
72418786664Sclaudio 	case IEEE80211_REASON_NOT_AUTHED:
72518786664Sclaudio 		printf(", not authenticated");
72618786664Sclaudio 		break;
72718786664Sclaudio 	case IEEE80211_REASON_NOT_ASSOCED:
72818786664Sclaudio 		printf(", not associated");
72918786664Sclaudio 		break;
73018786664Sclaudio 	case IEEE80211_REASON_ASSOC_LEAVE:
73118786664Sclaudio 		printf(", disassociated - station left");
73218786664Sclaudio 		break;
73318786664Sclaudio 	case IEEE80211_REASON_ASSOC_NOT_AUTHED:
73418786664Sclaudio 		printf(", association but not authenticated");
73518786664Sclaudio 		break;
73618786664Sclaudio 	case IEEE80211_REASON_RSN_REQUIRED:
73718786664Sclaudio 		printf(", rsn required");
73818786664Sclaudio 		break;
73918786664Sclaudio 	case IEEE80211_REASON_RSN_INCONSISTENT:
74018786664Sclaudio 		printf(", rsn inconsistent");
74118786664Sclaudio 		break;
74218786664Sclaudio 	case IEEE80211_REASON_IE_INVALID:
74318786664Sclaudio 		printf(", ie invalid");
74418786664Sclaudio 		break;
74518786664Sclaudio 	case IEEE80211_REASON_MIC_FAILURE:
74618786664Sclaudio 		printf(", mic failure");
74718786664Sclaudio 		break;
74818786664Sclaudio 	default:
74918786664Sclaudio 		printf(", unknown reason %u", reason);
75018786664Sclaudio 	}
75118786664Sclaudio }
752