]> The Tcpdump Group git mirrors - tcpdump/commitdiff
When parsing IEs in a management frame, save the *first* IE of a given
authorGuy Harris <[email protected]>
Wed, 4 Nov 2009 22:55:05 +0000 (14:55 -0800)
committerGuy Harris <[email protected]>
Wed, 4 Nov 2009 22:55:05 +0000 (14:55 -0800)
type we see, not the *last*, so the first one gets printed.  If,
however, a rates IE has a zero-length list of rates, don't save that
one; some devices send out frames with two rates IEs, one zero-length
and a later one containing the actual rates.

Have parse_elements() return an indication of whether truncation
occurred - and pass it the frame length, so it doesn't just keep parsing
until an end-of-captured-data test fails, as that would make *every*
frame look truncated.

ieee802_11.h
print-802_11.c

index 90846a9ab27d42642f39bb4a0e9cde025c24a3eb..2aa1345038a25c341fbe56800e01be7712563742 100644 (file)
@@ -144,12 +144,6 @@ struct mgmt_header_t {
 #define        CAPABILITY_CFP_REQ(cap) ((cap) & 0x0008)
 #define        CAPABILITY_PRIVACY(cap) ((cap) & 0x0010)
 
-typedef enum {
-       NOT_PRESENT,
-       PRESENT,
-       TRUNCATED
-} elem_status_t;
-
 struct ssid_t {
        u_int8_t        element_id;
        u_int8_t        length;
@@ -237,20 +231,20 @@ struct mgmt_body_t {
        u_int16_t       reason_code;
        u_int16_t       auth_alg;
        u_int16_t       auth_trans_seq_num;
-       elem_status_t   challenge_status;
+       int             challenge_present;
        struct challenge_t  challenge;
        u_int16_t       capability_info;
-       elem_status_t   ssid_status;
+       int             ssid_present;
        struct ssid_t   ssid;
-       elem_status_t   rates_status;
+       int             rates_present;
        struct rates_t  rates;
-       elem_status_t   ds_status;
+       int             ds_present;
        struct ds_t     ds;
-       elem_status_t   cf_status;
+       int             cf_present;
        struct cf_t     cf;
-       elem_status_t   fh_status;
+       int             fh_present;
        struct fh_t     fh;
-       elem_status_t   tim_status;
+       int             tim_present;
        struct tim_t    tim;
 };
 
index 72fd03cef7c8cf906b00f70102684979ad700bc5..9b1ba12f4e1871d75519941c5868753d7173482e 100644 (file)
@@ -47,51 +47,30 @@ static const char rcsid[] _U_ =
 #include "ieee802_11_radio.h"
 
 #define PRINT_SSID(p) \
-       switch (p.ssid_status) { \
-       case TRUNCATED: \
-               return 0; \
-       case PRESENT: \
+       if (p.ssid_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) \
-       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; \
+       if (p.rates_present) { \
+               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]"); \
        }
 
 #define PRINT_DS_CHANNEL(p) \
-       switch (p.ds_status) { \
-       case TRUNCATED: \
-               return 0; \
-       case PRESENT: \
+       if (p.ds_present) \
                printf(" CH: %u", p.ds.channel); \
-               break; \
-       case NOT_PRESENT: \
-               break; \
-       } \
        printf("%s", \
            CAPABILITY_PRIVACY(p.capability_info) ? ", PRIVACY" : "" );
 
@@ -286,141 +265,240 @@ wep_print(const u_char *p)
        return 1;
 }
 
-static void
-parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset)
+static int
+parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset,
+    u_int length)
 {
+       struct ssid_t ssid;
+       struct challenge_t challenge;
+       struct rates_t rates;
+       struct ds_t ds;
+       struct cf_t cf;
+       struct tim_t tim;
+
        /*
         * 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 (;;) {
+       pbody->challenge_present = 0;
+       pbody->ssid_present = 0;
+       pbody->rates_present = 0;
+       pbody->ds_present = 0;
+       pbody->cf_present = 0;
+       pbody->tim_present = 0;
+
+       while (length != 0) {
                if (!TTEST2(*(p + offset), 1))
-                       return;
+                       return 0;
+               if (length < 1)
+                       return 0;
                switch (*(p + offset)) {
                case E_SSID:
-                       /* Present, possibly truncated */
-                       pbody->ssid_status = TRUNCATED;
                        if (!TTEST2(*(p + offset), 2))
-                               return;
-                       memcpy(&pbody->ssid, p + offset, 2);
+                               return 0;
+                       if (length < 2)
+                               return 0;
+                       memcpy(&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;
+                       length -= 2;
+                       if (ssid.length != 0) {
+                               if (ssid.length > sizeof(ssid.ssid) - 1)
+                                       return 0;
+                               if (!TTEST2(*(p + offset), ssid.length))
+                                       return 0;
+                               if (length < ssid.length)
+                                       return 0;
+                               memcpy(&ssid.ssid, p + offset, ssid.length);
+                               offset += ssid.length;
+                               length -= ssid.length;
+                       }
+                       ssid.ssid[ssid.length] = '\0';
+                       /*
+                        * Present and not truncated.
+                        *
+                        * If we haven't already seen an SSID IE,
+                        * copy this one, otherwise ignore this one,
+                        * so we later report the first one we saw.
+                        */
+                       if (!pbody->ssid_present) {
+                               pbody->ssid = ssid;
+                               pbody->ssid_present = 1;
                        }
-                       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;
-                       memcpy(&pbody->challenge, p + offset, 2);
+                               return 0;
+                       if (length < 2)
+                               return 0;
+                       memcpy(&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;
+                       length -= 2;
+                       if (challenge.length != 0) {
+                               if (challenge.length >
+                                   sizeof(challenge.text) - 1)
+                                       return 0;
+                               if (!TTEST2(*(p + offset), challenge.length))
+                                       return 0;
+                               if (length < challenge.length)
+                                       return 0;
+                               memcpy(&challenge.text, p + offset,
+                                   challenge.length);
+                               offset += challenge.length;
+                               length -= challenge.length;
+                       }
+                       challenge.text[challenge.length] = '\0';
+                       /*
+                        * Present and not truncated.
+                        *
+                        * If we haven't already seen a challenge IE,
+                        * copy this one, otherwise ignore this one,
+                        * so we later report the first one we saw.
+                        */
+                       if (!pbody->challenge_present) {
+                               pbody->challenge = challenge;
+                               pbody->challenge_present = 1;
                        }
-                       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;
-                       memcpy(&(pbody->rates), p + offset, 2);
+                               return 0;
+                       if (length < 2)
+                               return 0;
+                       memcpy(&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;
+                       length -= 2;
+                       if (rates.length != 0) {
+                               if (rates.length > sizeof rates.rate)
+                                       return 0;
+                               if (!TTEST2(*(p + offset), rates.length))
+                                       return 0;
+                               if (length < rates.length)
+                                       return 0;
+                               memcpy(&rates.rate, p + offset, rates.length);
+                               offset += rates.length;
+                               length -= rates.length;
+                       }
+                       /*
+                        * Present and not truncated.
+                        *
+                        * If we haven't already seen a rates IE,
+                        * copy this one if it's not zero-length,
+                        * otherwise ignore this one, so we later
+                        * report the first one we saw.
+                        *
+                        * We ignore zero-length rates IEs as some
+                        * devices seem to put a zero-length rates
+                        * IE, followed by an SSID IE, followed by
+                        * a non-zero-length rates IE into frames,
+                        * even though IEEE Std 802.11-2007 doesn't
+                        * seem to indicate that a zero-length rates
+                        * IE is valid.
+                        */
+                       if (!pbody->rates_present && rates.length != 0) {
+                               pbody->rates = rates;
+                               pbody->rates_present = 1;
                        }
-                       /* 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;
-                       memcpy(&pbody->ds, p + offset, 3);
+                               return 0;
+                       if (length < 3)
+                               return 0;
+                       memcpy(&ds, p + offset, 3);
                        offset += 3;
-                       /* Present and not truncated */
-                       pbody->ds_status = PRESENT;
+                       length -= 3;
+                       /*
+                        * Present and not truncated.
+                        *
+                        * If we haven't already seen a DS IE,
+                        * copy this one, otherwise ignore this one,
+                        * so we later report the first one we saw.
+                        */
+                       if (!pbody->ds_present) {
+                               pbody->ds = ds;
+                               pbody->ds_present = 1;
+                       }
                        break;
                case E_CF:
-                       /* Present, possibly truncated */
-                       pbody->cf_status = TRUNCATED;
                        if (!TTEST2(*(p + offset), 8))
-                               return;
-                       memcpy(&pbody->cf, p + offset, 8);
+                               return 0;
+                       if (length < 8)
+                               return 0;
+                       memcpy(&cf, p + offset, 8);
                        offset += 8;
-                       /* Present and not truncated */
-                       pbody->cf_status = PRESENT;
+                       length -= 8;
+                       /*
+                        * Present and not truncated.
+                        *
+                        * If we haven't already seen a CF IE,
+                        * copy this one, otherwise ignore this one,
+                        * so we later report the first one we saw.
+                        */
+                       if (!pbody->cf_present) {
+                               pbody->cf = cf;
+                               pbody->cf_present = 1;
+                       }
                        break;
                case E_TIM:
-                       /* Present, possibly truncated */
-                       pbody->tim_status = TRUNCATED;
                        if (!TTEST2(*(p + offset), 2))
-                               return;
-                       memcpy(&pbody->tim, p + offset, 2);
+                               return 0;
+                       if (length < 2)
+                               return 0;
+                       memcpy(&tim, p + offset, 2);
                        offset += 2;
+                       length -= 2;
                        if (!TTEST2(*(p + offset), 3))
-                               return;
-                       memcpy(&pbody->tim.count, p + offset, 3);
+                               return 0;
+                       if (length < 3)
+                               return 0;
+                       memcpy(&tim.count, p + offset, 3);
                        offset += 3;
+                       length -= 3;
 
-                       if (pbody->tim.length <= 3)
+                       if (tim.length <= 3)
                                break;
-                       if (pbody->tim.length - 3 > (int)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;
+                       if (tim.length - 3 > (int)sizeof tim.bitmap)
+                               return 0;
+                       if (!TTEST2(*(p + offset), tim.length - 3))
+                               return 0;
+                       if (length < (u_int)(tim.length - 3))
+                               return 0;
+                       memcpy(tim.bitmap, p + (tim.length - 3),
+                           (tim.length - 3));
+                       offset += tim.length - 3;
+                       length -= tim.length - 3;
+                       /*
+                        * Present and not truncated.
+                        *
+                        * If we haven't already seen a TIM IE,
+                        * copy this one, otherwise ignore this one,
+                        * so we later report the first one we saw.
+                        */
+                       if (!pbody->tim_present) {
+                               pbody->tim = tim;
+                               pbody->tim_present = 1;
+                       }
                        break;
                default:
 #if 0
                        printf("(1) unhandled element_id (%d)  ",
-                           *(p + offset) );
+                           *(p + offset));
 #endif
                        if (!TTEST2(*(p + offset), 2))
-                               return;
+                               return 0;
+                       if (length < 2)
+                               return 0;
                        if (!TTEST2(*(p + offset + 2), *(p + offset + 1)))
-                               return;
+                               return 0;
+                       if (length < (u_int)(*(p + offset + 1) + 2))
+                               return 0;
                        offset += *(p + offset + 1) + 2;
+                       length -= *(p + offset + 1) + 2;
                        break;
                }
        }
+
+       /* No problems found. */
+       return 1;
 }
 
 /*********************************************************************************
@@ -428,24 +506,31 @@ parse_elements(struct mgmt_body_t *pbody, const u_char *p, int offset)
  *********************************************************************************/
 
 static int
-handle_beacon(const u_char *p)
+handle_beacon(const u_char *p, u_int length)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
+       int ret;
 
        memset(&pbody, 0, sizeof(pbody));
 
        if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
            IEEE802_11_CAPINFO_LEN))
                return 0;
