added some options and enhancements to the print output:
[obnox/wireshark/wip.git] / packet-icmpv6.c
index a5e49848302af158064093d072d9566c31504454..f4ff6fec075fcd9a620a86d46e6ca0770fe253e0 100644 (file)
@@ -1,7 +1,7 @@
 /* packet-icmpv6.c
  * Routines for ICMPv6 packet disassembly
  *
- * $Id: packet-icmpv6.c,v 1.74 2003/12/19 23:20:53 guy Exp $
+ * $Id: packet-icmpv6.c,v 1.78 2004/04/22 08:22:07 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * By Gerald Combs <gerald@ethereal.com>
@@ -75,6 +75,7 @@ static int hf_icmpv6_type = -1;
 static int hf_icmpv6_code = -1;
 static int hf_icmpv6_checksum = -1;
 static int hf_icmpv6_checksum_bad = -1;
+static int hf_icmpv6_haad_ha_addrs = -1;
 
 static gint ett_icmpv6 = -1;
 static gint ett_icmpv6opt = -1;
@@ -216,16 +217,19 @@ again:
     case ND_OPT_SOURCE_LINKADDR:
     case ND_OPT_TARGET_LINKADDR:
       {
-       char *t;
        int len, i, p;
+       const guint8 *a;
+       char *t;
+
+       p = offset + sizeof(*opt);
        len = (opt->nd_opt_len << 3) - sizeof(*opt);
+       a = tvb_get_ptr(tvb, p, len);
        t = g_malloc(len * 3);
        memset(t, 0, len * 3);
-       p = offset + sizeof(*opt);
        for (i = 0; i < len; i++) {
            if (i)
                t[i * 3 - 1] = ':';
-           sprintf(&t[i * 3], "%02x", tvb_get_guint8(tvb, p + i) & 0xff);
+           sprintf(&t[i * 3], "%02x", a[i]);
        }
        proto_tree_add_text(icmp6opt_tree, tvb,
            offset + sizeof(*opt), len, "Link-layer address: %s", t);
@@ -434,11 +438,7 @@ again:
  */
 
 static const char *
-bitrange0(v, s, buf, buflen)
-       guint32 v;
-       int s;
-       char *buf;
-       int buflen;
+bitrange0(guint32 v, int s, char *buf, int buflen)
 {
        guint32 v0;
        char *p, *ep;
@@ -935,7 +935,7 @@ dissect_rrenum(tvbuff_t *tvb, int offset, packet_info *pinfo, proto_tree *tree)
 }
 
 /*
- * See I-D draft-vida-mld-v2-03
+ * See I-D draft-vida-mld-v2-08
  */
 static const value_string mldrv2ModesNames[] = {
   { 1, "Include" },
@@ -997,6 +997,18 @@ dissect_mldrv2( tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree )
   }
 }
 
