]> 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 3b46fe7d0d24ca1847081a63b2730f4cf24d10ba..891439e0373a7ce3e1f614315c2e3b541d0629c4 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.26 2003-11-27 02:18:53 guy Exp $ (LBL)";
+    "@(#) $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,39 +41,62 @@ static const char rcsid[] _U_ =
 
 #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))); \
-               if (p.rates.rate[z] & 0x80) printf("*"); \
-               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  */
@@ -97,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 */
@@ -107,12 +130,12 @@ 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)
@@ -129,94 +152,141 @@ wep_print(const u_char *p)
        return 1;
 }
 
-static int
+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:
+                       /* Present, possibly truncated */
+                       pbody->ssid_status = TRUNCATED;
                        if (!TTEST2(*(p + offset), 2))
-                               return 0;
+                               return;
                        memcpy(&pbody->ssid, p + offset, 2);
                        offset += 2;
-                       if (pbody->ssid.length <= 0)
-                               break;
-                       if (!TTEST2(*(p + offset), pbody->ssid.length))
-                               return 0;
-                       memcpy(&pbody->ssid.ssid, p + offset,
-                           pbody->ssid.length);
-                       offset += pbody->ssid.length;
+                       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:
+                       /* Present, possibly truncated */
+                       pbody->challenge_status = TRUNCATED;
                        if (!TTEST2(*(p + offset), 2))
-                               return 0;
+                               return;
                        memcpy(&pbody->challenge, p + offset, 2);
                        offset += 2;
-                       if (pbody->challenge.length <= 0)
-                               break;
-                       if (!TTEST2(*(p + offset), pbody->challenge.length))
-                               return 0;
-                       memcpy(&pbody->challenge.text, p + offset,
-                           pbody->challenge.length);
-                       offset += pbody->challenge.length;
+                       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:
+                       /* Present, possibly truncated */
+                       pbody->rates_status = TRUNCATED;
                        if (!TTEST2(*(p + offset), 2))
-                               return 0;
+                               return;
                        memcpy(&(pbody->rates), p + offset, 2);
                        offset += 2;
-                       if (pbody->rates.length <= 0)
-                               break;
-                       if (!TTEST2(*(p + offset), pbody->rates.length))
-                               return 0;
-                       memcpy(&pbody->rates.rate, p + offset,
-                           pbody->rates.length);
-                       offset += pbody->rates.length;
+                       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:
+                       /* Present, possibly truncated */
+                       pbody->ds_status = TRUNCATED;
                        if (!TTEST2(*(p + offset), 3))
-                               return 0;
+                               return;
                        memcpy(&pbody->ds, p + offset, 3);
                        offset += 3;
+                       /* Present and not truncated */
+                       pbody->ds_status = PRESENT;
                        break;
                case E_CF:
+                       /* Present, possibly truncated */
+                       pbody->cf_status = TRUNCATED;
                        if (!TTEST2(*(p + offset), 8))
-                               return 0;
+                               return;
                        memcpy(&pbody->cf, p + offset, 8);
                        offset += 8;
+                       /* Present and not truncated */
+                       pbody->cf_status = PRESENT;
                        break;
                case E_TIM:
+                       /* Present, possibly truncated */
+                       pbody->tim_status = TRUNCATED;
                        if (!TTEST2(*(p + offset), 2))
-                               return 0;
+                               return;
                        memcpy(&pbody->tim, p + offset, 2);
                        offset += 2;
                        if (!TTEST2(*(p + offset), 3))
-                               return 0;
+                               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 0;
+                               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) );
 #endif
+                       if (!TTEST2(*(p + offset), 2))
+                               return;
+                       if (!TTEST2(*(p + offset + 2), *(p + offset + 1)))
+                               return;
                        offset += *(p + offset + 1) + 2;
                        break;
                }
        }
-       return 1;
 }
 
 /*********************************************************************************
@@ -224,7 +294,7 @@ parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset)
  *********************************************************************************/
 
 static int
-handle_beacon(u_int16_t fc, const u_char *p)
+handle_beacon(const u_char *p)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
@@ -234,30 +304,26 @@ handle_beacon(u_int16_t fc, const u_char *p)
        if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
            IEEE802_11_CAPINFO_LEN))
                return 0;
-       memcpy(&pbody.timestamp, p, 8);
+       memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
        offset += IEEE802_11_TSTAMP_LEN;
        pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_BCNINT_LEN;
        pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_CAPINFO_LEN;
 
-       if (!parse_elements(&pbody, p, offset))
-               return 0;
+       parse_elements(&pbody, p, offset);
 