+       if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
+           IEEE802_11_CAPINFO_LEN)
+               return 0;
        memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
        offset += IEEE802_11_TSTAMP_LEN;
+       length -= IEEE802_11_TSTAMP_LEN;
        pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_BCNINT_LEN;
+       length -= IEEE802_11_BCNINT_LEN;
        pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_CAPINFO_LEN;
+       length -= IEEE802_11_CAPINFO_LEN;
 
-       parse_elements(&pbody, p, offset);
+       ret = parse_elements(&pbody, p, offset, length);
 
        PRINT_SSID(pbody);
        PRINT_RATES(pbody);
@@ -453,50 +538,62 @@ handle_beacon(const u_char *p)
            CAPABILITY_ESS(pbody.capability_info) ? "ESS" : "IBSS");
        PRINT_DS_CHANNEL(pbody);
 
-       return 1;
+       return ret;
 }
 
 static int
-handle_assoc_request(const u_char *p)
+handle_assoc_request(const u_char *p, u_int length)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
+       int ret;
 
        memset(&pbody, 0, sizeof(pbody));
 
        if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN))
                return 0;
+       if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN)
+               return 0;
        pbody.capability_info = EXTRACT_LE_16BITS(p);
        offset += IEEE802_11_CAPINFO_LEN;
