]> The Tcpdump Group git mirrors - tcpdump/blobdiff - print-802_11.c
Update from current NetBSD version of ieee80211_radiotap.h.
[tcpdump] / print-802_11.c
index 355d8ac65db516e4a64bef1eab2d8ac3a46e32c9..891439e0373a7ce3e1f614315c2e3b541d0629c4 100644 (file)
@@ -21,8 +21,8 @@
  */
 
 #ifndef lint
-static const char rcsid[] =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.14 2002-12-12 07:39:19 guy Exp $ (LBL)";
+static const char rcsid[] _U_ =
+    "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.31.2.10 2005-11-13 20:23:09 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -41,38 +41,62 @@ static const char rcsid[] =
 
 #include "extract.h"
 
+#include "cpack.h"
+
 #include "ieee802_11.h"
+#include "ieee802_11_radio.h"
+
+#define PRINT_SSID(p) \
+       switch (p.ssid_status) { \
+       case TRUNCATED: \
+               return 0; \
+       case PRESENT: \
+               printf(" ("); \
+               fn_print(p.ssid.ssid, NULL); \
+               printf(")"); \
+               break; \
+       case NOT_PRESENT: \
+               break; \
+       }
 
+#define PRINT_RATE(_sep, _r, _suf) \
+       printf("%s%2.1f%s", _sep, (.5 * ((_r) & 0x7f)), _suf)
 #define PRINT_RATES(p) \
