print-pim.c revision 127675
1/*
2 * Copyright (c) 1995, 1996
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that: (1) source code distributions
7 * retain the above copyright notice and this paragraph in its entirety, (2)
8 * distributions including binary code include the above copyright notice and
9 * this paragraph in its entirety in the documentation or other materials
10 * provided with the distribution, and (3) all advertising materials mentioning
11 * features or use of this software display the following acknowledgement:
12 * ``This product includes software developed by the University of California,
13 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14 * the University nor the names of its contributors may be used to endorse
15 * or promote products derived from this software without specific prior
16 * written permission.
17 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 *
21 * $FreeBSD: head/contrib/tcpdump/print-pim.c 127675 2004-03-31 14:57:24Z bms $
22 */
23
24#ifndef lint
25static const char rcsid[] _U_ =
26    "@(#) $Header: /tcpdump/master/tcpdump/print-pim.c,v 1.37.2.4 2004/03/24 02:52:37 guy Exp $ (LBL)";
27#endif
28
29#ifdef HAVE_CONFIG_H
30#include "config.h"
31#endif
32
33#include <tcpdump-stdinc.h>
34
35/*
36 * XXX: We consider a case where IPv6 is not ready yet for portability,
37 * but PIM dependent defintions should be independent of IPv6...
38 */
39
40struct pim {
41	u_int8_t pim_typever;
42			/* upper 4bit: PIM version number; 2 for PIMv2 */
43			/* lower 4bit: the PIM message type, currently they are:
44			 * Hello, Register, Register-Stop, Join/Prune,
45			 * Bootstrap, Assert, Graft (PIM-DM only),
46			 * Graft-Ack (PIM-DM only), C-RP-Adv
47			 */
48#define PIM_VER(x)	(((x) & 0xf0) >> 4)
49#define PIM_TYPE(x)	((x) & 0x0f)
50	u_char  pim_rsv;	/* Reserved */
51	u_short	pim_cksum;	/* IP style check sum */
52};
53
54
55#include <stdio.h>
56#include <stdlib.h>
57
58#include "interface.h"
59#include "addrtoname.h"
60#include "extract.h"
61
62#include "ip.h"
63
64static void pimv2_print(register const u_char *bp, register u_int len);
65
66static void
67pimv1_join_prune_print(register const u_char *bp, register u_int len)
68{
69	int maddrlen, addrlen, ngroups, njoin, nprune;
70	int njp;
71
72	/* If it's a single group and a single source, use 1-line output. */
73	if (TTEST2(bp[0], 30) && bp[11] == 1 &&
74	    ((njoin = EXTRACT_16BITS(&bp[20])) + EXTRACT_16BITS(&bp[22])) == 1) {
75		int hold;
76
77		(void)printf(" RPF %s ", ipaddr_string(bp));
78		hold = EXTRACT_16BITS(&bp[6]);
79		if (hold != 180) {
80			(void)printf("Hold ");
81			relts_print(hold);
82		}
83		(void)printf("%s (%s/%d, %s", njoin ? "Join" : "Prune",
84		ipaddr_string(&bp[26]), bp[25] & 0x3f,
85		ipaddr_string(&bp[12]));
86		if (EXTRACT_32BITS(&bp[16]) != 0xffffffff)
87			(void)printf("/%s", ipaddr_string(&bp[16]));
88		(void)printf(") %s%s %s",
89		    (bp[24] & 0x01) ? "Sparse" : "Dense",
90		    (bp[25] & 0x80) ? " WC" : "",
91		    (bp[25] & 0x40) ? "RP" : "SPT");
92		return;
93	}
94
95	TCHECK2(bp[0], 4);
96	if (vflag > 1)
97		(void)printf("\n");
98	(void)printf(" Upstream Nbr: %s", ipaddr_string(bp));
99	TCHECK2(bp[6], 2);
100	if (vflag > 1)
101		(void)printf("\n");
102	(void)printf(" Hold time: ");
103	relts_print(EXTRACT_16BITS(&bp[6]));
104	if (vflag < 2)
105		return;
106	bp += 8;
107	len -= 8;
108
109	TCHECK2(bp[0], 4);
110	maddrlen = bp[1];
111	addrlen = bp[2];
112	ngroups = bp[3];
113	bp += 4;
114	len -= 4;
115	while (ngroups--) {
116		TCHECK2(bp[0], 4);
117		(void)printf("\n\tGroup: %s", ipaddr_string(bp));
118		TCHECK2(bp[4], 4);
119		if (EXTRACT_32BITS(&bp[4]) != 0xffffffff)
120			(void)printf("/%s", ipaddr_string(&bp[4]));
121		TCHECK2(bp[8], 4);
122		njoin = EXTRACT_16BITS(&bp[8]);
123		nprune = EXTRACT_16BITS(&bp[10]);
124		(void)printf(" joined: %d pruned: %d", njoin, nprune);
125		bp += 12;
126		len -= 12;
127		for (njp = 0; njp < (njoin + nprune); njp++) {
128			const char *type;
129
130			if (njp < njoin)
131				type = "Join ";
132			else
133				type = "Prune";
134			TCHECK2(bp[0], 6);
135			(void)printf("\n\t%s %s%s%s%s/%d", type,
136			    (bp[0] & 0x01) ? "Sparse " : "Dense ",
137			    (bp[1] & 0x80) ? "WC " : "",
138			    (bp[1] & 0x40) ? "RP " : "SPT ",
139			ipaddr_string(&bp[2]), bp[1] & 0x3f);
140			bp += 6;
141			len -= 6;
142		}
143	}
144	return;
145trunc:
146	(void)printf("[|pim]");
147	return;
148}
149
150void
151pimv1_print(register const u_char *bp, register u_int len)
152{
153	register const u_char *ep;
154	register u_char type;
155
156	ep = (const u_char *)snapend;
157	if (bp >= ep)
158		return;
159
160	TCHECK(bp[1]);
161	type = bp[1];
162
163	switch (type) {
164	case 0:
165		(void)printf(" Query");
166		if (TTEST(bp[8])) {
167			switch (bp[8] >> 4) {
168			case 0:
169				(void)printf(" Dense-mode");
170				break;
171			case 1:
172				(void)printf(" Sparse-mode");
173				break;
174			case 2:
175				(void)printf(" Sparse-Dense-mode");
176				break;
177			default:
178				(void)printf(" mode-%d", bp[8] >> 4);
179				break;
180			}
181		}
182		if (vflag) {
183			TCHECK2(bp[10],2);
184			(void)printf(" (Hold-time ");
185			relts_print(EXTRACT_16BITS(&bp[10]));
186			(void)printf(")");
187		}
188		break;
189
190	case 1:
191		(void)printf(" Register");
192		TCHECK2(bp[8], 20);			/* ip header */
193		(void)printf(" for %s > %s", ipaddr_string(&bp[20]),
194		    ipaddr_string(&bp[24]));
195		break;
196	case 2:
197		(void)printf(" Register-Stop");
198		TCHECK2(bp[12], 4);
199		(void)printf(" for %s > %s", ipaddr_string(&bp[8]),
200		    ipaddr_string(&bp[12]));
201		break;
202	case 3:
203		(void)printf(" Join/Prune");
204		if (vflag)
205			pimv1_join_prune_print(&bp[8], len - 8);
206		break;
207	case 4:
208		(void)printf(" RP-reachable");
209		if (vflag) {
210			TCHECK2(bp[22], 2);
211			(void)printf(" group %s",
212			ipaddr_string(&bp[8]));
213			if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
214				(void)printf("/%s", ipaddr_string(&bp[12]));
215			(void)printf(" RP %s hold ", ipaddr_string(&bp[16]));
216			relts_print(EXTRACT_16BITS(&bp[22]));
217		}
218		break;
219	case 5:
220		(void)printf(" Assert");
221		TCHECK2(bp[16], 4);
222		(void)printf(" for %s > %s", ipaddr_string(&bp[16]),
223		    ipaddr_string(&bp[8]));
224		if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
225			(void)printf("/%s", ipaddr_string(&bp[12]));
226		TCHECK2(bp[24], 4);
227		(void)printf(" %s pref %d metric %d",
228		    (bp[20] & 0x80) ? "RP-tree" : "SPT",
229		EXTRACT_32BITS(&bp[20]) & 0x7fffffff,
230		EXTRACT_32BITS(&bp[24]));
231		break;
232	case 6:
233		(void)printf(" Graft");
234		if (vflag)
235			pimv1_join_prune_print(&bp[8], len - 8);
236		break;
237	case 7:
238		(void)printf(" Graft-ACK");
239		if (vflag)
240			pimv1_join_prune_print(&bp[8], len - 8);
241		break;
242	case 8:
243		(void)printf(" Mode");
244		break;
245	default:
246		(void)printf(" [type %d]", type);
247		break;
248	}
249	if ((bp[4] >> 4) != 1)
250		(void)printf(" [v%d]", bp[4] >> 4);
251	return;
252
253trunc:
254	(void)printf("[|pim]");
255	return;
256}
257
258/*
259 * auto-RP is a cisco protocol, documented at
260 * ftp://ftpeng.cisco.com/ipmulticast/specs/pim-autorp-spec01.txt
261 *
262 * This implements version 1+, dated Sept 9, 1998.
263 */
264void
265cisco_autorp_print(register const u_char *bp, register u_int len)
266{
267	int type;
268	int numrps;
269	int hold;
270
271	TCHECK(bp[0]);
272	(void)printf(" auto-rp ");
273	type = bp[0];
274	switch (type) {
275	case 0x11:
276		(void)printf("candidate-advert");
277		break;
278	case 0x12:
279		(void)printf("mapping");
280		break;
281	default:
282		(void)printf("type-0x%02x", type);
283		break;
284	}
285
286	TCHECK(bp[1]);
287	numrps = bp[1];
288
289	TCHECK2(bp[2], 2);
290	(void)printf(" Hold ");
291	hold = EXTRACT_16BITS(&bp[2]);
292	if (hold)
293		relts_print(EXTRACT_16BITS(&bp[2]));
294	else
295		printf("FOREVER");
296
297	/* Next 4 bytes are reserved. */
298
299	bp += 8; len -= 8;
300
301	/*XXX skip unless -v? */
302
303	/*
304	 * Rest of packet:
305	 * numrps entries of the form:
306	 * 32 bits: RP
307	 * 6 bits: reserved
308	 * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
309	 * 8 bits: # of entries for this RP
310	 * each entry: 7 bits: reserved, 1 bit: negative,
311	 *	       8 bits: mask 32 bits: source
312	 * lather, rinse, repeat.
313	 */
314	while (numrps--) {
315		int nentries;
316		char s;
317
318		TCHECK2(bp[0], 4);
319		(void)printf(" RP %s", ipaddr_string(bp));
320		TCHECK(bp[4]);
321		switch (bp[4] & 0x3) {
322		case 0: printf(" PIMv?");
323			break;
324		case 1:	printf(" PIMv1");
325			break;
326		case 2:	printf(" PIMv2");
327			break;
328		case 3:	printf(" PIMv1+2");
329			break;
330		}
331		if (bp[4] & 0xfc)
332			(void)printf(" [rsvd=0x%02x]", bp[4] & 0xfc);
333		TCHECK(bp[5]);
334		nentries = bp[5];
335		bp += 6; len -= 6;
336		s = ' ';
337		for (; nentries; nentries--) {
338			TCHECK2(bp[0], 6);
339			(void)printf("%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
340			    ipaddr_string(&bp[2]), bp[1]);
341			if (bp[0] & 0xfe)
342				(void)printf("[rsvd=0x%02x]", bp[0] & 0xfe);
343			s = ',';
344			bp += 6; len -= 6;
345		}
346	}
347	return;
348
349trunc:
350	(void)printf("[|autorp]");
351	return;
352}
353
354void
355pim_print(register const u_char *bp, register u_int len)
356{
357	register const u_char *ep;
358	register struct pim *pim = (struct pim *)bp;
359
360	ep = (const u_char *)snapend;
361	if (bp >= ep)
362		return;
363#ifdef notyet			/* currently we see only version and type */
364	TCHECK(pim->pim_rsv);
365#endif
366
367	switch (PIM_VER(pim->pim_typever)) {
368	case 2:		/* avoid hardcoding? */
369		(void)printf("pim v2");
370		pimv2_print(bp, len);
371		break;
372	default:
373		(void)printf("pim v%d", PIM_VER(pim->pim_typever));
374		break;
375	}
376	return;
377}
378
379/*
380 * PIMv2 uses encoded address representations.
381 *
382 * The last PIM-SM I-D before RFC2117 was published specified the
383 * following representation for unicast addresses.  However, RFC2117
384 * specified no encoding for unicast addresses with the unicast
385 * address length specified in the header.  Therefore, we have to
386 * guess which encoding is being used (Cisco's PIMv2 implementation
387 * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
388 * field into a 'unicast-address-length-in-bytes' field.  We guess
389 * that it's the draft encoding if this reserved field is zero.
390 *
391 * RFC2362 goes back to the encoded format, and calls the addr length
392 * field "reserved" again.
393 *
394 * The first byte is the address family, from:
395 *
396 *    0    Reserved
397 *    1    IP (IP version 4)
398 *    2    IP6 (IP version 6)
399 *    3    NSAP
400 *    4    HDLC (8-bit multidrop)
401 *    5    BBN 1822
402 *    6    802 (includes all 802 media plus Ethernet "canonical format")
403 *    7    E.163
404 *    8    E.164 (SMDS, Frame Relay, ATM)
405 *    9    F.69 (Telex)
406 *   10    X.121 (X.25, Frame Relay)
407 *   11    IPX
408 *   12    Appletalk
409 *   13    Decnet IV
410 *   14    Banyan Vines
411 *   15    E.164 with NSAP format subaddress
412 *
413 * In addition, the second byte is an "Encoding".  0 is the default
414 * encoding for the address family, and no other encodings are currently
415 * specified.
416 *
417 */
418
419static int pimv2_addr_len;
420
421enum pimv2_addrtype {
422	pimv2_unicast, pimv2_group, pimv2_source
423};
424
425/*  0                   1                   2                   3
426 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
427 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
428 * | Addr Family   | Encoding Type |     Unicast Address           |
429 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
430 *  0                   1                   2                   3
431 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
432 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
433 * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
434 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
435 * |                Group multicast Address                        |
436 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
437 *  0                   1                   2                   3
438 *  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
439 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
440 * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
441 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
442 * |                        Source Address                         |
443 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
444 */
445static int
446pimv2_addr_print(const u_char *bp, enum pimv2_addrtype at, int silent)
447{
448	int af;
449	const char *afstr;
450	int len, hdrlen;
451
452	TCHECK(bp[0]);
453
454	if (pimv2_addr_len == 0) {
455		TCHECK(bp[1]);
456		switch (bp[0]) {
457		case 1:
458			af = AF_INET;
459			afstr = "IPv4";
460			len = 4;
461			break;
462#ifdef INET6
463		case 2:
464			af = AF_INET6;
465			afstr = "IPv6";
466			len = 16;
467			break;
468#endif
469		default:
470			return -1;
471		}
472		if (bp[1] != 0)
473			return -1;
474		hdrlen = 2;
475	} else {
476		switch (pimv2_addr_len) {
477		case 4:
478			af = AF_INET;
479			afstr = "IPv4";
480			break;
481#ifdef INET6
482		case 16:
483			af = AF_INET6;
484			afstr = "IPv6";
485			break;
486#endif
487		default:
488			return -1;
489			break;
490		}
491		len = pimv2_addr_len;
492		hdrlen = 0;
493	}
494
495	bp += hdrlen;
496	switch (at) {
497	case pimv2_unicast:
498		TCHECK2(bp[0], len);
499		if (af == AF_INET) {
500			if (!silent)
501				(void)printf("%s", ipaddr_string(bp));
502		}
503#ifdef INET6
504		else if (af == AF_INET6) {
505			if (!silent)
506				(void)printf("%s", ip6addr_string(bp));
507		}
508#endif
509		return hdrlen + len;
510	case pimv2_group:
511	case pimv2_source:
512		TCHECK2(bp[0], len + 2);
513		if (af == AF_INET) {
514			if (!silent) {
515				(void)printf("%s", ipaddr_string(bp + 2));
516				if (bp[1] != 32)
517					(void)printf("/%u", bp[1]);
518			}
519		}
520#ifdef INET6
521		else if (af == AF_INET6) {
522			if (!silent) {
523				(void)printf("%s", ip6addr_string(bp + 2));
524				if (bp[1] != 128)
525					(void)printf("/%u", bp[1]);
526			}
527		}
528#endif
529		if (bp[0] && !silent) {
530			if (at == pimv2_group) {
531				(void)printf("(0x%02x)", bp[0]);
532			} else {
533				(void)printf("(%s%s%s",
534					bp[0] & 0x04 ? "S" : "",
535					bp[0] & 0x02 ? "W" : "",
536					bp[0] & 0x01 ? "R" : "");
537				if (bp[0] & 0xf8) {
538					(void) printf("+0x%02x", bp[0] & 0xf8);
539				}
540				(void)printf(")");
541			}
542		}
543		return hdrlen + 2 + len;
544	default:
545		return -1;
546	}
547trunc:
548	return -1;
549}
550
551static void
552pimv2_print(register const u_char *bp, register u_int len)
553{
554	register const u_char *ep;
555	register struct pim *pim = (struct pim *)bp;
556	int advance;
557
558	ep = (const u_char *)snapend;
559	if (bp >= ep)
560		return;
561	if (ep > bp + len)
562		ep = bp + len;
563	TCHECK(pim->pim_rsv);
564	pimv2_addr_len = pim->pim_rsv;
565	if (pimv2_addr_len != 0)
566		(void)printf("[RFC2117-encoding] ");
567
568	switch (PIM_TYPE(pim->pim_typever)) {
569	case 0:
570	    {
571		u_int16_t otype, olen;
572		(void)printf(" Hello");
573		bp += 4;
574		while (bp < ep) {
575			TCHECK2(bp[0], 4);
576			otype = EXTRACT_16BITS(&bp[0]);
577			olen = EXTRACT_16BITS(&bp[2]);
578			TCHECK2(bp[0], 4 + olen);
579			switch (otype) {
580			case 1:		/* Hold time */
581				(void)printf(" (Hold-time ");
582				relts_print(EXTRACT_16BITS(&bp[4]));
583				(void)printf(")");
584				break;
585
586			case 2:		/* LAN Prune Delay */
587				(void)printf(" (LAN-Prune-Delay: ");
588				if (olen != 4) {
589					(void)printf("!olen=%d!)", olen);
590				} else {
591					char t_bit;
592					u_int16_t lan_delay, override_interval;
593					lan_delay = EXTRACT_16BITS(&bp[4]);
594					override_interval = EXTRACT_16BITS(&bp[6]);
595					t_bit = (lan_delay & 0x8000)? 1 : 0;
596					lan_delay &= ~0x8000;
597					(void)printf("T-bit=%d lan-delay=%dms override-interval=%dms)",
598					t_bit, lan_delay, override_interval);
599				}
600				break;
601
602			case 18:	/* Old DR-Priority */
603				if (olen == 4)
604					(void)printf(" (OLD-DR-Priority: %d)",
605							EXTRACT_32BITS(&bp[4]));
606				else
607					goto unknown;
608				break;
609
610
611			case 19:	/* DR-Priority */
612				if (olen == 0) {
613					(void)printf(" (OLD-bidir-capable)");
614					break;
615				}
616				(void)printf(" (DR-Priority: ");
617				if (olen != 4) {
618					(void)printf("!olen=%d!)", olen);
619				} else {
620					(void)printf("%d)", EXTRACT_32BITS(&bp[4]));
621				}
622				break;
623
624			case 20:
625				(void)printf(" (Genid: 0x%08x)", EXTRACT_32BITS(&bp[4]));
626				break;
627
628			case 21:
629				(void)printf(" (State Refresh Capable; v%d", bp[4]);
630				if (bp[5] != 0) {
631					(void)printf(" interval ");
632					relts_print(bp[5]);
633				}
634				if (EXTRACT_16BITS(&bp[6]) != 0) {
635					(void)printf(" ?0x%04x?", EXTRACT_16BITS(&bp[6]));
636				}
637				(void)printf(")");
638				break;
639
640			case 22:	/* Bidir-Capable */
641				(void)printf(" (bidir-capable)");
642				break;
643
644			case 24:	/* Address List */
645			case 65001:	/* Address List (old implementations) */
646				(void)printf(" (%saddr-list",
647					     otype == 65001 ? "old" : "");
648				if (vflag > 1) {
649					const u_char *ptr = &bp[4];
650					while (ptr < &bp[4 + olen]) {
651						int advance;
652
653						printf(" ");
654						advance = pimv2_addr_print(ptr, pimv2_unicast, 0);
655						if (advance < 0) {
656							printf("...");
657							break;
658						}
659						ptr += advance;
660					}
661				}
662				(void)printf(")");
663				break;
664			default:
665			unknown:
666				if (vflag)
667					(void)printf(" [Hello option %d]", otype);
668			}
669			bp += 4 + olen;
670		}
671		break;
672	    }
673
674	case 1:
675	{
676		struct ip *ip;
677
678		(void)printf(" Register");
679		if (vflag && bp + 8 <= ep) {
680			(void)printf(" %s%s", bp[4] & 0x80 ? "B" : "",
681				bp[4] & 0x40 ? "N" : "");
682		}
683		bp += 8; len -= 8;
684
685		/* encapsulated multicast packet */
686		if (bp >= ep)
687			break;
688		ip = (struct ip *)bp;
689		switch (IP_V(ip)) {
690		case 4:	/* IPv4 */
691			printf(" ");
692			ip_print(bp, len);
693			break;
694#ifdef INET6
695		case 6:	/* IPv6 */
696			printf(" ");
697			ip6_print(bp, len);
698			break;
699#endif
700		default:
701			(void)printf(" IP ver %d", IP_V(ip));
702			break;
703		}
704		break;
705	}
706
707	case 2:
708		(void)printf(" Register-Stop");
709		bp += 4; len -= 4;
710		if (bp >= ep)
711			break;
712		(void)printf(" group=");
713		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
714			(void)printf("...");
715			break;
716		}
717		bp += advance; len -= advance;
718		if (bp >= ep)
719			break;
720		(void)printf(" source=");
721		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
722			(void)printf("...");
723			break;
724		}
725		bp += advance; len -= advance;
726		break;
727
728	case 3:
729	case 6:
730	case 7:
731	    {
732		u_int8_t ngroup;
733		u_int16_t holdtime;
734		u_int16_t njoin;
735		u_int16_t nprune;
736		int i, j;
737
738		switch (PIM_TYPE(pim->pim_typever)) {
739		case 3:
740			(void)printf(" Join/Prune");
741			break;
742		case 6:
743			(void)printf(" Graft");
744			break;
745		case 7:
746			(void)printf(" Graft-ACK");
747			break;
748		}
749		bp += 4; len -= 4;
750		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
751			if (bp >= ep)
752				break;
753			(void)printf(" upstream-neighbor=");
754			if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
755				(void)printf("...");
756				break;
757			}
758			bp += advance; len -= advance;
759		}
760		if (bp + 4 > ep)
761			break;
762		ngroup = bp[1];
763		holdtime = EXTRACT_16BITS(&bp[2]);
764		(void)printf(" groups=%u", ngroup);
765		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
766			(void)printf(" holdtime=");
767			if (holdtime == 0xffff)
768				(void)printf("infty");
769			else
770				relts_print(holdtime);
771		}
772		bp += 4; len -= 4;
773		for (i = 0; i < ngroup; i++) {
774			if (bp >= ep)
775				goto jp_done;
776			(void)printf(" (group%d: ", i);
777			if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
778				(void)printf("...)");
779				goto jp_done;
780			}
781			bp += advance; len -= advance;
782			if (bp + 4 > ep) {
783				(void)printf("...)");
784				goto jp_done;
785			}
786			njoin = EXTRACT_16BITS(&bp[0]);
787			nprune = EXTRACT_16BITS(&bp[2]);
788			(void)printf(" join=%u", njoin);
789			bp += 4; len -= 4;
790			for (j = 0; j < njoin; j++) {
791				(void)printf(" ");
792				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
793					(void)printf("...)");
794					goto jp_done;
795				}
796				bp += advance; len -= advance;
797			}
798			(void)printf(" prune=%u", nprune);
799			for (j = 0; j < nprune; j++) {
800				(void)printf(" ");
801				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
802					(void)printf("...)");
803					goto jp_done;
804				}
805				bp += advance; len -= advance;
806			}
807			(void)printf(")");
808		}
809	jp_done:
810		break;
811	    }
812
813	case 4:
814	{
815		int i, j, frpcnt;
816
817		(void)printf(" Bootstrap");
818		bp += 4;
819
820		/* Fragment Tag, Hash Mask len, and BSR-priority */
821		if (bp + sizeof(u_int16_t) >= ep) break;
822		(void)printf(" tag=%x", EXTRACT_16BITS(bp));
823		bp += sizeof(u_int16_t);
824		if (bp >= ep) break;
825		(void)printf(" hashmlen=%d", bp[0]);
826		if (bp + 1 >= ep) break;
827		(void)printf(" BSRprio=%d", bp[1]);
828		bp += 2;
829
830		/* Encoded-Unicast-BSR-Address */
831		if (bp >= ep) break;
832		(void)printf(" BSR=");
833		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
834			(void)printf("...");
835			break;
836		}
837		bp += advance;
838
839		for (i = 0; bp < ep; i++) {
840			/* Encoded-Group Address */
841			(void)printf(" (group%d: ", i);
842			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
843			    < 0) {
844				(void)printf("...)");
845				goto bs_done;
846			}
847			bp += advance;
848
849			/* RP-Count, Frag RP-Cnt, and rsvd */
850			if (bp >= ep) {
851				(void)printf("...)");
852				goto bs_done;
853			}
854			(void)printf(" RPcnt=%d", bp[0]);
855			if (bp + 1 >= ep) {
856				(void)printf("...)");
857				goto bs_done;
858			}
859			(void)printf(" FRPcnt=%d", frpcnt = bp[1]);
860			bp += 4;
861
862			for (j = 0; j < frpcnt && bp < ep; j++) {
863				/* each RP info */
864				(void)printf(" RP%d=", j);
865				if ((advance = pimv2_addr_print(bp,
866								pimv2_unicast,
867								0)) < 0) {
868					(void)printf("...)");
869					goto bs_done;
870				}
871				bp += advance;
872
873				if (bp + 1 >= ep) {
874					(void)printf("...)");
875					goto bs_done;
876				}
877				(void)printf(",holdtime=");
878				relts_print(EXTRACT_16BITS(bp));
879				if (bp + 2 >= ep) {
880					(void)printf("...)");
881					goto bs_done;
882				}
883				(void)printf(",prio=%d", bp[2]);
884				bp += 4;
885			}
886			(void)printf(")");
887		}
888	   bs_done:
889		break;
890	}
891	case 5:
892		(void)printf(" Assert");
893		bp += 4; len -= 4;
894		if (bp >= ep)
895			break;
896		(void)printf(" group=");
897		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
898			(void)printf("...");
899			break;
900		}
901		bp += advance; len -= advance;
902		if (bp >= ep)
903			break;
904		(void)printf(" src=");
905		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
906			(void)printf("...");
907			break;
908		}
909		bp += advance; len -= advance;
910		if (bp + 8 > ep)
911			break;
912		if (bp[0] & 0x80)
913			(void)printf(" RPT");
914		(void)printf(" pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff);
915		(void)printf(" metric=%u", EXTRACT_32BITS(&bp[4]));
916		break;
917
918	case 8:
919	{
920		int i, pfxcnt;
921
922		(void)printf(" Candidate-RP-Advertisement");
923		bp += 4;
924
925		/* Prefix-Cnt, Priority, and Holdtime */
926		if (bp >= ep) break;
927		(void)printf(" prefix-cnt=%d", bp[0]);
928		pfxcnt = bp[0];
929		if (bp + 1 >= ep) break;
930		(void)printf(" prio=%d", bp[1]);
931		if (bp + 3 >= ep) break;
932		(void)printf(" holdtime=");
933		relts_print(EXTRACT_16BITS(&bp[2]));
934		bp += 4;
935
936		/* Encoded-Unicast-RP-Address */
937		if (bp >= ep) break;
938		(void)printf(" RP=");
939		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
940			(void)printf("...");
941			break;
942		}
943		bp += advance;
944
945		/* Encoded-Group Addresses */
946		for (i = 0; i < pfxcnt && bp < ep; i++) {
947			(void)printf(" Group%d=", i);
948			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
949			    < 0) {
950				(void)printf("...");
951				break;
952			}
953			bp += advance;
954		}
955		break;
956	}
957
958	case 9:
959		(void)printf(" Prune-Refresh");
960		(void)printf(" src=");
961		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
962			(void)printf("...");
963			break;
964		}
965		bp += advance;
966		(void)printf(" grp=");
967		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
968			(void)printf("...");
969			break;
970		}
971		bp += advance;
972		(void)printf(" forwarder=");
973		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
974			(void)printf("...");
975			break;
976		}
977		bp += advance;
978		TCHECK2(bp[0], 2);
979		(void)printf(" TUNR ");
980		relts_print(EXTRACT_16BITS(bp));
981		break;
982
983
984	 default:
985		(void)printf(" [type %d]", PIM_TYPE(pim->pim_typever));
986		break;
987	}
988
989	return;
990
991trunc:
992	(void)printf("[|pim]");
993}
994