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