xref: /freebsd/contrib/tcpdump/print-pim.c (revision f9218d3d4fd34f082473b3a021c6d4d109fb47cf)
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.4.1 2002/05/07 18:30:19 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 18:	/* Old DR-Priority */
590 				if (olen == 4)
591 					(void)printf(" (OLD-DR-Priority: %d)",
592 							EXTRACT_32BITS(&bp[4]));
593 				else
594 					goto unknown;
595 				break;
596 
597 
598 			case 19:	/* DR-Priority */
599 				if (olen == 0) {
600 					(void)printf(" (OLD-bidir-capable)");
601 					break;
602 				}
603 				(void)printf(" (DR-Priority: ");
604 				if (olen != 4) {
605 					(void)printf("!olen=%d!)", olen);
606 				} else {
607 					(void)printf("%d)", EXTRACT_32BITS(&bp[4]));
608 				}
609 				break;
610 
611 			case 20:
612 				(void)printf(" (Genid: 0x%08x)", EXTRACT_32BITS(&bp[4]));
613 				break;
614 
615 			case 21:
616 				(void)printf(" (State Refresh Capable; v%d", bp[4]);
617 				if (bp[5] != 0) {
618 					(void)printf(" interval ");
619 					relts_print(bp[5]);
620 				}
621 				if (EXTRACT_16BITS(&bp[6]) != 0) {
622 					(void)printf(" ?0x%04x?", EXTRACT_16BITS(&bp[6]));
623 				}
624 				(void)printf(")");
625 				break;
626 
627 			case 22:	/* Bidir-Capable */
628 				(void)printf(" (bidir-capable)");
629 				break;
630 
631 			default:
632 			unknown:
633 				if (vflag)
634 					(void)printf(" [Hello option %d]", otype);
635 			}
636 			bp += 4 + olen;
637 		}
638 		break;
639 	    }
640 
641 	case 1:
642 	{
643 		struct ip *ip;
644 
645 		(void)printf(" Register");
646 		if (vflag && bp + 8 <= ep) {
647 			(void)printf(" %s%s", bp[4] & 0x80 ? "B" : "",
648 				bp[4] & 0x40 ? "N" : "");
649 		}
650 		bp += 8; len -= 8;
651 
652 		/* encapsulated multicast packet */
653 		if (bp >= ep)
654 			break;
655 		ip = (struct ip *)bp;
656 		switch (IP_V(ip)) {
657 		case 4:	/* IPv4 */
658 			printf(" ");
659 			ip_print(bp, len);
660 			break;
661 #ifdef INET6
662 		case 6:	/* IPv6 */
663 			printf(" ");
664 			ip6_print(bp, len);
665 			break;
666 #endif
667 		default:
668 			(void)printf(" IP ver %d", IP_V(ip));
669 			break;
670 		}
671 		break;
672 	}
673 
674 	case 2:
675 		(void)printf(" Register-Stop");
676 		bp += 4; len -= 4;
677 		if (bp >= ep)
678 			break;
679 		(void)printf(" group=");
680 		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
681 			(void)printf("...");
682 			break;
683 		}
684 		bp += advance; len -= advance;
685 		if (bp >= ep)
686 			break;
687 		(void)printf(" source=");
688 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
689 			(void)printf("...");
690 			break;
691 		}
692 		bp += advance; len -= advance;
693 		break;
694 
695 	case 3:
696 	case 6:
697 	case 7:
698 	    {
699 		u_int8_t ngroup;
700 		u_int16_t holdtime;
701 		u_int16_t njoin;
702 		u_int16_t nprune;
703 		int i, j;
704 
705 		switch (PIM_TYPE(pim->pim_typever)) {
706 		case 3:
707 			(void)printf(" Join/Prune");
708 			break;
709 		case 6:
710 			(void)printf(" Graft");
711 			break;
712 		case 7:
713 			(void)printf(" Graft-ACK");
714 			break;
715 		}
716 		bp += 4; len -= 4;
717 		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
718 			if (bp >= ep)
719 				break;
720 			(void)printf(" upstream-neighbor=");
721 			if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
722 				(void)printf("...");
723 				break;
724 			}
725 			bp += advance; len -= advance;
726 		}
727 		if (bp + 4 > ep)
728 			break;
729 		ngroup = bp[1];
730 		holdtime = EXTRACT_16BITS(&bp[2]);
731 		(void)printf(" groups=%u", ngroup);
732 		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
733 			(void)printf(" holdtime=");
734 			if (holdtime == 0xffff)
735 				(void)printf("infty");
736 			else
737 				relts_print(holdtime);
738 		}
739 		bp += 4; len -= 4;
740 		for (i = 0; i < ngroup; i++) {
741 			if (bp >= ep)
742 				goto jp_done;
743 			(void)printf(" (group%d: ", i);
744 			if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
745 				(void)printf("...)");
746 				goto jp_done;
747 			}
748 			bp += advance; len -= advance;
749 			if (bp + 4 > ep) {
750 				(void)printf("...)");
751 				goto jp_done;
752 			}
753 			njoin = EXTRACT_16BITS(&bp[0]);
754 			nprune = EXTRACT_16BITS(&bp[2]);
755 			(void)printf(" join=%u", njoin);
756 			bp += 4; len -= 4;
757 			for (j = 0; j < njoin; j++) {
758 				(void)printf(" ");
759 				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
760 					(void)printf("...)");
761 					goto jp_done;
762 				}
763 				bp += advance; len -= advance;
764 			}
765 			(void)printf(" prune=%u", nprune);
766 			for (j = 0; j < nprune; j++) {
767 				(void)printf(" ");
768 				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
769 					(void)printf("...)");
770 					goto jp_done;
771 				}
772 				bp += advance; len -= advance;
773 			}
774 			(void)printf(")");
775 		}
776 	jp_done:
777 		break;
778 	    }
779 
780 	case 4:
781 	{
782 		int i, j, frpcnt;
783 
784 		(void)printf(" Bootstrap");
785 		bp += 4;
786 
787 		/* Fragment Tag, Hash Mask len, and BSR-priority */
788 		if (bp + sizeof(u_int16_t) >= ep) break;
789 		(void)printf(" tag=%x", EXTRACT_16BITS(bp));
790 		bp += sizeof(u_int16_t);
791 		if (bp >= ep) break;
792 		(void)printf(" hashmlen=%d", bp[0]);
793 		if (bp + 1 >= ep) break;
794 		(void)printf(" BSRprio=%d", bp[1]);
795 		bp += 2;
796 
797 		/* Encoded-Unicast-BSR-Address */
798 		if (bp >= ep) break;
799 		(void)printf(" BSR=");
800 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
801 			(void)printf("...");
802 			break;
803 		}
804 		bp += advance;
805 
806 		for (i = 0; bp < ep; i++) {
807 			/* Encoded-Group Address */
808 			(void)printf(" (group%d: ", i);
809 			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
810 			    < 0) {
811 				(void)printf("...)");
812 				goto bs_done;
813 			}
814 			bp += advance;
815 
816 			/* RP-Count, Frag RP-Cnt, and rsvd */
817 			if (bp >= ep) {
818 				(void)printf("...)");
819 				goto bs_done;
820 			}
821 			(void)printf(" RPcnt=%d", bp[0]);
822 			if (bp + 1 >= ep) {
823 				(void)printf("...)");
824 				goto bs_done;
825 			}
826 			(void)printf(" FRPcnt=%d", frpcnt = bp[1]);
827 			bp += 4;
828 
829 			for (j = 0; j < frpcnt && bp < ep; j++) {
830 				/* each RP info */
831 				(void)printf(" RP%d=", j);
832 				if ((advance = pimv2_addr_print(bp,
833 								pimv2_unicast,
834 								0)) < 0) {
835 					(void)printf("...)");
836 					goto bs_done;
837 				}
838 				bp += advance;
839 
840 				if (bp + 1 >= ep) {
841 					(void)printf("...)");
842 					goto bs_done;
843 				}
844 				(void)printf(",holdtime=");
845 				relts_print(EXTRACT_16BITS(bp));
846 				if (bp + 2 >= ep) {
847 					(void)printf("...)");
848 					goto bs_done;
849 				}
850 				(void)printf(",prio=%d", bp[2]);
851 				bp += 4;
852 			}
853 			(void)printf(")");
854 		}
855 	   bs_done:
856 		break;
857 	}
858 	case 5:
859 		(void)printf(" Assert");
860 		bp += 4; len -= 4;
861 		if (bp >= ep)
862 			break;
863 		(void)printf(" group=");
864 		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
865 			(void)printf("...");
866 			break;
867 		}
868 		bp += advance; len -= advance;
869 		if (bp >= ep)
870 			break;
871 		(void)printf(" src=");
872 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
873 			(void)printf("...");
874 			break;
875 		}
876 		bp += advance; len -= advance;
877 		if (bp + 8 > ep)
878 			break;
879 		if (bp[0] & 0x80)
880 			(void)printf(" RPT");
881 		(void)printf(" pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff);
882 		(void)printf(" metric=%u", EXTRACT_32BITS(&bp[4]));
883 		break;
884 
885 	case 8:
886 	{
887 		int i, pfxcnt;
888 
889 		(void)printf(" Candidate-RP-Advertisement");
890 		bp += 4;
891 
892 		/* Prefix-Cnt, Priority, and Holdtime */
893 		if (bp >= ep) break;
894 		(void)printf(" prefix-cnt=%d", bp[0]);
895 		pfxcnt = bp[0];
896 		if (bp + 1 >= ep) break;
897 		(void)printf(" prio=%d", bp[1]);
898 		if (bp + 3 >= ep) break;
899 		(void)printf(" holdtime=");
900 		relts_print(EXTRACT_16BITS(&bp[2]));
901 		bp += 4;
902 
903 		/* Encoded-Unicast-RP-Address */
904 		if (bp >= ep) break;
905 		(void)printf(" RP=");
906 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
907 			(void)printf("...");
908 			break;
909 		}
910 		bp += advance;
911 
912 		/* Encoded-Group Addresses */
913 		for (i = 0; i < pfxcnt && bp < ep; i++) {
914 			(void)printf(" Group%d=", i);
915 			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
916 			    < 0) {
917 				(void)printf("...");
918 				break;
919 			}
920 			bp += advance;
921 		}
922 		break;
923 	}
924 
925 	case 9:
926 		(void)printf(" Prune-Refresh");
927 		(void)printf(" src=");
928 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
929 			(void)printf("...");
930 			break;
931 		}
932 		bp += advance;
933 		(void)printf(" grp=");
934 		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
935 			(void)printf("...");
936 			break;
937 		}
938 		bp += advance;
939 		(void)printf(" forwarder=");
940 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
941 			(void)printf("...");
942 			break;
943 		}
944 		bp += advance;
945 		TCHECK2(bp[0], 2);
946 		(void)printf(" TUNR ");
947 		relts_print(EXTRACT_16BITS(bp));
948 		break;
949 
950 
951 	 default:
952 		(void)printf(" [type %d]", PIM_TYPE(pim->pim_typever));
953 		break;
954 	}
955 
956 	return;
957 
958 trunc:
959 	(void)printf("[|pim]");
960 }
961