-       printf(" (");
-       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)
+handle_assoc_request(const u_char *p)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
@@ -271,18 +337,15 @@ handle_assoc_request(u_int16_t fc, const u_char *p)
        pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_LISTENINT_LEN;
 
-       if (!parse_elements(&pbody, p, offset))
-               return 0;
+       parse_elements(&pbody, p, offset);
 
-       printf(" (");
-       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)
+handle_assoc_response(const u_char *p)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
@@ -299,18 +362,19 @@ handle_assoc_response(u_int16_t fc, const u_char *p)
        pbody.aid = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_AID_LEN;
 
-       if (!parse_elements(&pbody, p, offset))
-               return 0;
+       parse_elements(&pbody, p, offset);
 
        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)
+handle_reassoc_request(const u_char *p)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
@@ -327,44 +391,39 @@ handle_reassoc_request(u_int16_t fc, const u_char *p)
        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(" (");
-       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)
+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)
+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(" (");
-       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)
+handle_probe_response(const u_char *p)
 {
        struct mgmt_body_t  pbody;
        int offset = 0;
@@ -382,15 +441,11 @@ handle_probe_response(u_int16_t fc, const u_char *p)
        pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_CAPINFO_LEN;
 
-       if (!parse_elements(&pbody, p, offset))
-               return 0;
+       parse_elements(&pbody, p, offset);
 
-       printf(" (");
-       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;
 }
@@ -403,7 +458,7 @@ handle_atim(void)
 }
 
 static int
-handle_disassoc(u_int16_t fc, const u_char *p)
+handle_disassoc(const u_char *p)
 {
        struct mgmt_body_t  pbody;
 
@@ -414,14 +469,15 @@ handle_disassoc(u_int16_t fc, const u_char *p)
        pbody.reason_code = EXTRACT_LE_16BITS(p);
 
        printf(": %s",
-           (pbody.reason_code < 10) ? reason_text[pbody.reason_code]
-                                    : "Reserved" );
+           (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)
+handle_auth(const u_char *p)
 {
        struct mgmt_body_t  pbody;
        int offset = 0;
@@ -437,36 +493,38 @@ 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)-%x [Challenge Text] %s",
-                   (pbody.auth_alg < 4) ? auth_alg_text[pbody.auth_alg]
-                                        : "Reserved",
+                   (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)
+                       ? ((pbody.status_code < NUM_STATUSES)
                               ? status_text[pbody.status_code]
                               : "n/a") : ""));
                return 1;
        }
        printf(" (%s)-%x: %s",
-           (pbody.auth_alg < 4) ? auth_alg_text[pbody.auth_alg] : "Reserved",
+           (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.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)
+handle_deauth(const struct mgmt_header_t *pmh, const u_char *p)
 {
        struct mgmt_body_t  pbody;
        int offset = 0;
@@ -479,8 +537,9 @@ handle_deauth(u_int16_t fc, const struct mgmt_header_t *pmh,
        pbody.reason_code = EXTRACT_LE_16BITS(p);
        offset += IEEE802_11_REASON_LEN;
 
-       reason = (pbody.reason_code < 10) ? reason_text[pbody.reason_code]
-                                         : "Reserved";
+       reason = (pbody.reason_code < NUM_REASONS)
+                       ? reason_text[pbody.reason_code]
+                       : "Reserved";
 
        if (eflag) {
                printf(": %s", reason);
@@ -500,37 +559,46 @@ static int
 mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
     const u_char *p)
 {
-       printf("%s", subtype_text[FC_SUBTYPE(fc)]);
-
        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:
+               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 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 Management subtype(%x)",
@@ -896,7 +964,7 @@ ieee802_11_print(const u_char *p, u_int length, u_int caplen)
                                printf("(LLC %s) ",
                                    etherproto_string(
                                        htons(extracted_ethertype)));
-                       if (!xflag && !qflag)
+                       if (!suppress_default_print)
                                default_print(p, caplen);
                }
                break;
@@ -911,7 +979,7 @@ ieee802_11_print(const u_char *p, u_int length, u_int caplen)
 /*
  * 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.
  */
 u_int
@@ -920,8 +988,201 @@ ieee802_11_if_print(const struct pcap_pkthdr *h, const u_char *p)
        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;
+       }
+
+       iter = (u_char*)(last_presentp + 1);
+
+       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;
 
@@ -973,7 +1234,7 @@ prism_if_print(const struct pcap_pkthdr *h, const u_char *p)
        }
 
        if (EXTRACT_32BITS(p) == WLANCAP_MAGIC_COOKIE_V1)
-               return ieee802_11_radio_print(p, length, caplen);
+               return ieee802_11_avs_radio_print(p, length, caplen);
 
        if (caplen < PRISM_HDR_LEN) {
                printf("[|802.11]");