]> The Tcpdump Group git mirrors - tcpdump/blob - print-802_11.c
Make "mobility_opt_print()" static, as it's not used outside
[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.9 2002-08-01 08:52:59 risso 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 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,u_int length)
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 struct mgmt_header_t *pmh,
214 const u_char *p)
215 {
216 struct mgmt_body_t pbody;
217 int offset = 0;
218
219 memset(&pbody, 0, sizeof(pbody));
220
221 if (!TTEST2(*p, 12))
222 return 0;
223 memcpy(&pbody.timestamp, p, 8);
224 offset += 8;
225 pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
226 offset += 2;
227 pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
228 offset += 2;
229
230 if (!parse_elements(&pbody,p,offset))
231 return 0;
232
233 printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
234 fn_print(pbody.ssid.ssid, NULL);
235 printf(")");
236 PRINT_RATES(pbody);
237 printf(" %s CH: %u %s",
238 CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS",
239 pbody.ds.channel,
240 CAPABILITY_PRIVACY(pbody.capability_info) ? ", PRIVACY" : "" );
241
242 return 1;
243 }
244
245 static int handle_assoc_request(u_int16_t fc, const struct mgmt_header_t *pmh,
246 const u_char *p)
247 {
248 struct mgmt_body_t pbody;
249 int offset = 0;
250
251 memset(&pbody, 0, sizeof(pbody));
252
253 if (!TTEST2(*p, 4))
254 return 0;
255 pbody.capability_info = EXTRACT_LE_16BITS(p);
256 offset += 2;
257 pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
258 offset += 2;
259
260 if (!parse_elements(&pbody,p,offset))
261 return 0;
262
263 printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
264 fn_print(pbody.ssid.ssid, NULL);
265 printf(")");
266 PRINT_RATES(pbody);
267 return 1;
268 }
269
270 static int handle_assoc_response(u_int16_t fc, const struct mgmt_header_t *pmh,
271 const u_char *p)
272 {
273 struct mgmt_body_t pbody;
274 int offset = 0;
275
276 memset(&pbody, 0, sizeof(pbody));
277
278 if (!TTEST2(*p, 6))
279 return 0;
280 pbody.capability_info = EXTRACT_LE_16BITS(p);
281 offset += 2;
282 pbody.status_code = EXTRACT_LE_16BITS(p+offset);
283 offset += 2;
284 pbody.aid = EXTRACT_LE_16BITS(p+offset);
285 offset += 2;
286
287 if (!parse_elements(&pbody,p,offset))
288 return 0;
289
290 printf("%s AID(%x) :%s: %s", subtype_text[FC_SUBTYPE(fc)],
291 ((u_int16_t)(pbody.aid << 2 )) >> 2 ,
292 CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
293 (pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a"));
294
295 return 1;
296 }
297
298
299 static int handle_reassoc_request(u_int16_t fc, const struct mgmt_header_t *pmh,
300 const u_char *p)
301 {
302 struct mgmt_body_t pbody;
303 int offset = 0;
304
305 memset(&pbody, 0, sizeof(pbody));
306
307 if (!TTEST2(*p, 10))
308 return 0;
309 pbody.capability_info = EXTRACT_LE_16BITS(p);
310 offset += 2;
311 pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
312 offset += 2;
313 memcpy(&pbody.ap,p+offset,6);
314 offset += 6;
315
316 if (!parse_elements(&pbody,p,offset))
317 return 0;
318
319 printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
320 fn_print(pbody.ssid.ssid, NULL);
321 printf(") AP : %s", etheraddr_string( pbody.ap ));
322
323 return 1;
324 }
325
326 static int handle_reassoc_response(u_int16_t fc, const struct mgmt_header_t *pmh,
327 const u_char *p)
328 {
329 /* Same as a Association Reponse */
330 return handle_assoc_response(fc,pmh,p);
331 }
332
333 static int handle_probe_request(u_int16_t fc, const struct mgmt_header_t *pmh,
334 const u_char *p)
335 {
336 struct mgmt_body_t pbody;
337 int offset = 0;
338
339 memset(&pbody, 0, sizeof(pbody));
340
341 if (!parse_elements(&pbody, p, offset))
342 return 0;
343
344 printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
345 fn_print(pbody.ssid.ssid, NULL);
346 printf(")");
347 PRINT_RATES(pbody);
348
349 return 1;
350 }
351
352 static int handle_probe_response(u_int16_t fc, const struct mgmt_header_t *pmh,
353 const u_char *p)
354 {
355 struct mgmt_body_t pbody;
356 int offset = 0;
357
358 memset(&pbody, 0, sizeof(pbody));
359
360 if (!TTEST2(*p, 12))
361 return 0;
362 memcpy(&pbody.timestamp,p,8);
363 offset += 8;
364 pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
365 offset += 2;
366 pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
367 offset += 2;
368
369 if (!parse_elements(&pbody, p, offset))
370 return 0;
371
372 printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
373 fn_print(pbody.ssid.ssid, NULL);
374 printf(") ");
375 PRINT_RATES(pbody);
376 printf(" CH: %u%s", pbody.ds.channel,
377 CAPABILITY_PRIVACY(pbody.capability_info) ? ", PRIVACY" : "" );
378
379 return 1;
380 }
381
382 static int handle_atim(u_int16_t fc, const struct mgmt_header_t *pmh,
383 const u_char *p)
384 {
385 /* the frame body for ATIM is null. */
386 printf("ATIM");
387 return 1;
388 }
389
390 static int handle_disassoc(u_int16_t fc, const struct mgmt_header_t *pmh,
391 const u_char *p)
392 {
393 struct mgmt_body_t pbody;
394 int offset = 0;
395
396 memset(&pbody, 0, sizeof(pbody));
397
398 if (!TTEST2(*p, 2))
399 return 0;
400 pbody.reason_code = EXTRACT_LE_16BITS(p);
401 offset += 2;
402
403 printf("%s: %s", subtype_text[FC_SUBTYPE(fc)],
404 pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
405
406 return 1;
407 }
408
409 static int handle_auth(u_int16_t fc, const struct mgmt_header_t *pmh,
410 const u_char *p)
411 {
412 struct mgmt_body_t pbody;
413 int offset = 0;
414
415 memset(&pbody, 0, sizeof(pbody));
416
417 if (!TTEST2(*p, 6))
418 return 0;
419 pbody.auth_alg = EXTRACT_LE_16BITS(p);
420 offset += 2;
421 pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset);
422 offset += 2;
423 pbody.status_code = EXTRACT_LE_16BITS(p + offset);
424 offset += 2;
425
426 if (!parse_elements(&pbody,p,offset))
427 return 0;
428
429 if ((pbody.auth_alg == 1) &&
430 ((pbody.auth_trans_seq_num == 2) || (pbody.auth_trans_seq_num == 3))) {
431 printf("%s (%s)-%x [Challenge Text] %s",
432 subtype_text[FC_SUBTYPE(fc)],
433 pbody.auth_alg < 4 ? auth_alg_text[pbody.auth_alg] : "Reserved" ,
434 pbody.auth_trans_seq_num,
435 ((pbody.auth_trans_seq_num % 2) ?
436 (pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a") : "" ));
437 } else {
438 printf("%s (%s)-%x: %s",
439 subtype_text[FC_SUBTYPE(fc)],
440 pbody.auth_alg < 4 ? auth_alg_text[pbody.auth_alg] : "Reserved" ,
441 pbody.auth_trans_seq_num,
442 ((pbody.auth_trans_seq_num % 2) ? (pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a") : ""));
443 }
444
445 return 1;
446 }
447
448 static int handle_deauth(u_int16_t fc, const struct mgmt_header_t *pmh,
449 const u_char *p)
450 {
451 struct mgmt_body_t pbody;
452 int offset = 0;
453
454 memset(&pbody, 0, sizeof(pbody));
455
456 if (!TTEST2(*p, 2))
457 return 0;
458 pbody.reason_code = EXTRACT_LE_16BITS(p);
459 offset += 2;
460
461 if (eflag) {
462 printf("%s: %s",
463 subtype_text[FC_SUBTYPE(fc)],
464 pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
465 } else {
466 printf("%s (%s): %s",
467 subtype_text[FC_SUBTYPE(fc)], etheraddr_string(pmh->sa),
468 pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
469 }
470
471 return 1;
472 }
473
474
475 /*********************************************************************************
476 * Print Body funcs
477 *********************************************************************************/
478
479
480 static int mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
481 const u_char *p, u_int length)
482 {
483 switch (FC_SUBTYPE(fc)) {
484 case ST_ASSOC_REQUEST:
485 return (handle_assoc_request(fc, pmh, p));
486 case ST_ASSOC_RESPONSE:
487 return (handle_assoc_response(fc, pmh, p));
488 case ST_REASSOC_REQUEST:
489 return (handle_reassoc_request(fc, pmh, p));
490 case ST_REASSOC_RESPONSE:
491 return (handle_reassoc_response(fc, pmh, p));
492 case ST_PROBE_REQUEST:
493 return (handle_probe_request(fc, pmh, p));
494 case ST_PROBE_RESPONSE:
495 return (handle_probe_response(fc, pmh, p));
496 case ST_BEACON:
497 return (handle_beacon(fc, pmh, p));
498 case ST_ATIM:
499 return (handle_atim(fc, pmh, p));
500 case ST_DISASSOC:
501 return (handle_disassoc(fc, pmh, p));
502 case ST_AUTH:
503 if (!TTEST2(*p, 3))
504 return 0;
505 if ((p[0] == 0 ) && (p[1] == 0) && (p[2] == 0)) {
506 printf("Authentication (Shared-Key)-3 ");
507 return (wep_print(p, length));
508 }
509 else
510 return (handle_auth(fc, pmh, p));
511 case ST_DEAUTH:
512 return (handle_deauth(fc, pmh, p));
513 break;
514 default:
515 printf("Unhandled Managment subtype(%x)",
516 FC_SUBTYPE(fc));
517 return 1;
518 }
519 }
520
521
522 /*********************************************************************************
523 * Handles printing all the control frame types
524 *********************************************************************************/
525
526 static int ctrl_body_print(u_int16_t fc,const u_char *p, u_int length)
527 {
528 switch (FC_SUBTYPE(fc)) {
529 case CTRL_PS_POLL:
530 if (!TTEST2(*p, CTRL_PS_POLL_LEN))
531 return 0;
532 printf("Power Save-Poll AID(%x)",
533 EXTRACT_LE_16BITS(&(((const struct ctrl_ps_poll_t *)p)->aid)));
534 break;
535 case CTRL_RTS:
536 if (!TTEST2(*p, CTRL_RTS_LEN))
537 return 0;
538 if (eflag)
539 printf("Request-To-Send");
540 else
541 printf("Request-To-Send TA:%s ",
542 etheraddr_string(((const struct ctrl_rts_t *)p)->ta));
543 break;
544 case CTRL_CTS:
545 if (!TTEST2(*p, CTRL_CTS_LEN))
546 return 0;
547 if (eflag)
548 printf("Clear-To-Send");
549 else
550 printf("Clear-To-Send RA:%s ",
551 etheraddr_string(((const struct ctrl_cts_t *)p)->ra));
552 break;
553 case CTRL_ACK:
554 if (!TTEST2(*p, CTRL_ACK_LEN))
555 return 0;
556 if (eflag)
557 printf("Acknowledgment");
558 else
559 printf("Acknowledgment RA:%s ",
560 etheraddr_string(((const struct ctrl_ack_t *)p)->ra));
561 break;
562 case CTRL_CF_END:
563 if (!TTEST2(*p, CTRL_END_LEN))
564 return 0;
565 if (eflag)
566 printf("CF-End");
567 else
568 printf("CF-End RA:%s ",
569 etheraddr_string(((const struct ctrl_end_t *)p)->ra));
570 break;
571 case CTRL_END_ACK:
572 if (!TTEST2(*p, CTRL_END_ACK_LEN))
573 return 0;
574 if (eflag)
575 printf("CF-End+CF-Ack");
576 else
577 printf("CF-End+CF-Ack RA:%s ",
578 etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra));
579 break;
580 default:
581 printf("(B) Unknown Ctrl Subtype");
582 }
583 return 1;
584 }
585
586
587
588 /*
589 * Print Header funcs
590 */
591
592 /*
593 * Data Frame - Address field contents
594 *
595 * To Ds | From DS | Addr 1 | Addr 2 | Addr 3 | Addr 4
596 * 0 | 0 | DA | SA | BSSID | n/a
597 * 0 | 1 | DA | BSSID | SA | n/a
598 * 1 | 0 | BSSID | SA | DA | n/a
599 * 1 | 1 | RA | TA | DA | SA
600 */
601
602 static void data_header_print(u_int16_t fc,const u_char *p, u_int length)
603 {
604 #define ADDR1 (p + 4)
605 #define ADDR2 (p + 10)
606 #define ADDR3 (p + 16)
607 #define ADDR4 (p + 24)
608
609 if (!FC_TO_DS(fc)) {
610 if (!FC_FROM_DS(fc))
611 printf("DA:%s SA:%s BSSID:%s ",
612 etheraddr_string(ADDR1), etheraddr_string(ADDR2),
613 etheraddr_string(ADDR3));
614 else
615 printf("DA:%s BSSID:%s SA:%s ",
616 etheraddr_string(ADDR1), etheraddr_string(ADDR2),
617 etheraddr_string(ADDR3));
618 } else {
619 if (!FC_FROM_DS(fc))
620 printf("BSSID:%s SA:%s DA:%s ",
621 etheraddr_string(ADDR1), etheraddr_string(ADDR2),
622 etheraddr_string(ADDR3));
623 else
624 printf("RA:%s TA:%s DA:%s SA:%s ",
625 etheraddr_string(ADDR1), etheraddr_string(ADDR2),
626 etheraddr_string(ADDR3), etheraddr_string(ADDR4));
627 }
628
629 #undef ADDR1
630 #undef ADDR2
631 #undef ADDR3
632 #undef ADDR4
633 }
634
635
636 static void mgmt_header_print(const u_char *p, u_int length)
637 {
638 const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
639
640 printf("BSSID:%s DA:%s SA:%s ",
641 etheraddr_string((hp)->bssid), etheraddr_string((hp)->da),
642 etheraddr_string((hp)->sa));
643 }
644
645 static void ctrl_header_print(u_int16_t fc,const u_char *p, u_int length)
646 {
647 switch (FC_SUBTYPE(fc)) {
648 case CTRL_PS_POLL:
649 printf("BSSID:%s TA:%s ",
650 etheraddr_string(((const struct ctrl_ps_poll_t *)p)->bssid),
651 etheraddr_string(((const struct ctrl_ps_poll_t *)p)->ta));
652 break;
653 case CTRL_RTS:
654 printf("RA:%s TA:%s ",
655 etheraddr_string(((const struct ctrl_rts_t *)p)->ra),
656 etheraddr_string(((const struct ctrl_rts_t *)p)->ta));
657 break;
658 case CTRL_CTS:
659 printf("RA:%s ",
660 etheraddr_string(((const struct ctrl_cts_t *)p)->ra));
661 break;
662 case CTRL_ACK:
663 printf("RA:%s ",
664 etheraddr_string(((const struct ctrl_ack_t *)p)->ra));
665 break;
666 case CTRL_CF_END:
667 printf("RA:%s BSSID:%s ",
668 etheraddr_string(((const struct ctrl_end_t *)p)->ra),
669 etheraddr_string(((const struct ctrl_end_t *)p)->bssid));
670 break;
671 case CTRL_END_ACK:
672 printf("RA:%s BSSID:%s ",
673 etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra),
674 etheraddr_string(((const struct ctrl_end_ack_t *)p)->bssid));
675 break;
676 default:
677 printf("(H) Unknown Ctrl Subtype");
678 }
679 }
680
681 static int GetHeaderLength(u_int16_t fc)
682 {
683 int iLength=0;
684
685 switch (FC_TYPE(fc)) {
686 case T_MGMT:
687 iLength = MGMT_HEADER_LEN;
688 break;
689 case T_CTRL:
690 switch (FC_SUBTYPE(fc)) {
691 case CTRL_PS_POLL:
692 iLength = CTRL_PS_POLL_LEN;
693 break;
694 case CTRL_RTS:
695 iLength = CTRL_RTS_LEN;
696 break;
697 case CTRL_CTS:
698 iLength = CTRL_CTS_LEN;
699 break;
700 case CTRL_ACK:
701 iLength = CTRL_ACK_LEN;
702 break;
703 case CTRL_CF_END:
704 iLength = CTRL_END_LEN;
705 break;
706 case CTRL_END_ACK:
707 iLength = CTRL_END_ACK_LEN;
708 break;
709 default:
710 iLength = 0;
711 break;
712 }
713 break;
714 case T_DATA:
715 if (FC_TO_DS(fc) && FC_FROM_DS(fc))
716 iLength = 30;
717 else
718 iLength = 24;
719 break;
720 default:
721 printf("unknown IEEE802.11 frame type (%d)",
722 FC_TYPE(fc));
723 break;
724 }
725
726 return iLength;
727 }
728
729 /*
730 * Print the 802.11 MAC header
731 */
732 static inline void
733 ieee_802_11_print(u_int16_t fc, const u_char *p, u_int length)
734 {
735 switch (FC_TYPE(fc)) {
736 case T_MGMT:
737 mgmt_header_print(p, length);
738 break;
739
740 case T_CTRL:
741 ctrl_header_print(fc, p, length);
742 break;
743
744 case T_DATA:
745 data_header_print(fc, p, length);
746 break;
747
748 default:
749 printf("(header) unknown IEEE802.11 frame type (%d)",
750 FC_TYPE(fc));
751 break;
752 }
753 }
754
755 /*
756 * This is the top level routine of the printer. 'p' is the points
757 * to the ether header of the packet, 'h->tv' is the timestamp,
758 * 'h->length' is the length of the packet off the wire, and 'h->caplen'
759 * is the number of bytes actually captured.
760 */
761 void
762 ieee802_11_if_print(u_char *user, const struct pcap_pkthdr *h, const u_char *p)
763 {
764 u_int caplen = h->caplen;
765 u_int length = h->len;
766 u_int16_t fc;
767 u_int HEADER_LENGTH;
768 u_short extracted_ethertype;
769
770 ++infodelay;
771 ts_print(&h->ts);
772
773 if (caplen < IEEE802_11_FC_LEN) {
774 printf("[|802.11]");
775 goto out;
776 }
777
778 fc=EXTRACT_LE_16BITS(p);
779
780 if (eflag)
781 ieee_802_11_print(fc, p, length);
782
783 /*
784 * Some printers want to get back at the ethernet addresses,
785 * and/or check that they're not walking off the end of the packet.
786 * Rather than pass them all the way down, we set these globals.
787 */
788 packetp = p;
789 snapend = p + caplen;
790
791 HEADER_LENGTH=GetHeaderLength(fc);
792
793 length -= HEADER_LENGTH;
794 caplen -= HEADER_LENGTH;
795 p += HEADER_LENGTH;
796
797 switch (FC_TYPE(fc)) {
798 case T_MGMT:
799 if (!mgmt_body_print(fc, (const struct mgmt_header_t *)packetp,
800 p, length)) {
801 printf("[|802.11]");
802 goto out;
803 }
804 break;
805
806 case T_CTRL:
807 if (!ctrl_body_print(fc, p - HEADER_LENGTH,
808 length + HEADER_LENGTH)) {
809 printf("[|802.11]");
810 goto out;
811 }
812 break;
813
814 case T_DATA:
815 /* There may be a problem w/ AP not having this bit set */
816 if (FC_WEP(fc)) {
817 if (!wep_print(p,length)) {
818 printf("[|802.11]");
819 goto out;
820 }
821 } else {
822 if (llc_print(p, length, caplen, packetp + 10,
823 packetp + 4, &extracted_ethertype) == 0) {
824 /*
825 * Some kinds of LLC packet we cannot
826 * handle intelligently
827 */
828 if (!eflag)
829 ieee_802_11_print(fc, p - HEADER_LENGTH,
830 length + HEADER_LENGTH);
831 if (extracted_ethertype) {
832 printf("(LLC %s) ",
833 etherproto_string(htons(extracted_ethertype)));
834 }
835 if (!xflag && !qflag)
836 default_print(p, caplen);
837 }
838 }
839 break;
840
841 default:
842 printf("(body) unhandled IEEE802.11 frame type (%d)",
843 FC_TYPE(fc));
844 break;
845 }
846
847 if (xflag)
848 default_print(p, caplen);
849 out:
850 putchar('\n');
851 --infodelay;
852 if (infoprint)
853 info(0);
854 }