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