The hash table merely associates data structures with conversations,
[obnox/wireshark/wip.git] / packet-wccp.c
index 90723b25c020b381c15a9218ba11a4d315724c21..4879e9c346ed9bdbd73019c4b7994a22817460b1 100644 (file)
@@ -2,12 +2,11 @@
  * Routines for Web Cache Coordination Protocol dissection
  * Jerry Talkington <jerryt@netapp.com>
  *
- * $Id: packet-wccp.c,v 1.19 2001/03/20 04:30:09 guy Exp $
+ * $Id: packet-wccp.c,v 1.22 2001/08/04 01:52:07 guy Exp $
  *
  * Ethereal - Network traffic analyzer
- * By Gerald Combs <gerald@zing.org>
+ * By Gerald Combs <gerald@ethereal.com>
  * Copyright 1998 Gerald Combs
- *
  * 
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -67,34 +66,31 @@ static gint ett_wc_view_info = -1;
 static gint ett_router_assignment_element = -1;
 static gint ett_router_assignment_info = -1;
 static gint ett_query_info = -1;
-static gint ett_unknown_info = -1;
 static gint ett_capabilities_info = -1;
 static gint ett_capability_element = -1;
+static gint ett_capability_forwarding_method = -1;
+static gint ett_capability_assignment_method = -1;
+static gint ett_capability_return_method = -1;
+static gint ett_unknown_info = -1;
 
 /*
- * Unfortunately,
- *
- *     http://www.ietf.org/internet-drafts/draft-forster-wrec-wccp-v1-00.txt
- *
- * for WCCP 1.0, and
+ * At
  *
- *     http://www.ietf.org/internet-drafts/draft-wilson-wrec-wccp-v2-00.txt
+ *     http://www.alternic.org/drafts/drafts-f-g/draft-forster-wrec-wccp-v1-00.html
  *
- * for WCCP 2.0, have expired.  At
+ * is a copy of the now-expired Internet-Draft for WCCP 1.0.
  *
- *     http://www.ietf.org/internet-drafts/draft-forster-wrec-wccp-v1-01.txt
+ * At
  *
- * and
+ *     http://search.ietf.org/internet-drafts/draft-wilson-wrec-wccp-v2-01.txt
  *
- *     http://www.ietf.org/internet-drafts/draft-wilson-wrec-wccp-v2-01.txt
- *
- * are notes suggesting that you contact the authors "for more information
- * or a copy of the document", and giving the e-mail addresses of the authors.
+ * is an Internet-Draft for WCCP 2.0.
  */
 
 #define UDP_PORT_WCCP  2048
 
-#define WCCPv1                 0x0004
+#define WCCPv1                 4
+#define WCCPv2                 0x0200
 #define WCCP_HERE_I_AM         7
 #define WCCP_I_SEE_YOU         8
 #define WCCP_ASSIGN_BUCKET     9
