2 * Routines for PIM disassembly
3 * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-pim.c,v 1.31 2001/07/02 09:42:40 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"
48 #include "packet-ipv6.h"
51 #define PIM_TYPE(x) ((x) & 0x0f)
52 #define PIM_VER(x) (((x) & 0xf0) >> 4)
55 pimv2_unicast, pimv2_group, pimv2_source
58 static int proto_pim = -1;
59 static int hf_pim_version = -1;
60 static int hf_pim_type = -1;
61 static int hf_pim_code = -1;
62 static int hf_pim_cksum = -1;
64 static gint ett_pim = -1;
66 static dissector_handle_t ip_handle;
67 static dissector_handle_t ipv6_handle;
70 * Address family values.
72 #define PIM_AF_RESERVED 0
73 #define PIM_AF_IP 1 /* IPv4 */
74 #define PIM_AF_IPV6 2 /* IPv6 */
75 #define PIM_AF_NSAP 3 /* NSAP */
76 #define PIM_AF_HDLC 4 /* HDLC (8-bit multidrop) */
77 #define PIM_AF_BBN_1822 5 /* BBN 1822 */
78 #define PIM_AF_802 6 /* 802 (D/I/X Ethernet, 802.x, FDDI) */
79 #define PIM_AF_E_163 7 /* E.163 */
80 #define PIM_AF_E_164 8 /* E.164 (SMDS, Frame Relay, ATM) */
81 #define PIM_AF_F_69 9 /* F.69 (Telex) */
82 #define PIM_AF_X_121 10 /* X.121 (X.25, Frame Relay) */
83 #define PIM_AF_IPX 11 /* IPX */
84 #define PIM_AF_ATALK 12 /* Appletalk */
85 #define PIM_AF_DECNET_IV 13 /* DECnet Phase IV */
86 #define PIM_AF_VINES 14 /* Banyan Vines */
87 #define PIM_AF_E_164_NSAP 15 /* E.164 with NSAP format subaddress */
90 * For PIM v1, see the PDF slides at
92 * http://www.mbone.de/training/Module3.pdf
94 * Is it documented anywhere else?
97 dissect_pimv1_addr(tvbuff_t *tvb, int offset) {
99 guint16 flags_masklen;
101 flags_masklen = tvb_get_ntohs(tvb, offset);
102 if (flags_masklen & 0x0180) {
103 (void)snprintf(buf, sizeof(buf),
105 flags_masklen & 0x0100 ? "S" : "",
106 flags_masklen & 0x0080 ? "W" : "",
107 flags_masklen & 0x0040 ? "R" : "");
110 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "%s/%u",
111 ip_to_str(tvb_get_ptr(tvb, offset + 2, 4)), flags_masklen & 0x3f);
116 static const value_string type1vals[] = {
119 { 2, "Register-stop" },
121 { 4, "RP-Reachable" },
129 /* This function is only called from the IGMP dissector */
131 dissect_pimv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
135 guint length, pim_length;
136 guint16 pim_cksum, computed_cksum;
138 proto_tree *pim_tree = NULL;
140 proto_tree *pimopt_tree = NULL;
143 if (!proto_is_protocol_enabled(proto_pim)) {
145 * We are not enabled; skip entire packet to be nice to the
146 * IGMP layer (so clicking on IGMP will display the data).
148 return offset+tvb_length_remaining(tvb, offset);
151 if (check_col(pinfo->fd, COL_PROTOCOL))
152 col_set_str(pinfo->fd, COL_PROTOCOL, "PIMv1");
153 if (check_col(pinfo->fd, COL_INFO))
154 col_clear(pinfo->fd, COL_INFO);
157 ti = proto_tree_add_item(tree, proto_pim, tvb, offset,
158 tvb_length_remaining(tvb, offset), FALSE);
159 pim_tree = proto_item_add_subtree(ti, ett_pim);
161 /* Put IGMP type, 0x14, into the tree */
162 proto_tree_add_text(pim_tree, tvb, offset, 1,
167 pim_type = tvb_get_guint8(tvb, offset);
168 if (check_col(pinfo->fd, COL_INFO))
169 col_add_str(pinfo->fd, COL_INFO,
170 val_to_str(pim_type, type1vals, "Unknown (%u)"));
173 proto_tree_add_uint(pim_tree, hf_pim_code, tvb, offset, 1, pim_type);
177 pim_cksum = tvb_get_ntohs(tvb, offset);
178 pim_ver = PIM_VER(tvb_get_guint8(tvb, offset + 2));
181 * Not PIMv1 - what gives?
184 proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
185 offset, 2, pim_cksum);
189 proto_tree_add_uint(pim_tree, hf_pim_version, tvb, offset, 1, pim_ver);
190 return offset+tvb_length_remaining(tvb, offset);
194 * Well, it's PIM v1, so we can check whether this is a
195 * Register message, and thus can figure out how much to
196 * checksum and whether to make the columns read-only.
198 length = tvb_length(tvb);
201 * Register message - the PIM header is 8 bytes long.
202 * Also set the columns non-writable. Otherwise the IPv4 or
203 * IPv6 dissector for the encapsulated packet that caused
204 * this register will overwrite the PIM info in the columns.
207 col_set_writable(pinfo->fd, FALSE);
210 * Other message - checksum the entire packet.
212 pim_length = tvb_reported_length(tvb);
216 if (!pinfo->fragmented && length >= pim_length) {
218 * The packet isn't part of a fragmented datagram and isn't
219 * truncated, so we can checksum it.
221 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length);
222 cksum_vec[0].len = pim_length;
223 computed_cksum = in_cksum(&cksum_vec[0], 1);
224 if (computed_cksum == 0) {
225 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
226 offset, 2, pim_cksum,
227 "Checksum: 0x%04x (correct)",
230 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
231 offset, 2, pim_cksum,
232 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
233 pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum));
236 proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
237 offset, 2, pim_cksum);
243 proto_tree_add_uint(pim_tree, hf_pim_version, tvb, offset, 1, pim_ver);
246 offset += 3; /* skip reserved stuff */
249 if (tvb_reported_length_remaining(tvb, offset) > 0) {
250 tiopt = proto_tree_add_text(pim_tree, tvb, offset,
251 tvb_length_remaining(tvb, offset), "PIM parameters");
252 pimopt_tree = proto_item_add_subtree(tiopt, ett_pim);
256 /* version 1 decoder */
262 static const value_string pimv1_modevals[] = {
265 { 2, "Sparse-Dense" },
269 mode = tvb_get_guint8(tvb, offset) >> 4;
270 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
272 val_to_str(mode, pimv1_modevals, "Unknown (%u)"));
274 holdtime = tvb_get_ntohs(tvb, offset);
275 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
276 "Holdtime: %u%s", holdtime,
277 holdtime == 0xffff ? " (infty)" : "");
282 case 1: /* register */
288 * The rest of the packet is a multicast data packet.
290 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
293 * It's an IP packet - determine whether it's IPv4 or IPv6.
295 v_hl = tvb_get_guint8(tvb, offset);
296 switch((v_hl & 0xf0) >> 4) {
297 case 0: /* Null-Register dummy header.
298 * Has the same address family as the encapsulating PIM packet,
299 * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet.
301 if (pinfo->src.type == AT_IPv4) {
302 proto_tree_add_text(pimopt_tree, tvb, offset,
303 tvb_length_remaining(tvb, offset),
304 "IPv4 dummy header");
305 proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4,
307 ip_to_str(tvb_get_ptr(tvb, offset + 12, 4)));
308 proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4,
310 ip_to_str(tvb_get_ptr(tvb, offset + 16, 4)));
311 } else if (pinfo->src.type == AT_IPv6) {
312 struct ip6_hdr ip6_hdr;
313 tvb_memcpy(tvb, (guint8 *)&ip6_hdr, offset,
314 tvb_length_remaining(tvb, offset));
315 proto_tree_add_text(pimopt_tree, tvb, offset,
316 tvb_length_remaining(tvb, offset),
317 "IPv6 dummy header");
318 proto_tree_add_text(pimopt_tree, tvb,
319 offset + offsetof(struct ip6_hdr, ip6_src), 16,
321 ip6_to_str(&ip6_hdr.ip6_src));
322 proto_tree_add_text(pimopt_tree, tvb,
323 offset + offsetof(struct ip6_hdr, ip6_dst), 16,
325 ip6_to_str(&ip6_hdr.ip6_dst));
327 proto_tree_add_text(pimopt_tree, tvb, offset,
328 tvb_length_remaining(tvb, offset),
329 "Dummy header for an unknown protocol");
333 call_dissector(ip_handle, next_tvb, pinfo, tree);
335 call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree);
340 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
342 call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree);
346 proto_tree_add_text(pimopt_tree, tvb,
347 offset, tvb_length_remaining(tvb, offset),
348 "Unknown IP version %d", (v_hl & 0xf0) >> 4);
354 case 2: /* register-stop */
356 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
358 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
360 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
362 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
367 case 3: /* join/prune */
369 case 7: /* graft-ack */
373 int ngroup, i, njoin, nprune, j;
377 proto_tree *grouptree = NULL;
379 proto_tree *subtree = NULL;
382 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
383 "Upstream-neighbor: %s",
384 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
387 offset += 2; /* skip reserved stuff */
389 holdtime = tvb_get_ntohs(tvb, offset);
390 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
391 "Holdtime: %u%s", holdtime,
392 holdtime == 0xffff ? " (infty)" : "");
395 offset += 1; /* skip reserved stuff */
397 mask_len = tvb_get_guint8(tvb, offset);
398 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
399 "Mask length: %u", mask_len);
402 adr_len = tvb_get_guint8(tvb, offset);
403 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
404 "Address length: %u", adr_len);
407 ngroup = tvb_get_guint8(tvb, offset);
408 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
409 "Groups: %u", ngroup);
412 for (i = 0; i < ngroup; i++) {
413 tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, 4,
415 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
416 grouptree = proto_item_add_subtree(tigroup, ett_pim);
419 proto_tree_add_text(grouptree, tvb, offset, 4,
420 "Group %d Mask: %s", i,
421 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
424 njoin = tvb_get_ntohs(tvb, offset);
425 nprune = tvb_get_ntohs(tvb, offset + 2);
427 tisub = proto_tree_add_text(grouptree, tvb, offset, 2,
429 subtree = proto_item_add_subtree(tisub, ett_pim);
431 for (j = 0; j < njoin; j++) {
432 s = dissect_pimv1_addr(tvb, off);
433 proto_tree_add_text(subtree, tvb, off, 6,
434 "IP address: %s", s);
438 tisub = proto_tree_add_text(grouptree, tvb, offset + 2, 2,
439 "Prune: %d", nprune);
440 subtree = proto_item_add_subtree(tisub, ett_pim);
441 for (j = 0; j < nprune; j++) {
442 s = dissect_pimv1_addr(tvb, off);
443 proto_tree_add_text(subtree, tvb, off, 6,
444 "IP address: %s", s);
451 case 4: /* rp-reachability */
455 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
457 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
460 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
462 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
465 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
467 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
470 offset += 2; /* skip reserved stuff */
472 holdtime = tvb_get_ntohs(tvb, offset);
473 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
474 "Holdtime: %u%s", holdtime,
475 holdtime == 0xffff ? " (infty)" : "");
482 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
484 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
487 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
489 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
492 proto_tree_add_text(pimopt_tree, tvb, offset, 1, "%s",
493 decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x80, 8,
494 "RP Tree", "Not RP Tree"));
495 proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Preference: %u",
496 tvb_get_ntohl(tvb, offset) & 0x7fffffff);
499 proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Metric: %u",
500 tvb_get_ntohl(tvb, offset));
511 return offset+tvb_length_remaining(tvb, offset);
515 dissect_pim_addr(tvbuff_t *tvb, int offset, enum pimv2_addrtype at,
517 static char buf[512];
524 af = tvb_get_guint8(tvb, offset);
525 if (af != PIM_AF_IP && af != PIM_AF_IPV6) {
527 * We don't handle the other formats, and addresses don't include
528 * a length field, so we can't even show them as raw bytes.
533 et = tvb_get_guint8(tvb, offset + 1);
536 * The only defined encoding type is 0, for the native encoding;
537 * again, as addresses don't include a length field, we can't
538 * even show addresses with a different encoding type as raw
549 (void)snprintf(buf, sizeof(buf), "%s",
550 ip_to_str(tvb_get_ptr(tvb, offset + 2, len)));
555 (void)snprintf(buf, sizeof(buf), "%s",
556 ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 2, len)));
564 mask_len = tvb_get_guint8(tvb, offset + 3);
568 (void)snprintf(buf, sizeof(buf), "%s/%u",
569 ip_to_str(tvb_get_ptr(tvb, offset + 4, len)), mask_len);
574 (void)snprintf(buf, sizeof(buf), "%s/%u",
575 ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 4, len)), mask_len);
583 flags = tvb_get_guint8(tvb, offset + 2);
584 mask_len = tvb_get_guint8(tvb, offset + 3);
588 (void)snprintf(buf, sizeof(buf), "%s/%u",
589 ip_to_str(tvb_get_ptr(tvb, offset + 4, len)), mask_len);
594 (void)snprintf(buf, sizeof(buf), "%s/%u",
595 ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 4, len)), mask_len);
599 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
601 flags & 0x04 ? "S" : "",
602 flags & 0x02 ? "W" : "",
603 flags & 0x01 ? "R" : "");
615 static const value_string type2vals[] = {
618 { 2, "Register-stop" },
624 { 8, "Candidate-RP-Advertisement" },
629 dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
632 guint length, pim_length;
633 guint16 pim_cksum, computed_cksum;
636 proto_tree *pim_tree = NULL;
638 proto_tree *pimopt_tree = NULL;
641 if (check_col(pinfo->fd, COL_PROTOCOL))
642 col_set_str(pinfo->fd, COL_PROTOCOL, "PIM");
643 if (check_col(pinfo->fd, COL_INFO))
644 col_clear(pinfo->fd, COL_INFO);
646 pim_typever = tvb_get_guint8(tvb, 0);
648 switch (PIM_VER(pim_typever)) {
650 typestr = val_to_str(PIM_TYPE(pim_typever), type2vals, "Unknown (%u)");
652 case 1: /* PIMv1 - we should never see this */
658 if (check_col(pinfo->fd, COL_PROTOCOL)) {
659 col_add_fstr(pinfo->fd, COL_PROTOCOL, "PIMv%d",
660 PIM_VER(pim_typever));
662 if (check_col(pinfo->fd, COL_INFO))
663 col_add_str(pinfo->fd, COL_INFO, typestr);
666 ti = proto_tree_add_item(tree, proto_pim, tvb, offset,
667 tvb_length_remaining(tvb, offset), FALSE);
668 pim_tree = proto_item_add_subtree(ti, ett_pim);
670 proto_tree_add_uint(pim_tree, hf_pim_version, tvb, offset, 1,
671 PIM_VER(pim_typever));
672 proto_tree_add_uint(pim_tree, hf_pim_type, tvb, offset, 1,
673 PIM_TYPE(pim_typever));
675 pim_cksum = tvb_get_ntohs(tvb, offset + 2);
676 length = tvb_length(tvb);
677 if (PIM_VER(pim_typever) == 2) {
679 * Well, it's PIM v2, so we can check whether this is a Register
680 * message, and thus can figure out how much to checksum and
681 * whether to make the columns read-only.
683 if (PIM_TYPE(pim_typever) == 1) {
685 * Register message - the PIM header is 8 bytes long.
686 * Also set the columns non-writable. Otherwise the IPv4 or
687 * IPv6 dissector for the encapsulated packet that caused
688 * this register will overwrite the PIM info in the columns.
691 col_set_writable(pinfo->fd, FALSE);
694 * Other message - checksum the entire packet.
696 pim_length = tvb_reported_length(tvb);
700 * We don't know what type of message this is, so say that
701 * the length is 0, to force it not to be checksummed.
705 if (!pinfo->fragmented && length >= pim_length) {
707 * The packet isn't part of a fragmented datagram and isn't
708 * truncated, so we can checksum it.
710 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length);
711 cksum_vec[0].len = pim_length;
712 computed_cksum = in_cksum(&cksum_vec[0], 1);
713 if (computed_cksum == 0) {
714 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
715 offset + 2, 2, pim_cksum,
716 "Checksum: 0x%04x (correct)",
719 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
720 offset + 2, 2, pim_cksum,
721 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
722 pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum));
725 proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
726 offset + 2, 2, pim_cksum);
731 if (tvb_reported_length_remaining(tvb, offset) > 0) {
732 tiopt = proto_tree_add_text(pim_tree, tvb, offset,
733 tvb_length_remaining(tvb, offset), "PIM parameters");
734 pimopt_tree = proto_item_add_subtree(tiopt, ett_pim);
738 if (PIM_VER(pim_typever) != 2)
741 /* version 2 decoder */
742 switch (PIM_TYPE(pim_typever)) {
745 while (tvb_reported_length_remaining(tvb, offset) >= 2) {
746 if (tvb_get_ntohs(tvb, offset) == 1 &&
747 tvb_get_ntohs(tvb, offset + 2) == 2) {
750 holdtime = tvb_get_ntohs(tvb, offset + 4);
751 proto_tree_add_text(pimopt_tree, tvb, offset, 6,
752 "Holdtime: %u%s", holdtime,
753 holdtime == 0xffff ? " (infty)" : "");
761 case 1: /* register */
766 proto_tree *flag_tree = NULL;
769 flags = tvb_get_ntohl(tvb, offset);
770 tiflag = proto_tree_add_text(pimopt_tree, tvb, offset, 4,
771 "Flags: 0x%08x", flags);
772 flag_tree = proto_item_add_subtree(tiflag, ett_pim);
773 proto_tree_add_text(flag_tree, tvb, offset, 1, "%s",
774 decode_boolean_bitfield(flags, 0x80000000, 32,
775 "Border", "Not border"));
776 proto_tree_add_text(flag_tree, tvb, offset, 1, "%s",
777 decode_boolean_bitfield(flags, 0x40000000, 32,
778 "Null-Register", "Not Null-Register"));
782 * The rest of the packet is a multicast data packet.
784 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
787 * It's an IP packet - determine whether it's IPv4 or IPv6.
789 v_hl = tvb_get_guint8(tvb, offset);
790 switch((v_hl & 0xf0) >> 4) {
791 case 0: /* Null-Register dummy header.
792 * Has the same address family as the encapsulating PIM packet,
793 * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet.
795 if (pinfo->src.type == AT_IPv4) {
796 proto_tree_add_text(pimopt_tree, tvb, offset,
797 tvb_length_remaining(tvb, offset),
798 "IPv4 dummy header");
799 proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4,
801 ip_to_str(tvb_get_ptr(tvb, offset + 12, 4)));
802 proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4,
804 ip_to_str(tvb_get_ptr(tvb, offset + 16, 4)));
805 } else if (pinfo->src.type == AT_IPv6) {
806 struct ip6_hdr ip6_hdr;
807 tvb_memcpy(tvb, (guint8 *)&ip6_hdr, offset,
808 tvb_length_remaining(tvb, offset));
809 proto_tree_add_text(pimopt_tree, tvb, offset,
810 tvb_length_remaining(tvb, offset),
811 "IPv6 dummy header");
812 proto_tree_add_text(pimopt_tree, tvb,
813 offset + offsetof(struct ip6_hdr, ip6_src), 16,
815 ip6_to_str(&ip6_hdr.ip6_src));
816 proto_tree_add_text(pimopt_tree, tvb,
817 offset + offsetof(struct ip6_hdr, ip6_dst), 16,
819 ip6_to_str(&ip6_hdr.ip6_dst));
821 proto_tree_add_text(pimopt_tree, tvb, offset,
822 tvb_length_remaining(tvb, offset),
823 "Dummy header for an unknown protocol");
827 call_dissector(ip_handle, next_tvb, pinfo, tree);
829 call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree);
834 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
836 call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree);
840 proto_tree_add_text(pimopt_tree, tvb,
841 offset, tvb_length_remaining(tvb, offset),
842 "Unknown IP version %d", (v_hl & 0xf0) >> 4);
848 case 2: /* register-stop */
853 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
856 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s);
858 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
861 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s);
865 case 3: /* join/prune */
867 case 7: /* graft-ack */
872 int ngroup, i, njoin, nprune, j;
874 proto_tree *grouptree = NULL;
876 proto_tree *subtree = NULL;
879 if (PIM_TYPE(pim_typever) != 7) {
881 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
884 proto_tree_add_text(pimopt_tree, tvb, offset, advance,
885 "Upstream-neighbor: %s", s);
889 offset += 1; /* skip reserved field */
891 ngroup = tvb_get_guint8(tvb, offset);
892 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
893 "Groups: %u", ngroup);
896 if (PIM_TYPE(pim_typever) != 7) {
898 holdtime = tvb_get_ntohs(tvb, offset);
899 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
900 "Holdtime: %u%s", holdtime,
901 holdtime == 0xffff ? " (infty)" : "");
905 for (i = 0; i < ngroup; i++) {
906 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
909 tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance,
910 "Group %d: %s", i, s);
911 grouptree = proto_item_add_subtree(tigroup, ett_pim);
914 njoin = tvb_get_ntohs(tvb, offset);
915 nprune = tvb_get_ntohs(tvb, offset + 2);
917 tisub = proto_tree_add_text(grouptree, tvb, offset, 2,
919 subtree = proto_item_add_subtree(tisub, ett_pim);
921 for (j = 0; j < njoin; j++) {
922 s = dissect_pim_addr(tvb, off, pimv2_source,
926 proto_tree_add_text(subtree, tvb, off, advance,
927 "IP address: %s", s);
931 tisub = proto_tree_add_text(grouptree, tvb, offset + 2, 2,
932 "Prune: %d", nprune);
933 subtree = proto_item_add_subtree(tisub, ett_pim);
934 for (j = 0; j < nprune; j++) {
935 s = dissect_pim_addr(tvb, off, pimv2_source,
939 proto_tree_add_text(subtree, tvb, off, advance,
940 "IP address: %s", s);
948 case 4: /* bootstrap */
955 proto_tree *grouptree = NULL;
958 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
959 "Fragment tag: 0x%04x", tvb_get_ntohs(tvb, offset));
962 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
963 "Hash mask len: %u", tvb_get_guint8(tvb, offset));
965 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
966 "BSR priority: %u", tvb_get_guint8(tvb, offset));
969 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
972 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "BSR: %s", s);
975 for (i = 0; tvb_reported_length_remaining(tvb, offset) > 0; i++) {
976 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
979 tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance,
980 "Group %d: %s", i, s);
981 grouptree = proto_item_add_subtree(tigroup, ett_pim);
984 proto_tree_add_text(grouptree, tvb, offset, 1,
985 "RP count: %u", tvb_get_guint8(tvb, offset));
987 frpcnt = tvb_get_guint8(tvb, offset);
988 proto_tree_add_text(grouptree, tvb, offset, 1,
989 "FRP count: %u", frpcnt);
992 for (j = 0; j < frpcnt; j++) {
993 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
996 proto_tree_add_text(grouptree, tvb, offset, advance,
1000 holdtime = tvb_get_ntohs(tvb, offset);
1001 proto_tree_add_text(grouptree, tvb, offset, 2,
1002 "Holdtime: %u%s", holdtime,
1003 holdtime == 0xffff ? " (infty)" : "");
1005 proto_tree_add_text(grouptree, tvb, offset, 1,
1006 "Priority: %u", tvb_get_guint8(tvb, offset));
1007 offset += 2; /* also skips reserved field */
1015 case 5: /* assert */
1020 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1023 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s);
1026 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1029 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s);
1032 proto_tree_add_text(pimopt_tree, tvb, offset, 1, "%s",
1033 decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x80, 8,
1034 "RP Tree", "Not RP Tree"));
1035 proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Preference: %u",
1036 tvb_get_ntohl(tvb, offset) & 0x7fffffff);
1039 proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Metric: %u",
1040 tvb_get_ntohl(tvb, offset));
1045 case 8: /* Candidate-RP-Advertisement */
1053 pfxcnt = tvb_get_guint8(tvb, offset);
1054 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1055 "Prefix-count: %u", pfxcnt);
1057 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1058 "Priority: %u", tvb_get_guint8(tvb, offset));
1060 holdtime = tvb_get_ntohs(tvb, offset);
1061 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
1062 "Holdtime: %u%s", holdtime,
1063 holdtime == 0xffff ? " (infty)" : "");
1066 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1069 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "RP: %s", s);
1072 for (i = 0; i < pfxcnt; i++) {
1073 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1076 proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1077 "Group %d: %s", i, s);
1092 proto_register_pim(void)
1094 static hf_register_info hf[] = {
1096 { "Version", "pim.version",
1097 FT_UINT8, BASE_DEC, NULL, 0x0, "", HFILL }},
1099 { "Type", "pim.type",
1100 FT_UINT8, BASE_DEC, VALS(type2vals), 0x0, "", HFILL }},
1102 { "Code", "pim.code",
1103 FT_UINT8, BASE_DEC, VALS(type1vals), 0x0, "", HFILL }},
1105 { "Checksum", "pim.cksum",
1106 FT_UINT16, BASE_HEX, NULL, 0x0, "", HFILL }},
1108 static gint *ett[] = {
1112 proto_pim = proto_register_protocol("Protocol Independent Multicast",
1114 proto_register_field_array(proto_pim, hf, array_length(hf));
1115 proto_register_subtree_array(ett, array_length(ett));
1119 proto_reg_handoff_pim(void)
1121 dissector_add("ip.proto", IP_PROTO_PIM, dissect_pim, proto_pim);
1124 * Get handles for the IPv4 and IPv6 dissectors.
1126 ip_handle = find_dissector("ip");
1127 ipv6_handle = find_dissector("ipv6");