+       length -= IEEE802_11_CAPINFO_LEN;
        pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_LISTENINT_LEN;
+       length -= IEEE802_11_LISTENINT_LEN;
 
-       parse_elements(&pbody, p, offset);
+       ret = parse_elements(&pbody, p, offset, length);
 
        PRINT_SSID(pbody);
        PRINT_RATES(pbody);
-       return 1;
+       return ret;
 }
 
 static int
-handle_assoc_response(const u_char *p)
+handle_assoc_response(const u_char *p, u_int length)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
+       int ret;
 
        memset(&pbody, 0, sizeof(pbody));
 
        if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
            IEEE802_11_AID_LEN))
                return 0;
+       if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_STATUS_LEN +
+           IEEE802_11_AID_LEN)
+               return 0;
        pbody.capability_info = EXTRACT_LE_16BITS(p);
        offset += IEEE802_11_CAPINFO_LEN;
+       length -= IEEE802_11_CAPINFO_LEN;
        pbody.status_code = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_STATUS_LEN;
+       length -= IEEE802_11_STATUS_LEN;
        pbody.aid = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_AID_LEN;
+       length -= IEEE802_11_AID_LEN;
 
-       parse_elements(&pbody, p, offset);
+       ret = parse_elements(&pbody, p, offset, length);
 
        printf(" AID(%x) :%s: %s", ((u_int16_t)(pbody.aid << 2 )) >> 2 ,
            CAPABILITY_PRIVACY(pbody.capability_info) ? " PRIVACY " : "",
@@ -504,84 +601,98 @@ handle_assoc_response(const u_char *p)
                ? status_text[pbody.status_code]
                : "n/a"));
 
