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