]> The Tcpdump Group git mirrors - tcpdump/commitdiff
Have parse_elements() flag each item as "present (and not truncated)",
authorguy <guy>
Sun, 13 Nov 2005 12:07:25 +0000 (12:07 +0000)
committerguy <guy>
Sun, 13 Nov 2005 12:07:25 +0000 (12:07 +0000)
"present but truncated", and "not present", and don't have it return an
indication of whether we ran past the end of a packet - instead, have
the routines that handle particular management frame types use macros
that check what the status of a particular tagged parameter is and:

print it if present and not truncated;

skip it if not present;

return a "packet truncated" indication if present but truncated.

This means we handle tagged parameters that aren't present, and print
parameters that are present and not truncated even if there's a
present-but-truncated field after them.

Add some additional bounds checks.

Make the table of rates bigger - there can be more than 8 rates in a
rates tagged parameter.

ieee802_11.h
print-802_11.c

index d954c4ffc08941b2ef97b3da4654549357d56297..c8d0f9e3bd1bb2593dbd5e2ee41f6cf8e03ea0f3 100644 (file)
@@ -1,4 +1,4 @@
-/* @(#) $Header: /tcpdump/master/tcpdump/ieee802_11.h,v 1.10 2005-10-17 07:58:56 guy Exp $ (LBL) */
+/* @(#) $Header: /tcpdump/master/tcpdump/ieee802_11.h,v 1.11 2005-11-13 12:07:25 guy Exp $ (LBL) */
 /*
  * Copyright (c) 2001
  *     Fortress Technologies
@@ -122,6 +122,12 @@ 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;
@@ -131,7 +137,7 @@ struct ssid_t {
 struct rates_t {
        u_int8_t        element_id;
        u_int8_t        length;
-       u_int8_t        rate[8];
+       u_int8_t        rate[16];
 };
 
 struct challenge_t {
@@ -139,6 +145,7 @@ struct challenge_t {
        u_int8_t        length;
        u_int8_t        text[254]; /* 1-253 + 1 for null */
 };
+
 struct fh_t {
        u_int8_t        element_id;
        u_int8_t        length;
@@ -208,13 +215,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;
        struct challenge_t  challenge;
        u_int16_t       capability_info;
+       elem_status_t   ssid_status;
        struct ssid_t   ssid;
+       elem_status_t   rates_status;
        struct rates_t  rates;
+       elem_status_t   ds_status;
        struct ds_t     ds;
+       elem_status_t   cf_status;
        struct cf_t     cf;
+       elem_status_t   fh_status;
        struct fh_t     fh;
+       elem_status_t   tim_status;
        struct tim_t    tim;
 };
 
index f365f2ab1d2dff9a20aa4444fbf5df62aaad5e7a..6bf5e7a9822dc45d00142450bec352a2b470022f 100644 (file)
@@ -22,7 +22,7 @@
 
 #ifndef lint
 static const char rcsid[] _U_ =
-    "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.37 2005-10-17 07:58:57 guy Exp $ (LBL)";
+    "@(#) $Header: /tcpdump/master/tcpdump/print-802_11.c,v 1.38 2005-11-13 12:07:25 guy Exp $ (LBL)";
 #endif
 
 #ifdef HAVE_CONFIG_H
@@ -46,20 +46,54 @@ static const char rcsid[] _U_ =
 #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++) { \
-               PRINT_RATE(sep, p.rates.rate[z], \
-                       (p.rates.rate[z] & 0x80 ? "*" : "")); \
-               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"};
 #define NUM_AUTH_ALGS  (sizeof auth_alg_text / sizeof auth_alg_text[0])
@@ -118,102 +152,139 @@ 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;
                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 (pbody->ssid.length > 32)
-                               return 0;
-                       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 > 32)
+                                       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 (pbody->challenge.length > 253)
-                               return 0;
-                       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 > 253)
+                                       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 (pbody->rates.length > 8)
-                               return 0;
-                       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 > 251)
-                               return 0;
+                               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;
 }
 
 /*********************************************************************************
@@ -238,17 +309,13 @@ handle_beacon(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(" %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;
 }
@@ -268,12 +335,9 @@ handle_assoc_request(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;
 }
@@ -296,8 +360,7 @@ handle_assoc_response(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 " : "",
@@ -326,12 +389,10 @@ handle_reassoc_request(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;
 }
@@ -351,12 +412,9 @@ handle_probe_request(const u_char *p)
 
        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;
@@ -381,15 +439,11 @@ handle_probe_response(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;
 }
@@ -437,8 +491,7 @@ handle_auth(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) ||