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