2 * Routines for PIM disassembly
3 * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-pim.c,v 1.11 2000/04/16 22:46:22 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-ip.h"
49 #include "packet-ipv6.h"
52 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
57 #define PIM_TYPE(x) ((x) & 0x0f)
58 #define PIM_VER(x) (((x) & 0xf0) >> 4)
59 guint8 pim_rsv; /* Reserved */
60 guint16 pim_cksum; /* IP style check sum */
64 pimv2_unicast, pimv2_group, pimv2_source
67 static int proto_pim = -1;
68 static int hf_pim_version = -1;
69 static int hf_pim_type = -1;
70 static int hf_pim_cksum = -1;
72 static gint ett_pim = -1;
75 dissect_pim_addr(const u_char *bp, const u_char *ep, enum pimv2_addrtype at,
102 if (bp + 2 + len > ep)
104 (void)snprintf(buf, sizeof(buf), "%s", ip_to_str(bp + 2));
108 if (bp + 2 + len > ep)
110 (void)snprintf(buf, sizeof(buf), "%s",
111 ip6_to_str((struct e_in6_addr *)(bp + 2)));
120 if (bp + 4 + len > ep)
122 (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]);
126 if (bp + 4 + len > ep)
128 (void)snprintf(buf, sizeof(buf), "%s/%u",
129 ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]);
137 if (bp + 4 + len > ep)
139 (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]);
143 if (bp + 4 + len > ep)
145 (void)snprintf(buf, sizeof(buf), "%s/%u",
146 ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]);
149 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
151 bp[2] & 0x04 ? "S" : "",
152 bp[2] & 0x02 ? "W" : "",
153 bp[2] & 0x01 ? "R" : "");
166 dissect_pim(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
168 static const value_string type1vals[] = {
171 { 2, "Register-stop" },
173 { 4, "RP-Reachable" },
180 static const value_string type2vals[] = {
183 { 2, "Register-stop" },
189 { 8, "Candidate-RP-Advertisement" },
193 proto_tree *pim_tree = NULL;
195 proto_tree *pimopt_tree = NULL;
198 /* avoid alignment problem */
199 memcpy(&pim, &pd[offset], sizeof(pim));
201 switch (PIM_VER(pim.pim_typever)) {
203 typestr = val_to_str(PIM_TYPE(pim.pim_typever), type1vals, "Unknown");
206 typestr = val_to_str(PIM_TYPE(pim.pim_typever), type2vals, "Unknown");
213 if (check_col(fd, COL_PROTOCOL)) {
214 col_add_fstr(fd, COL_PROTOCOL, "PIM version %d",
215 PIM_VER(pim.pim_typever));
217 if (check_col(fd, COL_INFO))
218 col_add_fstr(fd, COL_INFO, "%s", typestr);
221 ti = proto_tree_add_item(tree, proto_pim, offset, END_OF_FRAME, NULL);
222 pim_tree = proto_item_add_subtree(ti, ett_pim);
224 proto_tree_add_item(pim_tree, hf_pim_version, offset, 1,
225 PIM_VER(pim.pim_typever));
226 proto_tree_add_uint_format(pim_tree, hf_pim_type, offset, 1,
227 PIM_TYPE(pim.pim_typever),
228 "Type: %s (%u)", typestr, PIM_TYPE(pim.pim_typever));
230 proto_tree_add_item(pim_tree, hf_pim_cksum,
231 offset + offsetof(struct pim, pim_cksum), sizeof(pim.pim_cksum),
232 ntohs(pim.pim_cksum));
234 if (sizeof(struct pim) < END_OF_FRAME) {
235 tiopt = proto_tree_add_text(pim_tree,
236 offset + sizeof(struct pim), END_OF_FRAME,
238 pimopt_tree = proto_item_add_subtree(tiopt, ett_pim);
242 if (PIM_VER(pim.pim_typever) != 2)
245 /* version 2 decoder */
246 switch (PIM_TYPE(pim.pim_typever)) {
250 w = (guint16 *)&pd[offset + sizeof(struct pim)];
251 while ((guint8 *)w < &pd[offset + END_OF_FRAME]) {
252 if (pntohs(&w[0]) == 1 && pntohs(&w[1]) == 2
253 && (guint8 *)&w[3] <= &pd[offset + END_OF_FRAME]) {
254 proto_tree_add_text(pimopt_tree, (guint8 *)w - pd, 6,
255 "Holdtime: %u%s", pntohs(&w[2]),
256 pntohs(&w[2]) == 0xffff ? " (infty)" : "");
264 case 1: /* register */
267 proto_tree *flag_tree = NULL;
271 flagoff = offset + sizeof(struct pim);
272 tiflag = proto_tree_add_text(pimopt_tree, flagoff, 4,
273 "Flags: 0x%08x", pntohl(&pd[flagoff]));
274 flag_tree = proto_item_add_subtree(tiflag, ett_pim);
275 proto_tree_add_text(flag_tree, flagoff, 1, "%s",
276 decode_boolean_bitfield(pd[flagoff], 0x80000000, 32,
277 "Border", "Not border"));
278 proto_tree_add_text(flag_tree, flagoff, 1, "%s",
279 decode_boolean_bitfield(pd[flagoff], 0x40000000, 32,
280 "Null-Register", "Not Null-Register"));
282 ip = &pd[flagoff + sizeof(guint32)];
283 switch((*ip & 0xf0) >> 4) {
286 dissect_ip(pd, ip - pd, fd, tree);
288 dissect_ip(pd, ip - pd, fd, pimopt_tree);
293 dissect_ipv6(pd, ip - pd, fd, tree);
295 dissect_ipv6(pd, ip - pd, fd, pimopt_tree);
299 proto_tree_add_text(pimopt_tree,
300 ip - pd, END_OF_FRAME,
301 "Unknown IP version %d", (*ip & 0xf0) >> 4);
307 case 2: /* register-stop */
313 ep = &pd[offset + END_OF_FRAME];
314 offset += sizeof(struct pim);
315 s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance);
318 proto_tree_add_text(pimopt_tree, offset, advance, "Group: %s", s);
320 s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance);
323 proto_tree_add_text(pimopt_tree, offset, advance, "Source: %s", s);
327 case 3: /* join/prune */
329 case 7: /* graft-ack */
335 int ngroup, i, njoin, nprune, j;
336 proto_tree *grouptree = NULL;
338 proto_tree *subtree = NULL;
341 ep = &pd[offset + END_OF_FRAME];
342 offset += sizeof(struct pim);
343 if (PIM_TYPE(pim.pim_typever) != 7) {
345 s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance);
348 proto_tree_add_text(pimopt_tree, offset, advance,
349 "Upstream-neighbor: %s", s);
353 if (&pd[offset + 2] > ep)
355 ngroup = pd[offset + 1];
356 proto_tree_add_text(pimopt_tree, offset + 1, 1,
357 "Groups: %u", pd[offset + 1]);
360 if (&pd[offset + 2] > ep)
362 if (PIM_TYPE(pim.pim_typever) != 7) {
364 proto_tree_add_text(pimopt_tree, offset, 2,
365 "Holdtime: %u%s", pntohs(&pd[offset]),
366 pntohs(&pd[offset]) == 0xffff ? " (infty)" : "");
370 for (i = 0; i < ngroup; i++) {
371 if (&pd[offset] >= ep)
374 s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance);
377 tigroup = proto_tree_add_text(pimopt_tree, offset, advance,
378 "Group %d: %s", i, s);
379 grouptree = proto_item_add_subtree(tigroup, ett_pim);
382 if (&pd[offset + 4] > ep)
384 njoin = pntohs(&pd[offset]);
385 nprune = pntohs(&pd[offset + 2]);
387 tisub = proto_tree_add_text(grouptree, offset, 2,
389 subtree = proto_item_add_subtree(tisub, ett_pim);
391 for (j = 0; j < nprune; j++) {
392 s = dissect_pim_addr(&pd[off], ep, pimv2_source,
396 proto_tree_add_text(subtree, off, advance,
397 "IP address: %s", s);
401 tisub = proto_tree_add_text(grouptree, offset + 2, 2,
402 "Prune: %d", nprune);
403 subtree = proto_item_add_subtree(tisub, ett_pim);
404 for (j = 0; j < nprune; j++) {
405 s = dissect_pim_addr(&pd[off], ep, pimv2_source,
409 proto_tree_add_text(subtree, off, advance,
410 "IP address: %s", s);
418 case 4: /* bootstrap */
424 proto_tree *grouptree = NULL;
427 offset += sizeof(struct pim);
429 if (END_OF_FRAME < 2)
431 proto_tree_add_text(pimopt_tree, offset, 2,
432 "Fragment tag: 0x%04x", pntohs(&pd[offset]));
435 if (END_OF_FRAME < 2)
437 proto_tree_add_text(pimopt_tree, offset, 1,
438 "Hash mask len: %u", pd[offset]);
439 proto_tree_add_text(pimopt_tree, offset + 1, 1,
440 "BSR priority: %u", pd[offset + 1]);
443 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
444 pimv2_unicast, &advance);
447 proto_tree_add_text(pimopt_tree, offset, advance, "BSR: %s", s);
450 for (i = 0; END_OF_FRAME > 0; i++) {
451 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
452 pimv2_group, &advance);
455 tigroup = proto_tree_add_text(pimopt_tree, offset, advance,
456 "Group %d: %s", i, s);
457 grouptree = proto_item_add_subtree(tigroup, ett_pim);
460 if (END_OF_FRAME < 2)
462 proto_tree_add_text(grouptree, offset, 1,
463 "RP count: %u", pd[offset]);
464 proto_tree_add_text(grouptree, offset + 1, 1,
465 "FRP count: %u", pd[offset + 1]);
466 frpcnt = pd[offset + 1];
469 for (j = 0; j < frpcnt && END_OF_FRAME > 0; j++) {
470 s = dissect_pim_addr(&pd[offset],
471 &pd[offset + END_OF_FRAME], pimv2_unicast, &advance);
474 proto_tree_add_text(grouptree, offset, advance,
478 if (END_OF_FRAME < 4)
480 proto_tree_add_text(grouptree, offset, 2,
481 "Holdtime: %u%s", pntohs(&pd[offset]),
482 pntohs(&pd[offset]) == 0xffff ? " (infty)" : "");
483 proto_tree_add_text(grouptree, offset + 3, 1,
484 "Priority: %u", pd[offset + 3]);
499 offset += sizeof(struct pim);
501 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
502 pimv2_group, &advance);
505 proto_tree_add_text(pimopt_tree, offset, advance, "Group: %s", s);
508 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
509 pimv2_unicast, &advance);
512 proto_tree_add_text(pimopt_tree, offset, advance, "Source: %s", s);
515 if (END_OF_FRAME < 4)
517 proto_tree_add_text(pimopt_tree, offset, 1, "%s",
518 decode_boolean_bitfield(pd[offset], 0x80, 8,
519 "RP Tree", "Not RP Tree"));
520 proto_tree_add_text(pimopt_tree, offset, 4, "Preference: %u",
521 pntohl(&pd[offset]) & 0x7fffffff);
524 if (END_OF_FRAME < 4)
526 proto_tree_add_text(pimopt_tree, offset, 4, "Metric: %u",
527 pntohl(&pd[offset]));
532 case 8: /* Candidate-RP-Advertisement */
539 offset += sizeof(struct pim);
540 if (END_OF_FRAME < 4)
543 proto_tree_add_text(pimopt_tree, offset, 1,
544 "Prefix-count: %u", pd[offset]);
545 proto_tree_add_text(pimopt_tree, offset + 1, 1,
546 "Priority: %u", pd[offset + 1]);
547 proto_tree_add_text(pimopt_tree, offset + 2, 2,
548 "Holdtime: %u%s", pntohs(&pd[offset + 2]),
549 pntohs(&pd[offset + 2]) == 0xffff ? " (infty)" : "");
552 if (END_OF_FRAME <= 0)
554 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
555 pimv2_unicast, &advance);
558 proto_tree_add_text(pimopt_tree, offset, advance, "RP: %s", s);
561 for (i = 0; i < pfxcnt && END_OF_FRAME > 0; i++) {
562 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
563 pimv2_group, &advance);
566 proto_tree_add_text(pimopt_tree, offset, advance,
567 "Group %d: %s", i, s);
582 proto_register_pim(void)
584 static hf_register_info hf[] = {
586 { "Version", "pim.version",
587 FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
589 { "Type", "pim.type",
590 FT_UINT8, BASE_DEC, NULL, 0x0, "" }},
592 { "Checksum", "pim.cksum",
593 FT_UINT16, BASE_HEX, NULL, 0x0, "" }},
595 static gint *ett[] = {
599 proto_pim = proto_register_protocol("Protocol Independent Multicast",
601 proto_register_field_array(proto_pim, hf, array_length(hf));
602 proto_register_subtree_array(ett, array_length(ett));
606 proto_reg_handoff_pim(void)
608 dissector_add("ip.proto", IP_PROTO_PIM, dissect_pim);