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