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