bugfix to a bug reported by Ian Schorr:
[obnox/wireshark/wip.git] / packet-pim.c
index fb23456fc918760720cfae51e5c8c8597cf64cfc..d1f598a9c993f9282ea22beab7e3bc8bf5b68995 100644 (file)
@@ -2,39 +2,31 @@
  * Routines for PIM disassembly
  * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org>
  *
- * $Id: packet-pim.c,v 1.38 2002/01/24 09:20:50 guy Exp $
+ * $Id: packet-pim.c,v 1.48 2004/07/06 19:44:56 guy Exp $
  *
  * Ethereal - Network traffic analyzer
  * 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
  * as published by the Free Software Foundation; either version 2
  * of the License, or (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
-#ifdef HAVE_CONFIG_H 
+#ifdef HAVE_CONFIG_H
 # include "config.h"
 #endif
 
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>
-#endif
-
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-
 #include <stddef.h>  /* For offsetof */
 #include <string.h>
 #include <glib.h>
@@ -117,11 +109,11 @@ dissect_pimv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
     guint16 pim_cksum, computed_cksum;
     vec_t cksum_vec[1];
     proto_tree *pim_tree = NULL;
-    proto_item *ti; 
+    proto_item *ti;
     proto_tree *pimopt_tree = NULL;
-    proto_item *tiopt; 
+    proto_item *tiopt;
 
-    if (!proto_is_protocol_enabled(proto_pim)) {
+    if (!proto_is_protocol_enabled(find_protocol_by_id(proto_pim))) {
        /*
         * We are not enabled; skip entire packet to be nice to the
         * IGMP layer (so clicking on IGMP will display the data).
@@ -227,8 +219,8 @@ dissect_pimv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
 
     if (tree) {
        if (tvb_reported_length_remaining(tvb, offset) > 0) {
-           tiopt = proto_tree_add_text(pim_tree, tvb, offset,
-                   tvb_length_remaining(tvb, offset), "PIM parameters");
+           tiopt = proto_tree_add_text(pim_tree, tvb, offset, -1,
+                   "PIM parameters");
            pimopt_tree = proto_item_add_subtree(tiopt, ett_pim);
        } else
            goto done;
@@ -290,7 +282,7 @@ dissect_pimv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                    } else if (pinfo->src.type == AT_IPv6) {
                            struct ip6_hdr ip6_hdr;
                            tvb_memcpy(tvb, (guint8 *)&ip6_hdr, offset,
-                                      tvb_length_remaining(tvb, offset));
+                                      sizeof ip6_hdr);
                            proto_tree_add_text(pimopt_tree, tvb, offset, -1,
                                                "IPv6 dummy header");
                            proto_tree_add_text(pimopt_tree, tvb,
@@ -351,9 +343,9 @@ dissect_pimv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
            guint8 mask_len;
            guint8 adr_len;
            proto_tree *grouptree = NULL;
-           proto_item *tigroup; 
+           proto_item *tigroup;
            proto_tree *subtree = NULL;
-           proto_item *tisub; 
+           proto_item *tisub;
 
            proto_tree_add_text(pimopt_tree, tvb, offset, 4,
                "Upstream-neighbor: %s",
@@ -420,6 +412,7 @@ dissect_pimv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
                        "IP address: %s", s);
                    off += 6;
                }
+               offset = off;
            }
            break;
          }
@@ -529,7 +522,7 @@ dissect_pim_addr(tvbuff_t *tvb, int offset, enum pimv2_addrtype at,
        case AFNUM_INET6:
            len = 16;
            (void)snprintf(buf, sizeof(buf), "%s",
-               ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 2, len)));
+               ip6_to_str((const struct e_in6_addr *)tvb_get_ptr(tvb, offset + 2, len)));
            break;
        }
        if (advance)
@@ -548,7 +541,7 @@ dissect_pim_addr(tvbuff_t *tvb, int offset, enum pimv2_addrtype at,
        case AFNUM_INET6:
            len = 16;
            (void)snprintf(buf, sizeof(buf), "%s/%u",
-               ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 4, len)), mask_len);
+               ip6_to_str((const struct e_in6_addr *)tvb_get_ptr(tvb, offset + 4, len)), mask_len);
            break;
        }
        if (advance)
@@ -568,7 +561,7 @@ dissect_pim_addr(tvbuff_t *tvb, int offset, enum pimv2_addrtype at,
        case AFNUM_INET6:
            len = 16;
            (void)snprintf(buf, sizeof(buf), "%s/%u",
-               ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 4, len)), mask_len);
+               ip6_to_str((const struct e_in6_addr *)tvb_get_ptr(tvb, offset + 4, len)), mask_len);
            break;
        }
        if (flags) {
@@ -606,7 +599,7 @@ static const value_string type2vals[] = {
  * is run over IPv6, the rules for computing the PIM checksum from the
  * draft in question, not from RFC 2362, should be used).
  */
-static void 
+static void
 dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
     int offset = 0;
     guint8 pim_typever;
@@ -616,9 +609,9 @@ dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
     guint32 phdr[2];
     char *typestr;
     proto_tree *pim_tree = NULL;
-    proto_item *ti; 
+    proto_item *ti;
     proto_tree *pimopt_tree = NULL;
-    proto_item *tiopt; 
+    proto_item *tiopt;
 
     if (check_col(pinfo->cinfo, COL_PROTOCOL))
         col_set_str(pinfo->cinfo, COL_PROTOCOL, "PIM");
@@ -642,16 +635,16 @@ dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
            PIM_VER(pim_typever));
     }
     if (check_col(pinfo->cinfo, COL_INFO))
-       col_add_str(pinfo->cinfo, COL_INFO, typestr); 
+       col_add_str(pinfo->cinfo, COL_INFO, typestr);
 
     if (tree) {
        ti = proto_tree_add_item(tree, proto_pim, tvb, offset, -1, FALSE);
        pim_tree = proto_item_add_subtree(ti, ett_pim);
 
        proto_tree_add_uint(pim_tree, hf_pim_version, tvb, offset, 1,
-           PIM_VER(pim_typever)); 
+           PIM_VER(pim_typever));
        proto_tree_add_uint(pim_tree, hf_pim_type, tvb, offset, 1,
-           PIM_TYPE(pim_typever)); 
+           PIM_TYPE(pim_typever));
 
        pim_cksum = tvb_get_ntohs(tvb, offset + 2);
        length = tvb_length(tvb);