-       return 1;
+       return ret;
 }
 
 static int
-handle_reassoc_request(const u_char *p)
+handle_reassoc_request(const u_char *p, u_int length)
 {
        struct mgmt_body_t pbody;
        int offset = 0;
+       int ret;
 
        memset(&pbody, 0, sizeof(pbody));
 
        if (!TTEST2(*p, IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
            IEEE802_11_AP_LEN))
                return 0;
+       if (length < IEEE802_11_CAPINFO_LEN + IEEE802_11_LISTENINT_LEN +
+           IEEE802_11_AP_LEN)
+               return 0;
        pbody.capability_info = EXTRACT_LE_16BITS(p);
        offset += IEEE802_11_CAPINFO_LEN;
+       length -= IEEE802_11_CAPINFO_LEN;
        pbody.listen_interval = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_LISTENINT_LEN;
+       length -= IEEE802_11_LISTENINT_LEN;
        memcpy(&pbody.ap, p+offset, IEEE802_11_AP_LEN);
        offset += IEEE802_11_AP_LEN;
+       length -= IEEE802_11_AP_LEN;
 
-       parse_elements(&pbody, p, offset);
+       ret = parse_elements(&pbody, p, offset, length);
 
        PRINT_SSID(pbody);
        printf(" AP : %s", etheraddr_string( pbody.ap ));
 
-       return 1;
+       return ret;
 }
 
 static int
