2 * Routines for PIM disassembly
3 * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-pim.c,v 1.5 1999/10/15 13:14:43 itojun 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.
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
33 #ifdef HAVE_NETINET_IN_H
34 #include <netinet/in.h>
37 #ifdef NEED_SNPRINTF_H
43 # include "snprintf.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;
72 dissect_pim_addr(const u_char *bp, const u_char *ep, enum pimv2_addrtype at,
99 if (bp + 2 + len > ep)
101 (void)snprintf(buf, sizeof(buf), "%s", ip_to_str(bp + 2));
105 if (bp + 2 + len > ep)
107 (void)snprintf(buf, sizeof(buf), "%s",
108 ip6_to_str((struct e_in6_addr *)(bp + 2)));
117 if (bp + 4 + len > ep)
119 (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]);
123 if (bp + 4 + len > ep)
125 (void)snprintf(buf, sizeof(buf), "%s/%u",
126 ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]);
134 if (bp + 4 + len > ep)
136 (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]);
140 if (bp + 4 + len > ep)
142 (void)snprintf(buf, sizeof(buf), "%s/%u",
143 ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]);
146 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
148 bp[2] & 0x04 ? "S" : "",
149 bp[2] & 0x02 ? "W" : "",
150 bp[2] & 0x01 ? "R" : "");
163 dissect_pim(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
165 static const value_string type1vals[] = {
168 { 2, "Register-stop" },
170 { 4, "RP-Reachable" },
177 static const value_string type2vals[] = {
180 { 2, "Register-stop" },
186 { 8, "Candidate-RP-Advertisement" },
190 proto_tree *pim_tree = NULL;
192 proto_tree *pimopt_tree = NULL;
195 /* avoid alignment problem */
196 memcpy(&pim, &pd[offset], sizeof(pim));
198 switch (PIM_VER(pim.pim_typever)) {
200 typestr = val_to_str(PIM_TYPE(pim.pim_typever), type1vals, "Unknown");
203 typestr = val_to_str(PIM_TYPE(pim.pim_typever), type2vals, "Unknown");
210 if (check_col(fd, COL_PROTOCOL)) {
211 col_add_fstr(fd, COL_PROTOCOL, "PIM version %d",
212 PIM_VER(pim.pim_typever));
214 if (check_col(fd, COL_INFO))
215 col_add_fstr(fd, COL_INFO, "%s", typestr);
218 ti = proto_tree_add_item(tree, proto_pim, offset, END_OF_FRAME, NULL);
219 pim_tree = proto_item_add_subtree(ti, ETT_PIM);
221 proto_tree_add_item(pim_tree, hf_pim_version, offset, 1,
222 PIM_VER(pim.pim_typever));
223 proto_tree_add_item_format(pim_tree, hf_pim_type, offset, 1,
224 PIM_TYPE(pim.pim_typever),
225 "Type: %s (%u)", typestr, PIM_TYPE(pim.pim_typever));
227 proto_tree_add_item(pim_tree, hf_pim_cksum,
228 offset + offsetof(struct pim, pim_cksum), sizeof(pim.pim_cksum),
229 ntohs(pim.pim_cksum));
231 if (sizeof(struct pim) < END_OF_FRAME) {
232 tiopt = proto_tree_add_text(pim_tree,
233 offset + sizeof(struct pim), END_OF_FRAME,
235 pimopt_tree = proto_item_add_subtree(tiopt, ETT_PIM);
239 if (PIM_VER(pim.pim_typever) != 2)
242 /* version 2 decoder */
243 switch (PIM_TYPE(pim.pim_typever)) {
247 w = (guint16 *)&pd[offset + sizeof(struct pim)];
248 while ((guint8 *)w < &pd[offset + END_OF_FRAME]) {
249 if (ntohs(w[0]) == 1 && ntohs(w[1]) == 2
250 && (guint8 *)&w[3] <= &pd[offset + END_OF_FRAME]) {
251 proto_tree_add_text(pimopt_tree, (guint8 *)w - pd, 6,
252 "Holdtime: %u%s", ntohs(w[2]),
253 ntohs(w[2]) == 0xffff ? " (infty)" : "");
261 case 1: /* register */
264 proto_tree *flag_tree = NULL;
268 flagoff = offset + sizeof(struct pim);
269 tiflag = proto_tree_add_text(pimopt_tree, flagoff, 4,
270 "Flags: 0x%08x", ntohl(*(guint32 *)&pd[flagoff]));
271 flag_tree = proto_item_add_subtree(tiflag, ETT_PIM);
272 proto_tree_add_text(flag_tree, flagoff, 1, "%s",
273 decode_boolean_bitfield(pd[flagoff], 0x80000000, 32,
274 "Border", "Not border"));
275 proto_tree_add_text(flag_tree, flagoff, 1, "%s",
276 decode_boolean_bitfield(pd[flagoff], 0x40000000, 32,
277 "Null-Register", "Not Null-Register"));
279 ip = &pd[flagoff + sizeof(guint32)];
280 switch((*ip & 0xf0) >> 4) {
283 dissect_ip(pd, ip - pd, fd, pimopt_tree);
285 dissect_ip(pd, ip - pd, fd, tree);
290 dissect_ipv6(pd, ip - pd, fd, pimopt_tree);
292 dissect_ipv6(pd, ip - pd, fd, tree);
296 proto_tree_add_text(pimopt_tree,
297 ip - pd, END_OF_FRAME,
298 "Unknown IP version %d", (*ip & 0xf0) >> 4);
304 case 2: /* register-stop */
310 ep = &pd[offset + END_OF_FRAME];
311 offset += sizeof(struct pim);
312 s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance);
315 proto_tree_add_text(pimopt_tree, offset, advance, "Group: %s", s);
317 s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance);
320 proto_tree_add_text(pimopt_tree, offset, advance, "Source: %s", s);
324 case 3: /* join/prune */
326 case 7: /* graft-ack */
332 int ngroup, i, njoin, nprune, j;
333 proto_tree *grouptree = NULL;
335 proto_tree *subtree = NULL;
338 ep = &pd[offset + END_OF_FRAME];
339 offset += sizeof(struct pim);
340 if (PIM_TYPE(pim.pim_typever) != 7) {
342 s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance);
345 proto_tree_add_text(pimopt_tree, offset, advance,
346 "Upstream-neighbor: %s", s);
350 if (&pd[offset + 2] > ep)
352 ngroup = pd[offset + 1];
353 proto_tree_add_text(pimopt_tree, offset + 1, 1,
354 "Groups: %u", pd[offset + 1]);
357 if (&pd[offset + 2] > ep)
359 if (PIM_TYPE(pim.pim_typever) != 7) {
361 proto_tree_add_text(pimopt_tree, offset, 2,
362 "Holdtime: %u%s", ntohs(*(guint16 *)&pd[offset]),
363 ntohs(*(guint16 *)&pd[offset]) == 0xffff ? " (infty)" : "");
367 for (i = 0; i < ngroup; i++) {
368 if (&pd[offset] >= ep)
371 s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance);
374 tigroup = proto_tree_add_text(pimopt_tree, offset, advance,
375 "Group %d: %s", i, s);
376 grouptree = proto_item_add_subtree(tigroup, ETT_PIM);
379 if (&pd[offset + 4] > ep)
381 njoin = ntohs(*(guint16 *)&pd[offset]);
382 nprune = ntohs(*(guint16 *)&pd[offset + 2]);
384 tisub = proto_tree_add_text(grouptree, offset, 2,
386 subtree = proto_item_add_subtree(tisub, ETT_PIM);
388 for (j = 0; j < nprune; j++) {
389 s = dissect_pim_addr(&pd[off], ep, pimv2_source,
393 proto_tree_add_text(subtree, off, advance,
394 "IP address: %s", s);
398 tisub = proto_tree_add_text(grouptree, offset + 2, 2,
399 "Prune: %d", nprune);
400 subtree = proto_item_add_subtree(tisub, ETT_PIM);
401 for (j = 0; j < nprune; j++) {
402 s = dissect_pim_addr(&pd[off], ep, pimv2_source,
406 proto_tree_add_text(subtree, off, advance,
407 "IP address: %s", s);
415 case 4: /* bootstrap */
421 proto_tree *grouptree = NULL;
424 offset += sizeof(struct pim);
426 if (END_OF_FRAME < 2)
428 proto_tree_add_text(pimopt_tree, offset, 2,
429 "Fragment tag: 0x%04x", ntohs(*(guint16 *)&pd[offset]));
432 if (END_OF_FRAME < 2)
434 proto_tree_add_text(pimopt_tree, offset, 1,
435 "Hash mask len: %u", pd[offset]);
436 proto_tree_add_text(pimopt_tree, offset + 1, 1,
437 "BSR priority: %u", pd[offset + 1]);
440 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
441 pimv2_unicast, &advance);
444 proto_tree_add_text(pimopt_tree, offset, advance, "BSR: %s", s);
447 for (i = 0; END_OF_FRAME > 0; i++) {
448 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
449 pimv2_group, &advance);
452 tigroup = proto_tree_add_text(pimopt_tree, offset, advance,
453 "Group %d: %s", i, s);
454 grouptree = proto_item_add_subtree(tigroup, ETT_PIM);
457 if (END_OF_FRAME < 2)
459 proto_tree_add_text(grouptree, offset, 1,
460 "RP count: %u", pd[offset]);
461 proto_tree_add_text(grouptree, offset + 1, 1,
462 "FRP count: %u", pd[offset + 1]);
463 frpcnt = pd[offset + 1];
466 for (j = 0; j < frpcnt && END_OF_FRAME > 0; j++) {
467 s = dissect_pim_addr(&pd[offset],
468 &pd[offset + END_OF_FRAME], pimv2_unicast, &advance);
471 proto_tree_add_text(grouptree, offset, advance,
475 if (END_OF_FRAME < 4)
477 proto_tree_add_text(grouptree, offset, 2,
478 "Holdtime: %u%s", ntohs(*(guint16 *)&pd[offset]),
479 ntohs(*(guint16 *)&pd[offset]) == 0xffff ? " (infty)" : "");
480 proto_tree_add_text(grouptree, offset + 3, 1,
481 "Priority: %u", pd[offset + 3]);
496 offset += sizeof(struct pim);
498 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
499 pimv2_group, &advance);
502 proto_tree_add_text(pimopt_tree, offset, advance, "Group: %s", s);
505 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
506 pimv2_unicast, &advance);
509 proto_tree_add_text(pimopt_tree, offset, advance, "Source: %s", s);
512 if (END_OF_FRAME < 4)
514 proto_tree_add_text(pimopt_tree, offset, 1, "%s",
515 decode_boolean_bitfield(pd[offset], 0x80, 8,
516 "RP Tree", "Not RP Tree"));
517 proto_tree_add_text(pimopt_tree, offset, 4, "Preference: %u",
518 ntohl(*(guint32 *)&pd[offset] & 0x7fffffff));
521 if (END_OF_FRAME < 4)
523 proto_tree_add_text(pimopt_tree, offset, 4, "Metric: %u",
524 ntohl(*(guint32 *)&pd[offset]));
529 case 8: /* Candidate-RP-Advertisement */
536 offset += sizeof(struct pim);
537 if (END_OF_FRAME < 4)
540 proto_tree_add_text(pimopt_tree, offset, 1,
541 "Prefix-count: %u", pd[offset]);
542 proto_tree_add_text(pimopt_tree, offset + 1, 1,
543 "Priority: %u", pd[offset + 1]);
544 proto_tree_add_text(pimopt_tree, offset + 2, 2,
545 "Holdtime: %u%s", ntohs(*(guint16 *)&pd[offset + 2]),
546 ntohs(*(guint16 *)&pd[offset + 2]) == 0xffff ? " (infty)" : "");
549 if (END_OF_FRAME <= 0)
551 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
552 pimv2_unicast, &advance);
555 proto_tree_add_text(pimopt_tree, offset, advance, "RP: %s", s);
558 for (i = 0; i < pfxcnt && END_OF_FRAME > 0; i++) {
559 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
560 pimv2_group, &advance);
563 proto_tree_add_text(pimopt_tree, offset, advance,
564 "Group %d: %s", i, s);
579 proto_register_pim(void)
581 static hf_register_info hf[] = {
583 { "Version", "pim.version",
584 FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
586 { "Type", "pim.type",
587 FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
589 { "Checksum", "pim.cksum",
590 FT_UINT16, BASE_HEX, NULL, 0x0, "" }},
593 proto_pim = proto_register_protocol("Protocol Independent Multicast",
595 proto_register_field_array(proto_pim, hf, array_length(hf));