2 * Routines for PIM disassembly
3 * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org>
5 * $Id: packet-pim.c,v 1.3 1999/10/14 01:39:47 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;
69 dissect_pim_addr(const u_char *bp, const u_char *ep, enum pimv2_addrtype at,
96 if (bp + 2 + len > ep)
98 (void)snprintf(buf, sizeof(buf), "%s", ip_to_str(bp + 2));
102 if (bp + 2 + len > ep)
104 (void)snprintf(buf, sizeof(buf), "%s",
105 ip6_to_str((struct e_in6_addr *)(bp + 2)));
114 if (bp + 4 + len > ep)
116 (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]);
120 if (bp + 4 + len > ep)
122 (void)snprintf(buf, sizeof(buf), "%s/%u",
123 ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]);
131 if (bp + 4 + len > ep)
133 (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]);
137 if (bp + 4 + len > ep)
139 (void)snprintf(buf, sizeof(buf), "%s/%u",
140 ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]);
143 (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
145 bp[2] & 0x04 ? "S" : "",
146 bp[2] & 0x02 ? "W" : "",
147 bp[2] & 0x01 ? "R" : "");
160 dissect_pim(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) {
162 char *packet_type1[] = {
163 "Query", "Register", "Register-Stop", "Join/Prune", "RP-Reachable",
164 "Assert", "Graft", "Graft-Ack", "Mode"
166 char *packet_type2[] = {
167 "Hello", "Register", "Register-Stop", "Join/Prune", "Bootstrap",
168 "Assert", "Graft", "Graft-Ack", "Candidate-RP-Advertisement"
171 proto_tree *pim_tree = NULL;
173 proto_tree *pimopt_tree = NULL;
176 /* avoid alignment problem */
177 memcpy(&pim, &pd[offset], sizeof(pim));
180 switch (PIM_VER(pim.pim_typever)) {
182 if (PIM_TYPE(pim.pim_typever) < sizeof(packet_type1) / sizeof(packet_type1[0])) {
183 typestr = packet_type1[PIM_TYPE(pim.pim_typever)];
187 if (PIM_TYPE(pim.pim_typever) < sizeof(packet_type2) / sizeof(packet_type2[0])) {
188 typestr = packet_type2[PIM_TYPE(pim.pim_typever)];
193 if (check_col(fd, COL_PROTOCOL)) {
194 col_add_fstr(fd, COL_PROTOCOL, "PIM version %d",
195 PIM_VER(pim.pim_typever));
197 if (check_col(fd, COL_INFO)) {
199 col_add_str(fd, COL_INFO, typestr);
201 col_add_fstr(fd, COL_INFO, "unknown type %d",
202 PIM_TYPE(pim.pim_typever));
207 ti = proto_tree_add_item(tree, proto_pim, offset, END_OF_FRAME, NULL);
208 pim_tree = proto_item_add_subtree(ti, ETT_PIM);
210 proto_tree_add_text(pim_tree, offset, 1,
211 "Version: %d", PIM_VER(pim.pim_typever));
213 proto_tree_add_text(pim_tree, offset, 1,
214 "Type: %d (%s)", PIM_TYPE(pim.pim_typever), typestr);
216 proto_tree_add_text(pim_tree, offset, 1,
217 "Type: %d (unknown)", PIM_TYPE(pim.pim_typever));
220 proto_tree_add_text(pim_tree, offset + offsetof(struct pim, pim_cksum),
221 sizeof(pim.pim_cksum),
222 "Checksum: 0x%04x", ntohs(pim.pim_cksum));
224 if (sizeof(struct pim) < END_OF_FRAME) {
225 tiopt = proto_tree_add_text(pim_tree,
226 offset + sizeof(struct pim), END_OF_FRAME,
227 "PIM parameters", PIM_TYPE(pim.pim_typever), typestr);
228 pimopt_tree = proto_item_add_subtree(tiopt, ETT_PIM);
232 if (PIM_VER(pim.pim_typever) != 2)
235 /* version 2 decoder */
236 switch (PIM_TYPE(pim.pim_typever)) {
240 w = (guint16 *)&pd[offset + sizeof(struct pim)];
241 while ((guint8 *)w < &pd[offset + END_OF_FRAME]) {
242 if (ntohs(w[0]) == 1 && ntohs(w[1]) == 2
243 && (guint8 *)&w[3] <= &pd[offset + END_OF_FRAME]) {
244 proto_tree_add_text(pimopt_tree, (guint8 *)w - pd, 6,
245 "Holdtime: %u%s", ntohs(w[2]),
246 ntohs(w[2]) == 0xffff ? " (infty)" : "");
254 case 1: /* register */
257 proto_tree *flag_tree = NULL;
261 flagoff = offset + sizeof(struct pim);
262 tiflag = proto_tree_add_text(pimopt_tree, flagoff, 4,
263 "Flags: 0x%08x", ntohl(*(guint32 *)&pd[flagoff]));
264 flag_tree = proto_item_add_subtree(tiflag, ETT_PIM);
265 proto_tree_add_text(flag_tree, flagoff, 1, "%s",
266 decode_boolean_bitfield(pd[flagoff], 0x80000000, 32,
267 "Border", "Not border"));
268 proto_tree_add_text(flag_tree, flagoff, 1, "%s",
269 decode_boolean_bitfield(pd[flagoff], 0x40000000, 32,
270 "Null-Register", "Not Null-Register"));
272 ip = &pd[flagoff + sizeof(guint32)];
273 switch((*ip & 0xf0) >> 4) {
275 dissect_ip(pd, ip - pd, fd, tree);
278 dissect_ipv6(pd, ip - pd, fd, tree);
281 proto_tree_add_text(pimopt_tree,
282 ip - pd, END_OF_FRAME,
283 "Unknown IP version %d", (*ip & 0xf0) >> 4);
289 case 2: /* register-stop */
295 ep = &pd[offset + END_OF_FRAME];
296 offset += sizeof(struct pim);
297 s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance);
300 proto_tree_add_text(pimopt_tree, offset, advance, "Group: %s", s);
302 s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance);
305 proto_tree_add_text(pimopt_tree, offset, advance, "Source: %s", s);
309 case 3: /* join/prune */
311 case 7: /* graft-ack */
317 int ngroup, i, njoin, nprune, j;
318 proto_tree *grouptree = NULL;
320 proto_tree *subtree = NULL;
323 ep = &pd[offset + END_OF_FRAME];
324 offset += sizeof(struct pim);
325 if (PIM_TYPE(pim.pim_typever) != 7) {
327 s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance);
330 proto_tree_add_text(pimopt_tree, offset, advance,
331 "Upstream-neighbor: %s", s);
335 if (&pd[offset + 2] > ep)
337 ngroup = pd[offset + 1];
338 proto_tree_add_text(pimopt_tree, offset + 1, 1,
339 "Groups: %u", pd[offset + 1]);
342 if (&pd[offset + 2] > ep)
344 if (PIM_TYPE(pim.pim_typever) != 7) {
346 proto_tree_add_text(pimopt_tree, offset, 2,
347 "Holdtime: %u%s", ntohs(*(guint16 *)&pd[offset]),
348 ntohs(*(guint16 *)&pd[offset]) == 0xffff ? " (infty)" : "");
352 for (i = 0; i < ngroup; i++) {
353 if (&pd[offset] >= ep)
356 s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance);
359 tigroup = proto_tree_add_text(pimopt_tree, offset, advance,
360 "Group %d: %s", i, s);
361 grouptree = proto_item_add_subtree(tigroup, ETT_PIM);
364 if (&pd[offset + 4] > ep)
366 njoin = ntohs(*(guint16 *)&pd[offset]);
367 nprune = ntohs(*(guint16 *)&pd[offset + 2]);
369 tisub = proto_tree_add_text(grouptree, offset, 2,
371 subtree = proto_item_add_subtree(tisub, ETT_PIM);
373 for (j = 0; j < nprune; j++) {
374 s = dissect_pim_addr(&pd[off], ep, pimv2_source,
378 proto_tree_add_text(subtree, off, advance,
379 "IP address: %s", s);
383 tisub = proto_tree_add_text(grouptree, offset + 2, 2,
384 "Prune: %d", nprune);
385 subtree = proto_item_add_subtree(tisub, ETT_PIM);
386 for (j = 0; j < nprune; j++) {
387 s = dissect_pim_addr(&pd[off], ep, pimv2_source,
391 proto_tree_add_text(subtree, off, advance,
392 "IP address: %s", s);
400 case 4: /* bootstrap */
406 proto_tree *grouptree = NULL;
409 offset += sizeof(struct pim);
411 if (END_OF_FRAME < 2)
413 proto_tree_add_text(pimopt_tree, offset, 2,
414 "Fragment tag: 0x%04x", ntohs(*(guint16 *)&pd[offset]));
417 if (END_OF_FRAME < 2)
419 proto_tree_add_text(pimopt_tree, offset, 1,
420 "Hash mask len: %u", pd[offset]);
421 proto_tree_add_text(pimopt_tree, offset + 1, 1,
422 "BSR priority: %u", pd[offset + 1]);
425 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
426 pimv2_unicast, &advance);
429 proto_tree_add_text(pimopt_tree, offset, advance, "BSR: %s", s);
432 for (i = 0; END_OF_FRAME > 0; i++) {
433 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
434 pimv2_group, &advance);
437 tigroup = proto_tree_add_text(pimopt_tree, offset, advance,
438 "Group %d: %s", i, s);
439 grouptree = proto_item_add_subtree(tigroup, ETT_PIM);
442 if (END_OF_FRAME < 2)
444 proto_tree_add_text(grouptree, offset, 1,
445 "RP count: %u", pd[offset]);
446 proto_tree_add_text(grouptree, offset + 1, 1,
447 "FRP count: %u", pd[offset + 1]);
448 frpcnt = pd[offset + 1];
451 for (j = 0; j < frpcnt && END_OF_FRAME > 0; j++) {
452 s = dissect_pim_addr(&pd[offset],
453 &pd[offset + END_OF_FRAME], pimv2_unicast, &advance);
456 proto_tree_add_text(grouptree, offset, advance,
460 if (END_OF_FRAME < 4)
462 proto_tree_add_text(grouptree, offset, 2,
463 "Holdtime: %u%s", ntohs(*(guint16 *)&pd[offset]),
464 ntohs(*(guint16 *)&pd[offset]) == 0xffff ? " (infty)" : "");
465 proto_tree_add_text(grouptree, offset + 3, 1,
466 "Priority: %u", pd[offset + 3]);
481 offset += sizeof(struct pim);
483 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
484 pimv2_group, &advance);
487 proto_tree_add_text(pimopt_tree, offset, advance, "Group: %s", s);
490 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
491 pimv2_unicast, &advance);
494 proto_tree_add_text(pimopt_tree, offset, advance, "Source: %s", s);
497 if (END_OF_FRAME < 4)
499 proto_tree_add_text(pimopt_tree, offset, 1, "%s",
500 decode_boolean_bitfield(pd[offset], 0x80, 8,
501 "RP Tree", "Not RP Tree"));
502 proto_tree_add_text(pimopt_tree, offset, 4, "Preference: %u",
503 ntohl(*(guint32 *)&pd[offset] & 0x7fffffff));
506 if (END_OF_FRAME < 4)
508 proto_tree_add_text(pimopt_tree, offset, 4, "Metric: %u",
509 ntohl(*(guint32 *)&pd[offset]));
514 case 8: /* Candidate-RP-Advertisement */
521 offset += sizeof(struct pim);
522 if (END_OF_FRAME < 4)
525 proto_tree_add_text(pimopt_tree, offset, 1,
526 "Prefix-count: %u", pd[offset]);
527 proto_tree_add_text(pimopt_tree, offset + 1, 1,
528 "Priority: %u", pd[offset + 1]);
529 proto_tree_add_text(pimopt_tree, offset + 2, 2,
530 "Holdtime: %u%s", ntohs(*(guint16 *)&pd[offset + 2]),
531 ntohs(*(guint16 *)&pd[offset + 2]) == 0xffff ? " (infty)" : "");
534 if (END_OF_FRAME <= 0)
536 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
537 pimv2_unicast, &advance);
540 proto_tree_add_text(pimopt_tree, offset, advance, "RP: %s", s);
543 for (i = 0; i < pfxcnt && END_OF_FRAME > 0; i++) {
544 s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME],
545 pimv2_group, &advance);
548 proto_tree_add_text(pimopt_tree, offset, advance,
549 "Group %d: %s", i, s);
564 proto_register_pim(void)
566 proto_pim = proto_register_protocol("Protocol Independent Multicast",