]> The Tcpdump Group git mirrors - tcpdump/blob - print-802_11.c
remove blank lines at EOF
[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.11 2002-09-05 21:25:36 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_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 /*
746 * This is the top level routine of the printer. 'p' points
747 * to the 802.11 header of the packet, 'h->ts' is the timestamp,
748 * 'h->length' is the length of the packet off the wire, and 'h->caplen'
749 * is the number of bytes actually captured.
750 */
751 void
752 ieee802_11_if_print(u_char *user _U_, const struct pcap_pkthdr *h, const u_char *p)
753 {
754 u_int caplen = h->caplen;
755 u_int length = h->len;
756 u_int16_t fc;
757 u_int HEADER_LENGTH;
758 u_short extracted_ethertype;
759
760 ++infodelay;
761 ts_print(&h->ts);
762
763 if (caplen < IEEE802_11_FC_LEN) {
764 printf("[|802.11]");
765 goto out;
766 }
767
768 fc = EXTRACT_LE_16BITS(p);
769 HEADER_LENGTH = GetHeaderLength(fc);
770
771 if (caplen < HEADER_LENGTH) {
772 printf("[|802.11]");
773 goto out;
774 }
775
776 if (eflag)
777 ieee_802_11_print(fc, p);
778
779 /*
780 * Some printers want to get back at the ethernet addresses,
781 * and/or check that they're not walking off the end of the packet.
782 * Rather than pass them all the way down, we set these globals.
783 */
784 packetp = p;
785 snapend = p + caplen;
786
787 length -= HEADER_LENGTH;
788 caplen -= HEADER_LENGTH;
789 p += HEADER_LENGTH;
790
791 switch (FC_TYPE(fc)) {
792 case T_MGMT:
793 if (!mgmt_body_print(fc, (const struct mgmt_header_t *)packetp,
794 p)) {
795 printf("[|802.11]");
796 goto out;
797 }
798 break;
799
800 case T_CTRL:
801 if (!ctrl_body_print(fc, p - HEADER_LENGTH)) {
802 printf("[|802.11]");
803 goto out;
804 }
805 break;
806
807 case T_DATA:
808 /* There may be a problem w/ AP not having this bit set */
809 if (FC_WEP(fc)) {
810 if (!wep_print(p)) {
811 printf("[|802.11]");
812 goto out;
813 }
814 } else {
815 if (llc_print(p, length, caplen, packetp + 10,
816 packetp + 4, &extracted_ethertype) == 0) {
817 /*
818 * Some kinds of LLC packet we cannot
819 * handle intelligently
820 */
821 if (!eflag)
822 ieee_802_11_print(fc, p - HEADER_LENGTH);
823 if (extracted_ethertype) {
824 printf("(LLC %s) ",
825 etherproto_string(htons(extracted_ethertype)));
826 }
827 if (!xflag && !qflag)
828 default_print(p, caplen);
829 }
830 }
831 break;
832
833 default:
834 printf("(body) unhandled IEEE802.11 frame type (%d)",
835 FC_TYPE(fc));
836 break;
837 }
838
839 if (xflag)
840 default_print(p, caplen);
841 out:
842 putchar('\n');
843 --infodelay;
844 if (infoprint)
845 info(0);
846 }