xref: /openbsd/usr.sbin/tcpdump/print-802_11.c (revision b72abdef)
1*b72abdefSreyk /*	$OpenBSD: print-802_11.c,v 1.4 2005/05/28 09:01:52 reyk Exp $	*/
212a08440Sreyk 
312a08440Sreyk /*
412a08440Sreyk  * Copyright (c) 2005 Reyk Floeter <reyk@vantronix.net>
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 *);
61*b72abdefSreyk 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);
6812a08440Sreyk 
6912a08440Sreyk #define TCARR(a)	TCHECK2(*a, sizeof(a))
7012a08440Sreyk 
7112a08440Sreyk int
7212a08440Sreyk ieee80211_hdr(struct ieee80211_frame *wh)
7312a08440Sreyk {
7412a08440Sreyk 	struct ieee80211_frame_addr4 *w4;
7512a08440Sreyk 
7612a08440Sreyk 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
7712a08440Sreyk 	case IEEE80211_FC1_DIR_NODS:
7812a08440Sreyk 		TCARR(wh->i_addr2);
7912a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr2));
8012a08440Sreyk 		TCARR(wh->i_addr1);
8112a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr1));
8212a08440Sreyk 		TCARR(wh->i_addr3);
8312a08440Sreyk 		printf(", bssid %s", etheraddr_string(wh->i_addr3));
8412a08440Sreyk 		break;
8512a08440Sreyk 	case IEEE80211_FC1_DIR_TODS:
8612a08440Sreyk 		TCARR(wh->i_addr2);
8712a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr2));
8812a08440Sreyk 		TCARR(wh->i_addr3);
8912a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr3));
9012a08440Sreyk 		TCARR(wh->i_addr1);
9112a08440Sreyk 		printf(", bssid %s, > DS", etheraddr_string(wh->i_addr1));
9212a08440Sreyk 		break;
9312a08440Sreyk 	case IEEE80211_FC1_DIR_FROMDS:
9412a08440Sreyk 		TCARR(wh->i_addr3);
9512a08440Sreyk 		printf("%s", etheraddr_string(wh->i_addr3));
9612a08440Sreyk 		TCARR(wh->i_addr1);
9712a08440Sreyk 		printf(" > %s", etheraddr_string(wh->i_addr1));
9812a08440Sreyk 		TCARR(wh->i_addr2);
9912a08440Sreyk 		printf(", bssid %s, DS >", etheraddr_string(wh->i_addr2));
10012a08440Sreyk 		break;
10112a08440Sreyk 	case IEEE80211_FC1_DIR_DSTODS:
10212a08440Sreyk 		w4 = (struct ieee80211_frame_addr4 *) wh;
10312a08440Sreyk 		TCARR(w4->i_addr4);
10412a08440Sreyk 		printf("%s", etheraddr_string(w4->i_addr4));
10512a08440Sreyk 		TCARR(w4->i_addr3);
10612a08440Sreyk 		printf(" > %s", etheraddr_string(w4->i_addr3));
10712a08440Sreyk 		TCARR(w4->i_addr2);
10812a08440Sreyk 		printf(", bssid %s", etheraddr_string(w4->i_addr2));
10912a08440Sreyk 		TCARR(w4->i_addr1);
11012a08440Sreyk 		printf(" > %s, DS > DS", etheraddr_string(w4->i_addr1));
11112a08440Sreyk 		break;
11212a08440Sreyk 	}
11312a08440Sreyk 	if (vflag) {
11412a08440Sreyk 		TCARR(wh->i_seq);
11512a08440Sreyk 		printf(" (seq %u): ", letoh16(*(u_int16_t *)&wh->i_seq[0]));
11612a08440Sreyk 	} else
11712a08440Sreyk 		printf(": ");
11812a08440Sreyk 
11912a08440Sreyk 	return (0);
12012a08440Sreyk 
12112a08440Sreyk  trunc:
12212a08440Sreyk 	/* Truncated elements in frame */
12312a08440Sreyk 	return (1);
12412a08440Sreyk }
12512a08440Sreyk 
126*b72abdefSreyk int
127*b72abdefSreyk ieee80211_data(struct ieee80211_frame *wh, u_int len)
128*b72abdefSreyk {
129*b72abdefSreyk 	u_int8_t *t = (u_int8_t *)wh;
130*b72abdefSreyk 	u_int datalen;
131*b72abdefSreyk 
132*b72abdefSreyk 	TCHECK2(*t, sizeof(struct ieee80211_frame));
133*b72abdefSreyk 	t += sizeof(struct ieee80211_frame);
134*b72abdefSreyk 	datalen = len - sizeof(struct ieee80211_frame);
135*b72abdefSreyk 
136*b72abdefSreyk 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
137*b72abdefSreyk 	case IEEE80211_FC1_DIR_TODS:
138*b72abdefSreyk 		llc_print(t, datalen, datalen, wh->i_addr2, wh->i_addr3);
139*b72abdefSreyk 		break;
140*b72abdefSreyk 	case IEEE80211_FC1_DIR_FROMDS:
141*b72abdefSreyk 		llc_print(t, datalen, datalen, wh->i_addr3, wh->i_addr1);
142*b72abdefSreyk 		break;
143*b72abdefSreyk 	case IEEE80211_FC1_DIR_NODS:
144*b72abdefSreyk 	case IEEE80211_FC1_DIR_DSTODS:
145*b72abdefSreyk 		break;
146*b72abdefSreyk 	}
147*b72abdefSreyk 
148*b72abdefSreyk 	return (0);
149*b72abdefSreyk 
150*b72abdefSreyk  trunc:
151*b72abdefSreyk 	/* Truncated elements in frame */
152*b72abdefSreyk 	return (1);
153*b72abdefSreyk }
154*b72abdefSreyk 
15512a08440Sreyk /* Caller checks len */
15612a08440Sreyk void
15712a08440Sreyk ieee80211_print_element(u_int8_t *data, u_int len)
15812a08440Sreyk {
15912a08440Sreyk 	u_int8_t *p;
1609cbdb746Sderaadt 	int i;
16112a08440Sreyk 
16212a08440Sreyk 	printf(" 0x");
1639cbdb746Sderaadt 	for (i = 0, p = data; i < len; i++, p++)
16412a08440Sreyk 		printf("%02x", *p);
16512a08440Sreyk }
16612a08440Sreyk 
16712a08440Sreyk /* Caller checks len */
16812a08440Sreyk void
16912a08440Sreyk ieee80211_print_essid(u_int8_t *essid, u_int len)
17012a08440Sreyk {
17112a08440Sreyk 	u_int8_t *p;
1729cbdb746Sderaadt 	int i;
17312a08440Sreyk 
17412a08440Sreyk 	if (len > IEEE80211_NWID_LEN)
17512a08440Sreyk 		len = IEEE80211_NWID_LEN;
17612a08440Sreyk 
17712a08440Sreyk 	/* determine printable or not */
17812a08440Sreyk 	for (i = 0, p = essid; i < len; i++, p++) {
17912a08440Sreyk 		if (*p < ' ' || *p > 0x7e)
18012a08440Sreyk 			break;
18112a08440Sreyk 	}
18212a08440Sreyk 	if (i == len) {
18312a08440Sreyk 		printf(" (");
18412a08440Sreyk 		for (i = 0, p = essid; i < len; i++, p++)
18512a08440Sreyk 			putchar(*p);
18612a08440Sreyk 		putchar(')');
1879cbdb746Sderaadt 	} else
18812a08440Sreyk 		ieee80211_print_element(essid, len);
18912a08440Sreyk }
19012a08440Sreyk 
19112a08440Sreyk int
19212a08440Sreyk ieee80211_elements(struct ieee80211_frame *wh, u_int flen)
19312a08440Sreyk {
19412a08440Sreyk 	u_int8_t *buf, *frm;
19512a08440Sreyk 	u_int8_t *tstamp, *bintval, *capinfo;
19612a08440Sreyk 	int i;
19712a08440Sreyk 
19812a08440Sreyk 	buf = (u_int8_t *)wh;
19912a08440Sreyk 	frm = (u_int8_t *)&wh[1];
20012a08440Sreyk 
20112a08440Sreyk 	tstamp = frm;
20212a08440Sreyk 	TCHECK2(*tstamp, 8);
20312a08440Sreyk 	frm += 8;
20412a08440Sreyk 
20512a08440Sreyk 	if (vflag > 1)
20612a08440Sreyk 		printf(", timestamp %llu", letoh64(*(u_int64_t *)tstamp));
20712a08440Sreyk 
20812a08440Sreyk 	bintval = frm;
20912a08440Sreyk 	TCHECK2(*bintval, 2);
21012a08440Sreyk 	frm += 2;
21112a08440Sreyk 
21212a08440Sreyk 	if (vflag > 1)
21312a08440Sreyk 		printf(", interval %u", letoh16(*(u_int16_t *)bintval));
21412a08440Sreyk 
21512a08440Sreyk 	capinfo = frm;
21612a08440Sreyk 	TCHECK2(*capinfo, 2);
21712a08440Sreyk 	frm += 2;
21812a08440Sreyk 
21912a08440Sreyk 	if (vflag)
22012a08440Sreyk 		printb(", caps", letoh16(*(u_int16_t *)capinfo),
22112a08440Sreyk 		    IEEE80211_CAPINFO_BITS);
22212a08440Sreyk 
22312a08440Sreyk 	while (TTEST2(*frm, 2)) {
22412a08440Sreyk 		u_int len = frm[1];
22512a08440Sreyk 		u_int8_t *data = frm + 2;
22612a08440Sreyk 
22712a08440Sreyk 		if (!TTEST2(*data, len))
22812a08440Sreyk 			break;
22912a08440Sreyk 
23012a08440Sreyk #define ELEM_CHECK(l)	if (len != l) break
23112a08440Sreyk 
23212a08440Sreyk 		switch (*frm) {
23312a08440Sreyk 		case IEEE80211_ELEMID_SSID:
23412a08440Sreyk 			printf(", ssid");
23512a08440Sreyk 			ieee80211_print_essid(data, len);
23612a08440Sreyk 			break;
23712a08440Sreyk 		case IEEE80211_ELEMID_RATES:
23812a08440Sreyk 			printf(", rates");
23912a08440Sreyk 			if (!vflag)
24012a08440Sreyk 				break;
24112a08440Sreyk 			for (i = len; i > 0; i--, data++)
24212a08440Sreyk 				printf(" %uM",
24312a08440Sreyk 				    (data[0] & IEEE80211_RATE_VAL) / 2);
24412a08440Sreyk 			break;
24512a08440Sreyk 		case IEEE80211_ELEMID_FHPARMS:
24612a08440Sreyk 			ELEM_CHECK(5);
24712a08440Sreyk 			printf(", fh (dwell %u, chan %u, index %u)",
24812a08440Sreyk 			    (data[1] << 8) | data[0],
24912a08440Sreyk 			    (data[2] - 1) * 80 + data[3],	/* FH_CHAN */
25012a08440Sreyk 			    data[4]);
25112a08440Sreyk 			break;
25212a08440Sreyk 		case IEEE80211_ELEMID_DSPARMS:
25312a08440Sreyk 			ELEM_CHECK(1);
25412a08440Sreyk 			printf(", ds");
25512a08440Sreyk 			if (vflag)
25612a08440Sreyk 				printf(" (chan %u)", data[0]);
25712a08440Sreyk 			break;
25812a08440Sreyk 		case IEEE80211_ELEMID_CFPARMS:
25912a08440Sreyk 			printf(", cf");
26012a08440Sreyk 			if (vflag)
26112a08440Sreyk 				ieee80211_print_element(data, len);
26212a08440Sreyk 			break;
26312a08440Sreyk 		case IEEE80211_ELEMID_TIM:
26412a08440Sreyk 			printf(", tim");
26512a08440Sreyk 			if (vflag)
26612a08440Sreyk 				ieee80211_print_element(data, len);
26712a08440Sreyk 			break;
26812a08440Sreyk 		case IEEE80211_ELEMID_IBSSPARMS:
26912a08440Sreyk 			printf(", ibss");
27012a08440Sreyk 			if (vflag)
27112a08440Sreyk 				ieee80211_print_element(data, len);
27212a08440Sreyk 			break;
27312a08440Sreyk 		case IEEE80211_ELEMID_COUNTRY:
27412a08440Sreyk 			printf(", country");
27512a08440Sreyk 			for (i = len; i > 0; i--, data++)
27612a08440Sreyk 				printf(" %u", data[0]);
27712a08440Sreyk 			break;
27812a08440Sreyk 		case IEEE80211_ELEMID_CHALLENGE:
27912a08440Sreyk 			printf(", challenge");
28012a08440Sreyk 			if (vflag)
28112a08440Sreyk 				ieee80211_print_element(data, len);
28212a08440Sreyk 			break;
28312a08440Sreyk 		case IEEE80211_ELEMID_ERP:
28412a08440Sreyk 			printf(", erp");
28512a08440Sreyk 			if (vflag)
28612a08440Sreyk 				ieee80211_print_element(data, len);
28712a08440Sreyk 			break;
28812a08440Sreyk 		case IEEE80211_ELEMID_RSN:
28912a08440Sreyk 			printf(", rsn");
29012a08440Sreyk 			if (vflag)
29112a08440Sreyk 				ieee80211_print_element(data, len);
29212a08440Sreyk 			break;
29312a08440Sreyk 		case IEEE80211_ELEMID_XRATES:
29412a08440Sreyk 			printf(", xrates");
29512a08440Sreyk 			if (!vflag)
29612a08440Sreyk 				break;
29712a08440Sreyk 			for (i = len; i > 0; i--, data++)
29812a08440Sreyk 				printf(" %uM",
29912a08440Sreyk 				    (data[0] & IEEE80211_RATE_VAL) / 2);
30012a08440Sreyk 			break;
30112a08440Sreyk 		case IEEE80211_ELEMID_TPC:
30212a08440Sreyk 			printf(", tpc");
30312a08440Sreyk 			if (vflag)
30412a08440Sreyk 				ieee80211_print_element(data, len);
30512a08440Sreyk 			break;
30612a08440Sreyk 		case IEEE80211_ELEMID_CCKM:
30712a08440Sreyk 			printf(", cckm");
30812a08440Sreyk 			if (vflag)
30912a08440Sreyk 				ieee80211_print_element(data, len);
31012a08440Sreyk 			break;
31112a08440Sreyk 		case IEEE80211_ELEMID_VENDOR:
31212a08440Sreyk 			printf(", vendor");
31312a08440Sreyk 			if (vflag)
31412a08440Sreyk 				ieee80211_print_element(data, len);
31512a08440Sreyk 			break;
31612a08440Sreyk 		default:
31712a08440Sreyk 			printf(", %u:%u", (u_int) *frm, len);
31812a08440Sreyk 			if (vflag)
31912a08440Sreyk 				ieee80211_print_element(data, len);
32012a08440Sreyk 			break;
32112a08440Sreyk 		}
32212a08440Sreyk 		frm += len + 2;
32312a08440Sreyk 
32412a08440Sreyk 		if (frm >= snapend)
32512a08440Sreyk 			break;
32612a08440Sreyk 	}
32712a08440Sreyk 
32812a08440Sreyk #undef ELEM_CHECK
32912a08440Sreyk 
33012a08440Sreyk 	return (0);
33112a08440Sreyk 
33212a08440Sreyk  trunc:
33312a08440Sreyk 	/* Truncated elements in frame */
33412a08440Sreyk 	return (1);
33512a08440Sreyk }
33612a08440Sreyk 
33712a08440Sreyk int
33812a08440Sreyk ieee80211_frame(struct ieee80211_frame *wh, u_int len)
33912a08440Sreyk {
34012a08440Sreyk 	u_int8_t subtype, type, *frm;
34112a08440Sreyk 
34212a08440Sreyk 	TCARR(wh->i_fc);
34312a08440Sreyk 
34412a08440Sreyk 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
34512a08440Sreyk 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
34612a08440Sreyk 
34712a08440Sreyk 	frm = (u_int8_t *)&wh[1];
34812a08440Sreyk 
34912a08440Sreyk 	switch (type) {
35012a08440Sreyk 	case IEEE80211_FC0_TYPE_DATA:
351*b72abdefSreyk 		printf(": data: ");
352*b72abdefSreyk 		ieee80211_data(wh, len);
35312a08440Sreyk 		break;
35412a08440Sreyk 	case IEEE80211_FC0_TYPE_MGT:
35512a08440Sreyk 		printf(": %s", ieee80211_mgt_subtype_name[
35612a08440Sreyk 		    subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
35712a08440Sreyk 		switch (subtype) {
35812a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_BEACON:
35912a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
36012a08440Sreyk 			if (ieee80211_elements(wh, len) != 0)
36112a08440Sreyk 				goto trunc;
36212a08440Sreyk 			break;
36312a08440Sreyk 		case IEEE80211_FC0_SUBTYPE_AUTH:
36412a08440Sreyk 			TCHECK2(*frm, 2);		/* Auth Algorithm */
36512a08440Sreyk 			switch (IEEE80211_AUTH_ALGORITHM(frm)) {
36612a08440Sreyk 			case IEEE80211_AUTH_ALG_OPEN:
36712a08440Sreyk 				TCHECK2(*frm, 4);	/* Auth Transaction */
36812a08440Sreyk 				switch (IEEE80211_AUTH_TRANSACTION(frm)) {
36912a08440Sreyk 				case IEEE80211_AUTH_OPEN_REQUEST:
37012a08440Sreyk 					printf(" request");
37112a08440Sreyk 					break;
37212a08440Sreyk 				case IEEE80211_AUTH_OPEN_RESPONSE:
37312a08440Sreyk 					printf(" response");
37412a08440Sreyk 					break;
37512a08440Sreyk 				}
37612a08440Sreyk 				break;
37712a08440Sreyk 			case IEEE80211_AUTH_ALG_SHARED:
37812a08440Sreyk 				TCHECK2(*frm, 4);	/* Auth Transaction */
37912a08440Sreyk 				switch (IEEE80211_AUTH_TRANSACTION(frm)) {
38012a08440Sreyk 				case IEEE80211_AUTH_SHARED_REQUEST:
38112a08440Sreyk 					printf(" request");
38212a08440Sreyk 					break;
38312a08440Sreyk 				case IEEE80211_AUTH_SHARED_CHALLENGE:
38412a08440Sreyk 					printf(" challenge");
38512a08440Sreyk 					break;
38612a08440Sreyk 				case IEEE80211_AUTH_SHARED_RESPONSE:
38712a08440Sreyk 					printf(" response");
38812a08440Sreyk 					break;
38912a08440Sreyk 				case IEEE80211_AUTH_SHARED_PASS:
39012a08440Sreyk 					printf(" pass");
39112a08440Sreyk 					break;
39212a08440Sreyk 				}
39312a08440Sreyk 				break;
39412a08440Sreyk 			case IEEE80211_AUTH_ALG_LEAP:
39512a08440Sreyk 				printf(" (leap)");
39612a08440Sreyk 				break;
39712a08440Sreyk 			}
39812a08440Sreyk 			break;
39912a08440Sreyk 		}
40012a08440Sreyk 		break;
40112a08440Sreyk 	default:
40212a08440Sreyk 		printf(": type#%d", type);
40312a08440Sreyk 		break;
40412a08440Sreyk 	}
40512a08440Sreyk 
40612a08440Sreyk 	if (wh->i_fc[1] & IEEE80211_FC1_WEP)
40712a08440Sreyk 		printf(", WEP");
40812a08440Sreyk 
40912a08440Sreyk 	return (0);
41012a08440Sreyk 
41112a08440Sreyk  trunc:
41212a08440Sreyk 	/* Truncated 802.11 frame */
41312a08440Sreyk 	return (1);
41412a08440Sreyk }
41512a08440Sreyk 
41612a08440Sreyk u_int
41712a08440Sreyk ieee80211_any2ieee(u_int freq, u_int flags)
41812a08440Sreyk {
41912a08440Sreyk 	if (flags & IEEE80211_CHAN_2GHZ) {
42012a08440Sreyk 		if (freq == 2484)
42112a08440Sreyk 			return 14;
42212a08440Sreyk 		if (freq < 2484)
42312a08440Sreyk 			return (freq - 2407) / 5;
42412a08440Sreyk 		else
42512a08440Sreyk 			return 15 + ((freq - 2512) / 20);
42612a08440Sreyk 	} else if (flags & IEEE80211_CHAN_5GHZ) {
42712a08440Sreyk 		return (freq - 5000) / 5;
42812a08440Sreyk 	} else {
42912a08440Sreyk 		/* Assume channel is already an IEEE number */
43012a08440Sreyk 		return (freq);
43112a08440Sreyk 	}
43212a08440Sreyk }
43312a08440Sreyk 
43412a08440Sreyk int
43512a08440Sreyk ieee80211_print(struct ieee80211_frame *wh, u_int len)
43612a08440Sreyk {
43712a08440Sreyk 	if (eflag)
43812a08440Sreyk 		if (ieee80211_hdr(wh))
43912a08440Sreyk 			return (1);
44012a08440Sreyk 
44112a08440Sreyk 	printf("802.11");
44212a08440Sreyk 
44312a08440Sreyk 	return (ieee80211_frame(wh, len));
44412a08440Sreyk }
44512a08440Sreyk 
44612a08440Sreyk void
44712a08440Sreyk ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h,
44812a08440Sreyk     const u_char *p)
44912a08440Sreyk {
45012a08440Sreyk 	struct ieee80211_frame *wh = (struct ieee80211_frame*)p;
45112a08440Sreyk 
45212a08440Sreyk 	ts_print(&h->ts);
45312a08440Sreyk 
45412a08440Sreyk 	packetp = p;
45512a08440Sreyk 	snapend = p + h->caplen;
45612a08440Sreyk 
45712a08440Sreyk 	if (ieee80211_print(wh, (u_int)h->caplen) != 0)
45812a08440Sreyk 		printf("[|802.11]");
45912a08440Sreyk 
46012a08440Sreyk 	if (xflag)
46112a08440Sreyk 		default_print(p, (u_int)h->caplen);
46212a08440Sreyk 
46312a08440Sreyk 	putchar('\n');
46412a08440Sreyk }
46512a08440Sreyk 
46612a08440Sreyk void
46712a08440Sreyk ieee802_11_radio_if_print(u_char *user, const struct pcap_pkthdr *h,
46812a08440Sreyk     const u_char *p)
46912a08440Sreyk {
47012a08440Sreyk 	struct ieee80211_radiotap_header *rh =
47112a08440Sreyk 	    (struct ieee80211_radiotap_header*)p;
47212a08440Sreyk 	struct ieee80211_frame *wh;
47312a08440Sreyk 	u_int8_t *t;
47412a08440Sreyk 	u_int32_t present;
47512a08440Sreyk 	u_int len, rh_len;
47612a08440Sreyk 
47712a08440Sreyk 	ts_print(&h->ts);
47812a08440Sreyk 
47912a08440Sreyk 	packetp = p;
48012a08440Sreyk 	snapend = p + h->caplen;
48112a08440Sreyk 
48212a08440Sreyk 	TCHECK(*rh);
48312a08440Sreyk 
48412a08440Sreyk 	len = h->caplen;
48512a08440Sreyk 	rh_len = letoh16(rh->it_len);
48612a08440Sreyk 	if (rh->it_version != 0) {
48712a08440Sreyk 		printf("[?radiotap + 802.11 v:%u]\n", rh->it_version);
48812a08440Sreyk 		goto out;
48912a08440Sreyk 	}
49012a08440Sreyk 
49112a08440Sreyk 	wh = (struct ieee80211_frame *)(p + rh_len);
49212a08440Sreyk 	if (len <= rh_len || ieee80211_print(wh, len - rh_len))
49312a08440Sreyk 		printf("[|802.11]");
49412a08440Sreyk 
49512a08440Sreyk 	t = (u_int8_t*)p + sizeof(struct ieee80211_radiotap_header);
49612a08440Sreyk 
49712a08440Sreyk 	if ((present = letoh32(rh->it_present)) == 0)
49812a08440Sreyk 		goto out;
49912a08440Sreyk 
50012a08440Sreyk 	printf(", <radiotap v%u", rh->it_version);
50112a08440Sreyk 
50212a08440Sreyk #define RADIOTAP(_x)	\
50312a08440Sreyk 	(present & (1 << IEEE80211_RADIOTAP_##_x))
50412a08440Sreyk 
50512a08440Sreyk 	if (RADIOTAP(TSFT)) {
50612a08440Sreyk 		TCHECK2(*t, 8);
50712a08440Sreyk 		if (vflag > 1)
50812a08440Sreyk 			printf(", tsf %llu", letoh64(*(u_int64_t*)t));
50912a08440Sreyk 		t += 8;
51012a08440Sreyk 	}
51112a08440Sreyk 
51212a08440Sreyk 	if (RADIOTAP(FLAGS)) {
51312a08440Sreyk 		u_int8_t flags = *(u_int8_t*)t;
514026ca542Sderaadt 		TCHECK2(*t, 1);
515026ca542Sderaadt 
51612a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_CFP)
51712a08440Sreyk 			printf(", CFP");
51812a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_SHORTPRE)
51912a08440Sreyk 			printf(", SHORTPRE");
52012a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_WEP)
52112a08440Sreyk 			printf(", WEP");
52212a08440Sreyk 		if (flags & IEEE80211_RADIOTAP_F_FRAG)
52312a08440Sreyk 			printf(", FRAG");
52412a08440Sreyk 		t += 1;
52512a08440Sreyk 	}
52612a08440Sreyk 
52712a08440Sreyk 	if (RADIOTAP(RATE)) {
52812a08440Sreyk 		TCHECK2(*t, 1);
52912a08440Sreyk 		if (vflag)
53012a08440Sreyk 			printf(", %uMbit/s", (*(u_int8_t*)t) / 2);
53112a08440Sreyk 		t += 1;
53212a08440Sreyk 	}
53312a08440Sreyk 
53412a08440Sreyk 	if (RADIOTAP(CHANNEL)) {
53512a08440Sreyk 		u_int16_t freq, flags;
53612a08440Sreyk 		TCHECK2(*t, 2);
53712a08440Sreyk 
53812a08440Sreyk 		freq = letoh16(*(u_int16_t*)t);
53912a08440Sreyk 		t += 2;
54012a08440Sreyk 		TCHECK2(*t, 2);
54112a08440Sreyk 		flags = letoh16(*(u_int16_t*)t);
54212a08440Sreyk 		t += 2;
54312a08440Sreyk 
54412a08440Sreyk 		printf(", chan %u", ieee80211_any2ieee(freq, flags));
54512a08440Sreyk 
54612a08440Sreyk 		if (flags & IEEE80211_CHAN_DYN &&
54712a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
54812a08440Sreyk 			printf(", 11g");
54912a08440Sreyk 		else if (flags & IEEE80211_CHAN_CCK &&
55012a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
55112a08440Sreyk 			printf(", 11b");
55212a08440Sreyk 		else if (flags & IEEE80211_CHAN_OFDM &&
55312a08440Sreyk 		    flags & IEEE80211_CHAN_2GHZ)
55412a08440Sreyk 			printf(", 11G");
55512a08440Sreyk 		else if (flags & IEEE80211_CHAN_OFDM &&
55612a08440Sreyk 		    flags & IEEE80211_CHAN_5GHZ)
55712a08440Sreyk 			printf(", 11a");
55812a08440Sreyk 
55912a08440Sreyk 		if (flags & IEEE80211_CHAN_TURBO)
56012a08440Sreyk 			printf(", TURBO");
56112a08440Sreyk 		if (flags & IEEE80211_CHAN_XR)
56212a08440Sreyk 			printf(", XR");
56312a08440Sreyk 	}
56412a08440Sreyk 
56512a08440Sreyk 	if (RADIOTAP(FHSS)) {
56612a08440Sreyk 		TCHECK2(*t, 2);
56712a08440Sreyk 		printf(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1);
56812a08440Sreyk 		t += 2;
56912a08440Sreyk 	}
57012a08440Sreyk 
57112a08440Sreyk 	if (RADIOTAP(DBM_ANTSIGNAL)) {
57212a08440Sreyk 		TCHECK(*t);
57312a08440Sreyk 		printf(", sig %ddBm", *(int8_t*)t);
57412a08440Sreyk 		t += 1;
57512a08440Sreyk 	}
57612a08440Sreyk 
57712a08440Sreyk 	if (RADIOTAP(DBM_ANTNOISE)) {
57812a08440Sreyk 		TCHECK(*t);
57912a08440Sreyk 		printf(", noise %ddBm", *(int8_t*)t);
58012a08440Sreyk 		t += 1;
58112a08440Sreyk 	}
58212a08440Sreyk 
58312a08440Sreyk 	if (RADIOTAP(LOCK_QUALITY)) {
58412a08440Sreyk 		TCHECK2(*t, 2);
58512a08440Sreyk 		if (vflag)
58612a08440Sreyk 			printf(", quality %u", letoh16(*(u_int16_t*)t));
58712a08440Sreyk 		t += 2;
58812a08440Sreyk 	}
58912a08440Sreyk 
59012a08440Sreyk 	if (RADIOTAP(TX_ATTENUATION)) {
59112a08440Sreyk 		TCHECK2(*t, 2);
59212a08440Sreyk 		if (vflag)
59312a08440Sreyk 			printf(", txatt %u",
59412a08440Sreyk 			    letoh16(*(u_int16_t*)t));
59512a08440Sreyk 		t += 2;
59612a08440Sreyk 	}
59712a08440Sreyk 
59812a08440Sreyk 	if (RADIOTAP(DB_TX_ATTENUATION)) {
59912a08440Sreyk 		TCHECK2(*t, 2);
60012a08440Sreyk 		if (vflag)
60112a08440Sreyk 			printf(", txatt %udB",
60212a08440Sreyk 			    letoh16(*(u_int16_t*)t));
60312a08440Sreyk 		t += 2;
60412a08440Sreyk 	}
60512a08440Sreyk 
60612a08440Sreyk 	if (RADIOTAP(DBM_TX_POWER)) {
60712a08440Sreyk 		TCHECK(*t);
60812a08440Sreyk 		printf(", txpower %ddBm", *(int8_t*)t);
60912a08440Sreyk 		t += 1;
61012a08440Sreyk 	}
61112a08440Sreyk 
61212a08440Sreyk 	if (RADIOTAP(ANTENNA)) {
61312a08440Sreyk 		TCHECK(*t);
61412a08440Sreyk 		if (vflag)
61512a08440Sreyk 			printf(", antenna %u", *(u_int8_t*)t);
61612a08440Sreyk 		t += 1;
61712a08440Sreyk 	}
61812a08440Sreyk 
61912a08440Sreyk 	if (RADIOTAP(DB_ANTSIGNAL)) {
62012a08440Sreyk 		TCHECK(*t);
62112a08440Sreyk 		printf(", signal %udB", *(u_int8_t*)t);
62212a08440Sreyk 		t += 1;
62312a08440Sreyk 	}
62412a08440Sreyk 
62512a08440Sreyk 	if (RADIOTAP(DB_ANTNOISE)) {
62612a08440Sreyk 		TCHECK(*t);
62712a08440Sreyk 		printf(", noise %udB", *(u_int8_t*)t);
62812a08440Sreyk 		t += 1;
62912a08440Sreyk 	}
63012a08440Sreyk 
63112a08440Sreyk 	if (RADIOTAP(FCS)) {
63212a08440Sreyk 		TCHECK2(*t, 4);
63312a08440Sreyk 		if (vflag)
63412a08440Sreyk 			printf(", fcs %08x", letoh32(*(u_int32_t*)t));
63512a08440Sreyk 		t += 4;
63612a08440Sreyk 	}
63712a08440Sreyk 
63812a08440Sreyk #undef RADIOTAP
63912a08440Sreyk 
64012a08440Sreyk 	putchar('>');
64112a08440Sreyk 	goto out;
64212a08440Sreyk 
64312a08440Sreyk  trunc:
64412a08440Sreyk 	/* Truncated frame */
64512a08440Sreyk 	printf("[|radiotap + 802.11]");
64612a08440Sreyk 
64712a08440Sreyk  out:
64812a08440Sreyk 	if (xflag)
64912a08440Sreyk 		default_print(p, h->caplen);
65012a08440Sreyk 	putchar('\n');
65112a08440Sreyk }
652