-handle_reassoc_response(const u_char *p)
+handle_reassoc_response(const u_char *p, u_int length)
 {
        /* Same as a Association Reponse */
-       return handle_assoc_response(p);
+       return handle_assoc_response(p, length);
 }
 
 static int
-handle_probe_request(const u_char *p)
+handle_probe_request(const u_char *p, u_int length)
 {
        struct mgmt_body_t  pbody;
        int offset = 0;
+       int ret;
 
        memset(&pbody, 0, sizeof(pbody));
 
-       parse_elements(&pbody, p, offset);
+       ret = parse_elements(&pbody, p, offset, length);
 
        PRINT_SSID(pbody);
        PRINT_RATES(pbody);
 
-       return 1;
+       return ret;
 }
 
 static int
-handle_probe_response(const u_char *p)
+handle_probe_response(const u_char *p, u_int length)
 {
        struct mgmt_body_t  pbody;
        int offset = 0;
+       int ret;
 
        memset(&pbody, 0, sizeof(pbody));
 
        if (!TTEST2(*p, IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
            IEEE802_11_CAPINFO_LEN))
                return 0;
-
+       if (length < IEEE802_11_TSTAMP_LEN + IEEE802_11_BCNINT_LEN +
+           IEEE802_11_CAPINFO_LEN)
+               return 0;
        memcpy(&pbody.timestamp, p, IEEE802_11_TSTAMP_LEN);
        offset += IEEE802_11_TSTAMP_LEN;
+       length -= IEEE802_11_TSTAMP_LEN;
        pbody.beacon_interval = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_BCNINT_LEN;
+       length -= IEEE802_11_BCNINT_LEN;
        pbody.capability_info = EXTRACT_LE_16BITS(p+offset);
        offset += IEEE802_11_CAPINFO_LEN;
+       length -= IEEE802_11_CAPINFO_LEN;
 
-       parse_elements(&pbody, p, offset);
+       ret = parse_elements(&pbody, p, offset, length);
 
        PRINT_SSID(pbody);
        PRINT_RATES(pbody);
        PRINT_DS_CHANNEL(pbody);
 
-       return 1;
+       return ret;
 }
 
 static int
@@ -592,7 +703,7 @@ handle_atim(void)
 }
 
 static int
-handle_disassoc(const u_char *p)
+handle_disassoc(const u_char *p, u_int length)
 {
        struct mgmt_body_t  pbody;
 
@@ -600,6 +711,8 @@ handle_disassoc(const u_char *p)
 
        if (!TTEST2(*p, IEEE802_11_REASON_LEN))
                return 0;
+       if (length < IEEE802_11_REASON_LEN)
+               return 0;
        pbody.reason_code = EXTRACT_LE_16BITS(p);
 
        printf(": %s",
@@ -611,23 +724,29 @@ handle_disassoc(const u_char *p)
 }
 
 static int
-handle_auth(const u_char *p)
+handle_auth(const u_char *p, u_int length)
 {
        struct mgmt_body_t  pbody;
        int offset = 0;
+       int ret;
 
        memset(&pbody, 0, sizeof(pbody));
 
        if (!TTEST2(*p, 6))
                return 0;
+       if (length < 6)
+               return 0;
        pbody.auth_alg = EXTRACT_LE_16BITS(p);
        offset += 2;
+       length -= 2;
        pbody.auth_trans_seq_num = EXTRACT_LE_16BITS(p + offset);
        offset += 2;
+       length -= 2;
        pbody.status_code = EXTRACT_LE_16BITS(p + offset);
        offset += 2;
+       length -= 2;
 
-       parse_elements(&pbody, p, offset);
+       ret = parse_elements(&pbody, p, offset, length);
 
        if ((pbody.auth_alg == 1) &&
            ((pbody.auth_trans_seq_num == 2) ||
@@ -641,7 +760,7 @@ handle_auth(const u_char *p)
                        ? ((pbody.status_code < NUM_STATUSES)
                               ? status_text[pbody.status_code]
                               : "n/a") : ""));
-               return 1;
+               return ret;
        }
        printf(" (%s)-%x: %s",
            (pbody.auth_alg < NUM_AUTH_ALGS)
@@ -654,11 +773,11 @@ handle_auth(const u_char *p)
                    : "n/a")
                : "");
 
