xref: /freebsd/contrib/tcpdump/print-pim.c (revision 5521ff5a4d1929056e7ffc982fac3341ca54df7c)
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.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 
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     (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;
140 trunc:
141     (void)printf("[|pim]");
142     return;
143 }
144 
145 void
146 pimv1_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 
255 trunc:
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  */
264 void
265 cisco_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 
345 trunc:
346     (void)printf("[|autorp]");
347     return;
348 }
349 
350 void
351 pim_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 
415 static int pimv2_addr_len;
416 
417 enum pimv2_addrtype {
418 	pimv2_unicast, pimv2_group, pimv2_source
419 };
420 #if 0
421 static 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  */
446 static int
447 pimv2_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 	}
548 trunc:
549 	return -1;
550 }
551 
552 static void
553 pimv2_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 
941 trunc:
942 	(void)printf("[|pim]");
943 }
944