xref: /freebsd/contrib/tcpdump/print-pim.c (revision 09e8dea79366f1e5b3a73e8a271b26e4b6bf2e6a)
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$
22  */
23 
24 #ifndef lint
25 static 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 
44 struct 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 
69 static void pimv2_print(register const u_char *bp, register u_int len);
70 
71 static void
72 pimv1_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;
149 trunc:
150 	(void)printf("[|pim]");
151 	return;
152 }
153 
154 void
155 pimv1_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 
256 trunc:
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  */
267 void
268 cisco_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 
352 trunc:
353 	(void)printf("[|autorp]");
354 	return;
355 }
356 
357 void
358 pim_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 
422 static int pimv2_addr_len;
423 
424 enum 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  */
448 static int
449 pimv2_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 	}
550 trunc:
551 	return -1;
552 }
553 
554 static void
555 pimv2_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 
944 trunc:
945 	(void)printf("[|pim]");
946 }
947