2 * Routines for PIM disassembly
3 * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-pim.c,v 1.37 2002/01/21 07:36:38 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h>
38 #include <stddef.h> /* For offsetof */
42 #ifdef NEED_SNPRINTF_H
43 # include "snprintf.h"
46 #include <epan/packet.h>
49 #include "packet-ipv6.h"
52 #define PIM_TYPE(x) ((x) & 0x0f)
53 #define PIM_VER(x) (((x) & 0xf0) >> 4)
56 pimv2_unicast, pimv2_group, pimv2_source
59 static int proto_pim = -1;
60 static int hf_pim_version = -1;
61 static int hf_pim_type = -1;
62 static int hf_pim_code = -1;
63 static int hf_pim_cksum = -1;
65 static gint ett_pim = -1;
67 static dissector_handle_t ip_handle;
68 static dissector_handle_t ipv6_handle;
71 * For PIM v1, see the PDF slides at
73 * http://www.mbone.de/training/Module3.pdf
75 * Is it documented anywhere else?
78 dissect_pimv1_addr(tvbuff_t *tvb, int offset) {
80 guint16 flags_masklen;
82 flags_masklen = tvb_get_ntohs(tvb, offset);
83 if (flags_masklen & 0x0180) {
84 (void)snprintf(buf, sizeof(buf),
86 flags_masklen & 0x0100 ? "S" : "",
87 flags_masklen & 0x0080 ? "W" : "",
88 flags_masklen & 0x0040 ? "R" : "");
91 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s/%u",
92 ip_to_str(tvb_get_ptr(tvb, offset + 2, 4)), flags_masklen & 0x3f);
97 static const value_string type1vals[] = {
100 { 2, "Register-stop" },
102 { 4, "RP-Reachable" },
110 /* This function is only called from the IGMP dissector */
112 dissect_pimv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
116 guint length, pim_length;
117 guint16 pim_cksum, computed_cksum;
119 proto_tree *pim_tree = NULL;
121 proto_tree *pimopt_tree = NULL;
124 if (!proto_is_protocol_enabled(proto_pim)) {
126 * We are not enabled; skip entire packet to be nice to the
127 * IGMP layer (so clicking on IGMP will display the data).
129 return offset+tvb_length_remaining(tvb, offset);
132 if (check_col(pinfo->cinfo, COL_PROTOCOL))
133 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PIMv1");
134 if (check_col(pinfo->cinfo, COL_INFO))
135 col_clear(pinfo->cinfo, COL_INFO);
138 ti = proto_tree_add_item(tree, proto_pim, tvb, offset,
139 tvb_length_remaining(tvb, offset), FALSE);
140 pim_tree = proto_item_add_subtree(ti, ett_pim);
142 /* Put IGMP type, 0x14, into the tree */
143 proto_tree_add_text(pim_tree, tvb, offset, 1,
148 pim_type = tvb_get_guint8(tvb, offset);
149 if (check_col(pinfo->cinfo, COL_INFO))
150 col_add_str(pinfo->cinfo, COL_INFO,
151 val_to_str(pim_type, type1vals, "Unknown (%u)"));
154 proto_tree_add_uint(pim_tree, hf_pim_code, tvb, offset, 1, pim_type);
158 pim_cksum = tvb_get_ntohs(tvb, offset);
159 pim_ver = PIM_VER(tvb_get_guint8(tvb, offset + 2));
162 * Not PIMv1 - what gives?
165 proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
166 offset, 2, pim_cksum);
170 proto_tree_add_uint(pim_tree, hf_pim_version, tvb, offset, 1, pim_ver);
171 return offset+tvb_length_remaining(tvb, offset);
175 * Well, it's PIM v1, so we can check whether this is a
176 * Register message, and thus can figure out how much to
177 * checksum and whether to make the columns read-only.
179 length = tvb_length(tvb);
182 * Register message - the PIM header is 8 bytes long.
183 * Also set the columns non-writable. Otherwise the IPv4 or
184 * IPv6 dissector for the encapsulated packet that caused
185 * this register will overwrite the PIM info in the columns.
188 col_set_writable(pinfo->cinfo, FALSE);
191 * Other message - checksum the entire packet.
193 pim_length = tvb_reported_length(tvb);
197 if (!pinfo->fragmented && length >= pim_length) {
199 * The packet isn't part of a fragmented datagram and isn't
200 * truncated, so we can checksum it.
202 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length);
203 cksum_vec[0].len = pim_length;
204 computed_cksum = in_cksum(&cksum_vec[0], 1);
205 if (computed_cksum == 0) {
206 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
207 offset, 2, pim_cksum,
208 "Checksum: 0x%04x (correct)",
211 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
212 offset, 2, pim_cksum,
213 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
214 pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum));
217 proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
218 offset, 2, pim_cksum);
224 proto_tree_add_uint(pim_tree, hf_pim_version, tvb, offset, 1, pim_ver);
227 offset += 3; /* skip reserved stuff */
230 if (tvb_reported_length_remaining(tvb, offset) > 0) {
231 tiopt = proto_tree_add_text(pim_tree, tvb, offset,
232 tvb_length_remaining(tvb, offset), "PIM parameters");
233 pimopt_tree = proto_item_add_subtree(tiopt, ett_pim);
237 /* version 1 decoder */
243 static const value_string pimv1_modevals[] = {
246 { 2, "Sparse-Dense" },
250 mode = tvb_get_guint8(tvb, offset) >> 4;
251 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
253 val_to_str(mode, pimv1_modevals, "Unknown (%u)"));
255 holdtime = tvb_get_ntohs(tvb, offset);
256 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
257 "Holdtime: %u%s", holdtime,
258 holdtime == 0xffff ? " (infty)" : "");
263 case 1: /* register */
269 * The rest of the packet is a multicast data packet.
271 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
274 * It's an IP packet - determine whether it's IPv4 or IPv6.
276 v_hl = tvb_get_guint8(tvb, offset);
277 switch((v_hl & 0xf0) >> 4) {
278 case 0: /* Null-Register dummy header.
279 * Has the same address family as the encapsulating PIM packet,
280 * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet.
282 if (pinfo->src.type == AT_IPv4) {
283 proto_tree_add_text(pimopt_tree, tvb, offset,
284 tvb_length_remaining(tvb, offset),
285 "IPv4 dummy header");
286 proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4,
288 ip_to_str(tvb_get_ptr(tvb, offset + 12, 4)));
289 proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4,
291 ip_to_str(tvb_get_ptr(tvb, offset + 16, 4)));
292 } else if (pinfo->src.type == AT_IPv6) {
293 struct ip6_hdr ip6_hdr;
294 tvb_memcpy(tvb, (guint8 *)&ip6_hdr, offset,
295 tvb_length_remaining(tvb, offset));
296 proto_tree_add_text(pimopt_tree, tvb, offset,
297 tvb_length_remaining(tvb, offset),
298 "IPv6 dummy header");
299 proto_tree_add_text(pimopt_tree, tvb,
300 offset + offsetof(struct ip6_hdr, ip6_src), 16,
302 ip6_to_str(&ip6_hdr.ip6_src));
303 proto_tree_add_text(pimopt_tree, tvb,
304 offset + offsetof(struct ip6_hdr, ip6_dst), 16,
306 ip6_to_str(&ip6_hdr.ip6_dst));
308 proto_tree_add_text(pimopt_tree, tvb, offset,
309 tvb_length_remaining(tvb, offset),
310 "Dummy header for an unknown protocol");
314 call_dissector(ip_handle, next_tvb, pinfo, tree);
316 call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree);
321 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
323 call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree);
327 proto_tree_add_text(pimopt_tree, tvb,
328 offset, tvb_length_remaining(tvb, offset),
329 "Unknown IP version %d", (v_hl & 0xf0) >> 4);
335 case 2: /* register-stop */
337 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
339 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
341 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
343 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
348 case 3: /* join/prune */
350 case 7: /* graft-ack */
354 int ngroup, i, njoin, nprune, j;
358 proto_tree *grouptree = NULL;
360 proto_tree *subtree = NULL;
363 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
364 "Upstream-neighbor: %s",
365 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
368 offset += 2; /* skip reserved stuff */
370 holdtime = tvb_get_ntohs(tvb, offset);
371 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
372 "Holdtime: %u%s", holdtime,
373 holdtime == 0xffff ? " (infty)" : "");
376 offset += 1; /* skip reserved stuff */
378 mask_len = tvb_get_guint8(tvb, offset);
379 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
380 "Mask length: %u", mask_len);
383 adr_len = tvb_get_guint8(tvb, offset);
384 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
385 "Address length: %u", adr_len);
388 ngroup = tvb_get_guint8(tvb, offset);
389 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
390 "Groups: %u", ngroup);
393 for (i = 0; i < ngroup; i++) {
394 tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, 4,
396 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
397 grouptree = proto_item_add_subtree(tigroup, ett_pim);
400 proto_tree_add_text(grouptree, tvb, offset, 4,
401 "Group %d Mask: %s", i,
402 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
405 njoin = tvb_get_ntohs(tvb, offset);
406 nprune = tvb_get_ntohs(tvb, offset + 2);
408 tisub = proto_tree_add_text(grouptree, tvb, offset, 2,
410 subtree = proto_item_add_subtree(tisub, ett_pim);
412 for (j = 0; j < njoin; j++) {
413 s = dissect_pimv1_addr(tvb, off);
414 proto_tree_add_text(subtree, tvb, off, 6,
415 "IP address: %s", s);
419 tisub = proto_tree_add_text(grouptree, tvb, offset + 2, 2,
420 "Prune: %d", nprune);
421 subtree = proto_item_add_subtree(tisub, ett_pim);
422 for (j = 0; j < nprune; j++) {
423 s = dissect_pimv1_addr(tvb, off);
424 proto_tree_add_text(subtree, tvb, off, 6,
425 "IP address: %s", s);
432 case 4: /* rp-reachability */
436 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
438 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
441 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
443 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
446 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
448 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
451 offset += 2; /* skip reserved stuff */
453 holdtime = tvb_get_ntohs(tvb, offset);
454 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
455 "Holdtime: %u%s", holdtime,
456 holdtime == 0xffff ? " (infty)" : "");
463 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
465 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
468 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
470 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
473 proto_tree_add_text(pimopt_tree, tvb, offset, 1, "%s",
474 decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x80, 8,
475 "RP Tree", "Not RP Tree"));
476 proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Preference: %u",
477 tvb_get_ntohl(tvb, offset) & 0x7fffffff);
480 proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Metric: %u",
481 tvb_get_ntohl(tvb, offset));
492 return offset+tvb_length_remaining(tvb, offset);
496 dissect_pim_addr(tvbuff_t *tvb, int offset, enum pimv2_addrtype at,
498 static char buf[512];
505 af = tvb_get_guint8(tvb, offset);
506 if (af != AFNUM_INET && af != AFNUM_INET6) {
508 * We don't handle the other formats, and addresses don't include
509 * a length field, so we can't even show them as raw bytes.
514 et = tvb_get_guint8(tvb, offset + 1);
517 * The only defined encoding type is 0, for the native encoding;
518 * again, as addresses don't include a length field, we can't
519 * even show addresses with a different encoding type as raw
530 (void)snprintf(buf, sizeof(buf), "%s",
531 ip_to_str(tvb_get_ptr(tvb, offset + 2, len)));
536 (void)snprintf(buf, sizeof(buf), "%s",
537 ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 2, len)));
545 mask_len = tvb_get_guint8(tvb, offset + 3);
549 (void)snprintf(buf, sizeof(buf), "%s/%u",
550 ip_to_str(tvb_get_ptr(tvb, offset + 4, len)), mask_len);
555 (void)snprintf(buf, sizeof(buf), "%s/%u",
556 ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 4, len)), mask_len);
564 flags = tvb_get_guint8(tvb, offset + 2);
565 mask_len = tvb_get_guint8(tvb, offset + 3);
569 (void)snprintf(buf, sizeof(buf), "%s/%u",
570 ip_to_str(tvb_get_ptr(tvb, offset + 4, len)), mask_len);
575 (void)snprintf(buf, sizeof(buf), "%s/%u",
576 ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 4, len)), mask_len);
580 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
582 flags & 0x04 ? "S" : "",
583 flags & 0x02 ? "W" : "",
584 flags & 0x01 ? "R" : "");
596 static const value_string type2vals[] = {
599 { 2, "Register-stop" },
605 { 8, "Candidate-RP-Advertisement" },
610 * For PIM v2, see RFC 2362, and draft-ietf-pim-sm-v2-new-03 (when PIM
611 * is run over IPv6, the rules for computing the PIM checksum from the
612 * draft in question, not from RFC 2362, should be used).
615 dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
618 guint length, pim_length;
619 guint16 pim_cksum, computed_cksum;
623 proto_tree *pim_tree = NULL;
625 proto_tree *pimopt_tree = NULL;
628 if (check_col(pinfo->cinfo, COL_PROTOCOL))
629 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PIM");
630 if (check_col(pinfo->cinfo, COL_INFO))
631 col_clear(pinfo->cinfo, COL_INFO);
633 pim_typever = tvb_get_guint8(tvb, 0);
635 switch (PIM_VER(pim_typever)) {
637 typestr = val_to_str(PIM_TYPE(pim_typever), type2vals, "Unknown (%u)");
639 case 1: /* PIMv1 - we should never see this */
645 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
646 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "PIMv%d",
647 PIM_VER(pim_typever));
649 if (check_col(pinfo->cinfo, COL_INFO))
650 col_add_str(pinfo->cinfo, COL_INFO, typestr);
653 ti = proto_tree_add_item(tree, proto_pim, tvb, offset,
654 tvb_length_remaining(tvb, offset), FALSE);
655 pim_tree = proto_item_add_subtree(ti, ett_pim);
657 proto_tree_add_uint(pim_tree, hf_pim_version, tvb, offset, 1,
658 PIM_VER(pim_typever));
659 proto_tree_add_uint(pim_tree, hf_pim_type, tvb, offset, 1,
660 PIM_TYPE(pim_typever));
662 pim_cksum = tvb_get_ntohs(tvb, offset + 2);
663 length = tvb_length(tvb);
664 if (PIM_VER(pim_typever) == 2) {
666 * Well, it's PIM v2, so we can check whether this is a Register
667 * message, and thus can figure out how much to checksum and
668 * whether to make the columns read-only.
670 if (PIM_TYPE(pim_typever) == 1) {
672 * Register message - the PIM header is 8 bytes long.
673 * Also set the columns non-writable. Otherwise the IPv4 or
674 * IPv6 dissector for the encapsulated packet that caused
675 * this register will overwrite the PIM info in the columns.
678 col_set_writable(pinfo->cinfo, FALSE);
681 * Other message - checksum the entire packet.
683 pim_length = tvb_reported_length(tvb);
687 * We don't know what type of message this is, so say that
688 * the length is 0, to force it not to be checksummed.
692 if (!pinfo->fragmented && length >= pim_length) {
694 * The packet isn't part of a fragmented datagram and isn't
695 * truncated, so we can checksum it.
698 switch (pinfo->src.type) {
700 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length);
701 cksum_vec[0].len = pim_length;
702 computed_cksum = in_cksum(&cksum_vec[0], 1);
705 /* Set up the fields of the pseudo-header. */
706 cksum_vec[0].ptr = pinfo->src.data;
707 cksum_vec[0].len = pinfo->src.len;
708 cksum_vec[1].ptr = pinfo->dst.data;
709 cksum_vec[1].len = pinfo->dst.len;
710 cksum_vec[2].ptr = (const guint8 *)&phdr;
711 phdr[0] = htonl(pim_length);
712 phdr[1] = htonl(IP_PROTO_PIM);
713 cksum_vec[2].len = 8;
714 cksum_vec[3].ptr = tvb_get_ptr(tvb, 0, pim_length);
715 cksum_vec[3].len = pim_length;
716 computed_cksum = in_cksum(&cksum_vec[0], 4);
719 /* PIM is available for IPv4 and IPv6 right now */
720 computed_cksum = 0; /* squelch GCC complaints */
721 g_assert_not_reached();
725 if (computed_cksum == 0) {
726 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
727 offset + 2, 2, pim_cksum,
728 "Checksum: 0x%04x (correct)",
731 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
732 offset + 2, 2, pim_cksum,
733 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
734 pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum));
737 proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
738 offset + 2, 2, pim_cksum);
743 if (tvb_reported_length_remaining(tvb, offset) > 0) {
744 tiopt = proto_tree_add_text(pim_tree, tvb, offset,
745 tvb_length_remaining(tvb, offset), "PIM parameters");
746 pimopt_tree = proto_item_add_subtree(tiopt, ett_pim);
750 if (PIM_VER(pim_typever) != 2)
753 /* version 2 decoder */
754 switch (PIM_TYPE(pim_typever)) {
757 while (tvb_reported_length_remaining(tvb, offset) >= 2) {
758 if (tvb_get_ntohs(tvb, offset) == 1 &&
759 tvb_get_ntohs(tvb, offset + 2) == 2) {
762 holdtime = tvb_get_ntohs(tvb, offset + 4);
763 proto_tree_add_text(pimopt_tree, tvb, offset, 6,
764 "Holdtime: %u%s", holdtime,
765 holdtime == 0xffff ? " (infty)" : "");
773 case 1: /* register */
778 proto_tree *flag_tree = NULL;
781 flags = tvb_get_ntohl(tvb, offset);
782 tiflag = proto_tree_add_text(pimopt_tree, tvb, offset, 4,
783 "Flags: 0x%08x", flags);
784 flag_tree = proto_item_add_subtree(tiflag, ett_pim);
785 proto_tree_add_text(flag_tree, tvb, offset, 1, "%s",
786 decode_boolean_bitfield(flags, 0x80000000, 32,
787 "Border", "Not border"));
788 proto_tree_add_text(flag_tree, tvb, offset, 1, "%s",
789 decode_boolean_bitfield(flags, 0x40000000, 32,
790 "Null-Register", "Not Null-Register"));
794 * The rest of the packet is a multicast data packet.
796 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
799 * It's an IP packet - determine whether it's IPv4 or IPv6.
801 v_hl = tvb_get_guint8(tvb, offset);
802 switch((v_hl & 0xf0) >> 4) {
803 case 0: /* Null-Register dummy header.
804 * Has the same address family as the encapsulating PIM packet,
805 * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet.
807 if (pinfo->src.type == AT_IPv4) {
808 proto_tree_add_text(pimopt_tree, tvb, offset,
809 tvb_length_remaining(tvb, offset),
810 "IPv4 dummy header");
811 proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4,
813 ip_to_str(tvb_get_ptr(tvb, offset + 12, 4)));
814 proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4,
816 ip_to_str(tvb_get_ptr(tvb, offset + 16, 4)));
817 } else if (pinfo->src.type == AT_IPv6) {
818 struct ip6_hdr ip6_hdr;
819 tvb_memcpy(tvb, (guint8 *)&ip6_hdr, offset,
820 tvb_length_remaining(tvb, offset));
821 proto_tree_add_text(pimopt_tree, tvb, offset,
822 tvb_length_remaining(tvb, offset),
823 "IPv6 dummy header");
824 proto_tree_add_text(pimopt_tree, tvb,
825 offset + offsetof(struct ip6_hdr, ip6_src), 16,
827 ip6_to_str(&ip6_hdr.ip6_src));
828 proto_tree_add_text(pimopt_tree, tvb,
829 offset + offsetof(struct ip6_hdr, ip6_dst), 16,
831 ip6_to_str(&ip6_hdr.ip6_dst));
833 proto_tree_add_text(pimopt_tree, tvb, offset,
834 tvb_length_remaining(tvb, offset),
835 "Dummy header for an unknown protocol");
839 call_dissector(ip_handle, next_tvb, pinfo, tree);
841 call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree);
846 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
848 call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree);
852 proto_tree_add_text(pimopt_tree, tvb,
853 offset, tvb_length_remaining(tvb, offset),
854 "Unknown IP version %d", (v_hl & 0xf0) >> 4);
860 case 2: /* register-stop */
865 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
868 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s);
870 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
873 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s);
877 case 3: /* join/prune */
879 case 7: /* graft-ack */
884 int ngroup, i, njoin, nprune, j;
886 proto_tree *grouptree = NULL;
888 proto_tree *subtree = NULL;
891 if (PIM_TYPE(pim_typever) != 7) {
893 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
896 proto_tree_add_text(pimopt_tree, tvb, offset, advance,
897 "Upstream-neighbor: %s", s);
901 offset += 1; /* skip reserved field */
903 ngroup = tvb_get_guint8(tvb, offset);
904 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
905 "Groups: %u", ngroup);
908 if (PIM_TYPE(pim_typever) != 7) {
910 holdtime = tvb_get_ntohs(tvb, offset);
911 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
912 "Holdtime: %u%s", holdtime,
913 holdtime == 0xffff ? " (infty)" : "");
917 for (i = 0; i < ngroup; i++) {
918 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
921 tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance,
922 "Group %d: %s", i, s);
923 grouptree = proto_item_add_subtree(tigroup, ett_pim);
926 njoin = tvb_get_ntohs(tvb, offset);
927 nprune = tvb_get_ntohs(tvb, offset + 2);
929 tisub = proto_tree_add_text(grouptree, tvb, offset, 2,
931 subtree = proto_item_add_subtree(tisub, ett_pim);
933 for (j = 0; j < njoin; j++) {
934 s = dissect_pim_addr(tvb, off, pimv2_source,
938 proto_tree_add_text(subtree, tvb, off, advance,
939 "IP address: %s", s);
943 tisub = proto_tree_add_text(grouptree, tvb, offset + 2, 2,
944 "Prune: %d", nprune);
945 subtree = proto_item_add_subtree(tisub, ett_pim);
946 for (j = 0; j < nprune; j++) {
947 s = dissect_pim_addr(tvb, off, pimv2_source,
951 proto_tree_add_text(subtree, tvb, off, advance,
952 "IP address: %s", s);
960 case 4: /* bootstrap */
967 proto_tree *grouptree = NULL;
970 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
971 "Fragment tag: 0x%04x", tvb_get_ntohs(tvb, offset));
974 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
975 "Hash mask len: %u", tvb_get_guint8(tvb, offset));
977 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
978 "BSR priority: %u", tvb_get_guint8(tvb, offset));
981 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
984 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "BSR: %s", s);
987 for (i = 0; tvb_reported_length_remaining(tvb, offset) > 0; i++) {
988 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
991 tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance,
992 "Group %d: %s", i, s);
993 grouptree = proto_item_add_subtree(tigroup, ett_pim);
996 proto_tree_add_text(grouptree, tvb, offset, 1,
997 "RP count: %u", tvb_get_guint8(tvb, offset));
999 frpcnt = tvb_get_guint8(tvb, offset);
1000 proto_tree_add_text(grouptree, tvb, offset, 1,
1001 "FRP count: %u", frpcnt);
1004 for (j = 0; j < frpcnt; j++) {
1005 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1008 proto_tree_add_text(grouptree, tvb, offset, advance,
1012 holdtime = tvb_get_ntohs(tvb, offset);
1013 proto_tree_add_text(grouptree, tvb, offset, 2,
1014 "Holdtime: %u%s", holdtime,
1015 holdtime == 0xffff ? " (infty)" : "");
1017 proto_tree_add_text(grouptree, tvb, offset, 1,
1018 "Priority: %u", tvb_get_guint8(tvb, offset));
1019 offset += 2; /* also skips reserved field */
1027 case 5: /* assert */
1032 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1035 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s);
1038 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1041 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s);
1044 proto_tree_add_text(pimopt_tree, tvb, offset, 1, "%s",
1045 decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x80, 8,
1046 "RP Tree", "Not RP Tree"));
1047 proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Preference: %u",
1048 tvb_get_ntohl(tvb, offset) & 0x7fffffff);
1051 proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Metric: %u",
1052 tvb_get_ntohl(tvb, offset));
1057 case 8: /* Candidate-RP-Advertisement */
1065 pfxcnt = tvb_get_guint8(tvb, offset);
1066 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1067 "Prefix-count: %u", pfxcnt);
1069 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1070 "Priority: %u", tvb_get_guint8(tvb, offset));
1072 holdtime = tvb_get_ntohs(tvb, offset);
1073 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
1074 "Holdtime: %u%s", holdtime,
1075 holdtime == 0xffff ? " (infty)" : "");
1078 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1081 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "RP: %s", s);
1084 for (i = 0; i < pfxcnt; i++) {
1085 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1088 proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1089 "Group %d: %s", i, s);
1104 proto_register_pim(void)
1106 static hf_register_info hf[] = {
1108 { "Version", "pim.version",
1109 FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1111 { "Type", "pim.type",
1112 FT_UINT8, BASE_DEC, VALS(type2vals), 0x0, "", HFILL }},
1114 { "Code", "pim.code",
1115 FT_UINT8, BASE_DEC, VALS(type1vals), 0x0, "", HFILL }},
1117 { "Checksum", "pim.cksum",
1118 FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1120 static gint *ett[] = {
1124 proto_pim = proto_register_protocol("Protocol Independent Multicast",
1126 proto_register_field_array(proto_pim, hf, array_length(hf));
1127 proto_register_subtree_array(ett, array_length(ett));
1131 proto_reg_handoff_pim(void)
1133 dissector_handle_t pim_handle;
1135 pim_handle = create_dissector_handle(dissect_pim, proto_pim);
1136 dissector_add("ip.proto", IP_PROTO_PIM, pim_handle);
1139 * Get handles for the IPv4 and IPv6 dissectors.
1141 ip_handle = find_dissector("ip");
1142 ipv6_handle = find_dissector("ipv6");