2 * Routines for PIM disassembly
3 * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-pim.c,v 1.27 2001/04/23 17:51:33 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@ethereal.com>
9 * Copyright 1998 Gerald Combs
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #ifdef HAVE_SYS_TYPES_H
32 #include <sys/types.h>
35 #ifdef HAVE_NETINET_IN_H
36 #include <netinet/in.h>
42 #ifdef NEED_SNPRINTF_H
43 # include "snprintf.h"
50 #define PIM_TYPE(x) ((x) & 0x0f)
51 #define PIM_VER(x) (((x) & 0xf0) >> 4)
54 pimv2_unicast, pimv2_group, pimv2_source
57 static int proto_pim = -1;
58 static int hf_pim_version = -1;
59 static int hf_pim_type = -1;
60 static int hf_pim_cksum = -1;
62 static gint ett_pim = -1;
64 static dissector_handle_t ip_handle;
65 static dissector_handle_t ipv6_handle;
68 * Address family values.
70 #define PIM_AF_RESERVED 0
71 #define PIM_AF_IP 1 /* IPv4 */
72 #define PIM_AF_IPV6 2 /* IPv6 */
73 #define PIM_AF_NSAP 3 /* NSAP */
74 #define PIM_AF_HDLC 4 /* HDLC (8-bit multidrop) */
75 #define PIM_AF_BBN_1822 5 /* BBN 1822 */
76 #define PIM_AF_802 6 /* 802 (D/I/X Ethernet, 802.x, FDDI) */
77 #define PIM_AF_E_163 7 /* E.163 */
78 #define PIM_AF_E_164 8 /* E.164 (SMDS, Frame Relay, ATM) */
79 #define PIM_AF_F_69 9 /* F.69 (Telex) */
80 #define PIM_AF_X_121 10 /* X.121 (X.25, Frame Relay) */
81 #define PIM_AF_IPX 11 /* IPX */
82 #define PIM_AF_ATALK 12 /* Appletalk */
83 #define PIM_AF_DECNET_IV 13 /* DECnet Phase IV */
84 #define PIM_AF_VINES 14 /* Banyan Vines */
85 #define PIM_AF_E_164_NSAP 15 /* E.164 with NSAP format subaddress */
88 dissect_pim_addr(tvbuff_t *tvb, int offset, enum pimv2_addrtype at,
97 af = tvb_get_guint8(tvb, offset);
98 if (af != PIM_AF_IP && af != PIM_AF_IPV6) {
100 * We don't handle the other formats, and addresses don't include
101 * a length field, so we can't even show them as raw bytes.
106 et = tvb_get_guint8(tvb, offset + 1);
109 * The only defined encoding type is 0, for the native encoding;
110 * again, as addresses don't include a length field, we can't
111 * even show addresses with a different encoding type as raw
122 (void)snprintf(buf, sizeof(buf), "%s",
123 ip_to_str(tvb_get_ptr(tvb, offset + 2, len)));
128 (void)snprintf(buf, sizeof(buf), "%s",
129 ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 2, len)));
137 mask_len = tvb_get_guint8(tvb, offset + 3);
141 (void)snprintf(buf, sizeof(buf), "%s/%u",
142 ip_to_str(tvb_get_ptr(tvb, offset + 4, len)), mask_len);
147 (void)snprintf(buf, sizeof(buf), "%s/%u",
148 ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 4, len)), mask_len);
156 flags = tvb_get_guint8(tvb, offset + 2);
157 mask_len = tvb_get_guint8(tvb, offset + 3);
161 (void)snprintf(buf, sizeof(buf), "%s/%u",
162 ip_to_str(tvb_get_ptr(tvb, offset + 4, len)), mask_len);
167 (void)snprintf(buf, sizeof(buf), "%s/%u",
168 ip6_to_str((struct e_in6_addr *)tvb_get_ptr(tvb, offset + 4, len)), mask_len);
172 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
174 flags & 0x04 ? "S" : "",
175 flags & 0x02 ? "W" : "",
176 flags & 0x01 ? "R" : "");
189 dissect_pim(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree) {
192 guint length, pim_length;
193 guint16 pim_cksum, computed_cksum;
195 static const value_string type1vals[] = {
198 { 2, "Register-stop" },
200 { 4, "RP-Reachable" },
207 static const value_string type2vals[] = {
210 { 2, "Register-stop" },
216 { 8, "Candidate-RP-Advertisement" },
220 proto_tree *pim_tree = NULL;
222 proto_tree *pimopt_tree = NULL;
225 if (check_col(pinfo->fd, COL_PROTOCOL))
226 col_set_str(pinfo->fd, COL_PROTOCOL, "PIM");
227 if (check_col(pinfo->fd, COL_INFO))
228 col_clear(pinfo->fd, COL_INFO);
230 pim_typever = tvb_get_guint8(tvb, 0);
232 switch (PIM_VER(pim_typever)) {
234 typestr = val_to_str(PIM_TYPE(pim_typever), type1vals, "Unknown");
237 typestr = val_to_str(PIM_TYPE(pim_typever), type2vals, "Unknown");
244 if (check_col(pinfo->fd, COL_PROTOCOL)) {
245 col_add_fstr(pinfo->fd, COL_PROTOCOL, "PIM version %d",
246 PIM_VER(pim_typever));
248 if (check_col(pinfo->fd, COL_INFO))
249 col_add_fstr(pinfo->fd, COL_INFO, "%s", typestr);
252 ti = proto_tree_add_item(tree, proto_pim, tvb, offset,
253 tvb_length_remaining(tvb, offset), FALSE);
254 pim_tree = proto_item_add_subtree(ti, ett_pim);
256 proto_tree_add_uint(pim_tree, hf_pim_version, tvb, offset, 1,
257 PIM_VER(pim_typever));
258 proto_tree_add_uint_format(pim_tree, hf_pim_type, tvb, offset, 1,
259 PIM_TYPE(pim_typever),
260 "Type: %s (%u)", typestr, PIM_TYPE(pim_typever));
262 pim_cksum = tvb_get_ntohs(tvb, offset + 2);
263 length = tvb_length(tvb);
264 if (PIM_VER(pim_typever) == 2) {
266 * Well, it's PIM v2, so we can check whether this is a Register
267 * mesage, and thus can figure out how much to checksum.
269 if (PIM_TYPE(pim_typever) == 1) {
271 * Register message - the PIM header is 8 bytes long.
276 * Other message - checksum the entire packet.
278 pim_length = tvb_reported_length(tvb);
282 * We don't know what type of message this is, so say that
283 * the length is 0, to force it not to be checksummed.
287 if (!pinfo->fragmented && length >= pim_length) {
289 * The packet isn't part of a fragmented datagram and isn't
290 * truncated, so we can checksum it.
292 cksum_vec[0].ptr = tvb_get_ptr(tvb, 0, pim_length);
293 cksum_vec[0].len = pim_length;
294 computed_cksum = in_cksum(&cksum_vec[0], 1);
295 if (computed_cksum == 0) {
296 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
297 offset + 2, 2, pim_cksum,
298 "Checksum: 0x%04x (correct)",
301 proto_tree_add_uint_format(pim_tree, hf_pim_cksum, tvb,
302 offset + 2, 2, pim_cksum,
303 "Checksum: 0x%04x (incorrect, should be 0x%04x)",
304 pim_cksum, in_cksum_shouldbe(pim_cksum, computed_cksum));
307 proto_tree_add_uint(pim_tree, hf_pim_cksum, tvb,
308 offset + 2, 2, pim_cksum);
313 if (tvb_reported_length_remaining(tvb, offset) > 0) {
314 tiopt = proto_tree_add_text(pim_tree, tvb, offset,
315 tvb_length_remaining(tvb, offset), "PIM parameters");
316 pimopt_tree = proto_item_add_subtree(tiopt, ett_pim);
320 if (PIM_VER(pim_typever) != 2)
323 /* version 2 decoder */
324 switch (PIM_TYPE(pim_typever)) {
327 while (tvb_reported_length_remaining(tvb, offset) >= 2) {
328 if (tvb_get_ntohs(tvb, offset) == 1 &&
329 tvb_get_ntohs(tvb, offset + 2) == 2) {
332 holdtime = tvb_get_ntohs(tvb, offset + 4);
333 proto_tree_add_text(pimopt_tree, tvb, offset, 6,
334 "Holdtime: %u%s", holdtime,
335 holdtime == 0xffff ? " (infty)" : "");
343 case 1: /* register */
348 proto_tree *flag_tree = NULL;
351 flags = tvb_get_ntohl(tvb, offset);
352 tiflag = proto_tree_add_text(pimopt_tree, tvb, offset, 4,
353 "Flags: 0x%08x", flags);
354 flag_tree = proto_item_add_subtree(tiflag, ett_pim);
355 proto_tree_add_text(flag_tree, tvb, offset, 1, "%s",
356 decode_boolean_bitfield(flags, 0x80000000, 32,
357 "Border", "Not border"));
358 proto_tree_add_text(flag_tree, tvb, offset, 1, "%s",
359 decode_boolean_bitfield(flags, 0x40000000, 32,
360 "Null-Register", "Not Null-Register"));
364 * The rest of the packet is a multicast data packet.
366 next_tvb = tvb_new_subset(tvb, offset, -1, -1);
369 * It's an IP packet - determine whether it's IPv4 or IPv6.
371 v_hl = tvb_get_guint8(tvb, offset);
372 switch((v_hl & 0xf0) >> 4) {
375 call_dissector(ip_handle, next_tvb, pinfo, tree);
377 call_dissector(ip_handle, next_tvb, pinfo, pimopt_tree);
382 call_dissector(ipv6_handle, next_tvb, pinfo, tree);
384 call_dissector(ipv6_handle, next_tvb, pinfo, pimopt_tree);
388 proto_tree_add_text(pimopt_tree, tvb,
389 offset, tvb_length_remaining(tvb, offset),
390 "Unknown IP version %d", (v_hl & 0xf0) >> 4);
396 case 2: /* register-stop */
401 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
404 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s);
406 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
409 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s);
413 case 3: /* join/prune */
415 case 7: /* graft-ack */
420 int ngroup, i, njoin, nprune, j;
422 proto_tree *grouptree = NULL;
424 proto_tree *subtree = NULL;
427 if (PIM_TYPE(pim_typever) != 7) {
429 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
432 proto_tree_add_text(pimopt_tree, tvb, offset, advance,
433 "Upstream-neighbor: %s", s);
437 offset += 1; /* skip reserved field */
439 ngroup = tvb_get_guint8(tvb, offset);
440 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
441 "Groups: %u", ngroup);
444 if (PIM_TYPE(pim_typever) != 7) {
446 holdtime = tvb_get_ntohs(tvb, offset);
447 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
448 "Holdtime: %u%s", holdtime,
449 holdtime == 0xffff ? " (infty)" : "");
453 for (i = 0; i < ngroup; i++) {
454 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
457 tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance,
458 "Group %d: %s", i, s);
459 grouptree = proto_item_add_subtree(tigroup, ett_pim);
462 njoin = tvb_get_ntohs(tvb, offset);
463 nprune = tvb_get_ntohs(tvb, offset + 2);
465 tisub = proto_tree_add_text(grouptree, tvb, offset, 2,
467 subtree = proto_item_add_subtree(tisub, ett_pim);
469 for (j = 0; j < nprune; j++) {
470 s = dissect_pim_addr(tvb, off, pimv2_source,
474 proto_tree_add_text(subtree, tvb, off, advance,
475 "IP address: %s", s);
479 tisub = proto_tree_add_text(grouptree, tvb, offset + 2, 2,
480 "Prune: %d", nprune);
481 subtree = proto_item_add_subtree(tisub, ett_pim);
482 for (j = 0; j < nprune; j++) {
483 s = dissect_pim_addr(tvb, off, pimv2_source,
487 proto_tree_add_text(subtree, tvb, off, advance,
488 "IP address: %s", s);
496 case 4: /* bootstrap */
503 proto_tree *grouptree = NULL;
506 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
507 "Fragment tag: 0x%04x", tvb_get_ntohs(tvb, offset));
510 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
511 "Hash mask len: %u", tvb_get_guint8(tvb, offset));
513 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
514 "BSR priority: %u", tvb_get_guint8(tvb, offset));
517 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
520 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "BSR: %s", s);
523 for (i = 0; tvb_reported_length_remaining(tvb, offset) > 0; i++) {
524 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
527 tigroup = proto_tree_add_text(pimopt_tree, tvb, offset, advance,
528 "Group %d: %s", i, s);
529 grouptree = proto_item_add_subtree(tigroup, ett_pim);
532 proto_tree_add_text(grouptree, tvb, offset, 1,
533 "RP count: %u", tvb_get_guint8(tvb, offset));
535 frpcnt = tvb_get_guint8(tvb, offset);
536 proto_tree_add_text(grouptree, tvb, offset, 1,
537 "FRP count: %u", frpcnt);
540 for (j = 0; j < frpcnt; j++) {
541 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
544 proto_tree_add_text(grouptree, tvb, offset, advance,
548 holdtime = tvb_get_ntohs(tvb, offset);
549 proto_tree_add_text(grouptree, tvb, offset, 2,
550 "Holdtime: %u%s", holdtime,
551 holdtime == 0xffff ? " (infty)" : "");
553 proto_tree_add_text(grouptree, tvb, offset, 1,
554 "Priority: %u", tvb_get_guint8(tvb, offset));
555 offset += 2; /* also skips reserved field */
568 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
571 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Group: %s", s);
574 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
577 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "Source: %s", s);
580 proto_tree_add_text(pimopt_tree, tvb, offset, 1, "%s",
581 decode_boolean_bitfield(tvb_get_guint8(tvb, offset), 0x80, 8,
582 "RP Tree", "Not RP Tree"));
583 proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Preference: %u",
584 tvb_get_ntohl(tvb, offset) & 0x7fffffff);
587 proto_tree_add_text(pimopt_tree, tvb, offset, 4, "Metric: %u",
588 tvb_get_ntohl(tvb, offset));
593 case 8: /* Candidate-RP-Advertisement */
601 pfxcnt = tvb_get_guint8(tvb, offset);
602 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
603 "Prefix-count: %u", pfxcnt);
605 proto_tree_add_text(pimopt_tree, tvb, offset, 1,
606 "Priority: %u", tvb_get_guint8(tvb, offset));
608 holdtime = tvb_get_ntohs(tvb, offset);
609 proto_tree_add_text(pimopt_tree, tvb, offset, 2,
610 "Holdtime: %u%s", holdtime,
611 holdtime == 0xffff ? " (infty)" : "");
614 s = dissect_pim_addr(tvb, offset, pimv2_unicast, &advance);
617 proto_tree_add_text(pimopt_tree, tvb, offset, advance, "RP: %s", s);
620 for (i = 0; i < pfxcnt; i++) {
621 s = dissect_pim_addr(tvb, offset, pimv2_group, &advance);
624 proto_tree_add_text(pimopt_tree, tvb, offset, advance,
625 "Group %d: %s", i, s);
640 proto_register_pim(void)
642 static hf_register_info hf[] = {
644 { "Version", "pim.version",
645 FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
647 { "Type", "pim.type",
648 FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
650 { "Checksum", "pim.cksum",
651 FT_UINT16, BASE_HEX, NULL, 0x0, "" }},
653 static gint *ett[] = {
657 proto_pim = proto_register_protocol("Protocol Independent Multicast",
659 proto_register_field_array(proto_pim, hf, array_length(hf));
660 proto_register_subtree_array(ett, array_length(ett));
664 proto_reg_handoff_pim(void)
666 dissector_add("ip.proto", IP_PROTO_PIM, dissect_pim, proto_pim);
669 * Get handles for the IPv4 and IPv6 dissectors.
671 ip_handle = find_dissector("ip");
672 ipv6_handle = find_dissector("ipv6");