-       return 1;
+       return ret;
 }
 
 static int
-handle_deauth(const struct mgmt_header_t *pmh, const u_char *p)
+handle_deauth(const struct mgmt_header_t *pmh, const u_char *p, u_int length)
 {
        struct mgmt_body_t  pbody;
        int offset = 0;
@@ -668,8 +787,11 @@ handle_deauth(const struct mgmt_header_t *pmh, const u_char *p)
 
        if (!TTEST2(*p, IEEE802_11_REASON_LEN))
                return 0;
+       if (length < IEEE802_11_REASON_LEN)
+               return 0;
        pbody.reason_code = EXTRACT_LE_16BITS(p);
        offset += IEEE802_11_REASON_LEN;
+       length -= IEEE802_11_REASON_LEN;
 
        reason = (pbody.reason_code < NUM_REASONS)
                        ? reason_text[pbody.reason_code]
@@ -714,10 +836,12 @@ handle_deauth(const struct mgmt_header_t *pmh, const u_char *p)
 )
 
 static int
-handle_action(const struct mgmt_header_t *pmh, const u_char *p)
+handle_action(const struct mgmt_header_t *pmh, const u_char *p, u_int length)
 {
        if (!TTEST2(*p, 2))
                return 0;
+       if (length < 2)
+               return 0;
        if (eflag) {
                printf(": ");
        } else {
@@ -751,36 +875,36 @@ handle_action(const struct mgmt_header_t *pmh, const u_char *p)
 
 static int
 mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
-    const u_char *p)
+    const u_char *p, u_int length)
 {
        switch (FC_SUBTYPE(fc)) {
        case ST_ASSOC_REQUEST:
                printf("Assoc Request");
-               return handle_assoc_request(p);
+               return handle_assoc_request(p, length);
        case ST_ASSOC_RESPONSE:
                printf("Assoc Response");
-               return handle_assoc_response(p);
+               return handle_assoc_response(p, length);
        case ST_REASSOC_REQUEST:
                printf("ReAssoc Request");
-               return handle_reassoc_request(p);
+               return handle_reassoc_request(p, length);
        case ST_REASSOC_RESPONSE:
                printf("ReAssoc Response");
-               return handle_reassoc_response(p);
+               return handle_reassoc_response(p, length);
        case ST_PROBE_REQUEST:
                printf("Probe Request");
-               return handle_probe_request(p);
+               return handle_probe_request(p, length);
        case ST_PROBE_RESPONSE:
                printf("Probe Response");
-               return handle_probe_response(p);
+               return handle_probe_response(p, length);
        case ST_BEACON:
                printf("Beacon");
-               return handle_beacon(p);
+               return handle_beacon(p, length);
        case ST_ATIM:
                printf("ATIM");
                return handle_atim();
        case ST_DISASSOC:
                printf("Disassociation");
-               return handle_disassoc(p);
+               return handle_disassoc(p, length);
        case ST_AUTH:
                printf("Authentication");
                if (!TTEST2(*p, 3))
@@ -789,14 +913,14 @@ mgmt_body_print(u_int16_t fc, const struct mgmt_header_t *pmh,
                        printf("Authentication (Shared-Key)-3 ");
                        return wep_print(p);
                }
-               return handle_auth(p);
+               return handle_auth(p, length);
        case ST_DEAUTH:
                printf("DeAuthentication");
-               return handle_deauth(pmh, p);
+               return handle_deauth(pmh, p, length);
                break;
        case ST_ACTION:
                printf("Action");
-               return handle_action(pmh, p);
+               return handle_action(pmh, p, length);
                break;
        default:
                printf("Unhandled Management subtype(%x)",
@@ -1221,7 +1345,7 @@ ieee802_11_print(const u_char *p, u_int length, u_int orig_caplen, int pad,
        switch (FC_TYPE(fc)) {
        case T_MGMT:
                if (!mgmt_body_print(fc,
-                   (const struct mgmt_header_t *)(p - hdrlen), p)) {
+                   (const struct mgmt_header_t *)(p - hdrlen), p, length)) {
                        printf("[|802.11]");
                        return hdrlen;
                }