2 * Routines for PIM disassembly
3 * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org>
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
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.
32 #include <epan/packet.h>
33 #include <epan/ipproto.h>
35 #include <epan/in_cksum.h>
36 #include "packet-pim.h"
38 #define PIM_TYPE(x) ((x) & 0x0f)
39 #define PIM_VER(x) (((x) & 0xf0) >> 4)
42 pimv2_unicast, pimv2_group, pimv2_source
45 static int proto_pim = -1;
46 static int hf_pim_version = -1;
47 static int hf_pim_type = -1;
48 static int hf_pim_code = -1;
49 static int hf_pim_cksum = -1;
50 static int hf_pim_res_bytes = -1;
51 /* PIM Hello options (RFC 4601, section 4.9.2 and RFC 3973, section 4.7.5) */
52 static int hf_pim_optiontype = -1;
53 static int hf_pim_optionlength = -1;
54 static int hf_pim_optionvalue = -1;
55 static int hf_pim_mode = -1;
56 static int hf_pim_holdtime = -1;
57 static int hf_pim_numgroups = -1;
58 static int hf_pim_numjoins = -1;
59 static int hf_pim_numprunes = -1;
60 static int hf_pim_t = -1;
61 static int hf_pim_propagation_delay = -1;
62 static int hf_pim_override_interval = -1;
63 static int hf_pim_dr_priority = -1;
64 static int hf_pim_generation_id = -1;
65 static int hf_pim_state_refresh_version = -1;
66 static int hf_pim_state_refresh_interval = -1;
67 static int hf_pim_state_refresh_reserved = -1;
69 static int hf_pim_rpt = -1;
70 static int hf_pim_metric_pref = -1;
71 static int hf_pim_metric = -1;
73 static gint ett_pim = -1;
74 static gint ett_pim_opts = -1;
75 static gint ett_pim_opt = -1;
77 static dissector_handle_t ip_handle;
78 static dissector_handle_t ipv6_handle;
83 * ftp://ftp.usc.edu/pub/csinfo/tech-reports/papers/95-599.ps.Z
85 * NOTE: There is still some doubt that this is THE definitive PIMv1
86 * specification. Of note, the type1vals entry, { 8, "Mode" }, does
87 * not appear as a valid code in the referenced document above.
89 * This one is likely closer to the last PIMv1 spec:
90 * http://tools.ietf.org/id/draft-ietf-idmr-pim-spec-02.txt
93 dissect_pimv1_addr(tvbuff_t *tvb, int offset) {
94 guint16 flags_masklen;
96 flags_masklen = tvb_get_ntohs(tvb, offset);
97 if (flags_masklen & 0x0180) {
98 return ep_strdup_printf("(%s%s%s) ",
99 flags_masklen & 0x0100 ? "S" : "",
100 flags_masklen & 0x0080 ? "W" : "",
101 flags_masklen & 0x0040 ? "R" : "");
103 return ep_strdup_printf("%s/%u",
104 tvb_ip_to_str(tvb, offset + 2), flags_masklen & 0x3f);
108 static const value_string type1vals[] = {
111 { 2, "Register-stop" },
113 { 4, "RP-Reachable" },
121 static const value_string pimv1_modevals[] = {
124 { 2, "Sparse-Dense" },
128 /* This function is only called from the IGMP dissector */
130 dissect_pimv1(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree,
134 guint length, pim_length;
135 guint16 pim_cksum, computed_cksum;
137 proto_tree *pim_tree = NULL;
139 proto_tree *pimopt_tree = NULL;
142 if (!proto_is_protocol_enabled(find_protocol_by_id(proto_pim))) {
144 * We are not enabled; skip entire packet to be nice to the
145 * IGMP layer (so clicking on IGMP will display the data).
147 return offset+tvb_length_remaining(tvb, offset);
150 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PIMv1");
151 col_clear(pinfo->cinfo, COL_INFO);
153 ti = proto_tree_add_item(tree, proto_pim, tvb, offset, -1, FALSE);
154 pim_tree = proto_item_add_subtree(ti, ett_pim);
156 /* Put IGMP type, 0x14, into the tree */
157 proto_tree_add_text(pim_tree, tvb, offset, 1,
161 pim_type = tvb_get_guint8(tvb, offset);
162 if (check_col(pinfo->cinfo, COL_INFO))
163 col_add_str(pinfo->cinfo, COL_INFO,
164 val_to_str(pim_type, type1vals, "Unknown (%u)"));
166 proto_tree_add_uint(pim_tree, hf_pim_code, tvb, offset, 1, pim_type);
169 pim_cksum = tvb_get_ntohs(tvb, offset);
170 pim_ver = PIM_VER(tvb_get_guint8(tvb, offset + 2));
173 * Not PIMv1 - what gives?
175 proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
176 offset, 2, pim_cksum);
179 proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, ENC_BIG_ENDIAN);
180 return offset+tvb_length_remaining(tvb, offset);
184 * Well, it's PIM v1, so we can check whether this is a
185 * Register message, and thus can figure out how much to
186 * checksum and whether to make the columns read-only.
188 length = tvb_length(tvb);
191 * Register message - the PIM header is 8 bytes long.
192 * Also set the columns non-writable. Otherwise the IPv4 or
193 * IPv6 dissector for the encapsulated packet that caused
194 * this register will overwrite the PIM info in the columns.
197 col_set_writable(pinfo->cinfo, FALSE);
200 * Other message - checksum the entire packet.
202 pim_length = tvb_reported_length(tvb);
205 if (!pinfo->fragmented && length >= pim_length) {
207 * The packet isn't part of a fragmented datagram and isn't
208 * truncated, so we can checksum it.
210 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length);
211 cksum_vec[0].len = pim_length;
212 computed_cksum = in_cksum(&cksum_vec[0], 1);
213 if (computed_cksum == 0) {
214 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
215 offset, 2, pim_cksum,
216 "Checksum: 0x%04x [correct]",
219 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
220 offset, 2, pim_cksum,
221 "Checksum: 0x%04x [incorrect, should be 0x%04x]",
222 pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum));
225 proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
226 offset, 2, pim_cksum);
230 proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, ENC_BIG_ENDIAN);
233 offset += 3; /* skip reserved stuff */
235 if (tvb_reported_length_remaining(tvb, offset) > 0) {
236 tiopt = proto_tree_add_text(pim_tree, tvb, offset, -1, "PIM options");
237 pimopt_tree = proto_item_add_subtree(tiopt, ett_pim_opts);
241 /* version 1 decoder */
247 proto_tree_add_item(pimopt_tree, hf_pim_mode, tvb, offset, 1, ENC_BIG_ENDIAN);
250 holdtime = tvb_get_ntohs(tvb, offset);
251 proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb,
253 "Holdtime: %us %s", holdtime,
254 holdtime == 0xffff ? "(infinity)": "");
259 case 1: /* register */
265 * The rest of the packet is a multicast data packet.
267 next_tvb = tvb_new_subset_remaining(tvb, offset);
270 * It's an IP packet - determine whether it's IPv4 or IPv6.
272 v_hl = tvb_get_guint8(tvb, offset);
273 switch((v_hl & 0xf0) >> 4) {
274 case 0: /* Null-Register dummy header.
275 * Has the same address family as the encapsulating PIM packet,
276 * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet.
278 if (pinfo->src.type == AT_IPv4) {
279 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
280 "IPv4 dummy header");
281 proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4,
283 tvb_ip_to_str(tvb, offset + 12));
284 proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4,
286 tvb_ip_to_str(tvb, offset + 16));
287 } else if (pinfo->src.type == AT_IPv6) {
288 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
289 "IPv6 dummy header");
290 proto_tree_add_text(pimopt_tree, tvb,
293 tvb_ip6_to_str(tvb, offset + 8));
294 proto_tree_add_text(pimopt_tree, tvb,
297 tvb_ip6_to_str(tvb, offset + 8));
299 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
300 "Dummy header for an unknown protocol");
304 call_dissector(ip_handle, next_tvb, pinfo, tree);
306 call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree);
311 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
313 call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree);
317 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
318 "Unknown IP version %d", (v_hl & 0xf0) >> 4);
324 case 2: /* register-stop */
326 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
328 tvb_ip_to_str(tvb, offset));
330 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
332 tvb_ip_to_str(tvb, offset));
337 case 3: /* join/prune */
339 case 7: /* graft-ack */
343 int ngroup, i, njoin, nprune, j;
347 proto_tree *grouptree = NULL;
349 proto_tree *subtree = NULL;
352 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
353 "Upstream-neighbor: %s",
354 tvb_ip_to_str(tvb, offset));
357 offset += 2; /* skip reserved stuff */
359 holdtime = tvb_get_ntohs(tvb, offset);
360 proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb,
362 "Holdtime: %us %s", holdtime,
363 holdtime == 0xffff ? "(infinity)": "");
366 offset += 1; /* skip reserved stuff */
368 mask_len = tvb_get_guint8(tvb, offset);
369 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
370 "Mask length: %u", mask_len);
373 adr_len = tvb_get_guint8(tvb, offset);
374 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
375 "Address length: %u", adr_len);
378 ngroup = tvb_get_guint8(tvb, offset);
379 proto_tree_add_item(pimopt_tree, hf_pim_numgroups, tvb, offset, 1, ENC_BIG_ENDIAN);
382 for (i = 0; i < ngroup; i++) {
384 * XXX - does the group address have the length "adr_len"
385 * and the group mask the length "mask_len"?
387 tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, 4,
389 tvb_ip_to_str(tvb, offset));
390 grouptree = proto_item_add_subtree(tigroup, ett_pim);
393 proto_tree_add_text(grouptree, tvb, offset, 4,
394 "Group %d Mask: %s", i,
395 tvb_ip_to_str(tvb, offset));
398 njoin = tvb_get_ntohs(tvb, offset);
399 nprune = tvb_get_ntohs(tvb, offset + 2);
400 tisub = proto_tree_add_item(grouptree, hf_pim_numjoins, tvb,
401 offset, 2, ENC_BIG_ENDIAN);
402 subtree = proto_item_add_subtree(tisub, ett_pim);
404 for (j = 0; j < njoin; j++) {
405 s = dissect_pimv1_addr(tvb, off);
406 proto_tree_add_text(subtree, tvb, off, 6,
407 "IP address: %s", s);
411 tisub = proto_tree_add_item(grouptree, hf_pim_numprunes, tvb,
412 offset + 2, 2, ENC_BIG_ENDIAN);
413 subtree = proto_item_add_subtree(tisub, ett_pim);
414 for (j = 0; j < nprune; j++) {
415 s = dissect_pimv1_addr(tvb, off);
416 proto_tree_add_text(subtree, tvb, off, 6,
417 "IP address: %s", s);
425 case 4: /* rp-reachability */
429 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
431 tvb_ip_to_str(tvb, offset));
434 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
436 tvb_ip_to_str(tvb, offset));
439 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
441 tvb_ip_to_str(tvb, offset));
444 offset += 2; /* skip reserved stuff */
446 holdtime = tvb_get_ntohs(tvb, offset);
447 proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb,
449 "Holdtime: %us %s", holdtime,
450 holdtime == 0xffff ? "(infinity)": "");
459 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
461 tvb_ip_to_str(tvb, offset));
464 proto_tree_add_text(pimopt_tree, tvb, offset, 4,
466 tvb_ip_to_str(tvb, offset));
469 proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, ENC_BIG_ENDIAN);
470 pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff;
471 proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb,
473 "Metric Preference: %u", pref);
476 proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, ENC_BIG_ENDIAN);
486 return offset+tvb_length_remaining(tvb, offset);
490 dissect_pim_addr(tvbuff_t *tvb, int offset, enum pimv2_addrtype at,
492 emem_strbuf_t *strbuf;
499 af = tvb_get_guint8(tvb, offset);
500 if (af != AFNUM_INET && af != AFNUM_INET6) {
502 * We don't handle the other formats, and addresses don't include
503 * a length field, so we can't even show them as raw bytes.
508 et = tvb_get_guint8(tvb, offset + 1);
511 * The only defined encoding type is 0, for the native encoding;
512 * again, as addresses don't include a length field, we can't
513 * even show addresses with a different encoding type as raw
519 strbuf = ep_strbuf_new_label(NULL);
525 ep_strbuf_printf(strbuf, "%s", tvb_ip_to_str(tvb, offset + 2));
530 ep_strbuf_printf(strbuf, "%s", tvb_ip6_to_str(tvb, offset + 2));
538 mask_len = tvb_get_guint8(tvb, offset + 3);
542 ep_strbuf_printf(strbuf, "%s/%u",
543 tvb_ip_to_str(tvb, offset + 4), mask_len);
548 ep_strbuf_printf(strbuf, "%s/%u",
549 tvb_ip6_to_str(tvb, offset + 4), mask_len);
557 flags = tvb_get_guint8(tvb, offset + 2);
558 mask_len = tvb_get_guint8(tvb, offset + 3);
562 ep_strbuf_printf(strbuf, "%s/%u",
563 tvb_ip_to_str(tvb, offset + 4), mask_len);
568 ep_strbuf_printf(strbuf, "%s/%u",
569 tvb_ip6_to_str(tvb, offset + 4), mask_len);
573 ep_strbuf_append_printf(strbuf,
575 flags & 0x04 ? "S" : "",
576 flags & 0x02 ? "W" : "",
577 flags & 0x01 ? "R" : "");
589 static const value_string type2vals[] = {
592 { 2, "Register-stop" },
598 { 8, "Candidate-RP-Advertisement" },
599 { 9, "State-Refresh" },
603 static const value_string pim_opt_vals[] = {
605 {2, "LAN Prune Delay"},
606 {18, "Deprecated and should not be used"},
608 {20, "Generation ID"},
609 {21, "State Refresh Capable"},
610 {22, "Bidir Capable"},
611 {24, "Address List"},
612 {65001, "Address List"}, /* old implementation */
617 * For PIM v2, see RFC 4601, RFC 3973 and draft-ietf-pim-sm-v2-new-03
618 * (when PIM is run over IPv6, the rules for computing the PIM checksum
619 * from the draft in question, not from RFC 2362, should be used).
622 dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
625 guint length, pim_length;
626 guint16 pim_cksum, computed_cksum;
630 proto_tree *pim_tree = NULL;
632 proto_tree *pimopt_tree = NULL;
635 col_set_str(pinfo->cinfo, COL_PROTOCOL, "PIM");
636 col_clear(pinfo->cinfo, COL_INFO);
638 pim_typever = tvb_get_guint8(tvb, 0);
640 switch (PIM_VER(pim_typever)) {
642 typestr = val_to_str(PIM_TYPE(pim_typever), type2vals, "Unknown (%u)");
644 case 1: /* PIMv1 - we should never see this */
650 if (check_col(pinfo->cinfo, COL_PROTOCOL)) {
651 col_add_fstr(pinfo->cinfo, COL_PROTOCOL, "PIMv%d",
652 PIM_VER(pim_typever));
654 if (check_col(pinfo->cinfo, COL_INFO))
655 col_add_str(pinfo->cinfo, COL_INFO, typestr);
657 ti = proto_tree_add_item(tree, proto_pim, tvb, offset, -1, FALSE);
658 pim_tree = proto_item_add_subtree(ti, ett_pim);
660 proto_tree_add_item(pim_tree, hf_pim_version, tvb, offset, 1, ENC_BIG_ENDIAN);
661 proto_tree_add_item(pim_tree, hf_pim_type, tvb, offset, 1, ENC_BIG_ENDIAN);
662 proto_tree_add_item(pim_tree, hf_pim_res_bytes, tvb, offset + 1, 1, ENC_NA);
663 pim_cksum = tvb_get_ntohs(tvb, offset + 2);
664 length = tvb_length(tvb);
665 if (PIM_VER(pim_typever) == 2) {
667 * Well, it's PIM v2, so we can check whether this is a Register
668 * message, and thus can figure out how much to checksum and
669 * whether to make the columns read-only.
671 if (PIM_TYPE(pim_typever) == 1) {
673 * Register message - the PIM header is 8 bytes long.
674 * Also set the columns non-writable. Otherwise the IPv4 or
675 * IPv6 dissector for the encapsulated packet that caused
676 * this register will overwrite the PIM info in the columns.
679 col_set_writable(pinfo->cinfo, FALSE);
682 * Other message - checksum the entire packet.
684 pim_length = tvb_reported_length(tvb);
688 * We don't know what type of message this is, so say that
689 * the length is 0, to force it not to be checksummed.
693 if (!pinfo->fragmented && length >= pim_length) {
695 * The packet isn't part of a fragmented datagram and isn't
696 * truncated, so we can checksum it.
699 switch (pinfo->src.type) {
701 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length);
702 cksum_vec[0].len = pim_length;
703 computed_cksum = in_cksum(&cksum_vec[0], 1);
706 /* Set up the fields of the pseudo-header. */
707 cksum_vec[0].ptr = pinfo->src.data;
708 cksum_vec[0].len = pinfo->src.len;
709 cksum_vec[1].ptr = pinfo->dst.data;
710 cksum_vec[1].len = pinfo->dst.len;
711 cksum_vec[2].ptr = (const guint8 *)&phdr;
712 phdr[0] = g_htonl(pim_length);
713 phdr[1] = g_htonl(IP_PROTO_PIM);
714 cksum_vec[2].len = 8;
715 cksum_vec[3].ptr = tvb_get_ptr(tvb, 0, pim_length);
716 cksum_vec[3].len = pim_length;
717 computed_cksum = in_cksum(&cksum_vec[0], 4);
720 /* PIM is available for IPv4 and IPv6 right now */
721 computed_cksum = 0; /* squelch GCC complaints */
722 DISSECTOR_ASSERT_NOT_REACHED();
726 if (computed_cksum == 0) {
727 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
728 offset + 2, 2, pim_cksum,
729 "Checksum: 0x%04x [correct]",
732 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
733 offset + 2, 2, pim_cksum,
734 "Checksum: 0x%04x [incorrect, should be 0x%04x]",
735 pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum));
738 proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
739 offset + 2, 2, pim_cksum);
744 if (tvb_reported_length_remaining(tvb, offset) > 0) {
745 tiopt = proto_tree_add_text(pim_tree, tvb, offset, -1, "PIM options");
746 pimopt_tree = proto_item_add_subtree(tiopt, ett_pim_opts);
750 if (PIM_VER(pim_typever) != 2)
753 /* version 2 decoder */
754 switch (PIM_TYPE(pim_typever)) {
759 while (tvb_reported_length_remaining(tvb, offset) >= 2) {
760 guint16 hello_opt, opt_len;
762 proto_item *opt_item;
763 proto_tree *opt_tree;
766 hello_opt = tvb_get_ntohs(tvb, offset);
767 opt_len = tvb_get_ntohs(tvb, offset + 2);
768 opt_item = proto_tree_add_text(pimopt_tree, tvb, offset, 4 + opt_len,
769 "Option %u: %s", hello_opt,
770 val_to_str(hello_opt, pim_opt_vals, "Unknown: %u"));
771 opt_tree = proto_item_add_subtree(opt_item, ett_pim_opt);
772 proto_tree_add_item(opt_tree, hf_pim_optiontype, tvb, offset, 2, ENC_BIG_ENDIAN);
773 proto_tree_add_item(opt_tree, hf_pim_optionlength, tvb, offset + 2, 2, ENC_BIG_ENDIAN);
776 case 1: /* Hello Hold Time Option */
777 opt_value = tvb_get_ntohs(tvb, offset + 4);
778 proto_tree_add_uint_format(opt_tree, hf_pim_holdtime, tvb,
779 offset + 4, opt_len, opt_value,
780 "Holdtime: %us %s", opt_value, opt_value == 0 ? "(goodbye)" :
781 opt_value == 0xffff ? "(infinity)": "");
782 proto_item_append_text(opt_item, ": %us %s", opt_value,
783 opt_value == 0 ? "(goodbye)" :
784 opt_value == 0xffff ? "(infinity)": "");
787 case 2: /* LAN Prune Delay Option */
788 proto_tree_add_item(opt_tree, hf_pim_t, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
789 proto_tree_add_item(opt_tree, hf_pim_propagation_delay, tvb, offset + 4, 2, ENC_BIG_ENDIAN);
790 proto_tree_add_item(opt_tree, hf_pim_override_interval, tvb, offset + 6, 2, ENC_BIG_ENDIAN);
791 proto_item_append_text(opt_item,
792 ": T = %u, Propagation Delay = %ums, Override Interval = %ums",
793 tvb_get_guint8(tvb, offset + 4) & 0x80 ? 1 : 0,
794 tvb_get_ntohs(tvb, offset + 4) & 0x7fff,
795 tvb_get_ntohs(tvb, offset + 6));
798 case 19: /* DR priority */
799 proto_tree_add_item(opt_tree, hf_pim_dr_priority, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
800 proto_item_append_text(opt_item, ": %u", tvb_get_ntohl(tvb, offset + 4));
803 case 20: /* Generation ID */
804 proto_tree_add_item(opt_tree, hf_pim_generation_id, tvb, offset + 4, 4, ENC_BIG_ENDIAN);
805 proto_item_append_text(opt_item, ": %u", tvb_get_ntohl(tvb, offset + 4));
808 case 21: /* State Refresh Capable Option */
809 proto_tree_add_item(opt_tree, hf_pim_state_refresh_version, tvb, offset + 4, 1, ENC_BIG_ENDIAN);
810 proto_tree_add_item(opt_tree, hf_pim_state_refresh_interval, tvb, offset + 5, 1, ENC_BIG_ENDIAN);
811 proto_tree_add_item(opt_tree, hf_pim_state_refresh_reserved, tvb, offset + 6, 2, ENC_BIG_ENDIAN);
812 proto_item_append_text(opt_item, ": Version = %u, Interval = %us",
813 tvb_get_guint8(tvb, offset + 4),
814 tvb_get_guint8(tvb, offset + 5));
817 case 24: /* address list */
818 case 65001: /* address list (old implementations) */
821 proto_tree *sub_tree = NULL;
822 proto_item *addrlist_option;
824 addrlist_option = proto_tree_add_text(opt_tree, tvb, offset, 4 + opt_len,
825 "%sAddress List (%u)",
826 hello_opt == 65001 ? "old " : "",
828 sub_tree = proto_item_add_subtree(addrlist_option, ett_pim_opt);
829 for (i = offset + 4; i < offset + 4 + opt_len; ) {
833 s = dissect_pim_addr(tvb, i, pimv2_unicast, &advance);
836 proto_tree_add_text(sub_tree, tvb, offset,
837 advance, "Address: %s", s);
845 proto_tree_add_item(opt_tree, hf_pim_optionvalue, tvb,
846 offset + 4, opt_len, ENC_NA);
849 offset += 4 + opt_len;
851 proto_item_append_text(tiopt, ": %u", opt_count);
855 case 1: /* register */
860 proto_tree *flag_tree = NULL;
863 flags = tvb_get_ntohl(tvb, offset);
864 tiflag = proto_tree_add_text(pimopt_tree, tvb, offset, 4,
865 "Flags: 0x%08x", flags);
866 flag_tree = proto_item_add_subtree(tiflag, ett_pim);
867 proto_tree_add_text(flag_tree, tvb, offset, 1, "%s",
868 decode_boolean_bitfield(flags, 0x80000000, 32,
869 "Border", "Not border"));
870 proto_tree_add_text(flag_tree, tvb, offset, 1, "%s",
871 decode_boolean_bitfield(flags, 0x40000000, 32,
872 "Null-Register", "Not Null-Register"));
876 * The rest of the packet is a multicast data packet.
878 next_tvb = tvb_new_subset_remaining(tvb, offset);
881 * It's an IP packet - determine whether it's IPv4 or IPv6.
883 v_hl = tvb_get_guint8(tvb, offset);
884 switch((v_hl & 0xf0) >> 4) {
885 case 0: /* Null-Register dummy header.
886 * Has the same address family as the encapsulating PIM packet,
887 * e.g. an IPv6 data packet is encapsulated in IPv6 PIM packet.
889 if (pinfo->src.type == AT_IPv4) {
890 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
891 "IPv4 dummy header");
892 proto_tree_add_text(pimopt_tree, tvb, offset + 12, 4,
894 tvb_ip_to_str(tvb, offset + 12));
895 proto_tree_add_text(pimopt_tree, tvb, offset + 16, 4,
897 tvb_ip_to_str(tvb, offset + 16));
898 } else if (pinfo->src.type == AT_IPv6) {
899 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
900 "IPv6 dummy header");
901 proto_tree_add_text(pimopt_tree, tvb,
904 tvb_ip6_to_str(tvb, offset + 8));
905 proto_tree_add_text(pimopt_tree, tvb,
908 tvb_ip6_to_str(tvb, offset + 8 + 16));
910 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
911 "Dummy header for an unknown protocol");
915 call_dissector(ip_handle, next_tvb, pinfo, tree);
917 call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree);
922 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
924 call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree);
928 proto_tree_add_text(pimopt_tree, tvb, offset, -1,
929 "Unknown IP version %d", (v_hl & 0xf0) >> 4);
935 case 2: /* register-stop */
940 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
943 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s);
945 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
948 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s);
952 case 3: /* join/prune */
954 case 7: /* graft-ack */
959 int ngroup, i, njoin, nprune, j;
961 proto_tree *grouptree = NULL;
963 proto_tree *subtree = NULL;
966 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
969 proto_tree_add_text(pimopt_tree, tvb, offset, advance,
970 "Upstream-neighbor: %s", s);
973 proto_tree_add_item(pimopt_tree, hf_pim_res_bytes, tvb, offset, 1, ENC_NA);
974 offset += 1; /* skip reserved field */
976 ngroup = tvb_get_guint8(tvb, offset);
977 proto_tree_add_item(pimopt_tree, hf_pim_numgroups, tvb, offset, 1, ENC_BIG_ENDIAN);
980 holdtime = tvb_get_ntohs(tvb, offset);
981 proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb,
983 "Holdtime: %us %s", holdtime,
984 holdtime == 0xffff ? "(infinity)": "");
987 for (i = 0; i < ngroup; 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 njoin = tvb_get_ntohs(tvb, offset);
997 nprune = tvb_get_ntohs(tvb, offset + 2);
998 tisub = proto_tree_add_item(grouptree, hf_pim_numjoins, tvb,
999 offset, 2, ENC_BIG_ENDIAN);
1000 subtree = proto_item_add_subtree(tisub, ett_pim);
1002 for (j = 0; j < njoin; j++) {
1003 s = dissect_pim_addr(tvb, off, pimv2_source, &advance);
1006 proto_tree_add_text(subtree, tvb, off, advance,
1007 "IP address: %s", s);
1011 tisub = proto_tree_add_item(grouptree, hf_pim_numprunes, tvb,
1012 offset + 2, 2, ENC_BIG_ENDIAN);
1013 subtree = proto_item_add_subtree(tisub, ett_pim);
1014 for (j = 0; j < nprune; j++) {
1015 s = dissect_pim_addr(tvb, off, pimv2_source, &advance);
1018 proto_tree_add_text(subtree, tvb, off, advance,
1019 "IP address: %s", s);
1028 case 4: /* bootstrap */
1035 proto_tree *grouptree = NULL;
1036 proto_item *tigroup;
1038 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
1039 "Fragment tag: 0x%04x", tvb_get_ntohs(tvb, offset));
1042 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1043 "Hash mask len: %u", tvb_get_guint8(tvb, offset));
1045 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1046 "BSR priority: %u", tvb_get_guint8(tvb, offset));
1049 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1052 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "BSR: %s", s);
1055 for (i = 0; tvb_reported_length_remaining(tvb, offset) > 0; i++) {
1056 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1059 tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1060 "Group %d: %s", i, s);
1061 grouptree = proto_item_add_subtree(tigroup, ett_pim);
1064 proto_tree_add_text(grouptree, tvb, offset, 1,
1065 "RP count: %u", tvb_get_guint8(tvb, offset));
1067 frpcnt = tvb_get_guint8(tvb, offset);
1068 proto_tree_add_text(grouptree, tvb, offset, 1,
1069 "FRP count: %u", frpcnt);
1072 for (j = 0; j < frpcnt; j++) {
1073 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1076 proto_tree_add_text(grouptree, tvb, offset, advance,
1080 holdtime = tvb_get_ntohs(tvb, offset);
1081 proto_tree_add_uint_format(grouptree, hf_pim_holdtime, tvb,
1082 offset, 2, holdtime,
1083 "Holdtime: %us %s", holdtime,
1084 holdtime == 0xffff ? "(infinity)": "");
1086 proto_tree_add_text(grouptree, tvb, offset, 1,
1087 "Priority: %u", tvb_get_guint8(tvb, offset));
1088 offset += 2; /* also skips reserved field */
1096 case 5: /* assert */
1102 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1105 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s);
1108 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1111 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s);
1114 proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, ENC_BIG_ENDIAN);
1115 pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff;
1116 proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb,
1118 "Metric Preference: %u", pref);
1121 proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, ENC_BIG_ENDIAN);
1126 case 8: /* Candidate-RP-Advertisement */
1134 pfxcnt = tvb_get_guint8(tvb, offset);
1135 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1136 "Prefix-count: %u", pfxcnt);
1138 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1139 "Priority: %u", tvb_get_guint8(tvb, offset));
1141 holdtime = tvb_get_ntohs(tvb, offset);
1142 proto_tree_add_uint_format(pimopt_tree, hf_pim_holdtime, tvb,
1143 offset, 2, holdtime,
1144 "Holdtime: %us %s", holdtime,
1145 holdtime == 0xffff ? "(infinity)": "");
1148 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1151 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "RP: %s", s);
1154 for (i = 0; i < pfxcnt; i++) {
1155 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1158 proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1159 "Group %d: %s", i, s);
1166 case 9: /* State-Refresh */
1172 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
1175 proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1179 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1182 proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1186 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
1189 proto_tree_add_text(pimopt_tree, tvb, offset, advance,
1190 "Originator: %s", s);
1193 proto_tree_add_item(pimopt_tree, hf_pim_rpt, tvb, offset, 1, ENC_BIG_ENDIAN);
1194 pref = tvb_get_ntohl(tvb, offset) & 0x7fffffff;
1195 proto_tree_add_uint_format(pimopt_tree, hf_pim_metric_pref, tvb,
1197 "Metric Preference: %u", pref);
1200 proto_tree_add_item(pimopt_tree, hf_pim_metric, tvb, offset, 4, ENC_BIG_ENDIAN);
1203 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1204 "Masklen: %u", tvb_get_guint8(tvb, offset));
1207 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1208 "TTL: %u", tvb_get_guint8(tvb, offset));
1211 proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Prune indicator %s",
1212 decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x80, 8,
1214 proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Prune now %s",
1215 decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x40, 8,
1217 proto_tree_add_text(pimopt_tree, tvb, offset, 1, "Assert override %s",
1218 decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x20, 8,
1222 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
1223 "Interval: %u", tvb_get_guint8(tvb, offset));
1236 proto_register_pim(void)
1238 static hf_register_info hf[] =
1241 { "Version", "pim.version",
1242 FT_UINT8, BASE_DEC, NULL, 0xf0,
1246 { "Type", "pim.type",
1247 FT_UINT8, BASE_DEC, VALS(type2vals), 0x0f,
1251 { "Code", "pim.code",
1252 FT_UINT8, BASE_DEC, VALS(type1vals), 0x0,
1256 { "Checksum", "pim.cksum",
1257 FT_UINT16, BASE_HEX, NULL, 0x0,
1260 { &hf_pim_res_bytes,
1261 { "Reserved byte(s)", "pim.res_bytes",
1262 FT_BYTES, BASE_NONE, NULL, 0x0,
1265 { &hf_pim_optiontype,
1266 { "Type", "pim.optiontype",
1267 FT_UINT16, BASE_DEC, NULL, 0x0,
1270 { &hf_pim_optionlength,
1271 { "Length", "pim.optionlength",
1272 FT_UINT16, BASE_DEC, NULL, 0x0,
1275 { &hf_pim_optionvalue,
1276 { "Unknown", "pim.optionvalue",
1277 FT_BYTES, BASE_NONE, NULL, 0x0,
1281 { "Mode", "pim.mode",
1282 FT_UINT8, BASE_DEC, VALS(pimv1_modevals), 0xf0,
1286 { "Holdtime", "pim.holdtime",
1287 FT_UINT16, BASE_DEC, NULL, 0x0,
1288 "The amount of time a receiver must keep the neighbor "
1289 "reachable, in seconds.", HFILL }
1291 { &hf_pim_numgroups,
1292 { "Num Groups", "pim.numgroups",
1293 FT_UINT16, BASE_DEC, NULL, 0x0,
1294 "Number of multicast group sets contained in the message.",
1298 { "Num Joins", "pim.numjoins",
1299 FT_UINT16, BASE_DEC, NULL, 0x0,
1300 "Number of joined sources.", HFILL }
1302 { &hf_pim_numprunes,
1303 { "Num Prunes", "pim.numprunes",
1304 FT_UINT16, BASE_DEC, NULL, 0x0,
1305 "Number of pruned sources.", HFILL }
1309 FT_BOOLEAN, 8, NULL, 0x80,
1310 "Specifies the ability of the sending router to disable joins "
1311 "suppression.", HFILL }
1313 { &hf_pim_propagation_delay,
1314 { "Propagation Delay", "pim.propagation_delay",
1315 FT_UINT16, BASE_DEC, NULL, 0x07fff,
1316 "Units are milli-seconds", HFILL }
1318 { &hf_pim_override_interval,
1319 { "Override Interval", "pim.override_interval",
1320 FT_UINT16, BASE_DEC, NULL, 0x0,
1321 "Units are milli-seconds", HFILL }
1323 { &hf_pim_dr_priority,
1324 { "DR Priority", "pim.dr_priority",
1325 FT_UINT32, BASE_DEC, NULL, 0x0,
1328 { &hf_pim_generation_id,
1329 { "Generation ID", "pim.generation_id",
1330 FT_UINT32, BASE_DEC, NULL, 0x0,
1333 { &hf_pim_state_refresh_version,
1334 { "Version", "pim.state_refresh_version",
1335 FT_UINT8, BASE_DEC, NULL, 0x0,
1338 { &hf_pim_state_refresh_interval,
1339 { "Interval", "pim.state_refresh_interval",
1340 FT_UINT8, BASE_DEC, NULL, 0x0,
1341 "Units in seconds.", HFILL }
1343 { &hf_pim_state_refresh_reserved,
1344 { "Reserved", "pim.state_refresh_reserved",
1345 FT_UINT16, BASE_DEC, NULL, 0x0,
1349 { "RP Tree", "pim.rpt",
1350 FT_BOOLEAN, 8, NULL, 0x80,
1351 "Set to 1 for assert(*,G) messages and 0 for assert(S,G) "
1352 "messages.", HFILL }
1354 { &hf_pim_metric_pref ,
1355 { "Metric Preference", "pim.metric_pref",
1356 FT_UINT32, BASE_DEC, NULL, 0x7fffffff,
1360 { "Metric", "pim.metric",
1361 FT_UINT32, BASE_DEC, NULL, 0x0,
1366 static gint *ett[] = {
1368 &ett_pim_opts, /* Tree for all options */
1369 &ett_pim_opt /* Tree for each option */
1372 proto_pim = proto_register_protocol("Protocol Independent Multicast",
1374 proto_register_field_array(proto_pim, hf, array_length(hf));
1375 proto_register_subtree_array(ett, array_length(ett));
1379 proto_reg_handoff_pim(void)
1381 dissector_handle_t pim_handle;
1383 pim_handle = create_dissector_handle(dissect_pim, proto_pim);
1384 dissector_add_uint("ip.proto", IP_PROTO_PIM, pim_handle);
1387 * Get handles for the IPv4 and IPv6 dissectors.
1389 ip_handle = find_dissector("ip");
1390 ipv6_handle = find_dissector("ipv6");