-do { \
-       int z; \
-       const char *sep = " ["; \
-       for (z = 0; z < p.rates.length ; z++) { \
-               printf("%s%2.1f", sep, (.5 * (p.rates.rate[z] & 0x7f))); \
-               sep = " "; \
+       switch (p.rates_status) { \
+       case TRUNCATED: \
+               return 0; \
+       case PRESENT: \
+               do { \
+                       int z; \
+                       const char *sep = " ["; \
+                       for (z = 0; z < p.rates.length ; z++) { \
+                               PRINT_RATE(sep, p.rates.rate[z], \
+                                       (p.rates.rate[z] & 0x80 ? "*" : "")); \
+                               sep = " "; \
+                       } \
+                       if (p.rates.length != 0) \
+                               printf(" Mbit]"); \
+               } while (0); \
+               break; \
+       case NOT_PRESENT: \
+               break; \
+       }
+
+#define PRINT_DS_CHANNEL(p) \
+       switch (p.ds_status) { \
+       case TRUNCATED: \
+               return 0; \
+       case PRESENT: \
+               printf(" CH: %u", p.ds.channel); \
+               break; \
+       case NOT_PRESENT: \
+               break; \
        } \
-       if (p.rates.length != 0) \
-               printf(" Mbit]"); \
-} while (0)
+       printf("%s", \
+           CAPABILITY_PRIVACY(p.capability_info) ? ", PRIVACY" : "" );
 
 static const char *auth_alg_text[]={"Open System","Shared Key","EAP"};
-static const char *subtype_text[]={
-       "Assoc Request",
-       "Assoc Response",
-       "ReAssoc Request",
-       "ReAssoc Response",
-       "Probe Request",
-       "Probe Response",
-       "RESERVED",
-       "RESERVED",
-       "Beacon",
-       "ATIM",
-       "Disassociation",
-       "Authentication",
-       "DeAuthentication",
-       "RESERVED",
-       "RESERVED"
-};
+#define NUM_AUTH_ALGS  (sizeof auth_alg_text / sizeof auth_alg_text[0])
 
 static const char *status_text[] = {
        "Succesful",  /*  0  */
@@ -96,8 +120,8 @@ static const char *status_text[] = {
        "Association denied because AP is unable to handle additional associated stations",       /*  17 */
        "Association denied due to requesting station not supporting all of the " \
                "data rates in BSSBasicRateSet parameter",        /*  18 */
-       NULL
 };
+#define NUM_STATUSES   (sizeof status_text / sizeof status_text[0])
 
 static const char *reason_text[] = {
        "Reserved", /* 0 */
@@ -106,18 +130,19 @@ static const char *reason_text[] = {
        "Deauthenticated because sending station is leaving (or has left) IBSS or ESS", /* 3 */
        "Disassociated due to inactivity", /* 4 */
        "Disassociated because AP is unable to handle all currently associated stations", /* 5 */
-       "Class 2 frame receivedfrom nonauthenticated station", /* 6 */
+       "Class 2 frame received from nonauthenticated station", /* 6 */
        "Class 3 frame received from nonassociated station", /* 7 */
        "Disassociated because sending station is leaving (or has left) BSS", /* 8 */
        "Station requesting (re)association is not authenticated with responding station", /* 9 */
-       NULL
 };
+#define NUM_REASONS    (sizeof reason_text / sizeof reason_text[0])
 
-static int wep_print(const u_char *p)
+static int
+wep_print(const u_char *p)
 {
        u_int32_t iv;
 
-       if (!TTEST2(*p, 4))
+       if (!TTEST2(*p, IEEE802_11_IV_LEN + IEEE802_11_KID_LEN))
                return 0;
        iv = EXTRACT_LE_32BITS(p);
 
@@ -127,277 +152,332 @@ static int wep_print(const u_char *p)
        return 1;
 }
 
-
-static int parse_elements(struct mgmt_body_t *pbody,const u_char *p,int offset)
+static void
+parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset)
 {
+       /*
+        * We haven't seen any elements yet.
+        */
+       pbody->challenge_status = NOT_PRESENT;
+       pbody->ssid_status = NOT_PRESENT;
+       pbody->rates_status = NOT_PRESENT;
+       pbody->ds_status = NOT_PRESENT;
+       pbody->cf_status = NOT_PRESENT;
+       pbody->tim_status = NOT_PRESENT;
+
        for (;;) {
                if (!TTEST2(*(p + offset), 1))
-                       return 1;
+                       return;
                switch (*(p + offset)) {
                case E_SSID:
-                       if (!TTEST2(*(p+offset), 2))
-                               return 0;
-                       memcpy(&(pbody->ssid),p+offset,2); offset += 2;
-                       if (pbody->ssid.length > 0)
-                       {
-                               if (!TTEST2(*(p+offset), pbody->ssid.length))
-                                       return 0;
-                               memcpy(&(pbody->ssid.ssid),p+offset,pbody->ssid.length); offset += pbody->ssid.length;
-                               pbody->ssid.ssid[pbody->ssid.length]='\0';
+                       /* Present, possibly truncated */
+                       pbody->ssid_status = TRUNCATED;
+                       if (!TTEST2(*(p + offset), 2))
+                               return;
+                       memcpy(&pbody->ssid, p + offset, 2);
+                       offset += 2;
+                       if (pbody->ssid.length != 0) {
+                               if (pbody->ssid.length >
+                                   sizeof(pbody->ssid.ssid) - 1)
+                                       return;
+                               if (!TTEST2(*(p + offset), pbody->ssid.length))
+                                       return;
+                               memcpy(&pbody->ssid.ssid, p + offset,
+                                   pbody->ssid.length);
+                               offset += pbody->ssid.length;
                        }
+                       pbody->ssid.ssid[pbody->ssid.length] = '\0';
+                       /* Present and not truncated */
+                       pbody->ssid_status = PRESENT;
                        break;
                case E_CHALLENGE:
-                       if (!TTEST2(*(p+offset), 2))
-                               return 0;
-                       memcpy(&(pbody->challenge),p+offset,2); offset += 2;
-                       if (pbody->challenge.length > 0)
-                       {
-                               if (!TTEST2(*(p+offset), pbody->challenge.length))
-                                       return 0;
-                               memcpy(&(pbody->challenge.text),p+offset,pbody->challenge.length); offset += pbody->challenge.length;
-                               pbody->challenge.text[pbody->challenge.length]='\0';
+                       /* Present, possibly truncated */
+                       pbody->challenge_status = TRUNCATED;
+                       if (!TTEST2(*(p + offset), 2))
+                               return;
+                       memcpy(&pbody->challenge, p + offset, 2);
+                       offset += 2;
+                       if (pbody->challenge.length != 0) {
+                               if (pbody->challenge.length >
+                                   sizeof(pbody->challenge.text) - 1)
+                                       return;
+                               if (!TTEST2(*(p + offset), pbody->challenge.length))
+                                       return;
+                               memcpy(&pbody->challenge.text, p + offset,
+                                   pbody->challenge.length);
+                               offset += pbody->challenge.length;
                        }
+                       pbody->challenge.text[pbody->challenge.length] = '\0';
+                       /* Present and not truncated */
+                       pbody->challenge_status = PRESENT;
                        break;
                case E_RATES:
-                       if (!TTEST2(*(p+offset), 2))
-                               return 0;
-                       memcpy(&(pbody->rates),p+offset,2); offset += 2;
-                       if (pbody->rates.length > 0) {
-                               if (!TTEST2(*(p+offset), pbody->rates.length))
-                                       return 0;
-                               memcpy(&(pbody->rates.rate),p+offset,pbody->rates.length); offset += pbody->rates.length;
+                       /* Present, possibly truncated */
+                       pbody->rates_status = TRUNCATED;
+                       if (!TTEST2(*(p + offset), 2))
+                               return;
+                       memcpy(&(pbody->rates), p + offset, 2);
+                       offset += 2;
+                       if (pbody->rates.length != 0) {
+                               if (pbody->rates.length > sizeof pbody->rates.rate)
+                                       return;
+                               if (!TTEST2(*(p + offset), pbody->rates.length))
+                                       return;
+                               memcpy(&pbody->rates.rate, p + offset,
+                                   pbody->rates.length);
+                               offset += pbody->rates.length;
                        }
+                       /* Present and not truncated */
+                       pbody->rates_status = PRESENT;
                        break;
                case E_DS:
-                       if (!TTEST2(*(p+offset), 3))
-                               return 0;
-                       memcpy(&(pbody->ds),p+offset,3); offset +=3;
+                       /* Present, possibly truncated */
+                       pbody->ds_status = TRUNCATED;
+                       if (!TTEST2(*(p + offset), 3))
+                               return;
+                       memcpy(&pbody->ds, p + offset, 3);
+                       offset += 3;
+                       /* Present and not truncated */
+                       pbody->ds_status = PRESENT;
                        break;
                case E_CF:
-                       if (!TTEST2(*(p+offset), 8))
-                               return 0;
-                       memcpy(&(pbody->cf),p+offset,8); offset +=8;
+                       /* Present, possibly truncated */
+                       pbody->cf_status = TRUNCATED;
+                       if (!TTEST2(*(p + offset), 8))
+                               return;
+                       memcpy(&pbody->cf, p + offset, 8);
+                       offset += 8;
+                       /* Present and not truncated */
+                       pbody->cf_status = PRESENT;
                        break;
                case E_TIM:
-                       if (!TTEST2(*(p+offset), 2))
-                               return 0;
-                       memcpy(&(pbody->tim),p+offset,2); offset +=2;
-                       if (!TTEST2(*(p+offset), 3))
-                               return 0;
-                       memcpy(&(pbody->tim.count),p+offset,3); offset +=3;
-
-                       if ((pbody->tim.length -3) > 0)
-                       {
-                               if (!TTEST2(*(p+offset), pbody->tim.length -3))
-                                       return 0;
-                               memcpy((pbody->tim.bitmap),p+(pbody->tim.length -3),(pbody->tim.length -3));
-                               offset += pbody->tim.length -3;
-                       }
+                       /* Present, possibly truncated */
+                       pbody->tim_status = TRUNCATED;
+                       if (!TTEST2(*(p + offset), 2))
+                               return;
+                       memcpy(&pbody->tim, p + offset, 2);
+                       offset += 2;
+                       if (!TTEST2(*(p + offset), 3))
+                               return;
+                       memcpy(&pbody->tim.count, p + offset, 3);
+                       offset += 3;
 
+                       if (pbody->tim.length <= 3)
+                               break;
+                       if (pbody->rates.length > sizeof pbody->tim.bitmap)
+                               return;
+                       if (!TTEST2(*(p + offset), pbody->tim.length - 3))
+                               return;
+                       memcpy(pbody->tim.bitmap, p + (pbody->tim.length - 3),
+                           (pbody->tim.length - 3));
+                       offset += pbody->tim.length - 3;
+                       /* Present and not truncated */
+                       pbody->tim_status = PRESENT;
                        break;
                default:
 #if 0
-                       printf("(1) unhandled element_id (%d)  ", *(p+offset) );
+                       printf("(1) unhandled element_id (%d)  ",
+                           *(p + offset) );
 #endif
-                       offset+= *(p+offset+1) + 2;
+                       if (!TTEST2(*(p + offset), 2))
+                               return;
+                       if (!TTEST2(*(p + offset + 2), *(p + offset + 1)))
+                               return;
+                       offset += *(p + offset + 1) + 2;
                        break;
                }
        }
-       return 1;
 }
 
 /*********************************************************************************
  * Print Handle functions for the management frame types
  *********************************************************************************/
 
-static int handle_beacon(u_int16_t fc, const u_char *p)
+static int
+handle_beacon(const u_char *p)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
 
        memset(&pbody, 0, sizeof(pbody));
 
-       if (!TTEST2(*p, 12))
+       if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
+           IEEE802_11_CAPINFO_LEN))
                return 0;
-       memcpy(&pbody.timestamp, p, 8);
-       offset += 8;
+       memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
+       offset += IEEE802_11_TSTAMP_LEN;
        pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
-       offset += 2;
+       offset += IEEE802_11_BCNINT_LEN;
        pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
-       offset += 2;
+       offset += IEEE802_11_CAPINFO_LEN;
 
-       if (!parse_elements(&pbody,p,offset))
-               return 0;
+       parse_elements(&pbody, p, offset);
 
-       printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
-       fn_print(pbody.ssid.ssid, NULL);
-       printf(")");
+       PRINT_SSID(pbody);
        PRINT_RATES(pbody);
-       printf(" %s CH: %u%s",
-           CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS",
-           pbody.ds.channel,
-           CAPABILITY_PRIVACY(pbody.capability_info) ? ", PRIVACY" : "" );
+       printf(" %s",
+           CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS");
+       PRINT_DS_CHANNEL(pbody);
 
        return 1;
 }
 
-static int handle_assoc_request(u_int16_t fc, const u_char *p)
+static int
+handle_assoc_request(const u_char *p)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
 
        memset(&pbody, 0, sizeof(pbody));
 
-       if (!TTEST2(*p, 4))
+       if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN))
                return 0;
        pbody.capability_info = EXTRACT_LE_16BITS(p);
-       offset += 2;
+       offset += IEEE802_11_CAPINFO_LEN;
        pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
-       offset += 2;
+       offset += IEEE802_11_LISTENINT_LEN;
 
-       if (!parse_elements(&pbody,p,offset))
-               return 0;
+       parse_elements(&pbody, p, offset);
 
-       printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
-       fn_print(pbody.ssid.ssid, NULL);
-       printf(")");
+       PRINT_SSID(pbody);
        PRINT_RATES(pbody);
        return 1;
 }
 
