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