3 * Fortress Technologies, Inc. All rights reserved.
4 * Charlie Lenahan (clenahan@fortresstech.com)
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
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.
24 static const char rcsid
[] =
25 "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.8 2002-06-11 17:08:41 itojun Exp $ (LBL)";
32 #include <sys/param.h>
34 #include <sys/socket.h>
36 #include <netinet/in.h>
42 #include "interface.h"
43 #include "addrtoname.h"
44 #include "ethertype.h"
48 #include "ieee802_11.h"
50 #define PRINT_RATES(p) \
54 for (z = 0; z < p.rates.length ; z++) { \
55 printf("%s%2.1f", sep, (.5 * (p.rates.rate[z] & 0x7f))); \
58 if (p.rates.length != 0) \
62 static const char *auth_alg_text
[]={"Open System","Shared Key","EAP"};
63 static const char *subtype_text
[]={
81 static const char *status_text
[] = {
83 "Unspecified failure", /* 1 */
92 "Cannot Support all requested capabilities in the Capability Information field", /* 10 */
93 "Reassociation denied due to inability to confirm that association exists", /* 11 */
94 "Association denied due to reason outside the scope of the standard", /* 12 */
95 "Responding station does not support the specified authentication algorithm ", /* 13 */
96 "Received an Authentication frame with authentication transaction " \
97 "sequence number out of expected sequence", /* 14 */
98 "Authentication rejected because of challenge failure", /* 15 */
99 "Authentication rejected due to timeout waiting for next frame in sequence", /* 16 */
100 "Association denied because AP is unable to handle additional associated stations", /* 17 */
101 "Association denied due to requesting station not supporting all of the " \
102 "data rates in BSSBasicRateSet parameter", /* 18 */
106 static const char *reason_text
[] = {
108 "Unspecified reason", /* 1 */
109 "Previous authentication no longer valid", /* 2 */
110 "Deauthenticated because sending station is leaving (or has left) IBSS or ESS", /* 3 */
111 "Disassociated due to inactivity", /* 4 */
112 "Disassociated because AP is unable to handle all currently associated stations", /* 5 */
113 "Class 2 frame receivedfrom nonauthenticated station", /* 6 */
114 "Class 3 frame received from nonassociated station", /* 7 */
115 "Disassociated because sending station is leaving (or has left) BSS", /* 8 */
116 "Station requesting (re)association is not authenticated with responding station", /* 9 */
120 static int wep_print(const u_char
*p
,u_int length
)
126 iv
= EXTRACT_LE_32BITS(p
);
128 printf("Data IV:%3x Pad %x KeyID %x", IV_IV(iv
), IV_PAD(iv
),
135 static int parse_elements(struct mgmt_body_t
*pbody
,const u_char
*p
,int offset
)
138 if (!TTEST2(*(p
+ offset
), 1))
140 switch (*(p
+ offset
)) {
142 if (!TTEST2(*(p
+offset
), 2))
144 memcpy(&(pbody
->ssid
),p
+offset
,2); offset
+= 2;
145 if (pbody
->ssid
.length
> 0)
147 if (!TTEST2(*(p
+offset
), pbody
->ssid
.length
))
149 memcpy(&(pbody
->ssid
.ssid
),p
+offset
,pbody
->ssid
.length
); offset
+= pbody
->ssid
.length
;
150 pbody
->ssid
.ssid
[pbody
->ssid
.length
]='\0';
154 if (!TTEST2(*(p
+offset
), 2))
156 memcpy(&(pbody
->challenge
),p
+offset
,2); offset
+= 2;
157 if (pbody
->challenge
.length
> 0)
159 if (!TTEST2(*(p
+offset
), pbody
->challenge
.length
))
161 memcpy(&(pbody
->challenge
.text
),p
+offset
,pbody
->challenge
.length
); offset
+= pbody
->challenge
.length
;
162 pbody
->challenge
.text
[pbody
->challenge
.length
]='\0';
166 if (!TTEST2(*(p
+offset
), 2))
168 memcpy(&(pbody
->rates
),p
+offset
,2); offset
+= 2;
169 if (pbody
->rates
.length
> 0) {
170 if (!TTEST2(*(p
+offset
), pbody
->rates
.length
))
172 memcpy(&(pbody
->rates
.rate
),p
+offset
,pbody
->rates
.length
); offset
+= pbody
->rates
.length
;
176 if (!TTEST2(*(p
+offset
), 3))
178 memcpy(&(pbody
->ds
),p
+offset
,3); offset
+=3;
181 if (!TTEST2(*(p
+offset
), 8))
183 memcpy(&(pbody
->cf
),p
+offset
,8); offset
+=8;
186 if (!TTEST2(*(p
+offset
), 2))
188 memcpy(&(pbody
->tim
),p
+offset
,2); offset
+=2;
189 if (!TTEST2(*(p
+offset
), 3))
191 memcpy(&(pbody
->tim
.count
),p
+offset
,3); offset
+=3;
193 if ((pbody
->tim
.length
-3) > 0)
195 if (!TTEST2(*(p
+offset
), pbody
->tim
.length
-3))
197 memcpy((pbody
->tim
.bitmap
),p
+(pbody
->tim
.length
-3),(pbody
->tim
.length
-3));
198 offset
+= pbody
->tim
.length
-3;
204 printf("(1) unhandled element_id (%d) ", *(p
+offset
) );
206 offset
+= *(p
+offset
+1) + 2;
213 /*********************************************************************************
214 * Print Handle functions for the management frame types
215 *********************************************************************************/
217 static int handle_beacon(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
220 struct mgmt_body_t pbody
;
223 memset(&pbody
, 0, sizeof(pbody
));
227 memcpy(&pbody
.timestamp
, p
, 8);
229 pbody
.beacon_interval
= EXTRACT_LE_16BITS(p
+offset
);
231 pbody
.capability_info
= EXTRACT_LE_16BITS(p
+offset
);
234 if (!parse_elements(&pbody
,p
,offset
))
237 printf("%s (", subtype_text
[FC_SUBTYPE(fc
)]);
238 fn_print(pbody
.ssid
.ssid
, NULL
);
241 printf(" %s CH: %u %s",
242 CAPABILITY_ESS(pbody
.capability_info
) ? "ESS" : "IBSS",
244 CAPABILITY_PRIVACY(pbody
.capability_info
) ? ", PRIVACY" : "" );
249 static int handle_assoc_request(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
252 struct mgmt_body_t pbody
;
255 memset(&pbody
, 0, sizeof(pbody
));
259 pbody
.capability_info
= EXTRACT_LE_16BITS(p
);
261 pbody
.listen_interval
= EXTRACT_LE_16BITS(p
+offset
);
264 if (!parse_elements(&pbody
,p
,offset
))
267 printf("%s (", subtype_text
[FC_SUBTYPE(fc
)]);
268 fn_print(pbody
.ssid
.ssid
, NULL
);
274 static int handle_assoc_response(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
277 struct mgmt_body_t pbody
;
280 memset(&pbody
, 0, sizeof(pbody
));
284 pbody
.capability_info
= EXTRACT_LE_16BITS(p
);
286 pbody
.status_code
= EXTRACT_LE_16BITS(p
+offset
);
288 pbody
.aid
= EXTRACT_LE_16BITS(p
+offset
);
291 if (!parse_elements(&pbody
,p
,offset
))
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"));
303 static int handle_reassoc_request(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
306 struct mgmt_body_t pbody
;
309 memset(&pbody
, 0, sizeof(pbody
));
313 pbody
.capability_info
= EXTRACT_LE_16BITS(p
);
315 pbody
.listen_interval
= EXTRACT_LE_16BITS(p
+offset
);
317 memcpy(&pbody
.ap
,p
+offset
,6);
320 if (!parse_elements(&pbody
,p
,offset
))
323 printf("%s (", subtype_text
[FC_SUBTYPE(fc
)]);
324 fn_print(pbody
.ssid
.ssid
, NULL
);
325 printf(") AP : %s", etheraddr_string( pbody
.ap
));
330 static int handle_reassoc_response(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
333 /* Same as a Association Reponse */
334 return handle_assoc_response(fc
,pmh
,p
);
337 static int handle_probe_request(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
340 struct mgmt_body_t pbody
;
343 memset(&pbody
, 0, sizeof(pbody
));
345 if (!parse_elements(&pbody
, p
, offset
))
348 printf("%s (", subtype_text
[FC_SUBTYPE(fc
)]);
349 fn_print(pbody
.ssid
.ssid
, NULL
);
356 static int handle_probe_response(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
359 struct mgmt_body_t pbody
;
362 memset(&pbody
, 0, sizeof(pbody
));
366 memcpy(&pbody
.timestamp
,p
,8);
368 pbody
.beacon_interval
= EXTRACT_LE_16BITS(p
+offset
);
370 pbody
.capability_info
= EXTRACT_LE_16BITS(p
+offset
);
373 if (!parse_elements(&pbody
, p
, offset
))
376 printf("%s (", subtype_text
[FC_SUBTYPE(fc
)]);
377 fn_print(pbody
.ssid
.ssid
, NULL
);
380 printf(" CH: %u%s", pbody
.ds
.channel
,
381 CAPABILITY_PRIVACY(pbody
.capability_info
) ? ", PRIVACY" : "" );
386 static int handle_atim(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
389 /* the frame body for ATIM is null. */
394 static int handle_disassoc(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
397 struct mgmt_body_t pbody
;
400 memset(&pbody
, 0, sizeof(pbody
));
404 pbody
.reason_code
= EXTRACT_LE_16BITS(p
);
407 printf("%s: %s", subtype_text
[FC_SUBTYPE(fc
)],
408 pbody
.reason_code
< 10 ? reason_text
[pbody
.reason_code
] : "Reserved" );
413 static int handle_auth(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
416 struct mgmt_body_t pbody
;
419 memset(&pbody
, 0, sizeof(pbody
));
423 pbody
.auth_alg
= EXTRACT_LE_16BITS(p
);
425 pbody
.auth_trans_seq_num
= EXTRACT_LE_16BITS(p
+ offset
);
427 pbody
.status_code
= EXTRACT_LE_16BITS(p
+ offset
);
430 if (!parse_elements(&pbody
,p
,offset
))
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") : "" ));
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") : ""));
452 static int handle_deauth(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
455 struct mgmt_body_t pbody
;
458 memset(&pbody
, 0, sizeof(pbody
));
462 pbody
.reason_code
= EXTRACT_LE_16BITS(p
);
467 subtype_text
[FC_SUBTYPE(fc
)],
468 pbody
.reason_code
< 10 ? reason_text
[pbody
.reason_code
] : "Reserved" );
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" );
479 /*********************************************************************************
481 *********************************************************************************/
484 static int mgmt_body_print(u_int16_t fc
, const struct mgmt_header_t
*pmh
,
485 const u_char
*p
, u_int length
)
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
));
501 return (handle_beacon(fc
, pmh
, p
));
503 return (handle_atim(fc
, pmh
, p
));
505 return (handle_disassoc(fc
, pmh
, p
));
509 if ((p
[0] == 0 ) && (p
[1] == 0) && (p
[2] == 0)) {
510 printf("Authentication (Shared-Key)-3 ");
511 return (wep_print(p
, length
));
514 return (handle_auth(fc
, pmh
, p
));
516 return (handle_deauth(fc
, pmh
, p
));
519 printf("Unhandled Managment subtype(%x)",
526 /*********************************************************************************
527 * Handles printing all the control frame types
528 *********************************************************************************/
530 static int ctrl_body_print(u_int16_t fc
,const u_char
*p
, u_int length
)
532 switch (FC_SUBTYPE(fc
)) {
534 if (!TTEST2(*p
, CTRL_PS_POLL_LEN
))
536 printf("Power Save-Poll AID(%x)",
537 EXTRACT_LE_16BITS(&(((const struct ctrl_ps_poll_t
*)p
)->aid
)));
540 if (!TTEST2(*p
, CTRL_RTS_LEN
))
543 printf("Request-To-Send");
545 printf("Request-To-Send TA:%s ",
546 etheraddr_string(((const struct ctrl_rts_t
*)p
)->ta
));
549 if (!TTEST2(*p
, CTRL_CTS_LEN
))
552 printf("Clear-To-Send");
554 printf("Clear-To-Send RA:%s ",
555 etheraddr_string(((const struct ctrl_cts_t
*)p
)->ra
));
558 if (!TTEST2(*p
, CTRL_ACK_LEN
))
561 printf("Acknowledgment");
563 printf("Acknowledgment RA:%s ",
564 etheraddr_string(((const struct ctrl_ack_t
*)p
)->ra
));
567 if (!TTEST2(*p
, CTRL_END_LEN
))
572 printf("CF-End RA:%s ",
573 etheraddr_string(((const struct ctrl_end_t
*)p
)->ra
));
576 if (!TTEST2(*p
, CTRL_END_ACK_LEN
))
579 printf("CF-End+CF-Ack");
581 printf("CF-End+CF-Ack RA:%s ",
582 etheraddr_string(((const struct ctrl_end_ack_t
*)p
)->ra
));
585 printf("(B) Unknown Ctrl Subtype");
597 * Data Frame - Address field contents
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
606 static void data_header_print(u_int16_t fc
,const u_char
*p
, u_int length
)
608 #define ADDR1 (p + 4)
609 #define ADDR2 (p + 10)
610 #define ADDR3 (p + 16)
611 #define ADDR4 (p + 24)
615 printf("DA:%s SA:%s BSSID:%s ",
616 etheraddr_string(ADDR1
), etheraddr_string(ADDR2
),
617 etheraddr_string(ADDR3
));
619 printf("DA:%s BSSID:%s SA:%s ",
620 etheraddr_string(ADDR1
), etheraddr_string(ADDR2
),
621 etheraddr_string(ADDR3
));
624 printf("BSSID:%s SA:%s DA:%s ",
625 etheraddr_string(ADDR1
), etheraddr_string(ADDR2
),
626 etheraddr_string(ADDR3
));
628 printf("RA:%s TA:%s DA:%s SA:%s ",
629 etheraddr_string(ADDR1
), etheraddr_string(ADDR2
),
630 etheraddr_string(ADDR3
), etheraddr_string(ADDR4
));
640 static void mgmt_header_print(const u_char
*p
, u_int length
)
642 const struct mgmt_header_t
*hp
= (const struct mgmt_header_t
*) p
;
644 printf("BSSID:%s DA:%s SA:%s ",
645 etheraddr_string((hp
)->bssid
), etheraddr_string((hp
)->da
),
646 etheraddr_string((hp
)->sa
));
649 static void ctrl_header_print(u_int16_t fc
,const u_char
*p
, u_int length
)
651 switch (FC_SUBTYPE(fc
)) {
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
));
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
));
664 etheraddr_string(((const struct ctrl_cts_t
*)p
)->ra
));
668 etheraddr_string(((const struct ctrl_ack_t
*)p
)->ra
));
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
));
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
));
681 printf("(H) Unknown Ctrl Subtype");
685 static int GetHeaderLength(u_int16_t fc
)
689 switch (FC_TYPE(fc
)) {
691 iLength
= MGMT_HEADER_LEN
;
694 switch (FC_SUBTYPE(fc
)) {
696 iLength
= CTRL_PS_POLL_LEN
;
699 iLength
= CTRL_RTS_LEN
;
702 iLength
= CTRL_CTS_LEN
;
705 iLength
= CTRL_ACK_LEN
;
708 iLength
= CTRL_END_LEN
;
711 iLength
= CTRL_END_ACK_LEN
;
719 if (FC_TO_DS(fc
) && FC_FROM_DS(fc
))
725 printf("unknown IEEE802.11 frame type (%d)",
734 * Print the 802.11 MAC header
737 ieee_802_11_print(u_int16_t fc
, const u_char
*p
, u_int length
)
739 switch (FC_TYPE(fc
)) {
741 mgmt_header_print(p
, length
);
745 ctrl_header_print(fc
, p
, length
);
749 data_header_print(fc
, p
, length
);
753 printf("(header) unknown IEEE802.11 frame type (%d)",
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.
766 ieee802_11_if_print(u_char
*user
, const struct pcap_pkthdr
*h
, const u_char
*p
)
768 u_int caplen
= h
->caplen
;
769 u_int length
= h
->len
;
772 u_short extracted_ethertype
;
777 if (caplen
< IEEE802_11_FC_LEN
) {
782 fc
=EXTRACT_LE_16BITS(p
);
785 ieee_802_11_print(fc
, p
, length
);
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.
793 snapend
= p
+ caplen
;
795 HEADER_LENGTH
=GetHeaderLength(fc
);
797 length
-= HEADER_LENGTH
;
798 caplen
-= HEADER_LENGTH
;
801 switch (FC_TYPE(fc
)) {
803 if (!mgmt_body_print(fc
, (const struct mgmt_header_t
*)packetp
,
811 if (!ctrl_body_print(fc
, p
- HEADER_LENGTH
,
812 length
+ HEADER_LENGTH
)) {
819 /* There may be a problem w/ AP not having this bit set */
821 if (!wep_print(p
,length
)) {
826 if (llc_print(p
, length
, caplen
, packetp
+ 10,
827 packetp
+ 4, &extracted_ethertype
) == 0) {
829 * Some kinds of LLC packet we cannot
830 * handle intelligently
833 ieee_802_11_print(fc
, p
- HEADER_LENGTH
,
834 length
+ HEADER_LENGTH
);
835 if (extracted_ethertype
) {
837 etherproto_string(htons(extracted_ethertype
)));
839 if (!xflag
&& !qflag
)
840 default_print(p
, caplen
);
846 printf("(body) unhandled IEEE802.11 frame type (%d)",
852 default_print(p
, caplen
);