Require that the LMP and RSVP message types be greater than 0.
[obnox/wireshark/wip.git] / packet-igmp.c
index 562a399997308c9c4f9a5190c75a5515c1200911..397cc160638b5db822a1bfee178b823393573121 100644 (file)
@@ -1,7 +1,7 @@
-/* packet-igmp.c   2001 Ronnie Sahlberg <rsahlber@bigpond.net.au>
+/* packet-igmp.c   2001 Ronnie Sahlberg <See AUTHORS for email>
  * Routines for IGMP packet disassembly
  *
- * $Id: packet-igmp.c,v 1.7 2001/06/29 18:55:49 guy Exp $
+ * $Id: packet-igmp.c,v 1.19 2002/05/02 07:54:41 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
 
    * Differs in second byte of protocol. Always 0 in V1
 
+
+       Multicast traceroute was taken from
+       draft-ietf-idmr-traceroute-ipm-07.txt
+
+       Size in bytes for each packet
+       type    draft-ietf-idmr-traceroute-ipm-07.ps
+       0x1e      24 + n*32
+       0x1f      24 + n*32 (n == 0 for Query) 
+
    x DVMRP Protocol  see packet-dvmrp.c
 
        DVMRP is defined in the following RFCs
 #include <string.h>
 #include <glib.h>
 
-#include "packet.h"
+#ifdef NEED_SNPRINTF_H
+# include "snprintf.h"
+#endif
+
+#include <epan/packet.h>
 #include "ipproto.h"
 #include "in_cksum.h"
 #include "packet-dvmrp.h"
+#include "packet-pim.h"
 #include "packet-mrdisc.h"
 #include "packet-msnip.h"
 
@@ -121,11 +135,31 @@ static int hf_record_type = -1;
 static int hf_aux_data_len = -1;
 static int hf_maddr = -1;
 static int hf_aux_data = -1;
+static int hf_mtrace_max_hops = -1;
+static int hf_mtrace_saddr = -1;
+static int hf_mtrace_raddr = -1;
+static int hf_mtrace_rspaddr = -1;
+static int hf_mtrace_resp_ttl = -1;
+static int hf_mtrace_q_id = -1;
+static int hf_mtrace_q_arrival = -1;
+static int hf_mtrace_q_inaddr = -1;
+static int hf_mtrace_q_outaddr = -1;
+static int hf_mtrace_q_prevrtr = -1;
+static int hf_mtrace_q_inpkt = -1;
+static int hf_mtrace_q_outpkt = -1;
+static int hf_mtrace_q_total = -1;
+static int hf_mtrace_q_rtg_proto = -1;
+static int hf_mtrace_q_fwd_ttl = -1;
+static int hf_mtrace_q_mbz = -1;
+static int hf_mtrace_q_s = -1;
+static int hf_mtrace_q_src_mask = -1;
+static int hf_mtrace_q_fwd_code = -1;
 
 static int ett_igmp = -1;
 static int ett_group_record = -1;
 static int ett_sqrv_bits = -1;
 static int ett_max_resp = -1;
+static int ett_mtrace_block = -1;
 
 #define MC_ALL_ROUTERS         0xe0000002
 #define MC_ALL_IGMPV3_ROUTERS  0xe0000016
@@ -145,14 +179,17 @@ static int ett_max_resp = -1;
 #define IGMP_V1_PIM_ROUTING_MESSAGE    0x14
 #define IGMP_V2_MEMBERSHIP_REPORT      0x16
 #define IGMP_V2_LEAVE_GROUP            0x17
-#define IGMP_V1_TRACEROUTE_RESPONSE    0x1e    /* XXX */
-#define IGMP_V1_TRACEROUTE_MESSAGE     0x1f    /* XXX */
+#define IGMP_TRACEROUTE_RESPONSE        0x1e
+#define IGMP_TRACEROUTE_QUERY_REQ       0x1f
 #define IGMP_V3_MEMBERSHIP_REPORT      0x22
 #define IGMP_TYPE_0x23                 0x23
 #define IGMP_TYPE_0x24                 0x24
 #define IGMP_TYPE_0x25                 0x25
 #define IGMP_TYPE_0x26                 0x26
        