-static int handle_assoc_response(u_int16_t fc, const u_char *p)
+static int
+handle_assoc_response(const u_char *p)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
 
        memset(&pbody, 0, sizeof(pbody));
 
-       if (!TTEST2(*p, 6))
+       if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
+           IEEE802_11_AID_LEN))
                return 0;
        pbody.capability_info = EXTRACT_LE_16BITS(p);
-       offset += 2;
+       offset += IEEE802_11_CAPINFO_LEN;
        pbody.status_code = EXTRACT_LE_16BITS(p+offset);
-       offset += 2;
+       offset += IEEE802_11_STATUS_LEN;
        pbody.aid = EXTRACT_LE_16BITS(p+offset);
-       offset += 2;
+       offset += IEEE802_11_AID_LEN;
 
-       if (!parse_elements(&pbody,p,offset))
-               return 0;
+       parse_elements(&pbody, p, offset);
 
-       printf("%s AID(%x) :%s: %s", subtype_text[FC_SUBTYPE(fc)],
-           ((u_int16_t)(pbody.aid << 2 )) >> 2 ,
+       printf(" AID(%x) :%s: %s", ((u_int16_t)(pbody.aid << 2 )) >> 2 ,
            CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
-           (pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a"));
+           (pbody.status_code < NUM_STATUSES
+               ? status_text[pbody.status_code]
+               : "n/a"));
 
        return 1;
 }
 
-
-static int handle_reassoc_request(u_int16_t fc, const u_char *p)
+static int
+handle_reassoc_request(const u_char *p)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
 
        memset(&pbody, 0, sizeof(pbody));
 
-       if (!TTEST2(*p, 10))
+       if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
+           IEEE802_11_AP_LEN))
                return 0;
        pbody.capability_info = EXTRACT_LE_16BITS(p);
-       offset += 2;
+       offset += IEEE802_11_CAPINFO_LEN;
        pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
-       offset += 2;
-       memcpy(&pbody.ap,p+offset,6);
-       offset += 6;
+       offset += IEEE802_11_LISTENINT_LEN;
+       memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN);
+       offset += IEEE802_11_AP_LEN;
 
-       if (!parse_elements(&pbody,p,offset))
-               return 0;
+       parse_elements(&pbody, p, offset);
 
-       printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
-       fn_print(pbody.ssid.ssid, NULL);
-       printf(") AP : %s", etheraddr_string( pbody.ap ));
+       PRINT_SSID(pbody);
+       printf(" AP : %s", etheraddr_string( pbody.ap ));
 
        return 1;
 }
 
-static int handle_reassoc_response(u_int16_t fc, const u_char *p)
+static int
+handle_reassoc_response(const u_char *p)
 {
        /* Same as a Association Reponse */
-       return handle_assoc_response(fc, p);
+       return handle_assoc_response(p);
 }
 
-static int handle_probe_request(u_int16_t fc, const u_char *p)
+static int
+handle_probe_request(const u_char *p)
 {
        struct mgmt_body_t  pbody;
        int offset = 0;
 
        memset(&pbody, 0, sizeof(pbody));
 
-       if (!parse_elements(&pbody, p, offset))
-               return 0;
+       parse_elements(&pbody, p, offset);
 
-       printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
-       fn_print(pbody.ssid.ssid, NULL);
-       printf(")");
+       PRINT_SSID(pbody);
        PRINT_RATES(pbody);
 
        return 1;
 }
 
-static int handle_probe_response(u_int16_t fc, const u_char *p)
+static int
+handle_probe_response(const u_char *p)
 {
        struct mgmt_body_t  pbody;
        int offset = 0;
 
        memset(&pbody, 0, sizeof(pbody));
 
-       if (!TTEST2(*p, 12))
+       if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
+           IEEE802_11_CAPINFO_LEN))
                return 0;
-       memcpy(&pbody.timestamp,p,8);
-       offset += 8;
+
+       memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
+       offset += IEEE802_11_TSTAMP_LEN;
        pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
-       offset += 2;
+       offset += IEEE802_11_BCNINT_LEN;
        pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
-       offset += 2;
+       offset += IEEE802_11_CAPINFO_LEN;
 
-       if (!parse_elements(&pbody, p, offset))
-               return 0;
+       parse_elements(&pbody, p, offset);
 
-       printf("%s (", subtype_text[FC_SUBTYPE(fc)]);
-       fn_print(pbody.ssid.ssid, NULL);
-       printf(") ");
+       PRINT_SSID(pbody);
        PRINT_RATES(pbody);
-       printf(" CH: %u%s", pbody.ds.channel,
-           CAPABILITY_PRIVACY(pbody.capability_info) ? ", PRIVACY" : "" );
+       PRINT_DS_CHANNEL(pbody);
 
        return 1;
 }
 
-static int handle_atim(void)
+static int
+handle_atim(void)
 {
        /* the frame body for ATIM is null. */
-       printf("ATIM");
        return 1;
 }
 