@@ -702,8 +695,8 @@ dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                cksum_vec[1].ptr = pinfo->dst.data;
                cksum_vec[1].len = pinfo->dst.len;
                cksum_vec[2].ptr = (const guint8 *)&phdr;
-               phdr[0] = htonl(pim_length);
-               phdr[1] = htonl(IP_PROTO_PIM);
+               phdr[0] = g_htonl(pim_length);
+               phdr[1] = g_htonl(IP_PROTO_PIM);
                cksum_vec[2].len = 8;
                cksum_vec[3].ptr = tvb_get_ptr(tvb, 0, pim_length);
                cksum_vec[3].len = pim_length;
@@ -749,17 +742,100 @@ dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
        case 0: /*hello*/
          {
            while (tvb_reported_length_remaining(tvb, offset) >= 2) {
-               if (tvb_get_ntohs(tvb, offset) == 1 &&
-                   tvb_get_ntohs(tvb, offset + 2) == 2) {
-                   guint16 holdtime;
-
-                   holdtime = tvb_get_ntohs(tvb, offset + 4);
-                   proto_tree_add_text(pimopt_tree, tvb, offset, 6,
-                       "Holdtime: %u%s", holdtime,
-                       holdtime == 0xffff ? " (infty)" : "");
-                   offset += 6;
-               } else
-                   break;
+               guint16 hello_opt, opt_len;
+               guint16 holdtime;
+               guint16 lan_delay;
+               guint16 override_interval;
+               guint32 priority;
+               guint32 opt_value = 0;
+
+               hello_opt = tvb_get_ntohs(tvb, offset);
+               opt_len = tvb_get_ntohs(tvb, offset + 2);
+
+               if(opt_len == 2)
+                       opt_value = tvb_get_ntohs(tvb, offset + 4);
+               if(opt_len == 4)
+                       opt_value = tvb_get_ntohl(tvb, offset + 4);
+
+               switch(hello_opt) {
+               case 1: /* holdtime */
+                       holdtime = opt_value;
+                       proto_tree_add_text(pimopt_tree, tvb, offset, 4 + opt_len,
+                                           "Holdtime (%u): %us %s", hello_opt, holdtime,
+                                           holdtime == 0xffff ? " (infty)" : "");
+                       break;
+               case 2: /* LAN prune delay
+                         *
+                         * 0                   1                   2                   3
+                         * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+                         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                         * |            Type = 2           |           Length = 4          |
+                         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                         * |T|       LAN Prune Delay       |       Override Interval       |
+                         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+                         */
+               {
+                       proto_tree *sub_tree = NULL;
+                       proto_item *landelay_option;
+
+                       landelay_option = proto_tree_add_text(pimopt_tree, tvb, offset, 4 + opt_len,
+                                                       "LAN Prune Delay (%u)", hello_opt);
+                       sub_tree = proto_item_add_subtree(landelay_option, ett_pim);
+
+                       lan_delay = (opt_value & 0x7fff0000) >> 16;
+                       override_interval = opt_value & 0x0000ffff;
+                       proto_tree_add_text(sub_tree, tvb, offset + 4, 1,
+                                           "T bit is %s",
+                                           opt_value & 0x8000 ? "set" : "not set");
+                       proto_tree_add_text(sub_tree, tvb, offset + 4, 2,
+                                           "LAN Delay: %ums", lan_delay);
+                       proto_tree_add_text(sub_tree, tvb, offset + 6, 2,
+                                           "Override Interval: %ums", override_interval);
+                       break;
+               }
+               case 19: /* priority */
+                       priority = opt_value;
+                       proto_tree_add_text(pimopt_tree, tvb, offset, 4 + opt_len,
+                                       "DR Priority (%u): %u", hello_opt, priority);
+                       break;
+               case 20: /* generation ID */
+                       proto_tree_add_text(pimopt_tree, tvb, offset, 4 + opt_len,
+                                           "Generation ID (%u): %d", hello_opt, opt_value);
+                       break;
+
+               case 24: /* address list */
+               case 65001: /* address list (old implementations) */
+               {
+                       int i;
+                       proto_tree *sub_tree = NULL;
+                       proto_item *addrlist_option;
+
+                       addrlist_option = proto_tree_add_text(pimopt_tree, tvb, offset, 4 + opt_len,
+                                           "%sAddress List (%u)",
+                                           hello_opt == 65001 ? "old " : "",
+                                            hello_opt);
+                       sub_tree = proto_item_add_subtree(addrlist_option, ett_pim);
+
+                       for (i = offset + 4; i < offset + 4 + opt_len; ) {
+                               int advance;
+                               const char *s;
+
+                               s = dissect_pim_addr(tvb, i, pimv2_unicast, &advance);
+                               if (s == NULL)
+                                       break;
+                               proto_tree_add_text(sub_tree, tvb, offset, 
+                                                   advance, "Address: %s", s);
+                               i += advance;
+                       }
+                       break;
+               }
+               default:
+                       proto_tree_add_text(pimopt_tree, tvb, offset, 4 + opt_len,
+                                           "Unknown option (%u), length: %u, value: 0x%x",
+                                           hello_opt, opt_len, opt_value);
+                       break;
+               }
+               offset += 4 + opt_len;
            }
            break;
          }
