2 * Routines for PIM disassembly
3 * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-pim.c,v 1.20 2001/01/03 06:55:30 guy Exp $
7 * Ethereal - Network traffic analyzer
8 * By Gerald Combs <gerald@zing.org>
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"
47 #include "packet-ip.h"
48 #include "packet-ipv6.h"
51 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
56 #define PIM_TYPE(x) ((x) & 0x0f)
57 #define PIM_VER(x) (((x) & 0xf0) >> 4)
58 guint8 pim_rsv; /* Reserved */
59 guint16 pim_cksum; /* IP style check sum */
63 pimv2_unicast, pimv2_group, pimv2_source
66 static int proto_pim = -1;
67 static int hf_pim_version = -1;
68 static int hf_pim_type = -1;
69 static int hf_pim_cksum = -1;
71 static gint ett_pim = -1;
73 static dissector_handle_t ip_handle;
76 dissect_pim_addr(const u_char *bp, const u_char *ep, enum pimv2_addrtype at,
103 if (bp + 2 + len > ep)
105 (void)snprintf(buf, sizeof(buf), "%s", ip_to_str(bp + 2));
109 if (bp + 2 + len > ep)
111 (void)snprintf(buf, sizeof(buf), "%s",
112 ip6_to_str((struct e_in6_addr *)(bp + 2)));
121 if (bp + 4 + len > ep)
123 (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]);
127 if (bp + 4 + len > ep)
129 (void)snprintf(buf, sizeof(buf), "%s/%u",
130 ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]);
138 if (bp + 4 + len > ep)
140 (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]);
144 if (bp + 4 + len > ep)
146 (void)snprintf(buf, sizeof(buf), "%s/%u",
147 ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]);
150 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
152 bp[2] & 0x04 ? "S" : "",
153 bp[2] & 0x02 ? "W" : "",
154 bp[2] & 0x01 ? "R" : "");
167 dissect_pim(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
169 static const value_string type1vals[] = {
172 { 2, "Register-stop" },
174 { 4, "RP-Reachable" },
181 static const value_string type2vals[] = {
184 { 2, "Register-stop" },
190 { 8, "Candidate-RP-Advertisement" },
194 proto_tree *pim_tree = NULL;
196 proto_tree *pimopt_tree = NULL;
199 OLD_CHECK_DISPLAY_AS_DATA(proto_pim, pd, offset, fd, tree);
201 /* avoid alignment problem */
202 memcpy(&pim, &pd[offset], sizeof(pim));
204 switch (PIM_VER(pim.pim_typever)) {
206 typestr = val_to_str(PIM_TYPE(pim.pim_typever), type1vals, "Unknown");
209 typestr = val_to_str(PIM_TYPE(pim.pim_typever), type2vals, "Unknown");
216 if (check_col(fd, COL_PROTOCOL)) {
217 col_add_fstr(fd, COL_PROTOCOL, "PIM version %d",
218 PIM_VER(pim.pim_typever));
220 if (check_col(fd, COL_INFO))
221 col_add_fstr(fd, COL_INFO, "%s", typestr);
224 ti = proto_tree_add_item(tree, proto_pim, NullTVB, offset, END_OF_FRAME, FALSE);
225 pim_tree = proto_item_add_subtree(ti, ett_pim);
227 proto_tree_add_uint(pim_tree, hf_pim_version, NullTVB, offset, 1,
228 PIM_VER(pim.pim_typever));
229 proto_tree_add_uint_format(pim_tree, hf_pim_type, NullTVB, offset, 1,
230 PIM_TYPE(pim.pim_typever),
231 "Type: %s (%u)", typestr, PIM_TYPE(pim.pim_typever));
233 proto_tree_add_uint(pim_tree, hf_pim_cksum, NullTVB,
234 offset + offsetof(struct pim, pim_cksum), sizeof(pim.pim_cksum),
235 ntohs(pim.pim_cksum));
237 if (sizeof(struct pim) < END_OF_FRAME) {
238 tiopt = proto_tree_add_text(pim_tree, NullTVB,
239 offset + sizeof(struct pim), END_OF_FRAME,
241 pimopt_tree = proto_item_add_subtree(tiopt, ett_pim);
245 if (PIM_VER(pim.pim_typever) != 2)
248 /* version 2 decoder */
249 switch (PIM_TYPE(pim.pim_typever)) {
253 w = (guint16 *)&pd[offset + sizeof(struct pim)];
254 while ((guint8 *)w < &pd[offset + END_OF_FRAME]) {
255 if (pntohs(&w[0]) == 1 && pntohs(&w[1]) == 2
256 && (guint8 *)&w[3] <= &pd[offset + END_OF_FRAME]) {
257 proto_tree_add_text(pimopt_tree, NullTVB, (guint8 *)w - pd, 6,
258 "Holdtime: %u%s", pntohs(&w[2]),
259 pntohs(&w[2]) == 0xffff ? " (infty)" : "");
267 case 1: /* register */
270 proto_tree *flag_tree = NULL;
274 flagoff = offset + sizeof(struct pim);
275 tiflag = proto_tree_add_text(pimopt_tree, NullTVB, flagoff, 4,
276 "Flags: 0x%08x", pntohl(&pd[flagoff]));
277 flag_tree = proto_item_add_subtree(tiflag, ett_pim);
278 proto_tree_add_text(flag_tree, NullTVB, flagoff, 1, "%s",
279 decode_boolean_bitfield(pd[flagoff], 0x80000000, 32,
280 "Border", "Not border"));
281 proto_tree_add_text(flag_tree, NullTVB, flagoff, 1, "%s",
282 decode_boolean_bitfield(pd[flagoff], 0x40000000, 32,
283 "Null-Register", "Not Null-Register"));
285 ip = &pd[flagoff + sizeof(guint32)];
286 switch((*ip & 0xf0) >> 4) {
289 old_call_dissector(ip_handle, pd, ip - pd, fd, tree);
291 old_call_dissector(ip_handle, pd, ip - pd, fd, pimopt_tree);
296 dissect_ipv6(pd, ip - pd, fd, tree);
298 dissect_ipv6(pd, ip - pd, fd, pimopt_tree);
302 proto_tree_add_text(pimopt_tree, NullTVB,
303 ip - pd, END_OF_FRAME,
304 "Unknown IP version %d", (*ip & 0xf0) >> 4);
310 case 2: /* register-stop */
316 ep = &pd[offset + END_OF_FRAME];
317 offset += sizeof(struct pim);
318 s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance);
321 proto_tree_add_text(pimopt_tree, NullTVB, offset, advance, "Group: %s", s);
323 s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance);
326 proto_tree_add_text(pimopt_tree, NullTVB, offset, advance, "Source: %s", s);
330 case 3: /* join/prune */
332 case 7: /* graft-ack */
338 int ngroup, i, njoin, nprune, j;
339 proto_tree *grouptree = NULL;
341 proto_tree *subtree = NULL;
344 ep = &pd[offset + END_OF_FRAME];
345 offset += sizeof(struct pim);
346 if (PIM_TYPE(pim.pim_typever) != 7) {
348 s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance);
351 proto_tree_add_text(pimopt_tree, NullTVB, offset, advance,
352 "Upstream-neighbor: %s", s);
356 if (&pd[offset + 2] > ep)
358 ngroup = pd[offset + 1];
359 proto_tree_add_text(pimopt_tree, NullTVB, offset + 1, 1,
360 "Groups: %u", pd[offset + 1]);
363 if (&pd[offset + 2] > ep)
365 if (PIM_TYPE(pim.pim_typever) != 7) {
367 proto_tree_add_text(pimopt_tree, NullTVB, offset, 2,
368 "Holdtime: %u%s", pntohs(&pd[offset]),
369 pntohs(&pd[offset]) == 0xffff ? " (infty)" : "");
373 for (i = 0; i < ngroup; i++) {
374 if (&pd[offset] >= ep)
377 s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance);
380 tigroup = proto_tree_add_text(pimopt_tree, NullTVB, offset, advance,
381 "Group %d: %s", i, s);
382 grouptree = proto_item_add_subtree(tigroup, ett_pim);
385 if (&pd[offset + 4] > ep)
387 njoin = pntohs(&pd[offset]);
388 nprune = pntohs(&pd[offset + 2]);
390 tisub = proto_tree_add_text(grouptree, NullTVB, offset, 2,
392 subtree = proto_item_add_subtree(tisub, ett_pim);
394 for (j = 0; j < nprune; j++) {
395 s = dissect_pim_addr(&pd[off], ep, pimv2_source,
399 proto_tree_add_text(subtree, NullTVB, off, advance,
400 "IP address: %s", s);
404 tisub = proto_tree_add_text(grouptree, NullTVB, offset + 2, 2,
405 "Prune: %d", nprune);
406 subtree = proto_item_add_subtree(tisub, ett_pim);
407 for (j = 0; j < nprune; j++) {
408 s = dissect_pim_addr(&pd[off], ep, pimv2_source,
412 proto_tree_add_text(subtree, NullTVB, off, advance,
413 "IP address: %s", s);
421 case 4: /* bootstrap */
427 proto_tree *grouptree = NULL;
430 offset += sizeof(struct pim);
432 if (END_OF_FRAME < 2)
434 proto_tree_add_text(pimopt_tree, NullTVB, offset, 2,
435 "Fragment tag: 0x%04x", pntohs(&pd[offset]));
438 if (END_OF_FRAME < 2)
440 proto_tree_add_text(pimopt_tree, NullTVB, offset, 1,
441 "Hash mask len: %u", pd[offset]);
442 proto_tree_add_text(pimopt_tree, NullTVB, offset + 1, 1,
443 "BSR priority: %u", pd[offset + 1]);
446 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
447 pimv2_unicast, &advance);
450 proto_tree_add_text(pimopt_tree, NullTVB, offset, advance, "BSR: %s", s);
453 for (i = 0; END_OF_FRAME > 0; i++) {
454 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
455 pimv2_group, &advance);
458 tigroup = proto_tree_add_text(pimopt_tree, NullTVB, offset, advance,
459 "Group %d: %s", i, s);
460 grouptree = proto_item_add_subtree(tigroup, ett_pim);
463 if (END_OF_FRAME < 2)
465 proto_tree_add_text(grouptree, NullTVB, offset, 1,
466 "RP count: %u", pd[offset]);
467 proto_tree_add_text(grouptree, NullTVB, offset + 1, 1,
468 "FRP count: %u", pd[offset + 1]);
469 frpcnt = pd[offset + 1];
472 for (j = 0; j < frpcnt && END_OF_FRAME > 0; j++) {
473 s = dissect_pim_addr(&pd[offset],
474 &pd[offset + END_OF_FRAME], pimv2_unicast, &advance);
477 proto_tree_add_text(grouptree, NullTVB, offset, advance,
481 if (END_OF_FRAME < 4)
483 proto_tree_add_text(grouptree, NullTVB, offset, 2,
484 "Holdtime: %u%s", pntohs(&pd[offset]),
485 pntohs(&pd[offset]) == 0xffff ? " (infty)" : "");
486 proto_tree_add_text(grouptree, NullTVB, offset + 3, 1,
487 "Priority: %u", pd[offset + 3]);
502 offset += sizeof(struct pim);
504 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
505 pimv2_group, &advance);
508 proto_tree_add_text(pimopt_tree, NullTVB, offset, advance, "Group: %s", s);
511 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
512 pimv2_unicast, &advance);
515 proto_tree_add_text(pimopt_tree, NullTVB, offset, advance, "Source: %s", s);
518 if (END_OF_FRAME < 4)
520 proto_tree_add_text(pimopt_tree, NullTVB, offset, 1, "%s",
521 decode_boolean_bitfield(pd[offset], 0x80, 8,
522 "RP Tree", "Not RP Tree"));
523 proto_tree_add_text(pimopt_tree, NullTVB, offset, 4, "Preference: %u",
524 pntohl(&pd[offset]) & 0x7fffffff);
527 if (END_OF_FRAME < 4)
529 proto_tree_add_text(pimopt_tree, NullTVB, offset, 4, "Metric: %u",
530 pntohl(&pd[offset]));
535 case 8: /* Candidate-RP-Advertisement */
542 offset += sizeof(struct pim);
543 if (END_OF_FRAME < 4)
546 proto_tree_add_text(pimopt_tree, NullTVB, offset, 1,
547 "Prefix-count: %u", pd[offset]);
548 proto_tree_add_text(pimopt_tree, NullTVB, offset + 1, 1,
549 "Priority: %u", pd[offset + 1]);
550 proto_tree_add_text(pimopt_tree, NullTVB, offset + 2, 2,
551 "Holdtime: %u%s", pntohs(&pd[offset + 2]),
552 pntohs(&pd[offset + 2]) == 0xffff ? " (infty)" : "");
555 if (END_OF_FRAME <= 0)
557 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
558 pimv2_unicast, &advance);
561 proto_tree_add_text(pimopt_tree, NullTVB, offset, advance, "RP: %s", s);
564 for (i = 0; i < pfxcnt && END_OF_FRAME > 0; i++) {
565 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
566 pimv2_group, &advance);
569 proto_tree_add_text(pimopt_tree, NullTVB, offset, advance,
570 "Group %d: %s", i, s);
585 proto_register_pim(void)
587 static hf_register_info hf[] = {
589 { "Version", "pim.version",
590 FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
592 { "Type", "pim.type",
593 FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
595 { "Checksum", "pim.cksum",
596 FT_UINT16, BASE_HEX, NULL, 0x0, "" }},
598 static gint *ett[] = {
602 proto_pim = proto_register_protocol("Protocol Independent Multicast",
604 proto_register_field_array(proto_pim, hf, array_length(hf));
605 proto_register_subtree_array(ett, array_length(ett));
609 proto_reg_handoff_pim(void)
611 old_dissector_add("ip.proto", IP_PROTO_PIM, dissect_pim);
614 * Get a handle for the IP dissector.
616 ip_handle = find_dissector("ip");