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