@@ -770,7 +846,7 @@ dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
            guint8 v_hl;
            tvbuff_t *next_tvb;
            proto_tree *flag_tree = NULL;
-           proto_item *tiflag; 
+           proto_item *tiflag;
 
            flags = tvb_get_ntohl(tvb, offset);
            tiflag = proto_tree_add_text(pimopt_tree, tvb, offset, 4,
@@ -783,7 +859,7 @@ dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                decode_boolean_bitfield(flags, 0x40000000, 32,
                    "Null-Register", "Not Null-Register"));
            offset += 4;
-           
+
            /*
             * The rest of the packet is a multicast data packet.
             */
@@ -810,7 +886,7 @@ dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                    } else if (pinfo->src.type == AT_IPv6) {
                            struct ip6_hdr ip6_hdr;
                            tvb_memcpy(tvb, (guint8 *)&ip6_hdr, offset,
-                                      tvb_length_remaining(tvb, offset));
+                                      sizeof ip6_hdr);
                            proto_tree_add_text(pimopt_tree, tvb, offset, -1,
                                                "IPv6 dummy header");
                            proto_tree_add_text(pimopt_tree, tvb,
@@ -874,9 +950,9 @@ dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
            int ngroup, i, njoin, nprune, j;
            guint16 holdtime;
            proto_tree *grouptree = NULL;
-           proto_item *tigroup; 
+           proto_item *tigroup;
            proto_tree *subtree = NULL;
-           proto_item *tisub; 
+           proto_item *tisub;
 
            if (PIM_TYPE(pim_typever) != 7) {
                /* not graft-ack */
@@ -942,6 +1018,7 @@ dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
                        "IP address: %s", s);
                    off += advance;
                }
+               offset = off;
            }
     breakbreak3:
            break;
@@ -955,7 +1032,7 @@ dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
            int frpcnt;
            guint16 holdtime;
            proto_tree *grouptree = NULL;
-           proto_item *tigroup; 
+           proto_item *tigroup;
 
            proto_tree_add_text(pimopt_tree, tvb, offset, 2,
                "Fragment tag: 0x%04x", tvb_get_ntohs(tvb, offset));