xref: /openbsd-src/usr.sbin/tcpdump/print-802_11.c (revision 91f110e064cd7c194e59e019b83bb7496c1c84d4)
1 /*	$OpenBSD: print-802_11.c,v 1.13 2013/01/17 02:53:07 claudio Exp $	*/
2 
3 /*
4  * Copyright (c) 2005 Reyk Floeter <reyk@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/param.h>
20 #include <sys/time.h>
21 #include <sys/socket.h>
22 #include <sys/file.h>
23 #include <sys/ioctl.h>
24 
25 #include <net/if.h>
26 
27 #include <netinet/in.h>
28 #include <netinet/in_systm.h>
29 #include <netinet/if_ether.h>
30 
31 #include <net80211/ieee80211.h>
32 #include <net80211/ieee80211_radiotap.h>
33 
34 #include <pcap.h>
35 #include <stdio.h>
36 #include <string.h>
37 
38 #include "addrtoname.h"
39 #include "interface.h"
40 
41 const char *ieee80211_mgt_subtype_name[] = {
42 	"association request",
43 	"association response",
44 	"reassociation request",
45 	"reassociation response",
46 	"probe request",
47 	"probe response",
48 	"reserved#6",
49 	"reserved#7",
50 	"beacon",
51 	"atim",
52 	"disassociation",
53 	"authentication",
54 	"deauthentication",
55 	"action",
56 	"action noack",
57 	"reserved#15"
58 };
59 
60 const char *ieee80211_data_subtype_name[] = {
61 	"data",
62 	"data cf ack",
63 	"data cf poll",
64 	"data cf poll ack",
65 	"no-data",
66 	"no-data cf poll",
67 	"no-data cf ack",
68 	"no-data cf poll ack",
69 	"QoS data",
70 	"QoS data cf ack",
71 	"QoS data cf poll",
72 	"QoS data cf poll ack",
73 	"QoS no-data",
74 	"QoS no-data cf poll",
75 	"QoS no-data cf ack",
76 	"QoS no-data cf poll ack"
77 };
78 
79 int	 ieee80211_hdr(struct ieee80211_frame *);
80 int	 ieee80211_data(struct ieee80211_frame *, u_int);
81 void	 ieee80211_print_element(u_int8_t *, u_int);
82 void	 ieee80211_print_essid(u_int8_t *, u_int);
83 int	 ieee80211_elements(struct ieee80211_frame *, u_int);
84 int	 ieee80211_frame(struct ieee80211_frame *, u_int);
85 int	 ieee80211_print(struct ieee80211_frame *, u_int);
86 u_int	 ieee80211_any2ieee(u_int, u_int);
87 void	 ieee80211_reason(u_int16_t);
88 
89 #define TCARR(a)	TCHECK2(*a, sizeof(a))
90 
91 int ieee80211_encap = 0;
92 
93 int
94 ieee80211_hdr(struct ieee80211_frame *wh)
95 {
96 	struct ieee80211_frame_addr4 *w4;
97 
98 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
99 	case IEEE80211_FC1_DIR_NODS:
100 		TCARR(wh->i_addr2);
101 		printf("%s", etheraddr_string(wh->i_addr2));
102 		TCARR(wh->i_addr1);
103 		printf(" > %s", etheraddr_string(wh->i_addr1));
104 		TCARR(wh->i_addr3);
105 		printf(", bssid %s", etheraddr_string(wh->i_addr3));
106 		break;
107 	case IEEE80211_FC1_DIR_TODS:
108 		TCARR(wh->i_addr2);
109 		printf("%s", etheraddr_string(wh->i_addr2));
110 		TCARR(wh->i_addr3);
111 		printf(" > %s", etheraddr_string(wh->i_addr3));
112 		TCARR(wh->i_addr1);
113 		printf(", bssid %s, > DS", etheraddr_string(wh->i_addr1));
114 		break;
115 	case IEEE80211_FC1_DIR_FROMDS:
116 		TCARR(wh->i_addr3);
117 		printf("%s", etheraddr_string(wh->i_addr3));
118 		TCARR(wh->i_addr1);
119 		printf(" > %s", etheraddr_string(wh->i_addr1));
120 		TCARR(wh->i_addr2);
121 		printf(", bssid %s, DS >", etheraddr_string(wh->i_addr2));
122 		break;
123 	case IEEE80211_FC1_DIR_DSTODS:
124 		w4 = (struct ieee80211_frame_addr4 *) wh;
125 		TCARR(w4->i_addr4);
126 		printf("%s", etheraddr_string(w4->i_addr4));
127 		TCARR(w4->i_addr3);
128 		printf(" > %s", etheraddr_string(w4->i_addr3));
129 		TCARR(w4->i_addr2);
130 		printf(", bssid %s", etheraddr_string(w4->i_addr2));
131 		TCARR(w4->i_addr1);
132 		printf(" > %s, DS > DS", etheraddr_string(w4->i_addr1));
133 		break;
134 	}
135 	if (vflag) {
136 		u_int16_t seq;
137 		TCARR(wh->i_seq);
138 		bcopy(wh->i_seq, &seq, sizeof(u_int16_t));
139 		printf(" (seq %u): ", letoh16(seq));
140 	} else
141 		printf(": ");
142 
143 	return (0);
144 
145  trunc:
146 	/* Truncated elements in frame */
147 	return (1);
148 }
149 
150 int
151 ieee80211_data(struct ieee80211_frame *wh, u_int len)
152 {
153 	u_int8_t *t = (u_int8_t *)wh;
154 	struct ieee80211_frame_addr4 *w4;
155 	u_int datalen;
156 	int data = !(wh->i_fc[1] & IEEE80211_FC0_SUBTYPE_NODATA);
157 	u_char *esrc = NULL, *edst = NULL;
158 
159 	TCHECK(*wh);
160 	t += sizeof(struct ieee80211_frame);
161 	datalen = len - sizeof(struct ieee80211_frame);
162 
163 	switch (wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) {
164 	case IEEE80211_FC1_DIR_TODS:
165 		esrc = wh->i_addr2;
166 		edst = wh->i_addr3;
167 		break;
168 	case IEEE80211_FC1_DIR_FROMDS:
169 		esrc = wh->i_addr3;
170 		edst = wh->i_addr1;
171 		break;
172 	case IEEE80211_FC1_DIR_NODS:
173 		esrc = wh->i_addr2;
174 		edst = wh->i_addr1;
175 		break;
176 	case IEEE80211_FC1_DIR_DSTODS:
177 		w4 = (struct ieee80211_frame_addr4 *) wh;
178 		TCHECK(*w4);
179 		t = (u_int8_t *) (w4 + 1);
180 		datalen = len - sizeof(*w4);
181 		esrc = w4->i_addr4;
182 		edst = w4->i_addr3;
183 		break;
184 	}
185 
186 	if (data && esrc)
187 		llc_print(t, datalen, datalen, esrc, edst);
188 	else if (eflag && esrc)
189 		printf("%s > %s",
190 		    etheraddr_string(esrc), etheraddr_string(edst));
191 
192 	return (0);
193 
194  trunc:
195 	/* Truncated elements in frame */
196 	return (1);
197 }
198 
199 /* Caller checks len */
200 void
201 ieee80211_print_element(u_int8_t *data, u_int len)
202 {
203 	u_int8_t *p;
204 	int i;
205 
206 	printf(" 0x");
207 	for (i = 0, p = data; i < len; i++, p++)
208 		printf("%02x", *p);
209 }
210 
211 /* Caller checks len */
212 void
213 ieee80211_print_essid(u_int8_t *essid, u_int len)
214 {
215 	u_int8_t *p;
216 	int i;
217 
218 	if (len > IEEE80211_NWID_LEN)
219 		len = IEEE80211_NWID_LEN;
220 
221 	/* determine printable or not */
222 	for (i = 0, p = essid; i < len; i++, p++) {
223 		if (*p < ' ' || *p > 0x7e)
224 			break;
225 	}
226 	if (i == len) {
227 		printf(" (");
228 		for (i = 0, p = essid; i < len; i++, p++)
229 			putchar(*p);
230 		putchar(')');
231 	} else
232 		ieee80211_print_element(essid, len);
233 }
234 
235 int
236 ieee80211_elements(struct ieee80211_frame *wh, u_int flen)
237 {
238 	u_int8_t *buf, *frm;
239 	u_int64_t tstamp;
240 	u_int16_t bintval, capinfo;
241 	int i;
242 
243 	buf = (u_int8_t *)wh;
244 	frm = (u_int8_t *)&wh[1];
245 
246 	TCHECK2(*frm, 8);
247 	bcopy(frm, &tstamp, sizeof(u_int64_t));
248 	frm += 8;
249 
250 	if (vflag > 1)
251 		printf(", timestamp %llu", letoh64(tstamp));
252 
253 	TCHECK2(*frm, 2);
254 	bcopy(frm, &bintval, sizeof(u_int16_t));
255 	frm += 2;
256 
257 	if (vflag > 1)
258 		printf(", interval %u", letoh16(bintval));
259 
260 	TCHECK2(*frm, 2);
261 	bcopy(frm, &capinfo, sizeof(u_int16_t));
262 	frm += 2;
263 
264 	if (vflag)
265 		printb(", caps", letoh16(capinfo),
266 		    IEEE80211_CAPINFO_BITS);
267 
268 	while (TTEST2(*frm, 2)) {
269 		u_int len = frm[1];
270 		u_int8_t *data = frm + 2;
271 
272 		if (!TTEST2(*data, len))
273 			break;
274 
275 #define ELEM_CHECK(l)	if (len != l) break
276 
277 		switch (*frm) {
278 		case IEEE80211_ELEMID_SSID:
279 			printf(", ssid");
280 			ieee80211_print_essid(data, len);
281 			break;
282 		case IEEE80211_ELEMID_RATES:
283 			printf(", rates");
284 			if (!vflag)
285 				break;
286 			for (i = len; i > 0; i--, data++)
287 				printf(" %uM",
288 				    (data[0] & IEEE80211_RATE_VAL) / 2);
289 			break;
290 		case IEEE80211_ELEMID_FHPARMS:
291 			ELEM_CHECK(5);
292 			printf(", fh (dwell %u, chan %u, index %u)",
293 			    (data[1] << 8) | data[0],
294 			    (data[2] - 1) * 80 + data[3],	/* FH_CHAN */
295 			    data[4]);
296 			break;
297 		case IEEE80211_ELEMID_DSPARMS:
298 			ELEM_CHECK(1);
299 			printf(", ds");
300 			if (vflag)
301 				printf(" (chan %u)", data[0]);
302 			break;
303 		case IEEE80211_ELEMID_CFPARMS:
304 			printf(", cf");
305 			if (vflag)
306 				ieee80211_print_element(data, len);
307 			break;
308 		case IEEE80211_ELEMID_TIM:
309 			printf(", tim");
310 			if (vflag)
311 				ieee80211_print_element(data, len);
312 			break;
313 		case IEEE80211_ELEMID_IBSSPARMS:
314 			printf(", ibss");
315 			if (vflag)
316 				ieee80211_print_element(data, len);
317 			break;
318 		case IEEE80211_ELEMID_COUNTRY:
319 			printf(", country");
320 			for (i = len; i > 0; i--, data++)
321 				printf(" %u", data[0]);
322 			break;
323 		case IEEE80211_ELEMID_CHALLENGE:
324 			printf(", challenge");
325 			if (vflag)
326 				ieee80211_print_element(data, len);
327 			break;
328 		case IEEE80211_ELEMID_ERP:
329 			printf(", erp");
330 			if (vflag)
331 				ieee80211_print_element(data, len);
332 			break;
333 		case IEEE80211_ELEMID_RSN:
334 			printf(", rsn");
335 			if (vflag)
336 				ieee80211_print_element(data, len);
337 			break;
338 		case IEEE80211_ELEMID_XRATES:
339 			printf(", xrates");
340 			if (!vflag)
341 				break;
342 			for (i = len; i > 0; i--, data++)
343 				printf(" %uM",
344 				    (data[0] & IEEE80211_RATE_VAL) / 2);
345 			break;
346 		case IEEE80211_ELEMID_TPC:
347 			printf(", tpc");
348 			if (vflag)
349 				ieee80211_print_element(data, len);
350 			break;
351 		case IEEE80211_ELEMID_CCKM:
352 			printf(", cckm");
353 			if (vflag)
354 				ieee80211_print_element(data, len);
355 			break;
356 		case IEEE80211_ELEMID_VENDOR:
357 			printf(", vendor");
358 			if (vflag)
359 				ieee80211_print_element(data, len);
360 			break;
361 		default:
362 			printf(", %u:%u", (u_int) *frm, len);
363 			if (vflag)
364 				ieee80211_print_element(data, len);
365 			break;
366 		}
367 		frm += len + 2;
368 
369 		if (frm >= snapend)
370 			break;
371 	}
372 
373 #undef ELEM_CHECK
374 
375 	return (0);
376 
377  trunc:
378 	/* Truncated elements in frame */
379 	return (1);
380 }
381 
382 int
383 ieee80211_frame(struct ieee80211_frame *wh, u_int len)
384 {
385 	u_int8_t subtype, type, *frm;
386 
387 	TCARR(wh->i_fc);
388 
389 	type = wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK;
390 	subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
391 
392 	frm = (u_int8_t *)&wh[1];
393 
394 	if (vflag)
395 		printb(" flags", wh->i_fc[1], IEEE80211_FC1_BITS);
396 
397 	switch (type) {
398 	case IEEE80211_FC0_TYPE_DATA:
399 		printf(": %s: ", ieee80211_data_subtype_name[
400 		    subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
401 		ieee80211_data(wh, len);
402 		break;
403 	case IEEE80211_FC0_TYPE_MGT:
404 		printf(": %s", ieee80211_mgt_subtype_name[
405 		    subtype >> IEEE80211_FC0_SUBTYPE_SHIFT]);
406 		switch (subtype) {
407 		case IEEE80211_FC0_SUBTYPE_BEACON:
408 		case IEEE80211_FC0_SUBTYPE_PROBE_RESP:
409 			if (ieee80211_elements(wh, len) != 0)
410 				goto trunc;
411 			break;
412 		case IEEE80211_FC0_SUBTYPE_AUTH:
413 			TCHECK2(*frm, 2);		/* Auth Algorithm */
414 			switch (IEEE80211_AUTH_ALGORITHM(frm)) {
415 			case IEEE80211_AUTH_ALG_OPEN:
416 				TCHECK2(*frm, 4);	/* Auth Transaction */
417 				switch (IEEE80211_AUTH_TRANSACTION(frm)) {
418 				case IEEE80211_AUTH_OPEN_REQUEST:
419 					printf(" request");
420 					break;
421 				case IEEE80211_AUTH_OPEN_RESPONSE:
422 					printf(" response");
423 					break;
424 				}
425 				break;
426 			case IEEE80211_AUTH_ALG_SHARED:
427 				TCHECK2(*frm, 4);	/* Auth Transaction */
428 				switch (IEEE80211_AUTH_TRANSACTION(frm)) {
429 				case IEEE80211_AUTH_SHARED_REQUEST:
430 					printf(" request");
431 					break;
432 				case IEEE80211_AUTH_SHARED_CHALLENGE:
433 					printf(" challenge");
434 					break;
435 				case IEEE80211_AUTH_SHARED_RESPONSE:
436 					printf(" response");
437 					break;
438 				case IEEE80211_AUTH_SHARED_PASS:
439 					printf(" pass");
440 					break;
441 				}
442 				break;
443 			case IEEE80211_AUTH_ALG_LEAP:
444 				printf(" (leap)");
445 				break;
446 			}
447 			break;
448 		case IEEE80211_FC0_SUBTYPE_DEAUTH:
449 		case IEEE80211_FC0_SUBTYPE_DISASSOC:
450 			TCHECK2(*frm, 2);		/* Reason Code */
451 			ieee80211_reason(frm[0] | (frm[1] << 8));
452 			break;
453 		}
454 		break;
455 	default:
456 		printf(": type#%d", type);
457 		break;
458 	}
459 
460 	return (0);
461 
462  trunc:
463 	/* Truncated 802.11 frame */
464 	return (1);
465 }
466 
467 u_int
468 ieee80211_any2ieee(u_int freq, u_int flags)
469 {
470 	if (flags & IEEE80211_CHAN_2GHZ) {
471 		if (freq == 2484)
472 			return 14;
473 		if (freq < 2484)
474 			return (freq - 2407) / 5;
475 		else
476 			return 15 + ((freq - 2512) / 20);
477 	} else if (flags & IEEE80211_CHAN_5GHZ) {
478 		return (freq - 5000) / 5;
479 	} else {
480 		/* Assume channel is already an IEEE number */
481 		return (freq);
482 	}
483 }
484 
485 int
486 ieee80211_print(struct ieee80211_frame *wh, u_int len)
487 {
488 	if (eflag)
489 		if (ieee80211_hdr(wh))
490 			return (1);
491 
492 	printf("802.11");
493 
494 	return (ieee80211_frame(wh, len));
495 }
496 
497 void
498 ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h,
499     const u_char *p)
500 {
501 	struct ieee80211_frame *wh = (struct ieee80211_frame*)p;
502 
503 	if (!ieee80211_encap)
504 		ts_print(&h->ts);
505 
506 	packetp = p;
507 	snapend = p + h->caplen;
508 
509 	if (ieee80211_print(wh, (u_int)h->len) != 0)
510 		printf("[|802.11]");
511 
512 	if (!ieee80211_encap) {
513 		if (xflag)
514 			default_print(p, (u_int)h->len);
515 		putchar('\n');
516 	}
517 }
518 
519 void
520 ieee802_11_radio_if_print(u_char *user, const struct pcap_pkthdr *h,
521     const u_char *p)
522 {
523 	struct ieee80211_radiotap_header *rh =
524 	    (struct ieee80211_radiotap_header*)p;
525 	struct ieee80211_frame *wh;
526 	u_int8_t *t;
527 	u_int32_t present;
528 	u_int len, rh_len;
529 	u_int16_t tmp;
530 
531 	if (!ieee80211_encap)
532 		ts_print(&h->ts);
533 
534 	packetp = p;
535 	snapend = p + h->caplen;
536 
537 	TCHECK(*rh);
538 
539 	len = h->len;
540 	rh_len = letoh16(rh->it_len);
541 	if (rh->it_version != 0) {
542 		printf("[?radiotap + 802.11 v:%u]", rh->it_version);
543 		goto out;
544 	}
545 
546 	wh = (struct ieee80211_frame *)(p + rh_len);
547 	if (len <= rh_len || ieee80211_print(wh, len - rh_len))
548 		printf("[|802.11]");
549 
550 	t = (u_int8_t*)p + sizeof(struct ieee80211_radiotap_header);
551 
552 	if ((present = letoh32(rh->it_present)) == 0)
553 		goto out;
554 
555 	printf(", <radiotap v%u", rh->it_version);
556 
557 #define RADIOTAP(_x)	\
558 	(present & (1 << IEEE80211_RADIOTAP_##_x))
559 
560 	if (RADIOTAP(TSFT)) {
561 		u_int64_t tsf;
562 
563 		TCHECK2(*t, 8);
564 		bcopy(t, &tsf, sizeof(u_int64_t));
565 		if (vflag > 1)
566 			printf(", tsf %llu", letoh64(tsf));
567 		t += 8;
568 	}
569 
570 	if (RADIOTAP(FLAGS)) {
571 		u_int8_t flags = *(u_int8_t*)t;
572 		TCHECK2(*t, 1);
573 
574 		if (flags & IEEE80211_RADIOTAP_F_CFP)
575 			printf(", CFP");
576 		if (flags & IEEE80211_RADIOTAP_F_SHORTPRE)
577 			printf(", SHORTPRE");
578 		if (flags & IEEE80211_RADIOTAP_F_WEP)
579 			printf(", WEP");
580 		if (flags & IEEE80211_RADIOTAP_F_FRAG)
581 			printf(", FRAG");
582 		t += 1;
583 	}
584 
585 	if (RADIOTAP(RATE)) {
586 		TCHECK2(*t, 1);
587 		if (vflag)
588 			printf(", %uMbit/s", (*(u_int8_t*)t) / 2);
589 		t += 1;
590 	}
591 
592 	if (RADIOTAP(CHANNEL)) {
593 		u_int16_t freq, flags;
594 		TCHECK2(*t, 2);
595 
596 		bcopy(t, &freq, sizeof(u_int16_t));
597 		freq = letoh16(freq);
598 		t += 2;
599 		TCHECK2(*t, 2);
600 		bcopy(t, &flags, sizeof(u_int16_t));
601 		flags = letoh16(flags);
602 		t += 2;
603 
604 		printf(", chan %u", ieee80211_any2ieee(freq, flags));
605 
606 		if (flags & IEEE80211_CHAN_DYN &&
607 		    flags & IEEE80211_CHAN_2GHZ)
608 			printf(", 11g");
609 		else if (flags & IEEE80211_CHAN_CCK &&
610 		    flags & IEEE80211_CHAN_2GHZ)
611 			printf(", 11b");
612 		else if (flags & IEEE80211_CHAN_OFDM &&
613 		    flags & IEEE80211_CHAN_2GHZ)
614 			printf(", 11G");
615 		else if (flags & IEEE80211_CHAN_OFDM &&
616 		    flags & IEEE80211_CHAN_5GHZ)
617 			printf(", 11a");
618 
619 		if (flags & IEEE80211_CHAN_TURBO)
620 			printf(", TURBO");
621 		if (flags & IEEE80211_CHAN_XR)
622 			printf(", XR");
623 	}
624 
625 	if (RADIOTAP(FHSS)) {
626 		TCHECK2(*t, 2);
627 		printf(", fhss %u/%u", *(u_int8_t*)t, *(u_int8_t*)t + 1);
628 		t += 2;
629 	}
630 
631 	if (RADIOTAP(DBM_ANTSIGNAL)) {
632 		TCHECK(*t);
633 		printf(", sig %ddBm", *(int8_t*)t);
634 		t += 1;
635 	}
636 
637 	if (RADIOTAP(DBM_ANTNOISE)) {
638 		TCHECK(*t);
639 		printf(", noise %ddBm", *(int8_t*)t);
640 		t += 1;
641 	}
642 
643 	if (RADIOTAP(LOCK_QUALITY)) {
644 		TCHECK2(*t, 2);
645 		if (vflag) {
646 			bcopy(t, &tmp, sizeof(u_int16_t));
647 			printf(", quality %u", letoh16(tmp));
648 		}
649 		t += 2;
650 	}
651 
652 	if (RADIOTAP(TX_ATTENUATION)) {
653 		TCHECK2(*t, 2);
654 		if (vflag) {
655 			bcopy(t, &tmp, sizeof(u_int16_t));
656 			printf(", txatt %u", letoh16(tmp));
657 		}
658 		t += 2;
659 	}
660 
661 	if (RADIOTAP(DB_TX_ATTENUATION)) {
662 		TCHECK2(*t, 2);
663 		if (vflag) {
664 			bcopy(t, &tmp, sizeof(u_int16_t));
665 			printf(", txatt %udB", letoh16(tmp));
666 		}
667 		t += 2;
668 	}
669 
670 	if (RADIOTAP(DBM_TX_POWER)) {
671 		TCHECK(*t);
672 		printf(", txpower %ddBm", *(int8_t*)t);
673 		t += 1;
674 	}
675 
676 	if (RADIOTAP(ANTENNA)) {
677 		TCHECK(*t);
678 		if (vflag)
679 			printf(", antenna %u", *(u_int8_t*)t);
680 		t += 1;
681 	}
682 
683 	if (RADIOTAP(DB_ANTSIGNAL)) {
684 		TCHECK(*t);
685 		printf(", signal %udB", *(u_int8_t*)t);
686 		t += 1;
687 	}
688 
689 	if (RADIOTAP(DB_ANTNOISE)) {
690 		TCHECK(*t);
691 		printf(", noise %udB", *(u_int8_t*)t);
692 		t += 1;
693 	}
694 
695 	if (RADIOTAP(FCS)) {
696 		TCHECK2(*t, 4);
697 		if (vflag) {
698 			u_int32_t fcs;
699 			bcopy(t, &fcs, sizeof(u_int32_t));
700 			printf(", fcs %08x", letoh32(fcs));
701 		}
702 		t += 4;
703 	}
704 
705 	if (RADIOTAP(RSSI)) {
706 		u_int8_t rssi, max_rssi;
707 		TCHECK(*t);
708 		rssi = *(u_int8_t*)t;
709 		t += 1;
710 		TCHECK(*t);
711 		max_rssi = *(u_int8_t*)t;
712 		t += 1;
713 
714 		printf(", rssi %u/%u", rssi, max_rssi);
715 	}
716 
717 #undef RADIOTAP
718 
719 	putchar('>');
720 	goto out;
721 
722  trunc:
723 	/* Truncated frame */
724 	printf("[|radiotap + 802.11]");
725 
726  out:
727 	if (!ieee80211_encap) {
728 		if (xflag)
729 			default_print(p, h->len);
730 		putchar('\n');
731 	}
732 }
733 
734 void
735 ieee80211_reason(u_int16_t reason)
736 {
737 	if (!vflag)
738 		return;
739 
740 	switch (reason) {
741 	case IEEE80211_REASON_UNSPECIFIED:
742 		printf(", unspecified failure");
743 		break;
744 	case IEEE80211_REASON_AUTH_EXPIRE:
745 		printf(", authentication expired");
746 		break;
747 	case IEEE80211_REASON_AUTH_LEAVE:
748 		printf(", deauth - station left");
749 		break;
750 	case IEEE80211_REASON_ASSOC_EXPIRE:
751 		printf(", association expired");
752 		break;
753 	case IEEE80211_REASON_ASSOC_TOOMANY:
754 		printf(", too many associated stations");
755 		break;
756 	case IEEE80211_REASON_NOT_AUTHED:
757 		printf(", not authenticated");
758 		break;
759 	case IEEE80211_REASON_NOT_ASSOCED:
760 		printf(", not associated");
761 		break;
762 	case IEEE80211_REASON_ASSOC_LEAVE:
763 		printf(", disassociated - station left");
764 		break;
765 	case IEEE80211_REASON_ASSOC_NOT_AUTHED:
766 		printf(", association but not authenticated");
767 		break;
768 	case IEEE80211_REASON_RSN_REQUIRED:
769 		printf(", rsn required");
770 		break;
771 	case IEEE80211_REASON_RSN_INCONSISTENT:
772 		printf(", rsn inconsistent");
773 		break;
774 	case IEEE80211_REASON_IE_INVALID:
775 		printf(", ie invalid");
776 		break;
777 	case IEEE80211_REASON_MIC_FAILURE:
778 		printf(", mic failure");
779 		break;
780 	default:
781 		printf(", unknown reason %u", reason);
782 	}
783 }
784