-static int handle_disassoc(u_int16_t fc, const u_char *p)
+static int
+handle_disassoc(const u_char *p)
 {
        struct mgmt_body_t  pbody;
-       int offset = 0;
 
        memset(&pbody, 0, sizeof(pbody));
 
-       if (!TTEST2(*p, 2))
+       if (!TTEST2(*p, IEEE802_11_REASON_LEN))
                return 0;
        pbody.reason_code = EXTRACT_LE_16BITS(p);
-       offset += 2;
 
-       printf("%s: %s", subtype_text[FC_SUBTYPE(fc)],
-           pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
+       printf(": %s",
+           (pbody.reason_code < NUM_REASONS)
+               ? reason_text[pbody.reason_code]
+               : "Reserved" );
 
        return 1;
 }
 
-static int handle_auth(u_int16_t fc, const u_char *p)
+static int
+handle_auth(const u_char *p)
 {
        struct mgmt_body_t  pbody;
        int offset = 0;
@@ -413,51 +493,59 @@ static int handle_auth(u_int16_t fc, const u_char *p)
        pbody.status_code = EXTRACT_LE_16BITS(p + offset);
        offset += 2;
 
-       if (!parse_elements(&pbody,p,offset))
-               return 0;
+       parse_elements(&pbody, p, offset);
 
        if ((pbody.auth_alg == 1) &&
-           ((pbody.auth_trans_seq_num == 2) || (pbody.auth_trans_seq_num == 3))) {
-               printf("%s (%s)-%x [Challenge Text] %s",
-                       subtype_text[FC_SUBTYPE(fc)],
-                       pbody.auth_alg < 4 ? auth_alg_text[pbody.auth_alg] : "Reserved" ,
-                       pbody.auth_trans_seq_num,
-                        ((pbody.auth_trans_seq_num % 2) ?
-                               (pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a") : "" ));
-       } else {
-               printf("%s (%s)-%x: %s",
-                   subtype_text[FC_SUBTYPE(fc)],
-                   pbody.auth_alg < 4 ? auth_alg_text[pbody.auth_alg] : "Reserved" ,
+           ((pbody.auth_trans_seq_num == 2) ||
+            (pbody.auth_trans_seq_num == 3))) {
+               printf(" (%s)-%x [Challenge Text] %s",
+                   (pbody.auth_alg < NUM_AUTH_ALGS)
+                       ? auth_alg_text[pbody.auth_alg]
+                       : "Reserved",
                    pbody.auth_trans_seq_num,
-                   ((pbody.auth_trans_seq_num % 2) ? (pbody.status_code < 19 ? status_text[pbody.status_code] : "n/a")  : ""));
+                   ((pbody.auth_trans_seq_num % 2)
+                       ? ((pbody.status_code < NUM_STATUSES)
+                              ? status_text[pbody.status_code]
+                              : "n/a") : ""));
+               return 1;
        }
+       printf(" (%s)-%x: %s",
+           (pbody.auth_alg < NUM_AUTH_ALGS)
+               ? auth_alg_text[pbody.auth_alg]
+               : "Reserved",
+           pbody.auth_trans_seq_num,
+           (pbody.auth_trans_seq_num % 2)
+               ? ((pbody.status_code < NUM_STATUSES)
+                   ? status_text[pbody.status_code]
+                   : "n/a")
+               : "");
 
        return 1;
 }
 
-static int handle_deauth(u_int16_t fc, const struct mgmt_header_t *pmh,
-    const u_char *p)
+static int
+handle_deauth(const struct mgmt_header_t *pmh, const u_char *p)
 {
        struct mgmt_body_t  pbody;
        int offset = 0;
+       const char *reason = NULL;
 
        memset(&pbody, 0, sizeof(pbody));
 
-       if (!TTEST2(*p, 2))
+       if (!TTEST2(*p, IEEE802_11_REASON_LEN))
                return 0;
        pbody.reason_code = EXTRACT_LE_16BITS(p);
-       offset += 2;
+       offset += IEEE802_11_REASON_LEN;
+
+       reason = (pbody.reason_code < NUM_REASONS)
+                       ? reason_text[pbody.reason_code]
+                       : "Reserved";
 
        if (eflag) {
-               printf("%s: %s",
-                   subtype_text[FC_SUBTYPE(fc)],
-                   pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
+               printf(": %s", reason);
        } else {
-               printf("%s (%s): %s",
-                   subtype_text[FC_SUBTYPE(fc)], etheraddr_string(pmh->sa),
-                   pbody.reason_code < 10 ? reason_text[pbody.reason_code] : "Reserved" );
+               printf(" (%s): %s", etheraddr_string(pmh->sa), reason);
        }
-
        return 1;
 }
 
@@ -467,42 +555,53 @@ static int handle_deauth(u_int16_t fc, const struct mgmt_header_t *pmh,
  *********************************************************************************/
 
 
-static int mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
+static int
+mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
     const u_char *p)
 {
        switch (FC_SUBTYPE(fc)) {
        case ST_ASSOC_REQUEST:
-               return (handle_assoc_request(fc, p));
+               printf("Assoc Request");
+               return handle_assoc_request(p);
        case ST_ASSOC_RESPONSE:
-               return (handle_assoc_response(fc, p));
+               printf("Assoc Response");
+               return handle_assoc_response(p);
        case ST_REASSOC_REQUEST:
-               return (handle_reassoc_request(fc, p));
+               printf("ReAssoc Request");
+               return handle_reassoc_request(p);
        case ST_REASSOC_RESPONSE:
-               return (handle_reassoc_response(fc, p));
+               printf("ReAssoc Response");
+               return handle_reassoc_response(p);
        case ST_PROBE_REQUEST:
-               return (handle_probe_request(fc, p));
+               printf("Probe Request");
+               return handle_probe_request(p);
        case ST_PROBE_RESPONSE:
-               return (handle_probe_response(fc, p));
+               printf("Probe Response");
+               return handle_probe_response(p);
        case ST_BEACON:
-               return (handle_beacon(fc, p));
+               printf("Beacon");
+               return handle_beacon(p);
        case ST_ATIM:
-               return (handle_atim());
+               printf("ATIM");
+               return handle_atim();
        case ST_DISASSOC:
-               return (handle_disassoc(fc, p));
+               printf("Disassociation");
+               return handle_disassoc(p);
        case ST_AUTH:
+               printf("Authentication");
                if (!TTEST2(*p, 3))
                        return 0;
                if ((p[0] == 0 ) && (p[1] == 0) && (p[2] == 0)) {
                        printf("Authentication (Shared-Key)-3 ");
-                       return (wep_print(p));
+                       return wep_print(p);
                }
-               else
-                       return (handle_auth(fc, p));
+               return handle_auth(p);
        case ST_DEAUTH:
-               return (handle_deauth(fc, pmh, p));
+               printf("DeAuthentication");
+               return handle_deauth(pmh, p);
                break;
        default:
-               printf("Unhandled Managment subtype(%x)",
+               printf("Unhandled Management subtype(%x)",
                    FC_SUBTYPE(fc));
                return 1;
        }
@@ -513,68 +612,63 @@ static int mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
  * Handles printing all the control frame types
  *********************************************************************************/
 
-static int ctrl_body_print(u_int16_t fc, const u_char *p)
+static int
+ctrl_body_print(u_int16_t fc, const u_char *p)
 {
        switch (FC_SUBTYPE(fc)) {
        case CTRL_PS_POLL:
-               if (!TTEST2(*p, CTRL_PS_POLL_LEN))
+               printf("Power Save-Poll");
+               if (!TTEST2(*p, CTRL_PS_POLL_HDRLEN))
                        return 0;
-               printf("Power Save-Poll AID(%x)",
+               printf(" AID(%x)",
                    EXTRACT_LE_16BITS(&(((const struct ctrl_ps_poll_t *)p)->aid)));
                break;
        case CTRL_RTS:
-               if (!TTEST2(*p, CTRL_RTS_LEN))
+               printf("Request-To-Send");
+               if (!TTEST2(*p, CTRL_RTS_HDRLEN))
                        return 0;
-               if (eflag)
-                       printf("Request-To-Send");
-               else
-                       printf("Request-To-Send TA:%s ",
+               if (!eflag)
+                       printf(" TA:%s ",
                            etheraddr_string(((const struct ctrl_rts_t *)p)->ta));
                break;
        case CTRL_CTS:
-               if (!TTEST2(*p, CTRL_CTS_LEN))
+               printf("Clear-To-Send");
+               if (!TTEST2(*p, CTRL_CTS_HDRLEN))
                        return 0;
-               if (eflag)
-                       printf("Clear-To-Send");
-               else
-                       printf("Clear-To-Send RA:%s ",
+               if (!eflag)
+                       printf(" RA:%s ",
                            etheraddr_string(((const struct ctrl_cts_t *)p)->ra));
                break;
        case CTRL_ACK:
-               if (!TTEST2(*p, CTRL_ACK_LEN))
+               printf("Acknowledgment");
+               if (!TTEST2(*p, CTRL_ACK_HDRLEN))
                        return 0;
-               if (eflag)
-                       printf("Acknowledgment");
-               else
-                       printf("Acknowledgment RA:%s ",
+               if (!eflag)
+                       printf(" RA:%s ",
                            etheraddr_string(((const struct ctrl_ack_t *)p)->ra));
                break;
        case CTRL_CF_END:
-               if (!TTEST2(*p, CTRL_END_LEN))
+               printf("CF-End");
+               if (!TTEST2(*p, CTRL_END_HDRLEN))
                        return 0;
-               if (eflag)
-                       printf("CF-End");
-               else
-                       printf("CF-End RA:%s ",
+               if (!eflag)
+                       printf(" RA:%s ",
                            etheraddr_string(((const struct ctrl_end_t *)p)->ra));
                break;
        case CTRL_END_ACK:
-               if (!TTEST2(*p, CTRL_END_ACK_LEN))
+               printf("CF-End+CF-Ack");
+               if (!TTEST2(*p, CTRL_END_ACK_HDRLEN))
                        return 0;
-               if (eflag)
-                       printf("CF-End+CF-Ack");
-               else
-                       printf("CF-End+CF-Ack RA:%s ",
+               if (!eflag)
+                       printf(" RA:%s ",
                            etheraddr_string(((const struct ctrl_end_ack_t *)p)->ra));
                break;
        default:
-               printf("(B) Unknown Ctrl Subtype");
+               printf("Unknown Ctrl Subtype");
        }
        return 1;
 }
 
-
-
 /*
  * Print Header funcs
  */
@@ -589,31 +683,73 @@ static int ctrl_body_print(u_int16_t fc, const u_char *p)
  *    1    |  1      |  RA    | TA     | DA     | SA
  */
 
-static void data_header_print(u_int16_t fc, const u_char *p)
+static void
+data_header_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp,
+    const u_int8_t **dstp)
 {
+       switch (FC_SUBTYPE(fc)) {
+       case DATA_DATA:
+       case DATA_NODATA:
+               break;
+       case DATA_DATA_CF_ACK:
+       case DATA_NODATA_CF_ACK:
+               printf("CF Ack ");
+               break;
+       case DATA_DATA_CF_POLL:
+       case DATA_NODATA_CF_POLL:
+               printf("CF Poll ");
+               break;
+       case DATA_DATA_CF_ACK_POLL:
+       case DATA_NODATA_CF_ACK_POLL:
+               printf("CF Ack/Poll ");
+               break;
+       }
+
 #define ADDR1  (p + 4)
 #define ADDR2  (p + 10)
 #define ADDR3  (p + 16)
 #define ADDR4  (p + 24)
 
-       if (!FC_TO_DS(fc)) {
-               if (!FC_FROM_DS(fc))
-                       printf("DA:%s SA:%s BSSID:%s ",
-                           etheraddr_string(ADDR1), etheraddr_string(ADDR2),
-                           etheraddr_string(ADDR3));
-               else
-                       printf("DA:%s BSSID:%s SA:%s ",
-                           etheraddr_string(ADDR1), etheraddr_string(ADDR2),
-                           etheraddr_string(ADDR3));
-       } else {
-               if (!FC_FROM_DS(fc))
-                       printf("BSSID:%s SA:%s DA:%s ",
-                           etheraddr_string(ADDR1), etheraddr_string(ADDR2),
-                           etheraddr_string(ADDR3));
-               else
-                       printf("RA:%s TA:%s DA:%s SA:%s ",
-                           etheraddr_string(ADDR1), etheraddr_string(ADDR2),
-                           etheraddr_string(ADDR3), etheraddr_string(ADDR4));
+       if (!FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
+               if (srcp != NULL)
+                       *srcp = ADDR2;
+               if (dstp != NULL)
+                       *dstp = ADDR1;
+               if (!eflag)
+                       return;
+               printf("DA:%s SA:%s BSSID:%s ",
+                   etheraddr_string(ADDR1), etheraddr_string(ADDR2),
+                   etheraddr_string(ADDR3));
+       } else if (!FC_TO_DS(fc) && FC_FROM_DS(fc)) {
+               if (srcp != NULL)
+                       *srcp = ADDR3;
+               if (dstp != NULL)
+                       *dstp = ADDR1;
+               if (!eflag)
+                       return;
+               printf("DA:%s BSSID:%s SA:%s ",
+                   etheraddr_string(ADDR1), etheraddr_string(ADDR2),
+                   etheraddr_string(ADDR3));
+       } else if (FC_TO_DS(fc) && !FC_FROM_DS(fc)) {
+               if (srcp != NULL)
+                       *srcp = ADDR2;
+               if (dstp != NULL)
+                       *dstp = ADDR3;
+               if (!eflag)
+                       return;
+               printf("BSSID:%s SA:%s DA:%s ",
+                   etheraddr_string(ADDR1), etheraddr_string(ADDR2),
+                   etheraddr_string(ADDR3));
+       } else if (FC_TO_DS(fc) && FC_FROM_DS(fc)) {
+               if (srcp != NULL)
+                       *srcp = ADDR4;
+               if (dstp != NULL)
+                       *dstp = ADDR3;
+               if (!eflag)
+                       return;
+               printf("RA:%s TA:%s DA:%s SA:%s ",
+                   etheraddr_string(ADDR1), etheraddr_string(ADDR2),
+                   etheraddr_string(ADDR3), etheraddr_string(ADDR4));
        }
 
 #undef ADDR1
@@ -622,18 +758,35 @@ static void data_header_print(u_int16_t fc, const u_char *p)
 #undef ADDR4
 }
 
-
-static void mgmt_header_print(const u_char *p)
+static void
+mgmt_header_print(const u_char *p, const u_int8_t **srcp,
+    const u_int8_t **dstp)
 {
        const struct mgmt_header_t *hp = (const struct mgmt_header_t *) p;
 
+       if (srcp != NULL)
+               *srcp = hp->sa;
+       if (dstp != NULL)
+               *dstp = hp->da;
+       if (!eflag)
+               return;
+
        printf("BSSID:%s DA:%s SA:%s ",
            etheraddr_string((hp)->bssid), etheraddr_string((hp)->da),
            etheraddr_string((hp)->sa));
 }
 
-static void ctrl_header_print(u_int16_t fc, const u_char *p)
+static void
+ctrl_header_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp,
+    const u_int8_t **dstp)
 {
+       if (srcp != NULL)
+               *srcp = NULL;
+       if (dstp != NULL)
+               *dstp = NULL;
+       if (!eflag)
+               return;
+
        switch (FC_SUBTYPE(fc)) {
        case CTRL_PS_POLL:
                printf("BSSID:%s TA:%s ",
@@ -665,222 +818,431 @@ static void ctrl_header_print(u_int16_t fc, const u_char *p)
                break;
        default:
                printf("(H) Unknown Ctrl Subtype");
+               break;
        }
 }
 
-static int GetHeaderLength(u_int16_t fc)
+static int
+extract_header_length(u_int16_t fc)
 {
-       int iLength=0;
-
        switch (FC_TYPE(fc)) {
        case T_MGMT:
-               iLength = MGMT_HEADER_LEN;
-               break;
+               return MGMT_HDRLEN;
        case T_CTRL:
                switch (FC_SUBTYPE(fc)) {
                case CTRL_PS_POLL:
-                       iLength = CTRL_PS_POLL_LEN;
-                       break;
+                       return CTRL_PS_POLL_HDRLEN;
                case CTRL_RTS:
-                       iLength = CTRL_RTS_LEN;
-                       break;
+                       return CTRL_RTS_HDRLEN;
                case CTRL_CTS:
-                       iLength = CTRL_CTS_LEN;
-                       break;
+                       return CTRL_CTS_HDRLEN;
                case CTRL_ACK:
-                       iLength = CTRL_ACK_LEN;
-                       break;
+                       return CTRL_ACK_HDRLEN;
                case CTRL_CF_END:
-                       iLength = CTRL_END_LEN;
-                       break;
+                       return CTRL_END_HDRLEN;
                case CTRL_END_ACK:
-                       iLength = CTRL_END_ACK_LEN;
-                       break;
+                       return CTRL_END_ACK_HDRLEN;
                default:
-                       iLength = 0;
-                       break;
+                       return 0;
                }
-               break;
        case T_DATA:
-               if (FC_TO_DS(fc) && FC_FROM_DS(fc))
-                       iLength = 30;
-               else
-                       iLength = 24;
-               break;
+               return (FC_TO_DS(fc) && FC_FROM_DS(fc)) ? 30 : 24;
        default:
-               printf("unknown IEEE802.11 frame type (%d)",
-                   FC_TYPE(fc));
-               break;
+               printf("unknown IEEE802.11 frame type (%d)", FC_TYPE(fc));
+               return 0;
        }
-
-       return iLength;
 }
 
 /*
- * Print the 802.11 MAC header
+ * Print the 802.11 MAC header if eflag is set, and set "*srcp" and "*dstp"
+ * to point to the source and destination MAC addresses in any case if
+ * "srcp" and "dstp" aren't null.
  */
 static inline void
-ieee_802_11_hdr_print(u_int16_t fc, const u_char *p)
+ieee_802_11_hdr_print(u_int16_t fc, const u_char *p, const u_int8_t **srcp,
+    const u_int8_t **dstp)
 {
+       if (vflag) {
+               if (FC_MORE_DATA(fc))
+                       printf("More Data ");
+               if (FC_MORE_FLAG(fc))
+                       printf("More Fragments ");
+               if (FC_POWER_MGMT(fc))
+                       printf("Pwr Mgmt ");
+               if (FC_RETRY(fc))
+                       printf("Retry ");
+               if (FC_ORDER(fc))
+                       printf("Strictly Ordered ");
+               if (FC_WEP(fc))
+                       printf("WEP Encrypted ");
+               if (FC_TYPE(fc) != T_CTRL || FC_SUBTYPE(fc) != CTRL_PS_POLL)
+                       printf("%dus ",
+                           EXTRACT_LE_16BITS(
+                               &((const struct mgmt_header_t *)p)->duration));
+       }
+
        switch (FC_TYPE(fc)) {
        case T_MGMT:
-               mgmt_header_print(p);
+               mgmt_header_print(p, srcp, dstp);
                break;
-
        case T_CTRL:
-               ctrl_header_print(fc, p);
+               ctrl_header_print(fc, p, srcp, dstp);
                break;
-
        case T_DATA:
-               data_header_print(fc, p);
+               data_header_print(fc, p, srcp, dstp);
                break;
-
        default:
                printf("(header) unknown IEEE802.11 frame type (%d)",
                    FC_TYPE(fc));
+               *srcp = NULL;
+               *dstp = NULL;
                break;
        }
 }
 
-static void
+static u_int
 ieee802_11_print(const u_char *p, u_int length, u_int caplen)
 {
        u_int16_t fc;
-       u_int HEADER_LENGTH;
+       u_int hdrlen;
+       const u_int8_t *src, *dst;
        u_short extracted_ethertype;
 
        if (caplen < IEEE802_11_FC_LEN) {
                printf("[|802.11]");
-               return;
+               return caplen;
        }
 
        fc = EXTRACT_LE_16BITS(p);
-       HEADER_LENGTH = GetHeaderLength(fc);
+       hdrlen = extract_header_length(fc);
 
-       if (caplen < HEADER_LENGTH) {
+       if (caplen < hdrlen) {
                printf("[|802.11]");
-               return;
+               return hdrlen;
        }
 
-       if (eflag)
-               ieee_802_11_hdr_print(fc, p);
+       ieee_802_11_hdr_print(fc, p, &src, &dst);
 
        /*
-        * Some printers want to get back at the ethernet addresses,
-        * and/or check that they're not walking off the end of the packet.
-        * Rather than pass them all the way down, we set these globals.
+        * Go past the 802.11 header.
         */
-       packetp = p;
-       snapend = p + caplen;
-
-       length -= HEADER_LENGTH;
-       caplen -= HEADER_LENGTH;
-       p += HEADER_LENGTH;
+       length -= hdrlen;
+       caplen -= hdrlen;
+       p += hdrlen;
 
        switch (FC_TYPE(fc)) {
        case T_MGMT:
-               if (!mgmt_body_print(fc, (const struct mgmt_header_t *)packetp,
-                   p)) {
+               if (!mgmt_body_print(fc,
+                   (const struct mgmt_header_t *)(p - hdrlen), p)) {
                        printf("[|802.11]");
-                       return;
+                       return hdrlen;
                }
                break;
-
        case T_CTRL:
-               if (!ctrl_body_print(fc, p - HEADER_LENGTH)) {
+               if (!ctrl_body_print(fc, p - hdrlen)) {
                        printf("[|802.11]");
-                       return;
+                       return hdrlen;
                }
                break;
-
        case T_DATA:
                /* There may be a problem w/ AP not having this bit set */
                if (FC_WEP(fc)) {
                        if (!wep_print(p)) {
                                printf("[|802.11]");
-                               return;
-                       }
-               } else {
-                       if (llc_print(p, length, caplen, packetp + 10,
-                           packetp + 4, &extracted_ethertype) == 0) {
-                               /*
-                                * Some kinds of LLC packet we cannot
-                                * handle intelligently
-                                */
-                               if (!eflag)
-                                       ieee_802_11_hdr_print(fc, p - HEADER_LENGTH);
-                               if (extracted_ethertype) {
-                                       printf("(LLC %s) ",
-                                           etherproto_string(htons(extracted_ethertype)));
-                               }
-                               if (!xflag && !qflag)
-                                       default_print(p, caplen);
+                               return hdrlen;
                        }
+               } else if (llc_print(p, length, caplen, dst, src,
+                   &extracted_ethertype) == 0) {
+                       /*
+                        * Some kinds of LLC packet we cannot
+                        * handle intelligently
+                        */
+                       if (!eflag)
+                               ieee_802_11_hdr_print(fc, p - hdrlen, NULL,
+                                   NULL);
+                       if (extracted_ethertype)
+                               printf("(LLC %s) ",
+                                   etherproto_string(
+                                       htons(extracted_ethertype)));
+                       if (!suppress_default_print)
+                               default_print(p, caplen);
                }
                break;
-
        default:
-               printf("(body) unhandled IEEE802.11 frame type (%d)",
-                   FC_TYPE(fc));
+               printf("unknown 802.11 frame type (%d)", FC_TYPE(fc));
                break;
        }
 
-       if (xflag)
-               default_print(p, caplen);
+       return hdrlen;
 }
 
 /*
  * This is the top level routine of the printer.  'p' points
  * to the 802.11 header of the packet, 'h->ts' is the timestamp,
- * 'h->length' is the length of the packet off the wire, and 'h->caplen'
+ * 'h->len' is the length of the packet off the wire, and 'h->caplen'
  * is the number of bytes actually captured.
  */
-void
-ieee802_11_if_print(u_char *user _U_, const struct pcap_pkthdr *h, const u_char *p)
+u_int
+ieee802_11_if_print(const struct pcap_pkthdr *h, const u_char *p)
 {
-       u_int caplen = h->caplen;
-       u_int length = h->len;
+       return ieee802_11_print(p, h->len, h->caplen);
+}
+
+static int
+print_radiotap_field(struct cpack_state *s, u_int32_t bit)
+{
+       union {
+               int8_t          i8;
+               u_int8_t        u8;
+               int16_t         i16;
+               u_int16_t       u16;
+               u_int32_t       u32;
+               u_int64_t       u64;
+       } u, u2;
+       int rc;
+
+       switch (bit) {
+       case IEEE80211_RADIOTAP_FLAGS:
+       case IEEE80211_RADIOTAP_RATE:
+       case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+       case IEEE80211_RADIOTAP_DB_ANTNOISE:
+       case IEEE80211_RADIOTAP_ANTENNA:
+               rc = cpack_uint8(s, &u.u8);
+               break;
+       case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+       case IEEE80211_RADIOTAP_DBM_ANTNOISE:
+               rc = cpack_int8(s, &u.i8);
+               break;
+       case IEEE80211_RADIOTAP_CHANNEL:
+               rc = cpack_uint16(s, &u.u16);
+               if (rc != 0)
+                       break;
+               rc = cpack_uint16(s, &u2.u16);
+               break;
+       case IEEE80211_RADIOTAP_FHSS:
+       case IEEE80211_RADIOTAP_LOCK_QUALITY:
+       case IEEE80211_RADIOTAP_TX_ATTENUATION:
+               rc = cpack_uint16(s, &u.u16);
+               break;
+       case IEEE80211_RADIOTAP_DB_TX_ATTENUATION:
+               rc = cpack_uint8(s, &u.u8);
+               break;
+       case IEEE80211_RADIOTAP_DBM_TX_POWER:
+               rc = cpack_int8(s, &u.i8);
+               break;
+       case IEEE80211_RADIOTAP_TSFT:
+               rc = cpack_uint64(s, &u.u64);
+               break;
+       default:
+               /* this bit indicates a field whose
+                * size we do not know, so we cannot
+                * proceed.
+                */
+               printf("[0x%08x] ", bit);
+               return -1;
+       }
+
+       if (rc != 0) {
+               printf("[|802.11]");
+               return rc;
+       }
+
+       switch (bit) {
+       case IEEE80211_RADIOTAP_CHANNEL:
+               printf("%u MHz ", u.u16);
+               if (u2.u16 != 0)
+                       printf("(0x%04x) ", u2.u16);
+               break;
+       case IEEE80211_RADIOTAP_FHSS:
+               printf("fhset %d fhpat %d ", u.u16 & 0xff, (u.u16 >> 8) & 0xff);
+               break;
+       case IEEE80211_RADIOTAP_RATE:
+               PRINT_RATE("", u.u8, " Mb/s ");
+               break;
+       case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+               printf("%ddB signal ", u.i8);
+               break;
+       case IEEE80211_RADIOTAP_DBM_ANTNOISE:
+               printf("%ddB noise ", u.i8);
+               break;
+       case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+               printf("%ddB signal ", u.u8);
+               break;
+       case IEEE80211_RADIOTAP_DB_ANTNOISE:
+               printf("%ddB noise ", u.u8);
+               break;
+       case IEEE80211_RADIOTAP_LOCK_QUALITY:
+               printf("%u sq ", u.u16);
+               break;
+       case IEEE80211_RADIOTAP_TX_ATTENUATION:
+               printf("%d tx power ", -(int)u.u16);
+               break;
+       case IEEE80211_RADIOTAP_DB_TX_ATTENUATION:
+               printf("%ddB tx power ", -(int)u.u8);
+               break;
+       case IEEE80211_RADIOTAP_DBM_TX_POWER:
+               printf("%ddBm tx power ", u.i8);
+               break;
+       case IEEE80211_RADIOTAP_FLAGS:
+               if (u.u8 & IEEE80211_RADIOTAP_F_CFP)
+                       printf("cfp ");
+               if (u.u8 & IEEE80211_RADIOTAP_F_SHORTPRE)
+                       printf("short preamble ");
+               if (u.u8 & IEEE80211_RADIOTAP_F_WEP)
+                       printf("wep ");
+               if (u.u8 & IEEE80211_RADIOTAP_F_FRAG)
+                       printf("fragmented ");
+               break;
+       case IEEE80211_RADIOTAP_ANTENNA:
+               printf("antenna %d ", u.u8);
+               break;
+       case IEEE80211_RADIOTAP_TSFT:
+               printf("%" PRIu64 "us tsft ", u.u64);
+               break;
+       }
+       return 0;
+}
+
+static u_int
+ieee802_11_radio_print(const u_char *p, u_int length, u_int caplen)
+{
+#define        BITNO_32(x) (((x) >> 16) ? 16 + BITNO_16((x) >> 16) : BITNO_16((x)))
+#define        BITNO_16(x) (((x) >> 8) ? 8 + BITNO_8((x) >> 8) : BITNO_8((x)))
+#define        BITNO_8(x) (((x) >> 4) ? 4 + BITNO_4((x) >> 4) : BITNO_4((x)))
+#define        BITNO_4(x) (((x) >> 2) ? 2 + BITNO_2((x) >> 2) : BITNO_2((x)))
+#define        BITNO_2(x) (((x) & 2) ? 1 : 0)
+#define        BIT(n)  (1 << n)
+#define        IS_EXTENDED(__p)        \
+           (EXTRACT_LE_32BITS(__p) & BIT(IEEE80211_RADIOTAP_EXT)) != 0
+
+       struct cpack_state cpacker;
+       struct ieee80211_radiotap_header *hdr;
+       u_int32_t present, next_present;
+       u_int32_t *presentp, *last_presentp;
+       enum ieee80211_radiotap_type bit;
+       int bit0;
+       const u_char *iter;
+       u_int len;
+
+       if (caplen < sizeof(*hdr)) {
+               printf("[|802.11]");
+               return caplen;
+       }
+
+       hdr = (struct ieee80211_radiotap_header *)p;
+
+       len = EXTRACT_LE_16BITS(&hdr->it_len);
+
+       if (caplen < len) {
+               printf("[|802.11]");
+               return caplen;
+       }
+       for (last_presentp = &hdr->it_present;
+            IS_EXTENDED(last_presentp) &&
+            (u_char*)(last_presentp + 1) <= p + len;
+            last_presentp++);
+
+       /* are there more bitmap extensions than bytes in header? */
+       if (IS_EXTENDED(last_presentp)) {
+               printf("[|802.11]");
+               return caplen;
+       }
 
-       ++infodelay;
-       ts_print(&h->ts);
+       iter = (u_char*)(last_presentp + 1);
 
-       ieee802_11_print(p, length, caplen);
+       if (cpack_init(&cpacker, (u_int8_t*)iter, len - (iter - p)) != 0) {
+               /* XXX */
+               printf("[|802.11]");
+               return caplen;
+       }
+
+       for (bit0 = 0, presentp = &hdr->it_present; presentp <= last_presentp;
+            presentp++, bit0 += 32) {
+               for (present = EXTRACT_LE_32BITS(presentp); present;
+                    present = next_present) {
+                       /* clear the least significant bit that is set */
+                       next_present = present & (present - 1);
+
+                       /* extract the least significant bit that is set */
+                       bit = (enum ieee80211_radiotap_type)
+                           (bit0 + BITNO_32(present ^ next_present));
+
+                       if (print_radiotap_field(&cpacker, bit) != 0)
+                               goto out;
+               }
+       }
+out:
+       return len + ieee802_11_print(p + len, length - len, caplen - len);
+#undef BITNO_32
+#undef BITNO_16
+#undef BITNO_8
+#undef BITNO_4
+#undef BITNO_2
+#undef BIT
+}
+
+static u_int
+ieee802_11_avs_radio_print(const u_char *p, u_int length, u_int caplen)
+{
+       u_int32_t caphdr_len;
+
+       caphdr_len = EXTRACT_32BITS(p + 4);
+       if (caphdr_len < 8) {
+               /*
+                * Yow!  The capture header length is claimed not
+                * to be large enough to include even the version
+                * cookie or capture header length!
+                */
+               printf("[|802.11]");
+               return caplen;
+       }
+
+       if (caplen < caphdr_len) {
+               printf("[|802.11]");
+               return caplen;
+       }
 
-       putchar('\n');
-       --infodelay;
-       if (infoprint)
-               info(0);
+       return caphdr_len + ieee802_11_print(p + caphdr_len,
+           length - caphdr_len, caplen - caphdr_len);
 }
 
-#define PRISM_HDR_LEN  144
+#define PRISM_HDR_LEN          144
+
+#define WLANCAP_MAGIC_COOKIE_V1        0x80211001
 
 /*
  * For DLT_PRISM_HEADER; like DLT_IEEE802_11, but with an extra header,
  * containing information such as radio information, which we
  * currently ignore.
+ *
+ * If, however, the packet begins with WLANCAP_MAGIC_COOKIE_V1, it's
+ * really DLT_IEEE802_11_RADIO (currently, on Linux, there's no
+ * ARPHRD_ type for DLT_IEEE802_11_RADIO, as there is a
+ * ARPHRD_IEEE80211_PRISM for DLT_PRISM_HEADER, so
+ * ARPHRD_IEEE80211_PRISM is used for DLT_IEEE802_11_RADIO, and
+ * the first 4 bytes of the header are used to indicate which it is).
  */
-void
-prism_if_print(u_char *user _U_, const struct pcap_pkthdr *h, const u_char *p)
+u_int
+prism_if_print(const struct pcap_pkthdr *h, const u_char *p)
 {
        u_int caplen = h->caplen;
        u_int length = h->len;
 
-       ++infodelay;
-       ts_print(&h->ts);
+       if (caplen < 4) {
+               printf("[|802.11]");
+               return caplen;
+       }
+
+       if (EXTRACT_32BITS(p) == WLANCAP_MAGIC_COOKIE_V1)
+               return ieee802_11_avs_radio_print(p, length, caplen);
 
        if (caplen < PRISM_HDR_LEN) {
                printf("[|802.11]");
-               goto out;
+               return caplen;
        }
 
-       ieee802_11_print(p + PRISM_HDR_LEN, length - PRISM_HDR_LEN,
-           caplen - PRISM_HDR_LEN);
-
-out:
-       putchar('\n');
-       --infodelay;
-       if (infoprint)
-               info(0);
+       return PRISM_HDR_LEN + ieee802_11_print(p + PRISM_HDR_LEN,
+           length - PRISM_HDR_LEN, caplen - PRISM_HDR_LEN);
 }
 
 /*
@@ -888,44 +1250,16 @@ out:
  * header, containing information such as radio information, which we
  * currently ignore.
  */
-void
-ieee802_11_radio_if_print(u_char *user _U_, const struct pcap_pkthdr *h,
-    const u_char *p)
+u_int
+ieee802_11_radio_if_print(const struct pcap_pkthdr *h, const u_char *p)
 {
        u_int caplen = h->caplen;
        u_int length = h->len;
-       u_int32_t caphdr_len;
-
-       ++infodelay;
-       ts_print(&h->ts);
 
        if (caplen < 8) {
                printf("[|802.11]");
-               goto out;
-       }
-
-       caphdr_len = EXTRACT_32BITS(p + 4);
-       if (caphdr_len < 8) {
-               /*
-                * Yow!  The capture header length is claimed not
-                * to be large enough to include even the version
-                * cookie or capture header length!
-                */
-               printf("[|802.11]");
-               goto out;
+               return caplen;
        }
 
-       if (caplen < caphdr_len) {
-               printf("[|802.11]");
-               goto out;
-       }
-
-       ieee802_11_print(p + caphdr_len, length - caphdr_len,
-           caplen - caphdr_len);
-
-out:
-       putchar('\n');
-       --infodelay;
-       if (infoprint)
-               info(0);
+       return ieee802_11_radio_print(p, length, caplen);
 }