@@ -116,6 +112,7 @@ static const value_string wccp_type_vals[] = {
 
 static const value_string wccp_version_val[] = {
        { WCCPv1, "1"},
+       { WCCPv2, "2"},
        { 0, NULL}
 };
 
@@ -155,6 +152,12 @@ const value_string service_id_vals[] = {
     { 0,    NULL }
 };
 
+typedef struct capability_flag {
+       guint32 value;
+       const char *short_name;
+       const char *long_name;
+} capability_flag;
+
 static void dissect_hash_data(tvbuff_t *tvb, int offset,
     proto_tree *wccp_tree);
 static void dissect_web_cache_list_entry(tvbuff_t *tvb, int offset,
@@ -184,6 +187,9 @@ static gboolean dissect_wccp2_router_query_info(tvbuff_t *tvb, int offset,
     int length, proto_tree *info_tree);
 static gboolean dissect_wccp2_capability_info(tvbuff_t *tvb, int offset,
     int length, proto_tree *info_tree);
+static void dissect_32_bit_capability_flags(tvbuff_t *tvb, int curr_offset,
+    guint16 capability_len, gint ett, const capability_flag *flags,
+    proto_tree *element_tree);
 
 static void 
 dissect_wccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
@@ -192,10 +198,9 @@ dissect_wccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        proto_tree *wccp_tree = NULL;
        proto_item *wccp_tree_item;
        guint32 wccp_message_type;
-       guint32 wccp_version;
        guint16 length;
        guint32 cache_count;
-       int i;
+       guint i;
 
        if(check_col(pinfo->fd, COL_PROTOCOL)) {
                col_set_str(pinfo->fd, COL_PROTOCOL, "WCCP");
@@ -223,9 +228,8 @@ dissect_wccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                switch (wccp_message_type) {
 
                case WCCP_HERE_I_AM:
-                       wccp_version = tvb_get_ntohl(tvb, offset);
-                       proto_tree_add_uint(wccp_tree, hf_wccp_version, tvb,
-                           offset, 4, wccp_version);
+                       proto_tree_add_item(wccp_tree, hf_wccp_version, tvb,
+                           offset, 4, FALSE);
                        offset += 4;
                        dissect_hash_data(tvb, offset, wccp_tree);
                        offset += HASH_INFO_SIZE;
@@ -235,9 +239,8 @@ dissect_wccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        break;
 
                case WCCP_I_SEE_YOU:
-                       wccp_version = tvb_get_ntohl(tvb, offset);
-                       proto_tree_add_uint(wccp_tree, hf_wccp_version, tvb,
-                           offset, 4, wccp_version);
+                       proto_tree_add_item(wccp_tree, hf_wccp_version, tvb,
+                           offset, 4, FALSE);
                        offset += 4;
                        proto_tree_add_item(wccp_tree, hf_change_num, tvb, offset,
                            4, FALSE);
@@ -260,6 +263,10 @@ dissect_wccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                        /*
                         * This hasn't been tested, since I don't have any
                         * traces with this in it.
+                        *
+                        * The V1 spec claims that this does, indeed,
+                        * have a Received ID field after the type,
+                        * rather than a Version field.
                         */
                        proto_tree_add_item(wccp_tree, hf_recvd_id, tvb, offset,
                            4, FALSE);
@@ -292,19 +299,11 @@ dissect_wccp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                case WCCP2_I_SEE_YOU:
                case WCCP2_REMOVAL_QUERY:
                case WCCP2_REDIRECT_ASSIGN:
+               default:        /* assume unknown packets are v2 */
                        length = dissect_wccp2_header(tvb, offset, wccp_tree);
                        offset += 4;
-
                        dissect_wccp2_info(tvb, offset, length, wccp_tree);
                        break;
-
-               default:
-                       wccp_version = tvb_get_ntohl(tvb, offset);
-                       proto_tree_add_uint(wccp_tree, hf_wccp_version, tvb,
-                           offset, 4, wccp_version);
-                       offset += 4;
-                       dissect_data(tvb, offset, pinfo, wccp_tree);
-                       break;
                }
        }
 }
@@ -407,8 +406,8 @@ dissect_wccp2_header(tvbuff_t *tvb, int offset, proto_tree *wccp_tree)
 {
        guint16 length;
 
-       proto_tree_add_text(wccp_tree, tvb, offset, 2, "Version: 0x%04X",
-           tvb_get_ntohs(tvb, offset));
+       proto_tree_add_item(wccp_tree, hf_wccp_version, tvb, offset, 2,
+           FALSE);
        offset += 2;
        length = tvb_get_ntohs(tvb, offset);
        proto_tree_add_text(wccp_tree, tvb, offset, 2, "Length: %u",
@@ -717,7 +716,7 @@ dissect_wccp2_router_identity_info(tvbuff_t *tvb, int offset, int length,
     proto_tree *info_tree)
 {
        guint32 n_received_from;
-       int i;
+       guint i;
        proto_item *te;
        proto_tree *element_tree;
 
@@ -855,7 +854,7 @@ dissect_wccp2_router_view_info(tvbuff_t *tvb, int offset, int length,
 {
        guint32 n_routers;
        guint32 n_web_caches;
-       int i;
+       guint i;
        proto_item *te;
        proto_tree *element_tree;
 
@@ -913,7 +912,7 @@ dissect_wccp2_wc_view_info(tvbuff_t *tvb, int offset, int length,
 {
        guint32 n_routers;
        guint32 n_web_caches;
-       int i;
+       guint i;
        proto_item *te;
        proto_tree *element_tree;
 
@@ -1001,7 +1000,7 @@ dissect_wccp2_assignment_info(tvbuff_t *tvb, int offset, int length,
 {
        guint32 n_routers;
        guint32 n_web_caches;
-       int i;
+       guint i;
        proto_item *te;
        proto_tree *element_tree;
 
@@ -1102,28 +1101,34 @@ static const value_string capability_type_vals[] = {
 #define WCCP2_FORWARDING_METHOD_GRE    0x00000001
 #define WCCP2_FORWARDING_METHOD_L2     0x00000002
 
-static const value_string forwarding_method_vals[] = {
-       { WCCP2_FORWARDING_METHOD_GRE, "IP-GRE" },
-       { WCCP2_FORWARDING_METHOD_L2,  "L2" },
-       { 0,                           NULL }
+static const capability_flag forwarding_method_flags[] = {
+       { WCCP2_FORWARDING_METHOD_GRE,
+         "IP-GRE", "GRE-encapsulated" },
+       { WCCP2_FORWARDING_METHOD_L2,
+         "L2", "L2 rewrite" },
+       { 0, 
+         NULL, NULL }
 };
 
 #define WCCP2_ASSIGNMENT_METHOD_HASH    0x00000001
 #define WCCP2_ASSIGNMENT_METHOD_MASK    0x00000002
 
-static const value_string assignment_method_vals[] = {
-       { WCCP2_ASSIGNMENT_METHOD_HASH, "Hash" },
-       { WCCP2_ASSIGNMENT_METHOD_MASK, "Mask" },
-       { 0,                            NULL }
+static const capability_flag assignment_method_flags[] = {
+       { WCCP2_ASSIGNMENT_METHOD_HASH, "Hash", "Hash" },
+       { WCCP2_ASSIGNMENT_METHOD_MASK, "Mask", "Mask" },
+       { 0,                            NULL,   NULL }
 };
 
 #define WCCP2_PACKET_RETURN_METHOD_GRE  0x00000001
 #define WCCP2_PACKET_RETURN_METHOD_L2   0x00000002
 
-static const value_string packet_return_method_vals[] = {
-       { WCCP2_PACKET_RETURN_METHOD_GRE, "IP-GRE" },
-       { WCCP2_PACKET_RETURN_METHOD_L2,  "L2" },
-       { 0,                              NULL }
+static const capability_flag packet_return_method_flags[] = {
+       { WCCP2_PACKET_RETURN_METHOD_GRE,
+         "IP-GRE", "GRE-encapsulated" },
+       { WCCP2_PACKET_RETURN_METHOD_L2,
+         "L2", "L2 rewrite" },
+       { 0, 
+         NULL, NULL }
 };
 
 static gboolean
@@ -1132,61 +1137,117 @@ dissect_wccp2_capability_info(tvbuff_t *tvb, int offset, int length,
 {
        guint16 capability_type;
        guint16 capability_len;
-       guint32 capability_val;
        int curr_offset;
        proto_item *te;
        proto_tree *element_tree;
 
-       curr_offset = offset;
-       while (curr_offset < (length + offset)) {
+       for (curr_offset = offset; curr_offset < (length + offset);
+           curr_offset += capability_len) {
                capability_type = tvb_get_ntohs(tvb, curr_offset);
                capability_len = tvb_get_ntohs(tvb, curr_offset + 2);
-               capability_val = tvb_get_ntohl(tvb, curr_offset + 4);
-               te = proto_tree_add_text(info_tree, tvb, offset, 8,
-                   "Capability Element");
+               te = proto_tree_add_text(info_tree, tvb, curr_offset,
+                   capability_len, "%s",
+                   val_to_str(capability_type,
+                     capability_type_vals, "Unknown Capability Element (0x%08X)"));
                element_tree = proto_item_add_subtree(te,
                    ett_capability_element);
 
-               proto_tree_add_text(element_tree, tvb, offset, 2,
+               proto_tree_add_text(element_tree, tvb, curr_offset, 2,
                    "Type: %s",
                    val_to_str(capability_type,
                      capability_type_vals, "Unknown (0x%08X)"));
-               proto_tree_add_text(element_tree, tvb, offset+2, 2,
+
+               if (capability_len < 4) {
+                       proto_tree_add_text(element_tree, tvb, curr_offset+2, 2,
+                           "Length: %u (illegal, must be >= 4)",
+                           capability_len);
+                       break;
+               }
+               proto_tree_add_text(element_tree, tvb, curr_offset+2, 2,
                    "Length: %u", capability_len);
 
                switch (capability_type) {
 
                case WCCP2_FORWARDING_METHOD:
-                       proto_tree_add_text(element_tree, tvb, offset+4, 4,
-                           "Value: %s",
-                           val_to_str(capability_val,
-                             forwarding_method_vals, "Unknown (0x%08X)"));
+                       dissect_32_bit_capability_flags(tvb, curr_offset,
+                           capability_len, ett_capability_forwarding_method,
+                           forwarding_method_flags, element_tree);
                        break;
 
                case WCCP2_ASSIGNMENT_METHOD:
-                       proto_tree_add_text(element_tree, tvb, offset+4, 4,
-                           "Value: %s",
-                           val_to_str(capability_val,
-                             assignment_method_vals, "Unknown (0x%08X)"));
+                       dissect_32_bit_capability_flags(tvb, curr_offset,
+                           capability_len, ett_capability_assignment_method,
+                           assignment_method_flags, element_tree);
                        break;
 
                case WCCP2_PACKET_RETURN_METHOD:
-                       proto_tree_add_text(element_tree, tvb, offset+4, 4,
-                           "Value: %s",
-                           val_to_str(capability_val,
-                             packet_return_method_vals, "Unknown (0x%08X)"));
+                       dissect_32_bit_capability_flags(tvb, curr_offset,
+                           capability_len, ett_capability_return_method,
+                           packet_return_method_flags, element_tree);
                        break;
 
                default:
-                       proto_tree_add_text(element_tree, tvb, offset+4, 4,
-                           "Value: 0x%08X", capability_val);
+                       proto_tree_add_text(element_tree, tvb,
+                           curr_offset+4, capability_len-4,
+                           "Value: %s",
+                           tvb_bytes_to_str(tvb, curr_offset+4, capability_len-4));
                        break;
                }
 
-               curr_offset += 8;
        }
        return TRUE;
+}
 
+static void
+dissect_32_bit_capability_flags(tvbuff_t *tvb, int curr_offset,
+    guint16 capability_len, gint ett, const capability_flag *flags,
+    proto_tree *element_tree)
+{
+       guint32 capability_val;
+       proto_item *tm;
+       proto_tree *method_tree;
+       int i;
+       char flags_string[128+1];
+       char *p;
+       int space_left;
+       char buf[1025];
+
+       if (capability_len != 8) {
+               proto_tree_add_text(element_tree, tvb,
+                   curr_offset+4, capability_len-4,
+                   "Illegal length (must be 8)");
+               return;
+       }
+
+       capability_val = tvb_get_ntohl(tvb, curr_offset + 4);
+       flags_string[0] = '\0';
+       p = &flags_string[0];
+       space_left = sizeof flags_string;
+       for (i = 0; flags[i].short_name != NULL; i++) {
+               if (capability_val & flags[i].value) {
+                       if (p != &flags_string[0]) {
+                               snprintf(p, space_left, ",");
+                               p = &flags_string[strlen(flags_string)];
+                       }
+                       snprintf(p, space_left, "%s", flags[i].short_name);
+                       p = &flags_string[strlen(flags_string)];
+               }
+       }
+       tm = proto_tree_add_text(element_tree, tvb, curr_offset+4, 4,
+           "Value: 0x%08X (%s)", capability_val, flags_string);
+       method_tree = proto_item_add_subtree(tm, ett);
+       for (i = 0; flags[i].long_name != NULL; i++) {
+               p = decode_bitfield_value(buf, capability_val,
+                     flags[i].value, 32);
+               strcpy(p, flags[i].long_name);
+               strcat(p, ": ");
+               if (capability_val & flags[i].value)
+                   strcat(p, "Supported");
+               else
+                   strcat(p, "Not supported");
+               proto_tree_add_text(method_tree, tvb, curr_offset+4, 4,
+                   "%s", buf);
+       }
 }
 
 void
@@ -1195,27 +1256,27 @@ proto_register_wccp(void)
        static hf_register_info hf[] = {
                { &hf_wccp_message_type,
                        { "WCCP Message Type", "wccp.message", FT_UINT32, BASE_DEC, VALS(wccp_type_vals), 0x0,
-                               "The WCCP message that was sent"}
+                               "The WCCP message that was sent", HFILL }
                },
                { &hf_wccp_version, 
-                       { "WCCP Version", "wccp.version", FT_UINT32, BASE_DEC, VALS(wccp_version_val), 0x0,
-                               "The WCCP version"}
+                       { "WCCP Version", "wccp.version", FT_UINT32, BASE_HEX, VALS(wccp_version_val), 0x0,
+                               "The WCCP version", HFILL }
                },
                { &hf_hash_revision,
                        { "Hash Revision", "wccp.hash_revision", FT_UINT32, BASE_DEC, 0x0, 0x0,
-                               "The cache hash revision"}
+                               "The cache hash revision", HFILL }
                },
                { &hf_change_num,
                        { "Change Number", "wccp.change_num", FT_UINT32, BASE_DEC, 0x0, 0x0,
-                               "The Web-Cache list entry change number"}
+                               "The Web-Cache list entry change number", HFILL }
                },
                { &hf_recvd_id,
                        { "Received ID", "wccp.recvd_id", FT_UINT32, BASE_DEC, 0x0, 0x0,
-                               "The number of I_SEE_YOU's that have been sent"}
+                               "The number of I_SEE_YOU's that have been sent", HFILL }
                },
                { &hf_cache_ip,
                        { "Web Cache IP address", "wccp.cache_ip", FT_IPv4, BASE_NONE, NULL, 0x0,
-                               "The IP address of a Web cache"}
+                               "The IP address of a Web cache", HFILL }
                },
        };
        static gint *ett[] = {
@@ -1238,6 +1299,9 @@ proto_register_wccp(void)
                &ett_router_assignment_info,
                &ett_capabilities_info,
                &ett_capability_element,
+               &ett_capability_forwarding_method,
+               &ett_capability_assignment_method,
+               &ett_capability_return_method,
                &ett_unknown_info,
        };