2 * Routines for PIM disassembly
3 * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-pim.c,v 1.8 2000/01/15 04:17:35 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.
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;
71 static gint ett_pim = -1;
74 dissect_pim_addr(const u_char *bp, const u_char *ep, enum pimv2_addrtype at,
101 if (bp + 2 + len > ep)
103 (void)snprintf(buf, sizeof(buf), "%s", ip_to_str(bp + 2));
107 if (bp + 2 + len > ep)
109 (void)snprintf(buf, sizeof(buf), "%s",
110 ip6_to_str((struct e_in6_addr *)(bp + 2)));
119 if (bp + 4 + len > ep)
121 (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]);
125 if (bp + 4 + len > ep)
127 (void)snprintf(buf, sizeof(buf), "%s/%u",
128 ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]);
136 if (bp + 4 + len > ep)
138 (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]);
142 if (bp + 4 + len > ep)
144 (void)snprintf(buf, sizeof(buf), "%s/%u",
145 ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]);
148 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
150 bp[2] & 0x04 ? "S" : "",
151 bp[2] & 0x02 ? "W" : "",
152 bp[2] & 0x01 ? "R" : "");
165 dissect_pim(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
167 static const value_string type1vals[] = {
170 { 2, "Register-stop" },
172 { 4, "RP-Reachable" },
179 static const value_string type2vals[] = {
182 { 2, "Register-stop" },
188 { 8, "Candidate-RP-Advertisement" },
192 proto_tree *pim_tree = NULL;
194 proto_tree *pimopt_tree = NULL;
197 /* avoid alignment problem */
198 memcpy(&pim, &pd[offset], sizeof(pim));
200 switch (PIM_VER(pim.pim_typever)) {
202 typestr = val_to_str(PIM_TYPE(pim.pim_typever), type1vals, "Unknown");
205 typestr = val_to_str(PIM_TYPE(pim.pim_typever), type2vals, "Unknown");
212 if (check_col(fd, COL_PROTOCOL)) {
213 col_add_fstr(fd, COL_PROTOCOL, "PIM version %d",
214 PIM_VER(pim.pim_typever));
216 if (check_col(fd, COL_INFO))
217 col_add_fstr(fd, COL_INFO, "%s", typestr);
220 ti = proto_tree_add_item(tree, proto_pim, offset, END_OF_FRAME, NULL);
221 pim_tree = proto_item_add_subtree(ti, ett_pim);
223 proto_tree_add_item(pim_tree, hf_pim_version, offset, 1,
224 PIM_VER(pim.pim_typever));
225 proto_tree_add_item_format(pim_tree, hf_pim_type, offset, 1,
226 PIM_TYPE(pim.pim_typever),
227 "Type: %s (%u)", typestr, PIM_TYPE(pim.pim_typever));
229 proto_tree_add_item(pim_tree, hf_pim_cksum,
230 offset + offsetof(struct pim, pim_cksum), sizeof(pim.pim_cksum),
231 ntohs(pim.pim_cksum));
233 if (sizeof(struct pim) < END_OF_FRAME) {
234 tiopt = proto_tree_add_text(pim_tree,
235 offset + sizeof(struct pim), END_OF_FRAME,
237 pimopt_tree = proto_item_add_subtree(tiopt, ett_pim);
241 if (PIM_VER(pim.pim_typever) != 2)
244 /* version 2 decoder */
245 switch (PIM_TYPE(pim.pim_typever)) {
249 w = (guint16 *)&pd[offset + sizeof(struct pim)];
250 while ((guint8 *)w < &pd[offset + END_OF_FRAME]) {
251 if (pntohs(&w[0]) == 1 && pntohs(&w[1]) == 2
252 && (guint8 *)&w[3] <= &pd[offset + END_OF_FRAME]) {
253 proto_tree_add_text(pimopt_tree, (guint8 *)w - pd, 6,
254 "Holdtime: %u%s", pntohs(&w[2]),
255 pntohs(&w[2]) == 0xffff ? " (infty)" : "");
263 case 1: /* register */
266 proto_tree *flag_tree = NULL;
270 flagoff = offset + sizeof(struct pim);
271 tiflag = proto_tree_add_text(pimopt_tree, flagoff, 4,
272 "Flags: 0x%08x", pntohl(&pd[flagoff]));
273 flag_tree = proto_item_add_subtree(tiflag, ett_pim);
274 proto_tree_add_text(flag_tree, flagoff, 1, "%s",
275 decode_boolean_bitfield(pd[flagoff], 0x80000000, 32,
276 "Border", "Not border"));
277 proto_tree_add_text(flag_tree, flagoff, 1, "%s",
278 decode_boolean_bitfield(pd[flagoff], 0x40000000, 32,
279 "Null-Register", "Not Null-Register"));
281 ip = &pd[flagoff + sizeof(guint32)];
282 switch((*ip & 0xf0) >> 4) {
285 dissect_ip(pd, ip - pd, fd, tree);
287 dissect_ip(pd, ip - pd, fd, pimopt_tree);
292 dissect_ipv6(pd, ip - pd, fd, tree);
294 dissect_ipv6(pd, ip - pd, fd, pimopt_tree);
298 proto_tree_add_text(pimopt_tree,
299 ip - pd, END_OF_FRAME,
300 "Unknown IP version %d", (*ip & 0xf0) >> 4);
306 case 2: /* register-stop */
312 ep = &pd[offset + END_OF_FRAME];
313 offset += sizeof(struct pim);
314 s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance);
317 proto_tree_add_text(pimopt_tree, offset, advance, "Group: %s", s);
319 s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance);
322 proto_tree_add_text(pimopt_tree, offset, advance, "Source: %s", s);
326 case 3: /* join/prune */
328 case 7: /* graft-ack */
334 int ngroup, i, njoin, nprune, j;
335 proto_tree *grouptree = NULL;
337 proto_tree *subtree = NULL;
340 ep = &pd[offset + END_OF_FRAME];
341 offset += sizeof(struct pim);
342 if (PIM_TYPE(pim.pim_typever) != 7) {
344 s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance);
347 proto_tree_add_text(pimopt_tree, offset, advance,
348 "Upstream-neighbor: %s", s);
352 if (&pd[offset + 2] > ep)
354 ngroup = pd[offset + 1];
355 proto_tree_add_text(pimopt_tree, offset + 1, 1,
356 "Groups: %u", pd[offset + 1]);
359 if (&pd[offset + 2] > ep)
361 if (PIM_TYPE(pim.pim_typever) != 7) {
363 proto_tree_add_text(pimopt_tree, offset, 2,
364 "Holdtime: %u%s", pntohs(&pd[offset]),
365 pntohs(&pd[offset]) == 0xffff ? " (infty)" : "");
369 for (i = 0; i < ngroup; i++) {
370 if (&pd[offset] >= ep)
373 s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance);
376 tigroup = proto_tree_add_text(pimopt_tree, offset, advance,
377 "Group %d: %s", i, s);
378 grouptree = proto_item_add_subtree(tigroup, ett_pim);
381 if (&pd[offset + 4] > ep)
383 njoin = pntohs(&pd[offset]);
384 nprune = pntohs(&pd[offset + 2]);
386 tisub = proto_tree_add_text(grouptree, offset, 2,
388 subtree = proto_item_add_subtree(tisub, ett_pim);
390 for (j = 0; j < nprune; j++) {
391 s = dissect_pim_addr(&pd[off], ep, pimv2_source,
395 proto_tree_add_text(subtree, off, advance,
396 "IP address: %s", s);
400 tisub = proto_tree_add_text(grouptree, offset + 2, 2,
401 "Prune: %d", nprune);
402 subtree = proto_item_add_subtree(tisub, ett_pim);
403 for (j = 0; j < nprune; j++) {
404 s = dissect_pim_addr(&pd[off], ep, pimv2_source,
408 proto_tree_add_text(subtree, off, advance,
409 "IP address: %s", s);
417 case 4: /* bootstrap */
423 proto_tree *grouptree = NULL;
426 offset += sizeof(struct pim);
428 if (END_OF_FRAME < 2)
430 proto_tree_add_text(pimopt_tree, offset, 2,
431 "Fragment tag: 0x%04x", pntohs(&pd[offset]));
434 if (END_OF_FRAME < 2)
436 proto_tree_add_text(pimopt_tree, offset, 1,
437 "Hash mask len: %u", pd[offset]);
438 proto_tree_add_text(pimopt_tree, offset + 1, 1,
439 "BSR priority: %u", pd[offset + 1]);
442 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
443 pimv2_unicast, &advance);
446 proto_tree_add_text(pimopt_tree, offset, advance, "BSR: %s", s);
449 for (i = 0; END_OF_FRAME > 0; i++) {
450 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
451 pimv2_group, &advance);
454 tigroup = proto_tree_add_text(pimopt_tree, offset, advance,
455 "Group %d: %s", i, s);
456 grouptree = proto_item_add_subtree(tigroup, ett_pim);
459 if (END_OF_FRAME < 2)
461 proto_tree_add_text(grouptree, offset, 1,
462 "RP count: %u", pd[offset]);
463 proto_tree_add_text(grouptree, offset + 1, 1,
464 "FRP count: %u", pd[offset + 1]);
465 frpcnt = pd[offset + 1];
468 for (j = 0; j < frpcnt && END_OF_FRAME > 0; j++) {
469 s = dissect_pim_addr(&pd[offset],
470 &pd[offset + END_OF_FRAME], pimv2_unicast, &advance);
473 proto_tree_add_text(grouptree, offset, advance,
477 if (END_OF_FRAME < 4)
479 proto_tree_add_text(grouptree, offset, 2,
480 "Holdtime: %u%s", pntohs(&pd[offset]),
481 pntohs(&pd[offset]) == 0xffff ? " (infty)" : "");
482 proto_tree_add_text(grouptree, offset + 3, 1,
483 "Priority: %u", pd[offset + 3]);
498 offset += sizeof(struct pim);
500 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
501 pimv2_group, &advance);
504 proto_tree_add_text(pimopt_tree, offset, advance, "Group: %s", s);
507 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
508 pimv2_unicast, &advance);
511 proto_tree_add_text(pimopt_tree, offset, advance, "Source: %s", s);
514 if (END_OF_FRAME < 4)
516 proto_tree_add_text(pimopt_tree, offset, 1, "%s",
517 decode_boolean_bitfield(pd[offset], 0x80, 8,
518 "RP Tree", "Not RP Tree"));
519 proto_tree_add_text(pimopt_tree, offset, 4, "Preference: %u",
520 pntohl(&pd[offset]) & 0x7fffffff);
523 if (END_OF_FRAME < 4)
525 proto_tree_add_text(pimopt_tree, offset, 4, "Metric: %u",
526 pntohl(&pd[offset]));
531 case 8: /* Candidate-RP-Advertisement */
538 offset += sizeof(struct pim);
539 if (END_OF_FRAME < 4)
542 proto_tree_add_text(pimopt_tree, offset, 1,
543 "Prefix-count: %u", pd[offset]);
544 proto_tree_add_text(pimopt_tree, offset + 1, 1,
545 "Priority: %u", pd[offset + 1]);
546 proto_tree_add_text(pimopt_tree, offset + 2, 2,
547 "Holdtime: %u%s", pntohs(&pd[offset + 2]),
548 pntohs(&pd[offset + 2]) == 0xffff ? " (infty)" : "");
551 if (END_OF_FRAME <= 0)
553 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
554 pimv2_unicast, &advance);
557 proto_tree_add_text(pimopt_tree, offset, advance, "RP: %s", s);
560 for (i = 0; i < pfxcnt && END_OF_FRAME > 0; i++) {
561 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
562 pimv2_group, &advance);
565 proto_tree_add_text(pimopt_tree, offset, advance,
566 "Group %d: %s", i, s);
581 proto_register_pim(void)
583 static hf_register_info hf[] = {
585 { "Version", "pim.version",
586 FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
588 { "Type", "pim.type",
589 FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
591 { "Checksum", "pim.cksum",
592 FT_UINT16, BASE_HEX, NULL, 0x0, "" }},
594 static gint *ett[] = {
598 proto_pim = proto_register_protocol("Protocol Independent Multicast",
600 proto_register_field_array(proto_pim, hf, array_length(hf));
601 proto_register_subtree_array(ett, array_length(ett));