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