+static void
+dissect_mldqv2(tvbuff_t *tvb, guint32 offset, guint16 count, proto_tree *tree)
+{
+  struct e_in6_addr addr;
+
+  for ( ; count; count--, offset += 16) {
+      tvb_memcpy(tvb, (guint8 *)&addr, offset, sizeof(addr));
+      proto_tree_add_text(tree, tvb, offset, 16, 
+                         "Source Address: %s (%s)", get_hostname6(&addr), ip6_to_str(&addr));
+  }
+}
+
 static void
 dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
 {
@@ -1316,6 +1328,55 @@ dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
        case ICMP6_MEMBERSHIP_QUERY:
        case ICMP6_MEMBERSHIP_REPORT:
        case ICMP6_MEMBERSHIP_REDUCTION:
+#define MLDV2_MINLEN 28
+#define MLDV1_MINLEN 24
+           if (dp->icmp6_type == ICMP6_MEMBERSHIP_QUERY) {
+               if (length >= MLDV2_MINLEN) {
+                   guint32 mrc;
+                   guint16 qqi;
+                   guint8 flag;
+                   guint16 nsrcs;
+                   
+                   mrc = g_ntohs(dp->icmp6_maxdelay);
+                   flag = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16);
+                   qqi = tvb_get_guint8(tvb, offset + sizeof(*dp) + 16 + 1);
+                   nsrcs = tvb_get_ntohs(tvb, offset + sizeof(*dp) + 16 + 2);
+
+                   if (mrc >= 32768)
+                       mrc = ((mrc & 0x0fff) | 0x1000) << 
+                               (((mrc & 0x7000) >> 12) + 3);
+                   proto_tree_add_text(icmp6_tree, tvb,
+                       offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
+                       "Maximum response delay[ms]: %u", mrc);
+
+                   proto_tree_add_text(icmp6_tree, tvb, offset + sizeof(*dp),
+                       16, "Multicast Address: %s",
+                       ip6_to_str((const struct e_in6_addr *)(tvb_get_ptr(tvb,
+                           offset + sizeof *dp, sizeof (struct e_in6_addr)))));
+
+                   proto_tree_add_text(icmp6_tree, tvb,
+                       offset + sizeof(*dp) + 16, 1, "S Flag: %s",
+                       flag & 0x08 ? "ON" : "OFF");
+                   proto_tree_add_text(icmp6_tree, tvb,
+                       offset + sizeof(*dp) + 16, 1, "Robustness: %d",
+                       flag & 0x07);
+                   if (qqi >= 128)
+                       qqi = ((qqi & 0x0f) | 0x10) << (((qqi & 0x70) >> 4) + 3);
+                   proto_tree_add_text(icmp6_tree, tvb,
+                       offset + sizeof(*dp) + 17, 1, "QQI: %d", qqi);
+
+                   dissect_mldqv2(tvb, offset + sizeof(*dp) + 20, nsrcs,
+                       icmp6_tree);
+                   break;
+               } else if (length > MLDV1_MINLEN) {
+                   next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
+                   call_dissector(data_handle,next_tvb, pinfo, tree);
+                   break;
+               }
+               /* MLDv1 Query -> FALLTHOUGH */
+           }
+#undef MLDV2_MINLEN
+#undef MLDV1_MINLEN
            proto_tree_add_text(icmp6_tree, tvb,
                offset + offsetof(struct icmp6_hdr, icmp6_maxdelay), 2,
                "Maximum response delay: %u",
@@ -1490,7 +1551,18 @@ dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
            proto_tree_add_text(icmp6_tree, tvb,
                offset + 6, 2, "Reserved: %d",
                tvb_get_ntohs(tvb, offset + 6));
-           /* TODO Show all Home Agent Addresses */
+           /* Show all Home Agent Addresses */
+           {
+               int i, suboffset;
+               int ha_num = (length - 8)/16;
+
+               for (i = 0; i < ha_num; i++) {
+                   suboffset = 16 * i;
+                   proto_tree_add_ipv6(icmp6_tree, hf_icmpv6_haad_ha_addrs,
+                       tvb, offset + 8 + suboffset, 16,
+                       tvb_get_ptr(tvb, offset + 8 + suboffset, 16));
+               }
+           }
            break;
        case ICMP6_MIP6_MPS:
            proto_tree_add_text(icmp6_tree, tvb,
@@ -1507,18 +1579,22 @@ dissect_icmpv6(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
                tvb_get_ntohs(tvb, offset + 4),
                tvb_get_ntohs(tvb, offset + 4));
            proto_tree_add_text(icmp6_tree, tvb,
-               offset + 6, 2,
+               offset + 6, 1,
                decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
-                   0x8000, 16,
+                   0x80, 8,
                    "Managed Address Configuration",
                    "No Managed Address Configuration"));
            proto_tree_add_text(icmp6_tree, tvb,
-               offset + 6, 2,
+               offset + 6, 1,
                decode_boolean_bitfield(tvb_get_guint8(tvb, offset + 6),
-                   0x4000, 16,
+                   0x40, 8,
                    "Other Stateful Configuration",
                    "No Other Stateful Configuration"));
-           /* TODO Show all options */
+           proto_tree_add_text(icmp6_tree, tvb,
+               offset + 7, 1, "Reserved: %d",
+               tvb_get_guint8(tvb, offset + 7));
+           /* Show all options */
+           dissect_icmpv6opt(tvb, offset + 8, pinfo, icmp6_tree);
            break;
        default:
            next_tvb = tvb_new_subset(tvb, offset + sizeof(*dp), -1, -1);
@@ -1544,6 +1620,10 @@ proto_register_icmpv6(void)
     { &hf_icmpv6_checksum_bad,
       { "Bad Checksum",   "icmpv6.checksum_bad", FT_BOOLEAN, BASE_NONE,        NULL, 0x0,
        "", HFILL }},
+    { &hf_icmpv6_haad_ha_addrs,
+      { "Home Agent Addresses", "icmpv6.haad.ha_addrs",
+       FT_IPv6, BASE_HEX, NULL, 0x0,
+       "", HFILL }},
   };
   static gint *ett[] = {
     &ett_icmpv6,