]> The Tcpdump Group git mirrors - tcpdump/blob - print-802_11.c
Add support for DLT_PRISM and DLT_IEEE802_11_RADIO.
[tcpdump] / print-802_11.c
1 /*
2 * Copyright (c) 2001
3 * Fortress Technologies, Inc. All rights reserved.
4 * Charlie Lenahan (clenahan@fortresstech.com)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that: (1) source code distributions
8 * retain the above copyright notice and this paragraph in its entirety, (2)
9 * distributions including binary code include the above copyright notice and
10 * this paragraph in its entirety in the documentation or other materials
11 * provided with the distribution, and (3) all advertising materials mentioning
12 * features or use of this software display the following acknowledgement:
13 * ``This product includes software developed by the University of California,
14 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
15 * the University nor the names of its contributors may be used to endorse
16 * or promote products derived from this software without specific prior
17 * written permission.
18 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
19 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
20 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 */
22
23 #ifndef lint
24 static const char rcsid[] =
25 "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.13 2002-12-12 07:28:35 guy Exp $ (LBL)";
26 #endif
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <tcpdump-stdinc.h>
33
34 #include <stdio.h>
35 #include <pcap.h>
36 #include <string.h>
37
38 #include "interface.h"
39 #include "addrtoname.h"
40 #include "ethertype.h"
41
42 #include "extract.h"
43
44 #include "ieee802_11.h"
45
46 #define PRINT_RATES(p) \
47 do { \
48 int z; \
49 const char *sep = " ["; \
50 for (z = 0; z < p.rates.length ; z++) { \
51 printf("%s%2.1f", sep, (.5 * (p.rates.rate[z] & 0x7f))); \
52 sep = " "; \
53 } \
54 if (p.rates.length != 0) \
55 printf(" Mbit]"); \
56 } while (0)
57
58 static const char *auth_alg_text[]={"Open System","Shared Key","EAP"};
59 static const char *subtype_text[]={
60 "Assoc Request",
61 "Assoc Response",
62 "ReAssoc Request",
63 "ReAssoc Response",
64 "Probe Request",
65 "Probe Response",
66 "RESERVED",
67 "RESERVED",
68 "Beacon",
69 "ATIM",
70 "Disassociation",
71 "Authentication",
72 "DeAuthentication",
73 "RESERVED",
74 "RESERVED"
75 };
76
77 static const char *status_text[] = {
78 "Succesful", /* 0 */
79 "Unspecified failure", /* 1 */
80 "Reserved", /* 2 */
81 "Reserved", /* 3 */
82 "Reserved", /* 4 */
83 "Reserved", /* 5 */
84 "Reserved", /* 6 */
85 "Reserved", /* 7 */
86 "Reserved", /* 8 */
87 "Reserved", /* 9 */
88 "Cannot Support all requested capabilities in the Capability Information field", /* 10 */
89 "Reassociation denied due to inability to confirm that association exists", /* 11 */
90 "Association denied due to reason outside the scope of the standard", /* 12 */
91 "Responding station does not support the specified authentication algorithm ", /* 13 */
92 "Received an Authentication frame with authentication transaction " \
93 "sequence number out of expected sequence", /* 14 */
94 "Authentication rejected because of challenge failure", /* 15 */
95 "Authentication rejected due to timeout waiting for next frame in sequence", /* 16 */
96 "Association denied because AP is unable to handle additional associated stations", /* 17 */
97 "Association denied due to requesting station not supporting all of the " \
98 "data rates in BSSBasicRateSet parameter", /* 18 */
99 NULL
100 };
101
102 static const char *reason_text[] = {
103 "Reserved", /* 0 */
104 "Unspecified reason", /* 1 */
105 "Previous authentication no longer valid", /* 2 */
106 "Deauthenticated because sending station is leaving (or has left) IBSS or ESS", /* 3 */
107 "Disassociated due to inactivity", /* 4 */
108 "Disassociated because AP is unable to handle all currently associated stations", /* 5 */
109 "Class 2 frame receivedfrom nonauthenticated station", /* 6 */
110 "Class 3 frame received from nonassociated station", /* 7 */
111 "Disassociated because sending station is leaving (or has left) BSS", /* 8 */
112 "Station requesting (re)association is not authenticated with responding station", /* 9 */
113 NULL
114 };
115
116 static int wep_print(const u_char *p)
117 {
118 u_int32_t iv;
119
120 if (!TTEST2(*p, 4))
121 return 0;
122 iv = EXTRACT_LE_32BITS(p);
123
124 printf("Data IV:%3x Pad %x KeyID %x", IV_IV(iv), IV_PAD(iv),
125 IV_KEYID(iv));
126
127 return 1;
128 }
129
130
131 static int parse_elements(struct mgmt_body_t *pbody,const u_char *p,int offset)
132 {
133 for (;;) {
134 if (!TTEST2(*(p + offset), 1))
135 return 1;
136 switch (*(p + offset)) {
137 case E_SSID:
138 if (!TTEST2(*(p+offset), 2))
139 return 0;
140 memcpy(&(pbody->ssid),p+offset,2); offset += 2;
141 if (pbody->ssid.length > 0)
142 {
143 if (!TTEST2(*(p+offset), pbody->ssid.length))
144 return 0;
145 memcpy(&(pbody->ssid.ssid),p+offset,pbody->ssid.length); offset += pbody->ssid.length;
146 pbody->ssid.ssid[pbody->ssid.length]='\0';
147 }
148 break;
149 case E_CHALLENGE:
150 if (!TTEST2(*(p+offset), 2))
151 return 0;
152 memcpy(&(pbody->challenge),p+offset,2); offset += 2;
153 if (pbody->challenge.length > 0)
154 {
155 if (!TTEST2(*(p+offset), pbody->challenge.length))
156 return 0;
157 memcpy(&(pbody->challenge.text),p+offset,pbody->challenge.length); offset += pbody->challenge.length;
158 pbody->challenge.text[pbody->challenge.length]='\0';
159 }
160 break;
161 case E_RATES:
162 if (!TTEST2(*(p+offset), 2))
163 return 0;
164 memcpy(&(pbody->rates),p+offset,2); offset += 2;
165 if (pbody->rates.length > 0) {
166 if (!TTEST2(*(p+offset), pbody->rates.length))
167 return 0;
168 memcpy(&(pbody->rates.rate),p+offset,pbody->rates.length); offset += pbody->rates.length;
169 }
170 break;
171 case E_DS:
172 if (!TTEST2(*(p+offset), 3))
173 return 0;
174 memcpy(&(pbody->ds),p+offset,3); offset +=3;
175 break;
176 case E_CF:
177 if (!TTEST2(*(p+offset), 8))
178 return 0;
179 memcpy(&(pbody->cf),p+offset,8); offset +=8;
180 break;
181 case E_TIM:
182 if (!TTEST2(*(p+offset), 2))
183 return 0;
184 memcpy(&(pbody->tim),p+offset,2); offset +=2;
185 if (!TTEST2(*(p+offset), 3))
186 return 0;
187 memcpy(&(pbody->tim.count),p+offset,3); offset +=3;
188
189 if ((pbody->tim.length -3) > 0)
190 {
191 if (!TTEST2(*(p+offset), pbody->tim.length -3))
192 return 0;
193 memcpy((pbody->tim.bitmap),p+(pbody->tim.length -3),(pbody->tim.length -3));
194 offset += pbody->tim.length -3;
195 }
196
197 break;
198 default:
199 #if 0
200 printf("(1) unhandled element_id (%d) ", *(p+offset) );
201 #endif
202 offset+= *(p+offset+1) + 2;
203 break;
204 }
205 }
206 return 1;
207 }
208
209 /*********************************************************************************
210 * Print Handle functions for the management frame types
211 *********************************************************************************/
212
213 static int handle_beacon(u_int16_t fc, const u_char *p)
214 {
215 struct mgmt_body_t pbody;
216 int offset = 0;
217
218 memset(&pbody, 0, sizeof(pbody));
219
220 if (!TTEST2(*p, 12))
221 return 0;
222 memcpy(&pbody.timestamp, p, 8);
223 offset += 8;
224 pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
225 offset += 2;
226 pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
227 offset += 2;
228
229 if (!parse_elements(&pbody,p,offset))
230 return 0;
231
232 printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
233 fn_print(pbody.ssid.ssid, NULL);
234 printf(")");
235 PRINT_RATES(pbody);
236 printf(" %s CH: %u%s",
237 CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS",
238 pbody.ds.channel,
239 CAPABILITY_PRIVACY(pbody.capability_info) ? ", PRIVACY" : "" );
240
241 return 1;
242 }
243
244 static int handle_assoc_request(u_int16_t fc, const u_char *p)
245 {
246 struct mgmt_body_t pbody;
247 int offset = 0;
248
249 memset(&pbody, 0, sizeof(pbody));
250
251 if (!TTEST2(*p, 4))
252 return 0;
253 pbody.capability_info = EXTRACT_LE_16BITS(p);
254 offset += 2;
255 pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
256 offset += 2;
257
258 if (!parse_elements(&pbody,p,offset))
259 return 0;
260
261 printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
262 fn_print(pbody.ssid.ssid, NULL);
263 printf(")");
264 PRINT_RATES(pbody);
265 return 1;
266 }
267
268 static int handle_assoc_response(u_int16_t fc, const u_char *p)
269 {
270 struct mgmt_body_t pbody;
271 int offset = 0;
272
273 memset(&pbody, 0, sizeof(pbody));
274
275 if (!TTEST2(*p, 6))
276 return 0;
277 pbody.capability_info = EXTRACT_LE_16BITS(p);
278 offset += 2;
279 pbody.status_code = EXTRACT_LE_16BITS(p+offset);
280 offset += 2;
281 pbody.aid = EXTRACT_LE_16BITS(p+offset);
282 offset += 2;
283
284 if (!parse_elements(&pbody,p,offset))
285 return 0;
286
287 printf("%s AID(%x) :%s: %s", subtype_text[FC_SUBTYPE(fc)],
288 ((u_int16_t)(pbody.aid << 2 )) >> 2 ,
289 CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
290 (pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a"));
291
292 return 1;
293 }
294
295
296 static int handle_reassoc_request(u_int16_t fc, const u_char *p)
297 {
298 struct mgmt_body_t pbody;
299 int offset = 0;
300
301 memset(&pbody, 0, sizeof(pbody));
302
303 if (!TTEST2(*p, 10))
304 return 0;
305 pbody.capability_info = EXTRACT_LE_16BITS(p);
306 offset += 2;
307 pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
308 offset += 2;
309 memcpy(&pbody.ap,p+offset,6);
310 offset += 6;
311
312 if (!parse_elements(&pbody,p,offset))
313 return 0;
314
315 printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
316 fn_print(pbody.ssid.ssid, NULL);
317 printf(") AP : %s", etheraddr_string( pbody.ap ));
318
319 return 1;
320 }
321
322 static int handle_reassoc_response(u_int16_t fc, const u_char *p)
323 {
324 /* Same as a Association Reponse */
325 return handle_assoc_response(fc, p);
326 }
327
328 static int handle_probe_request(u_int16_t fc, const u_char *p)
329 {
330 struct mgmt_body_t pbody;
331 int offset = 0;
332
333 memset(&pbody, 0, sizeof(pbody));
334
335 if (!parse_elements(&pbody, p, offset))
336 return 0;
337
338 printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
339 fn_print(pbody.ssid.ssid, NULL);
340 printf(")");
341 PRINT_RATES(pbody);
342
343 return 1;
344 }
345
346 static int handle_probe_response(u_int16_t fc, const u_char *p)
347 {
348 struct mgmt_body_t pbody;
349 int offset = 0;
350
351 memset(&pbody, 0, sizeof(pbody));
352
353 if (!TTEST2(*p, 12))
354 return 0;
355 memcpy(&pbody.timestamp,p,8);
356 offset += 8;
357 pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
358 offset += 2;
359 pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
360 offset += 2;
361
362 if (!parse_elements(&pbody, p, offset))
363 return 0;
364
365 printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
366 fn_print(pbody.ssid.ssid, NULL);
367 printf(") ");
368 PRINT_RATES(pbody);
369 printf(" CH: %u%s", pbody.ds.channel,
370 CAPABILITY_PRIVACY(pbody.capability_info) ? ", PRIVACY" : "" );
371
372 return 1;
373 }
374
375 static int handle_atim(void)
376 {
377 /* the frame body for ATIM is null. */
378 printf("ATIM");
379 return 1;
380 }
381
382 static int handle_disassoc(u_int16_t fc, const u_char *p)
383 {
384 struct mgmt_body_t pbody;
385 int offset = 0;
386
387 memset(&pbody, 0, sizeof(pbody));
388
389 if (!TTEST2(*p, 2))
390 return 0;
391 pbody.reason_code = EXTRACT_LE_16BITS(p);
392 offset += 2;
393
394 printf("%s: %s", subtype_text[FC_SUBTYPE(fc)],
395 pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
396
397 return 1;
398 }
399
400 static int handle_auth(u_int16_t fc, const u_char *p)
401 {
402 struct mgmt_body_t pbody;
403 int offset = 0;
404
405 memset(&pbody, 0, sizeof(pbody));
406
407 if (!TTEST2(*p, 6))
408 return 0;
409 pbody.auth_alg = EXTRACT_LE_16BITS(p);
410 offset += 2;
411 pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset);
412 offset += 2;
413 pbody.status_code = EXTRACT_LE_16BITS(p + offset);
414 offset += 2;
415
416 if (!parse_elements(&pbody,p,offset))
417 return 0;
418
419 if ((pbody.auth_alg == 1) &&
420 ((pbody.auth_trans_seq_num == 2) || (pbody.auth_trans_seq_num == 3))) {
421 printf("%s (%s)-%x [Challenge Text] %s",
422 subtype_text[FC_SUBTYPE(fc)],
423 pbody.auth_alg < 4 ? auth_alg_text[pbody.auth_alg] : "Reserved" ,
424 pbody.auth_trans_seq_num,
425 ((pbody.auth_trans_seq_num % 2) ?
426 (pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a") : "" ));
427 } else {
428 printf("%s (%s)-%x: %s",
429 subtype_text[FC_SUBTYPE(fc)],
430 pbody.auth_alg < 4 ? auth_alg_text[pbody.auth_alg] : "Reserved" ,
431 pbody.auth_trans_seq_num,
432 ((pbody.auth_trans_seq_num % 2) ? (pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a") : ""));
433 }
434
435 return 1;
436 }
437
438 static int handle_deauth(u_int16_t fc, const struct mgmt_header_t *pmh,
439 const u_char *p)
440 {
441 struct mgmt_body_t pbody;
442 int offset = 0;
443
444 memset(&pbody, 0, sizeof(pbody));
445
446 if (!TTEST2(*p, 2))
447 return 0;
448 pbody.reason_code = EXTRACT_LE_16BITS(p);
449 offset += 2;
450
451 if (eflag) {
452 printf("%s: %s",
453 subtype_text[FC_SUBTYPE(fc)],
454 pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
455 } else {
456 printf("%s (%s): %s",
457 subtype_text[FC_SUBTYPE(fc)], etheraddr_string(pmh->sa),
458 pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
459 }
460
461 return 1;
462 }
463
464
465 /*********************************************************************************
466 * Print Body funcs
467 *********************************************************************************/
468
469
470 static int mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
471 const u_char *p)
472 {
473 switch (FC_SUBTYPE(fc)) {
474 case ST_ASSOC_REQUEST:
475 return (handle_assoc_request(fc, p));
476 case ST_ASSOC_RESPONSE:
477 return (handle_assoc_response(fc, p));
478 case ST_REASSOC_REQUEST:
479 return (handle_reassoc_request(fc, p));
480 case ST_REASSOC_RESPONSE:
481 return (handle_reassoc_response(fc, p));
482 case ST_PROBE_REQUEST:
483 return (handle_probe_request(fc, p));
484 case ST_PROBE_RESPONSE:
485 return (handle_probe_response(fc, p));
486 case ST_BEACON:
487 return (handle_beacon(fc, p));
488 case ST_ATIM:
489 return (handle_atim());
490 case ST_DISASSOC:
491 return (handle_disassoc(fc, p));
492 case ST_AUTH:
493 if (!TTEST2(*p, 3))
494 return 0;
495 if ((p[0] == 0 ) && (p[1] == 0) && (p[2] == 0)) {
496 printf("Authentication (Shared-Key)-3 ");
497 return (wep_print(p));
498 }
499 else
500 return (handle_auth(fc, p));
501 case ST_DEAUTH:
502 return (handle_deauth(fc, pmh, p));
503 break;
504 default:
505 printf("Unhandled Managment subtype(%x)",
506 FC_SUBTYPE(fc));
507 return 1;
508 }
509 }
510
511
512 /*********************************************************************************
513 * Handles printing all the control frame types
514 *********************************************************************************/
515
516 static int ctrl_body_print(u_int16_t fc, const u_char *p)
517 {
518 switch (FC_SUBTYPE(fc)) {
519 case CTRL_PS_POLL:
520 if (!TTEST2(*p, CTRL_PS_POLL_LEN))
521 return 0;
522 printf("Power Save-Poll AID(%x)",
523 EXTRACT_LE_16BITS(&(((const struct ctrl_ps_poll_t *)p)->aid)));
524 break;
525 case CTRL_RTS:
526 if (!TTEST2(*p, CTRL_RTS_LEN))
527 return 0;
528 if (eflag)
529 printf("Request-To-Send");
530 else
531 printf("Request-To-Send TA:%s ",
532 etheraddr_string(((const struct ctrl_rts_t *)p)->ta));
533 break;
534 case CTRL_CTS:
535 if (!TTEST2(*p, CTRL_CTS_LEN))
536 return 0;
537 if (eflag)
538 printf("Clear-To-Send");
539 else
540 printf("Clear-To-Send RA:%s ",
541 etheraddr_string(((const struct ctrl_cts_t *)p)->ra));
542 break;
543 case CTRL_ACK:
544 if (!TTEST2(*p, CTRL_ACK_LEN))
545 return 0;
546 if (eflag)
547 printf("Acknowledgment");
548 else
549 printf("Acknowledgment RA:%s ",
550 etheraddr_string(((const struct ctrl_ack_t *)p)->ra));
551 break;
552 case CTRL_CF_END:
553 if (!TTEST2(*p, CTRL_END_LEN))
554 return 0;
555 if (eflag)
556 printf("CF-End");
557 else
558 printf("CF-End RA:%s ",
559 etheraddr_string(((const struct ctrl_end_t *)p)->ra));
560 break;
561 case CTRL_END_ACK:
562 if (!TTEST2(*p, CTRL_END_ACK_LEN))
563 return 0;
564 if (eflag)
565 printf("CF-End+CF-Ack");
566 else
567 printf("CF-End+CF-Ack RA:%s ",
568 etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra));
569 break;
570 default:
571 printf("(B) Unknown Ctrl Subtype");
572 }
573 return 1;
574 }
575
576
577
578 /*
579 * Print Header funcs
580 */
581
582 /*
583 * Data Frame - Address field contents
584 *
585 * To Ds | From DS | Addr 1 | Addr 2 | Addr 3 | Addr 4
586 * 0 | 0 | DA | SA | BSSID | n/a
587 * 0 | 1 | DA | BSSID | SA | n/a
588 * 1 | 0 | BSSID | SA | DA | n/a
589 * 1 | 1 | RA | TA | DA | SA
590 */
591
592 static void data_header_print(u_int16_t fc, const u_char *p)
593 {
594 #define ADDR1 (p + 4)
595 #define ADDR2 (p + 10)
596 #define ADDR3 (p + 16)
597 #define ADDR4 (p + 24)
598
599 if (!FC_TO_DS(fc)) {
600 if (!FC_FROM_DS(fc))
601 printf("DA:%s SA:%s BSSID:%s ",
602 etheraddr_string(ADDR1), etheraddr_string(ADDR2),
603 etheraddr_string(ADDR3));
604 else
605 printf("DA:%s BSSID:%s SA:%s ",
606 etheraddr_string(ADDR1), etheraddr_string(ADDR2),
607 etheraddr_string(ADDR3));
608 } else {
609 if (!FC_FROM_DS(fc))
610 printf("BSSID:%s SA:%s DA:%s ",
611 etheraddr_string(ADDR1), etheraddr_string(ADDR2),
612 etheraddr_string(ADDR3));
613 else
614 printf("RA:%s TA:%s DA:%s SA:%s ",
615 etheraddr_string(ADDR1), etheraddr_string(ADDR2),
616 etheraddr_string(ADDR3), etheraddr_string(ADDR4));
617 }
618
619 #undef ADDR1
620 #undef ADDR2
621 #undef ADDR3
622 #undef ADDR4
623 }
624
625
626 static void mgmt_header_print(const u_char *p)
627 {
628 const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
629
630 printf("BSSID:%s DA:%s SA:%s ",
631 etheraddr_string((hp)->bssid), etheraddr_string((hp)->da),
632 etheraddr_string((hp)->sa));
633 }
634
635 static void ctrl_header_print(u_int16_t fc, const u_char *p)
636 {
637 switch (FC_SUBTYPE(fc)) {
638 case CTRL_PS_POLL:
639 printf("BSSID:%s TA:%s ",
640 etheraddr_string(((const struct ctrl_ps_poll_t *)p)->bssid),
641 etheraddr_string(((const struct ctrl_ps_poll_t *)p)->ta));
642 break;
643 case CTRL_RTS:
644 printf("RA:%s TA:%s ",
645 etheraddr_string(((const struct ctrl_rts_t *)p)->ra),
646 etheraddr_string(((const struct ctrl_rts_t *)p)->ta));
647 break;
648 case CTRL_CTS:
649 printf("RA:%s ",
650 etheraddr_string(((const struct ctrl_cts_t *)p)->ra));
651 break;
652 case CTRL_ACK:
653 printf("RA:%s ",
654 etheraddr_string(((const struct ctrl_ack_t *)p)->ra));
655 break;
656 case CTRL_CF_END:
657 printf("RA:%s BSSID:%s ",
658 etheraddr_string(((const struct ctrl_end_t *)p)->ra),
659 etheraddr_string(((const struct ctrl_end_t *)p)->bssid));
660 break;
661 case CTRL_END_ACK:
662 printf("RA:%s BSSID:%s ",
663 etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra),
664 etheraddr_string(((const struct ctrl_end_ack_t *)p)->bssid));
665 break;
666 default:
667 printf("(H) Unknown Ctrl Subtype");
668 }
669 }
670
671 static int GetHeaderLength(u_int16_t fc)
672 {
673 int iLength=0;
674
675 switch (FC_TYPE(fc)) {
676 case T_MGMT:
677 iLength = MGMT_HEADER_LEN;
678 break;
679 case T_CTRL:
680 switch (FC_SUBTYPE(fc)) {
681 case CTRL_PS_POLL:
682 iLength = CTRL_PS_POLL_LEN;
683 break;
684 case CTRL_RTS:
685 iLength = CTRL_RTS_LEN;
686 break;
687 case CTRL_CTS:
688 iLength = CTRL_CTS_LEN;
689 break;
690 case CTRL_ACK:
691 iLength = CTRL_ACK_LEN;
692 break;
693 case CTRL_CF_END:
694 iLength = CTRL_END_LEN;
695 break;
696 case CTRL_END_ACK:
697 iLength = CTRL_END_ACK_LEN;
698 break;
699 default:
700 iLength = 0;
701 break;
702 }
703 break;
704 case T_DATA:
705 if (FC_TO_DS(fc) && FC_FROM_DS(fc))
706 iLength = 30;
707 else
708 iLength = 24;
709 break;
710 default:
711 printf("unknown IEEE802.11 frame type (%d)",
712 FC_TYPE(fc));
713 break;
714 }
715
716 return iLength;
717 }
718
719 /*
720 * Print the 802.11 MAC header
721 */
722 static inline void
723 ieee_802_11_hdr_print(u_int16_t fc, const u_char *p)
724 {
725 switch (FC_TYPE(fc)) {
726 case T_MGMT:
727 mgmt_header_print(p);
728 break;
729
730 case T_CTRL:
731 ctrl_header_print(fc, p);
732 break;
733
734 case T_DATA:
735 data_header_print(fc, p);
736 break;
737
738 default:
739 printf("(header) unknown IEEE802.11 frame type (%d)",
740 FC_TYPE(fc));
741 break;
742 }
743 }
744
745 static void
746 ieee802_11_print(const u_char *p, u_int length, u_int caplen)
747 {
748 u_int16_t fc;
749 u_int HEADER_LENGTH;
750 u_short extracted_ethertype;
751
752 fc = EXTRACT_LE_16BITS(p);
753 HEADER_LENGTH = GetHeaderLength(fc);
754
755 if (caplen < HEADER_LENGTH) {
756 printf("[|802.11]");
757 return;
758 }
759
760 if (eflag)
761 ieee_802_11_hdr_print(fc, p);
762
763 /*
764 * Some printers want to get back at the ethernet addresses,
765 * and/or check that they're not walking off the end of the packet.
766 * Rather than pass them all the way down, we set these globals.
767 */
768 packetp = p;
769 snapend = p + caplen;
770
771 length -= HEADER_LENGTH;
772 caplen -= HEADER_LENGTH;
773 p += HEADER_LENGTH;
774
775 switch (FC_TYPE(fc)) {
776 case T_MGMT:
777 if (!mgmt_body_print(fc, (const struct mgmt_header_t *)packetp,
778 p)) {
779 printf("[|802.11]");
780 return;
781 }
782 break;
783
784 case T_CTRL:
785 if (!ctrl_body_print(fc, p - HEADER_LENGTH)) {
786 printf("[|802.11]");
787 return;
788 }
789 break;
790
791 case T_DATA:
792 /* There may be a problem w/ AP not having this bit set */
793 if (FC_WEP(fc)) {
794 if (!wep_print(p)) {
795 printf("[|802.11]");
796 return;
797 }
798 } else {
799 if (llc_print(p, length, caplen, packetp + 10,
800 packetp + 4, &extracted_ethertype) == 0) {
801 /*
802 * Some kinds of LLC packet we cannot
803 * handle intelligently
804 */
805 if (!eflag)
806 ieee_802_11_hdr_print(fc, p - HEADER_LENGTH);
807 if (extracted_ethertype) {
808 printf("(LLC %s) ",
809 etherproto_string(htons(extracted_ethertype)));
810 }
811 if (!xflag && !qflag)
812 default_print(p, caplen);
813 }
814 }
815 break;
816
817 default:
818 printf("(body) unhandled IEEE802.11 frame type (%d)",
819 FC_TYPE(fc));
820 break;
821 }
822
823 if (xflag)
824 default_print(p, caplen);
825 }
826
827 /*
828 * This is the top level routine of the printer. 'p' points
829 * to the 802.11 header of the packet, 'h->ts' is the timestamp,
830 * 'h->length' is the length of the packet off the wire, and 'h->caplen'
831 * is the number of bytes actually captured.
832 */
833 void
834 ieee802_11_if_print(u_char *user _U_, const struct pcap_pkthdr *h, const u_char *p)
835 {
836 u_int caplen = h->caplen;
837 u_int length = h->len;
838
839 ++infodelay;
840 ts_print(&h->ts);
841
842 if (caplen < IEEE802_11_FC_LEN) {
843 printf("[|802.11]");
844 goto out;
845 }
846
847 ieee802_11_print(p, length, caplen);
848
849 out:
850 putchar('\n');
851 --infodelay;
852 if (infoprint)
853 info(0);
854 }
855
856 #define PRISM_HDR_LEN 144
857
858 /*
859 * For DLT_PRISM_HEADER; like DLT_IEEE802_11, but with an extra header,
860 * containing information such as radio information, which we
861 * currently ignore.
862 */
863 void
864 prism_if_print(u_char *user _U_, const struct pcap_pkthdr *h, const u_char *p)
865 {
866 u_int caplen = h->caplen;
867 u_int length = h->len;
868
869 ++infodelay;
870 ts_print(&h->ts);
871
872 if (caplen < PRISM_HDR_LEN + IEEE802_11_FC_LEN) {
873 printf("[|802.11]");
874 goto out;
875 }
876
877 ieee802_11_print(p + PRISM_HDR_LEN, length - PRISM_HDR_LEN,
878 caplen - PRISM_HDR_LEN);
879
880 out:
881 putchar('\n');
882 --infodelay;
883 if (infoprint)
884 info(0);
885 }
886
887 #define IEEE802_11_RADIO_HDR_LEN 146
888
889 /*
890 * For DLT_IEEE802_11_RADIO; like DLT_IEEE802_11, but with an extra
891 * header, containing information such as radio information, which we
892 * currently ignore.
893 */
894 void
895 ieee802_11_radio_if_print(u_char *user _U_, const struct pcap_pkthdr *h,
896 const u_char *p)
897 {
898 u_int caplen = h->caplen;
899 u_int length = h->len;
900
901 ++infodelay;
902 ts_print(&h->ts);
903
904 if (caplen < IEEE802_11_RADIO_HDR_LEN + IEEE802_11_FC_LEN) {
905 printf("[|802.11]");
906 goto out;
907 }
908
909 ieee802_11_print(p + IEEE802_11_RADIO_HDR_LEN,
910 length - IEEE802_11_RADIO_HDR_LEN,
911 caplen - IEEE802_11_RADIO_HDR_LEN);
912
913 out:
914 putchar('\n');
915 --infodelay;
916 if (infoprint)
917 info(0);
918 }