+#define IGMP_TRACEROUTE_HDR_LEN           24
+#define IGMP_TRACEROUTE_RSP_LEN           32
+
 static const value_string commands[] = {
        {IGMP_V0_CREATE_GROUP_REQUEST,  "Create Group Request"          },
        {IGMP_V0_CREATE_GROUP_REPLY,    "Create Group Reply"            },
@@ -168,8 +205,8 @@ static const value_string commands[] = {
        {IGMP_V1_PIM_ROUTING_MESSAGE,   "PIM Routing Message"           },
        {IGMP_V2_MEMBERSHIP_REPORT,     "Membership Report"             },
        {IGMP_V2_LEAVE_GROUP,           "Leave Group"                   },
-       {IGMP_V1_TRACEROUTE_RESPONSE,   "Traceroute Response"           },
-       {IGMP_V1_TRACEROUTE_MESSAGE,    "Traceroute Message"            },
+       {IGMP_TRACEROUTE_RESPONSE,      "Traceroute Response"           },
+       {IGMP_TRACEROUTE_QUERY_REQ,     "Traceroute Query or Request"   },
        {IGMP_V3_MEMBERSHIP_REPORT,     "Membership Report"             },
        {0,             NULL}
 };
@@ -226,9 +263,43 @@ static const value_string vs_record_type[] = {
        { 0,    NULL}
 };
 
+static const value_string mtrace_rtg_vals[] = {
+       {1,  "DVMRP"                                        },
+       {2,  "MOSPF"                                        },
+       {3,  "PIM"                                          },
+       {4,  "CBT"                                          },
+       {5,  "PIM using special routing table"              },
+       {6,  "PIM using a static route"                     },
+       {7,  "DVMRP using a static route"                   },
+       {8,  "PIM using MBGP (aka BGP4+) route"             },
+       {9,  "CBT using special routing table"              },
+       {10, "CBT using a static route"                     },
+       {11, "PIM using state created by Assert processing" },
+       {0,  NULL}
+};
+
+static const value_string mtrace_fwd_code_vals[] = {
+       {0x00, "NO_ERROR"       },
+       {0x01, "WRONG_IF"       },
+       {0x02, "PRUNE_SENT"     },
+       {0x03, "PRUNE_RCVD"     },
+       {0x04, "SCOPED"         },
+       {0x05, "NO_ROUTE"       },
+       {0x06, "WRONG_LAST_HOP" },
+       {0x07, "NOT_FORWARDING" },
+       {0x08, "REACHED_RP"     },
+       {0x09, "RPF_IF"         },
+       {0x0A, "NO_MULTICAST"   },
+       {0x0B, "INFO_HIDDEN"    },
+       {0x81, "NO_SPACE"       },
+       {0x82, "OLD_ROUTER"     },
+       {0x83, "ADMIN_PROHIB"   },
+       {0, NULL}
+};
+
 #define PRINT_IGMP_VERSION(version)                                    \
-       if (check_col(pinfo->fd, COL_INFO)) {                           \
-               col_add_fstr(pinfo->fd, COL_INFO,                       \
+       if (check_col(pinfo->cinfo, COL_INFO)) {                                \
+               col_add_fstr(pinfo->cinfo, COL_INFO,                    \
                        "V%d %s",version,val_to_str(type, commands,     \
                                "Unknown Type:0x%02x"));                \
        }                                                               \
@@ -238,23 +309,43 @@ static const value_string vs_record_type[] = {
        proto_tree_add_uint(tree, hf_type, tvb, offset, 1, type);       \
        offset += 1;
 
-static void igmp_checksum(proto_tree *tree,tvbuff_t *tvb, int len)
+void igmp_checksum(proto_tree *tree, tvbuff_t *tvb, int hf_index,
+    int hf_index_bad, packet_info *pinfo, guint len)
 {
-       guint16 cksum,hdrcksum;
+       guint16 cksum, hdrcksum;
        vec_t cksum_vec[1];
 
-       cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, len);
-       cksum_vec[0].len = len;
+       if (len == 0) {
+               /*
+                * Checksum the entire IGMP packet.
+                */
+               len = tvb_reported_length(tvb);
+       }
 
        hdrcksum = tvb_get_ntohs(tvb, 2);
-       cksum = in_cksum(&cksum_vec[0],1);
+       if (!pinfo->fragmented && tvb_length(tvb) >= len) {
+               /*
+                * The packet isn't part of a fragmented datagram and isn't
+                * truncated, so we can checksum it.
+                */
+               cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, len);
+               cksum_vec[0].len = len;
 
-       if (cksum==0) {
-               proto_tree_add_uint_format(tree, hf_checksum, tvb, 2, 2, hdrcksum, "Header checksum: 0x%04x (correct)", hdrcksum);
-       } else {
-               proto_tree_add_item_hidden(tree, hf_checksum_bad, tvb, 2, 2, TRUE);
-               proto_tree_add_uint_format(tree, hf_checksum, tvb, 2, 2, hdrcksum, "Header checksum: 0x%04x (incorrect, should be 0x%04x)", hdrcksum,in_cksum_shouldbe(hdrcksum,cksum));
-       }
+               cksum = in_cksum(&cksum_vec[0],1);
+
+               if (cksum == 0) {
+                       proto_tree_add_uint_format(tree, hf_index,
+                           tvb, 2, 2, hdrcksum,
+                           "Header checksum: 0x%04x (correct)", hdrcksum);
+               } else {
+                       proto_tree_add_boolean_hidden(tree, hf_index_bad,
+                           tvb, 2, 2, TRUE);
+                       proto_tree_add_uint_format(tree, hf_index,
+                           tvb, 2, 2, hdrcksum,
+                           "Header checksum: 0x%04x (incorrect, should be 0x%04x)", hdrcksum,in_cksum_shouldbe(hdrcksum,cksum));
+               }
+       } else
+               proto_tree_add_uint(tree, hf_index, tvb, 2, 2, hdrcksum);
 
        return;
 }
@@ -266,8 +357,8 @@ dissect_igmp_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int ty
 {
        int len;
 
-       if (check_col(pinfo->fd, COL_INFO)) {
-               col_add_str(pinfo->fd, COL_INFO,
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_add_str(pinfo->cinfo, COL_INFO,
                        val_to_str(type, commands, "Unknown Type:0x%02x"));
        }
 
@@ -289,7 +380,7 @@ dissect_igmp_unknown(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int ty
  * IGMP Protocol dissectors
  *************************************************************/
 static int
-dissect_v3_max_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
+dissect_v3_max_resp(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
 {
        proto_tree *tree;
        proto_item *item;
@@ -322,7 +413,7 @@ dissect_v3_max_resp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
 }
 
 static int
-dissect_v3_sqrv_bits(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
+dissect_v3_sqrv_bits(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
 {
        proto_tree *tree;
        proto_item *item;
@@ -345,7 +436,7 @@ dissect_v3_sqrv_bits(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree,
 }
 
 static int
-dissect_v3_group_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree, int offset)
+dissect_v3_group_record(tvbuff_t *tvb, proto_tree *parent_tree, int offset)
 {
        proto_tree *tree;
        proto_item *item;
@@ -354,8 +445,8 @@ dissect_v3_group_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tr
        guint16 num;
        guint32 ip;
 
-       ip = tvb_get_letohl(tvb, offset+4);
-       item = proto_tree_add_text(parent_tree, tvb, offset, 0, 
+       tvb_memcpy(tvb, (guint8 *)&ip, offset+4, 4);
+       item = proto_tree_add_text(parent_tree, tvb, offset, -1,
                "Group Record : %s  %s", 
                        ip_to_str((gchar*)&ip), 
                        val_to_str(tvb_get_guint8(tvb, offset), vs_record_type,"")
@@ -363,7 +454,7 @@ dissect_v3_group_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tr
        tree = proto_item_add_subtree(item, ett_group_record);
 
        /* record type */
-       proto_tree_add_uint(tree, hf_record_type, tvb, offset, 1, tvb_get_guint8(tvb, offset));
+       proto_tree_add_item(tree, hf_record_type, tvb, offset, 1, FALSE);
        offset += 1;
 
        /* aux data len */
@@ -377,20 +468,19 @@ dissect_v3_group_record(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tr
        offset += 2;
 
        /* multicast address */
-       proto_tree_add_ipv4(tree, hf_maddr, tvb, 
-               offset, 4, tvb_get_letohl(tvb, offset));
+       proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
        offset += 4;
 
        /* source addresses */
        while(num--){
-               proto_tree_add_ipv4(tree, hf_saddr, tvb, 
-                       offset, 4, tvb_get_letohl(tvb, offset));
+               proto_tree_add_item(tree, hf_saddr, tvb, offset, 4, FALSE);
                offset += 4;
        }
 
        /* aux data */
        if(adl){
-               proto_tree_add_bytes(tree, hf_aux_data, tvb, offset, adl*4, tvb_get_ptr(tvb, offset, adl*4));
+               proto_tree_add_item(tree, hf_aux_data, tvb, offset, adl*4,
+                   FALSE);
                offset += adl*4;
        }
 
@@ -410,8 +500,8 @@ dissect_igmp_v3_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, in
        offset += 1;
 
        /* checksum */
-       igmp_checksum(tree, tvb, pinfo->iplen-pinfo->iphdrlen*4);
-       offset +=2;
+       igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
+       offset += 2;
 
        /* skip reserved field */
        offset += 2;
@@ -422,7 +512,7 @@ dissect_igmp_v3_response(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, in
        offset += 2;
        
        while (num--) {
-               offset = dissect_v3_group_record(tvb,pinfo,tree,offset);
+               offset = dissect_v3_group_record(tvb, tree, offset);
        }
 
        return offset;
@@ -437,21 +527,21 @@ dissect_igmp_v3_query(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int t
 
        num = tvb_get_ntohs(tvb, offset+9);
        /* max resp code */
-       offset = dissect_v3_max_resp(tvb, pinfo, tree, offset);
+       offset = dissect_v3_max_resp(tvb, tree, offset);
 
        /* checksum */
-       igmp_checksum(tree, tvb, pinfo->iplen-pinfo->iphdrlen*4);
+       igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
        offset += 2;
 
        /* group address */
-       proto_tree_add_ipv4(tree, hf_maddr, tvb, offset, 4, tvb_get_letohl(tvb, offset));
+       proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
        offset +=4;
 
        /* bitmask for S and QRV */
-       offset = dissect_v3_sqrv_bits(tvb, pinfo, tree, offset);
+       offset = dissect_v3_sqrv_bits(tvb, tree, offset);
 
        /* qqic */
-       proto_tree_add_uint(tree, hf_qqic, tvb, offset, 1, tvb_get_guint8(tvb, offset));
+       proto_tree_add_item(tree, hf_qqic, tvb, offset, 1, FALSE);
        offset += 1;
 
        /*number of sources*/
@@ -459,8 +549,7 @@ dissect_igmp_v3_query(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int t
        offset += 2;
 
        while(num--){
-               proto_tree_add_ipv4(tree, hf_saddr, tvb, 
-                       offset, 4, tvb_get_letohl(tvb, offset));
+               proto_tree_add_item(tree, hf_saddr, tvb, offset, 4, FALSE);
                offset += 4;
        }
 
@@ -482,11 +571,11 @@ dissect_igmp_v2(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, i
        offset += 1;
 
        /* checksum */
-       igmp_checksum(tree, tvb, 8);
+       igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 8);
        offset += 2;
 
        /* group address */
-       proto_tree_add_ipv4(tree, hf_maddr, tvb, offset, 4, tvb_get_letohl(tvb, offset));
+       proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
        offset +=4;
 
        return offset;
@@ -502,61 +591,16 @@ dissect_igmp_v1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, i
        offset += 1;
 
        /* checksum */
-       igmp_checksum(tree, tvb, 8);
+       igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 8);
        offset += 2;
 
        /* group address */
-       proto_tree_add_ipv4(tree, hf_maddr, tvb, offset, 4, tvb_get_letohl(tvb, offset));
+       proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
        offset +=4;
 
        return offset;
 }
 
-/*
- * Dissector for V1 PIM messages.
- *
- * XXX - are these just PIM V1 messages (which we don't dissect in the PIM
- * dissector)?  Where is PIM V1 documented?  I'm inferring some of this
- * from the tcpdump IGMP dissector.
- */
-#define PIMV1_QUERY            0
-#define PIMV1_REGISTER         1
-#define PIMV1_REGISTER_STOP    2
-#define PIMV1_JOIN_PRUNE       3
-#define PIMV1_RP_REACHABLE     4
-#define PIMV1_ASSERT           5
-#define PIMV1_GRAFT            6
-#define PIMV1_GRAFT_ACK                7
-#define PIMV1_MODE             8
-
-static const value_string pim_routing_type[] = {
-       { PIMV1_QUERY,          "Query" },
-       { PIMV1_REGISTER,       "Register" },
-       { PIMV1_REGISTER_STOP,  "Register-Stop" },
-       { PIMV1_JOIN_PRUNE,     "Join/Prune" },
-       { PIMV1_RP_REACHABLE,   "RP-reachable" },
-       { PIMV1_ASSERT,         "Assert" },
-       { PIMV1_GRAFT,          "Graft" },
-       { PIMV1_GRAFT_ACK,      "Graft-ACK" },
-       { PIMV1_MODE,           "Mode" },
-       { 0,                    NULL }
-};
-
-static int
-dissect_igmp_v1_pim_routing(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
-{
-       guint8 pimv1_type;
-
-       PRINT_IGMP_VERSION(1);
-
-       pimv1_type = tvb_get_guint8(tvb, offset);
-       proto_tree_add_text(tree, tvb, offset, 2, "Message type: %s",
-           val_to_str(pimv1_type, pim_routing_type, "Unknown (%u)"));
-
-       /* XXX - dissect the rest of it */
-       return offset;
-}
-
 /* dissector for version 0, rfc988 */
 static int
 dissect_igmp_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
@@ -579,24 +623,158 @@ dissect_igmp_v0(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, i
        offset += 1;
 
        /* checksum */
-       igmp_checksum(tree, tvb, 20);
+       igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 20);
        offset += 2;
 
        /* identifier */
-       proto_tree_add_uint(tree, hf_identifier, tvb, offset, 4, tvb_get_ntohl(tvb, offset));
+       proto_tree_add_item(tree, hf_identifier, tvb, offset, 4, FALSE);
        offset += 4;
 
        /* group address */
-       proto_tree_add_ipv4(tree, hf_maddr, tvb, offset, 4, tvb_get_letohl(tvb, offset));
+       proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
        offset +=4;
 
        /* access key */
-       proto_tree_add_bytes(tree, hf_access_key, tvb, offset, 8, tvb_get_ptr(tvb, offset, 8));
+       proto_tree_add_item(tree, hf_access_key, tvb, offset, 8, FALSE);
        offset +=8;
 
        return offset;          
 } 
 
+/* dissector for multicast traceroute, rfc???? */
+static int
+dissect_igmp_mtrace(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, int type, int offset)
+{
+       char *typestr, *blocks = NULL;
+       char buf[20];
+
+       /* All multicast traceroute packets (Query, Request and
+        * Response) have the same fixed header. Request and Response
+        * have one or more response data blocks following this fixed
+        * header. Since Query and Request share the same IGMP type,
+        * the method to differentiate between them is to check the
+        * IGMP packet length. Queries are only
+        * IGMP_TRACEROUTE_HDR_LEN bytes long.
+        */
+       if (type == IGMP_TRACEROUTE_RESPONSE) {
+               int i = (tvb_reported_length_remaining(tvb, offset) - IGMP_TRACEROUTE_HDR_LEN) / IGMP_TRACEROUTE_RSP_LEN;
+               snprintf(buf, sizeof buf, ", %d block%s", i, plurality(i, "", "s"));
+               typestr = "Traceroute Response";
+               blocks = buf;
+       } else if (tvb_reported_length_remaining(tvb, offset) == IGMP_TRACEROUTE_HDR_LEN)
+               typestr = "Traceroute Query";
+       else
+               typestr = "Traceroute Request";
+
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_set_str(pinfo->cinfo, COL_INFO, typestr);
+               if (blocks) col_append_str(pinfo->cinfo, COL_INFO, blocks);
+       }
+
+       proto_tree_add_uint_format(tree, hf_type, tvb, offset, 1, type,
+           "Type: %s (0x%02x)", typestr, type);
+       offset += 1;
+
+       /* maximum number of hops that the requester wants to trace */
+       proto_tree_add_item(tree, hf_mtrace_max_hops, tvb, offset, 1, FALSE);
+       offset += 1;
+
+       /* checksum */
+       igmp_checksum(tree, tvb, hf_checksum, hf_checksum_bad, pinfo, 0);
+       offset += 2;
+
+       /* group address to be traced */
+       proto_tree_add_item(tree, hf_maddr, tvb, offset, 4, FALSE);
+       offset += 4;
+
+       /* address of multicast source for the path being traced */
+       proto_tree_add_item(tree, hf_mtrace_saddr, tvb, offset, 4, FALSE);
+       offset += 4;
+
+       /* address of multicast receiver for the path being traced */
+       proto_tree_add_item(tree, hf_mtrace_raddr, tvb, offset, 4, FALSE);
+       offset += 4;
+
+       /* address where the completed traceroute response packet gets sent */
+       proto_tree_add_item(tree, hf_mtrace_rspaddr, tvb, offset, 4, FALSE);
+       offset += 4;
+
+       /* for multicasted responses, TTL at which to multicast the response */
+       proto_tree_add_item(tree, hf_mtrace_resp_ttl, tvb, offset, 1, FALSE);
+       offset += 1;
+
+       /* unique identifier for this traceroute request (for e.g. duplicate/delay detection) */
+       proto_tree_add_item(tree, hf_mtrace_q_id, tvb, offset, 3, FALSE);
+       offset += 3;
+
+       /* If this was Query, we only had the fixed header */
+       if (tvb_reported_length_remaining(tvb, offset) == 0)
+               return offset;
+
+       /* Loop through the response data blocks */
+        while (tvb_reported_length_remaining(tvb, offset) >= IGMP_TRACEROUTE_RSP_LEN) {
+                proto_item *bi;
+                proto_tree *block_tree;
+
+                bi = proto_tree_add_text(tree, tvb, offset, IGMP_TRACEROUTE_RSP_LEN,
+                                         "Response data block: %s -> %s,  Proto: %s,  Forwarding Code: %s",
+                                         ip_to_str(tvb_get_ptr(tvb, offset + 4, 4)),
+                                         ip_to_str(tvb_get_ptr(tvb, offset + 8, 4)),
+                                         val_to_str(tvb_get_guint8(tvb, offset + 28), mtrace_rtg_vals, "Unknown"),
+                                         val_to_str(tvb_get_guint8(tvb, offset + 31), mtrace_fwd_code_vals, "Unknown"));
+                block_tree = proto_item_add_subtree(bi, ett_mtrace_block);
+
+               /* Query Arrival Time */
+               proto_tree_add_item(block_tree, hf_mtrace_q_arrival, tvb, offset, 4, FALSE);
+               offset += 4;
+
+               /* Incoming Interface Address */
+               proto_tree_add_item(block_tree, hf_mtrace_q_inaddr, tvb, offset, 4, FALSE);
+               offset += 4;
+
+               /* Outgoing Interface Address */
+               proto_tree_add_item(block_tree, hf_mtrace_q_outaddr, tvb, offset, 4, FALSE);
+               offset += 4;
+
+               /* Previous-Hop Router Address */
+               proto_tree_add_item(block_tree, hf_mtrace_q_prevrtr, tvb, offset, 4, FALSE);
+               offset += 4;
+
+               /* Input packet count on incoming interface */
+               proto_tree_add_item(block_tree, hf_mtrace_q_inpkt, tvb, offset, 4, FALSE);
+               offset += 4;
+
+               /* Output packet count on outgoing interface */
+               proto_tree_add_item(block_tree, hf_mtrace_q_outpkt, tvb, offset, 4, FALSE);
+               offset += 4;
+
+               /* Total number of packets for this source-group pair */
+               proto_tree_add_item(block_tree, hf_mtrace_q_total, tvb, offset, 4, FALSE);
+               offset += 4;
+
+               /* Routing protocol in use between this and previous-hop router */
+               proto_tree_add_item(block_tree, hf_mtrace_q_rtg_proto, tvb, offset, 1, FALSE);
+               offset += 1;
+
+               /* TTL that a packet is required to be forwarded */
+               proto_tree_add_item(block_tree, hf_mtrace_q_fwd_ttl, tvb, offset, 1, FALSE);
+               offset += 1;
+
+               /* Must be zeroed and ignored bit, S bit and src network mask length */
+               proto_tree_add_item(block_tree, hf_mtrace_q_mbz, tvb, offset, 1, FALSE);
+               proto_tree_add_item(block_tree, hf_mtrace_q_s, tvb, offset, 1, FALSE);
+               proto_tree_add_item(block_tree, hf_mtrace_q_src_mask, tvb, offset, 1, FALSE);
+               offset += 1;
+
+               /* Forwarding information/error code */
+               proto_tree_add_item(block_tree, hf_mtrace_q_fwd_code, tvb, offset, 1, FALSE);   
+               offset += 1;
+       }
+
+
+       return offset;
+}
+
 static void
 dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
 {
@@ -606,15 +784,15 @@ dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
        unsigned char type;
        guint32 dst;
 
-       item = proto_tree_add_item(parent_tree, proto_igmp, tvb, offset, 0, FALSE);
+       item = proto_tree_add_item(parent_tree, proto_igmp, tvb, offset, -1, FALSE);
        tree = proto_item_add_subtree(item, ett_igmp);
 
 
-       if (check_col(pinfo->fd, COL_PROTOCOL)) {
-               col_set_str(pinfo->fd, COL_PROTOCOL, "IGMP");
+       if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
+               col_set_str(pinfo->cinfo, COL_PROTOCOL, "IGMP");
        }
-       if (check_col(pinfo->fd, COL_INFO)) {
-               col_clear(pinfo->fd, COL_INFO);
+       if (check_col(pinfo->cinfo, COL_INFO)) {
+               col_clear(pinfo->cinfo, COL_INFO);
        }
 
 
@@ -657,7 +835,7 @@ dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                break;
 
        case IGMP_V1_PIM_ROUTING_MESSAGE:
-               offset = dissect_igmp_v1_pim_routing(tvb, pinfo, tree, type, offset);
+               offset = dissect_pimv1(tvb, pinfo, parent_tree, offset);
                break;
 
        case IGMP_V2_MEMBERSHIP_REPORT:
@@ -665,33 +843,22 @@ dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                offset = dissect_igmp_v2(tvb, pinfo, tree, type, offset);
                break;
 
-       case IGMP_V1_TRACEROUTE_RESPONSE:
-               /* XXX - V1 or V2? */
-               offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
-               /*
-                * XXX - dissect the rest as traceroute response; see the
-                * tcpdump IGMP dissector.
-                */
-               break;
-
-       case IGMP_V1_TRACEROUTE_MESSAGE:
-               /* XXX - V1 or V2? */
-               offset = dissect_igmp_v1(tvb, pinfo, tree, type, offset);
-               /*
-                * XXX - dissect the rest as traceroute message; see the
-                * tcpdump IGMP dissector.
-                */
+       case IGMP_TRACEROUTE_RESPONSE:
+       case IGMP_TRACEROUTE_QUERY_REQ:
+               offset = dissect_igmp_mtrace(tvb, pinfo, tree, type, offset);
                break;
 
        case IGMP_V3_MEMBERSHIP_REPORT:
                offset = dissect_igmp_v3_response(tvb, pinfo, tree, type, offset);
                break;
+
        case IGMP_TYPE_0x23:
                dst = htonl(MC_ALL_IGMPV3_ROUTERS);
                if (!memcmp(pinfo->dst.data, &dst, 4)) {
                        offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
                }
                break;
+
        case IGMP_TYPE_0x24:
                dst = htonl(MC_ALL_ROUTERS);
                if (!memcmp(pinfo->dst.data, &dst, 4)) {
@@ -702,6 +869,7 @@ dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                        offset = dissect_msnip(tvb, pinfo, parent_tree, offset);
                }
                break;
+
        case IGMP_TYPE_0x25:
                if ( (pinfo->iplen-pinfo->iphdrlen*4)>=8 ) {
                        /* if len of igmp packet>=8 we assume it is MSNIP */
@@ -714,6 +882,7 @@ dissect_igmp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *parent_tree)
                        }
                }
                break;
+
        case IGMP_TYPE_0x26:
                dst = htonl(MC_ALL_ROUTERS);
                if (!memcmp(pinfo->dst.data, &dst, 4)) {
@@ -822,12 +991,89 @@ proto_register_igmp(void)
                        { "Mantissa", "igmp.max_resp.mant", FT_UINT8, BASE_HEX,
                        NULL, IGMP_MAX_RESP_MANT, "Maxmimum Response Time, Mantissa", HFILL }},
 
+               { &hf_mtrace_max_hops,
+                       { "# hops", "igmp.mtrace.max_hops", FT_UINT8, BASE_DEC,
+                       NULL, 0, "Maxmimum Number of Hops to Trace", HFILL }},
+
+               { &hf_mtrace_saddr,
+                       { "Source Address", "igmp.mtrace.saddr", FT_IPv4, BASE_NONE,
+                         NULL, 0, "Multicast Source for the Path Being Traced", HFILL }},
+
+               { &hf_mtrace_raddr,
+                       { "Receiver Address", "igmp.mtrace.raddr", FT_IPv4, BASE_NONE,
+                         NULL, 0, "Multicast Receiver for the Path Being Traced", HFILL }},
+
+               { &hf_mtrace_rspaddr,
+                       { "Response Address", "igmp.mtrace.rspaddr", FT_IPv4, BASE_NONE,
+                         NULL, 0, "Destination of Completed Traceroute Response", HFILL }},
+
+               { &hf_mtrace_resp_ttl,
+                       { "Response TTL", "igmp.mtrace.resp_ttl", FT_UINT8, BASE_DEC,
+                       NULL, 0, "TTL for Multicasted Responses", HFILL }},
+
+               { &hf_mtrace_q_id,
+                       { "Query ID", "igmp.mtrace.q_id", FT_UINT24, BASE_DEC,
+                       NULL, 0, "Identifier for this Traceroute Request", HFILL }},
+
+               { &hf_mtrace_q_arrival,
+                       { "Query Arrival", "igmp.mtrace.q_arrival", FT_UINT32, BASE_DEC,
+                       NULL, 0, "Query Arrival Time", HFILL }},
+
+               { &hf_mtrace_q_inaddr,
+                       { "In itf addr", "igmp.mtrace.q_inaddr", FT_IPv4, BASE_NONE,
+                       NULL, 0, "Incoming Interface Address", HFILL }},
+
+               { &hf_mtrace_q_outaddr,
+                       { "Out itf addr", "igmp.mtrace.q_outaddr", FT_IPv4, BASE_NONE,
+                       NULL, 0, "Outgoing Interface Address", HFILL }},
+
+               { &hf_mtrace_q_prevrtr,
+                       { "Previous rtr addr", "igmp.mtrace.q_prevrtr", FT_IPv4, BASE_NONE,
+                       NULL, 0, "Previous-Hop Router Address", HFILL }},
+
+               { &hf_mtrace_q_inpkt,
+                       { "In pkts", "igmp.mtrace.q_inpkt", FT_UINT32, BASE_DEC,
+                       NULL, 0, "Input packet count on incoming interface", HFILL }},
+
+               { &hf_mtrace_q_outpkt,
+                       { "Out pkts", "igmp.mtrace.q_outpkt", FT_UINT32, BASE_DEC,
+                       NULL, 0, "Output packet count on outgoing interface", HFILL }},
+
+               { &hf_mtrace_q_total,
+                       { "S,G pkt count", "igmp.mtrace.q_total", FT_UINT32, BASE_DEC,
+                       NULL, 0, "Total number of packets for this source-group pair", HFILL }},
+
+               { &hf_mtrace_q_rtg_proto,
+                       { "Rtg Protocol", "igmp.mtrace.q_rtg_proto", FT_UINT8, BASE_DEC,
+                       VALS(&mtrace_rtg_vals), 0, "Routing protocol between this and previous hop rtr", HFILL }},
+
+               { &hf_mtrace_q_fwd_ttl,
+                       { "FwdTTL", "igmp.mtrace.q_fwd_ttl", FT_UINT8, BASE_DEC,
+                       NULL, 0, "TTL required for forwarding", HFILL }},
+
+               { &hf_mtrace_q_mbz,
+                       { "MBZ", "igmp.mtrace.q_mbz", FT_UINT8, BASE_HEX,
+                       NULL, 0x80, "Must be zeroed on transmission and ignored on reception", HFILL }},
+
+               { &hf_mtrace_q_s,
+                       { "S", "igmp.mtrace.q_s", FT_UINT8, BASE_HEX,
+                       NULL, 0x40, "Set if S,G packet count is for source network", HFILL }},
+
+               { &hf_mtrace_q_src_mask,
+                       { "Src Mask", "igmp.mtrace.q_src_mask", FT_UINT8, BASE_HEX,
+                       NULL, 0x3F, "Source mask length. 63 when forwarding on group state", HFILL }},
+
+               { &hf_mtrace_q_fwd_code,
+                       { "Forwarding Code", "igmp.mtrace.q_fwd_code", FT_UINT8, BASE_HEX,
+                       VALS(&mtrace_fwd_code_vals), 0, "Forwarding information/error code", HFILL }},
+
        };
        static gint *ett[] = {
                &ett_igmp,
                &ett_group_record,
                &ett_sqrv_bits,
                &ett_max_resp,
+               &ett_mtrace_block,
        };
 
        proto_igmp = proto_register_protocol("Internet Group Management Protocol",
@@ -839,5 +1085,8 @@ proto_register_igmp(void)
 void
 proto_reg_handoff_igmp(void)
 {
-       dissector_add("ip.proto", IP_PROTO_IGMP, dissect_igmp, proto_igmp);
+       dissector_handle_t igmp_handle;
+
+       igmp_handle = create_dissector_handle(dissect_igmp, proto_igmp);
+       dissector_add("ip.proto", IP_PROTO_IGMP, igmp_handle);
 }