xref: /freebsd/contrib/tcpdump/print-pim.c (revision 29292c17af721e5dabd42f1d89b511352ed945ed)
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
25cc391cceSBruce M Simpson static const char rcsid[] _U_ =
2629292c17SSam Leffler     "@(#) $Header: /tcpdump/master/tcpdump/print-pim.c,v 1.45.2.2 2005/04/20 22:08:44 guy Exp $ (LBL)";
27b0453382SBill Fenner #endif
28b0453382SBill Fenner 
29b0453382SBill Fenner #ifdef HAVE_CONFIG_H
30b0453382SBill Fenner #include "config.h"
314edb46e9SPaul Traina #endif
324edb46e9SPaul Traina 
33cc391cceSBruce M Simpson #include <tcpdump-stdinc.h>
34c1ad1296SSam Leffler #include "interface.h"
35c1ad1296SSam Leffler 
36c1ad1296SSam Leffler #define PIMV2_TYPE_HELLO         0
37c1ad1296SSam Leffler #define PIMV2_TYPE_REGISTER      1
38c1ad1296SSam Leffler #define PIMV2_TYPE_REGISTER_STOP 2
39c1ad1296SSam Leffler #define PIMV2_TYPE_JOIN_PRUNE    3
40c1ad1296SSam Leffler #define PIMV2_TYPE_BOOTSTRAP     4
41c1ad1296SSam Leffler #define PIMV2_TYPE_ASSERT        5
42c1ad1296SSam Leffler #define PIMV2_TYPE_GRAFT         6
43c1ad1296SSam Leffler #define PIMV2_TYPE_GRAFT_ACK     7
44c1ad1296SSam Leffler #define PIMV2_TYPE_CANDIDATE_RP  8
45c1ad1296SSam Leffler #define PIMV2_TYPE_PRUNE_REFRESH 9
46c1ad1296SSam Leffler 
47c1ad1296SSam Leffler static struct tok pimv2_type_values[] = {
48c1ad1296SSam Leffler     { PIMV2_TYPE_HELLO,         "Hello" },
49c1ad1296SSam Leffler     { PIMV2_TYPE_REGISTER,      "Register" },
50c1ad1296SSam Leffler     { PIMV2_TYPE_REGISTER_STOP, "Register Stop" },
51c1ad1296SSam Leffler     { PIMV2_TYPE_JOIN_PRUNE,    "Join / Prune" },
52c1ad1296SSam Leffler     { PIMV2_TYPE_BOOTSTRAP,     "Bootstrap" },
53c1ad1296SSam Leffler     { PIMV2_TYPE_ASSERT,        "Assert" },
54c1ad1296SSam Leffler     { PIMV2_TYPE_GRAFT,         "Graft" },
55c1ad1296SSam Leffler     { PIMV2_TYPE_GRAFT_ACK,     "Graft Acknowledgement" },
56c1ad1296SSam Leffler     { PIMV2_TYPE_CANDIDATE_RP,  "Candidate RP Advertisement" },
57c1ad1296SSam Leffler     { PIMV2_TYPE_PRUNE_REFRESH, "Prune Refresh" },
58c1ad1296SSam Leffler     { 0, NULL}
59c1ad1296SSam Leffler };
60c1ad1296SSam Leffler 
61c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_HOLDTIME             1
62c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_LANPRUNEDELAY        2
63c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_DR_PRIORITY_OLD     18
64c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_DR_PRIORITY         19
65c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_GENID               20
66c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_REFRESH_CAP         21
67c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_BIDIR_CAP           22
68c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_ADDRESS_LIST        24
69c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD 65001
70c1ad1296SSam Leffler 
71c1ad1296SSam Leffler static struct tok pimv2_hello_option_values[] = {
72c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_HOLDTIME,         "Hold Time" },
73c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_LANPRUNEDELAY,    "LAN Prune Delay" },
74c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_DR_PRIORITY_OLD,  "DR Priority (Old)" },
75c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_DR_PRIORITY,      "DR Priority" },
76c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_GENID,            "Generation ID" },
77c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_REFRESH_CAP,      "State Refresh Capability" },
78c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_BIDIR_CAP,        "Bi-Directional Capability" },
79c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_ADDRESS_LIST,     "Address List" },
80c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD, "Address List (Old)" },
81c1ad1296SSam Leffler     { 0, NULL}
82c1ad1296SSam Leffler };
83c1ad1296SSam Leffler 
84b0453382SBill Fenner 
85b0453382SBill Fenner /*
86b0453382SBill Fenner  * XXX: We consider a case where IPv6 is not ready yet for portability,
87b0453382SBill Fenner  * but PIM dependent defintions should be independent of IPv6...
88b0453382SBill Fenner  */
89b0453382SBill Fenner 
90b0453382SBill Fenner struct pim {
91b0453382SBill Fenner 	u_int8_t pim_typever;
929537d84eSBill Fenner 			/* upper 4bit: PIM version number; 2 for PIMv2 */
939537d84eSBill Fenner 			/* lower 4bit: the PIM message type, currently they are:
94b0453382SBill Fenner 			 * Hello, Register, Register-Stop, Join/Prune,
95b0453382SBill Fenner 			 * Bootstrap, Assert, Graft (PIM-DM only),
96b0453382SBill Fenner 			 * Graft-Ack (PIM-DM only), C-RP-Adv
97b0453382SBill Fenner 			 */
989537d84eSBill Fenner #define PIM_VER(x)	(((x) & 0xf0) >> 4)
999537d84eSBill Fenner #define PIM_TYPE(x)	((x) & 0x0f)
100b0453382SBill Fenner 	u_char  pim_rsv;	/* Reserved */
101b0453382SBill Fenner 	u_short	pim_cksum;	/* IP style check sum */
102b0453382SBill Fenner };
103b0453382SBill Fenner 
1044edb46e9SPaul Traina 
1054edb46e9SPaul Traina #include <stdio.h>
1064edb46e9SPaul Traina #include <stdlib.h>
1074edb46e9SPaul Traina 
1084edb46e9SPaul Traina #include "interface.h"
1094edb46e9SPaul Traina #include "addrtoname.h"
110b0453382SBill Fenner #include "extract.h"
111b0453382SBill Fenner 
112943ee2b1SBill Fenner #include "ip.h"
113943ee2b1SBill Fenner 
114b0453382SBill Fenner static void pimv2_print(register const u_char *bp, register u_int len);
115b0453382SBill Fenner 
116b0453382SBill Fenner static void
117b0453382SBill Fenner pimv1_join_prune_print(register const u_char *bp, register u_int len)
118b0453382SBill Fenner {
119b0453382SBill Fenner 	int maddrlen, addrlen, ngroups, njoin, nprune;
120b0453382SBill Fenner 	int njp;
121b0453382SBill Fenner 
122b0453382SBill Fenner 	/* If it's a single group and a single source, use 1-line output. */
123b0453382SBill Fenner 	if (TTEST2(bp[0], 30) && bp[11] == 1 &&
124b0453382SBill Fenner 	    ((njoin = EXTRACT_16BITS(&bp[20])) + EXTRACT_16BITS(&bp[22])) == 1) {
125b0453382SBill Fenner 		int hold;
126b0453382SBill Fenner 
127b0453382SBill Fenner 		(void)printf(" RPF %s ", ipaddr_string(bp));
128b0453382SBill Fenner 		hold = EXTRACT_16BITS(&bp[6]);
129b0453382SBill Fenner 		if (hold != 180) {
130b0453382SBill Fenner 			(void)printf("Hold ");
131b0453382SBill Fenner 			relts_print(hold);
132b0453382SBill Fenner 		}
133b0453382SBill Fenner 		(void)printf("%s (%s/%d, %s", njoin ? "Join" : "Prune",
134b0453382SBill Fenner 		ipaddr_string(&bp[26]), bp[25] & 0x3f,
135b0453382SBill Fenner 		ipaddr_string(&bp[12]));
136b0453382SBill Fenner 		if (EXTRACT_32BITS(&bp[16]) != 0xffffffff)
137b0453382SBill Fenner 			(void)printf("/%s", ipaddr_string(&bp[16]));
138b0453382SBill Fenner 		(void)printf(") %s%s %s",
139b0453382SBill Fenner 		    (bp[24] & 0x01) ? "Sparse" : "Dense",
140b0453382SBill Fenner 		    (bp[25] & 0x80) ? " WC" : "",
141b0453382SBill Fenner 		    (bp[25] & 0x40) ? "RP" : "SPT");
142b0453382SBill Fenner 		return;
143b0453382SBill Fenner 	}
144b0453382SBill Fenner 
145b0453382SBill Fenner 	TCHECK2(bp[0], 4);
146a1c2090eSBill Fenner 	if (vflag > 1)
147a1c2090eSBill Fenner 		(void)printf("\n");
148a1c2090eSBill Fenner 	(void)printf(" Upstream Nbr: %s", ipaddr_string(bp));
149b0453382SBill Fenner 	TCHECK2(bp[6], 2);
150a1c2090eSBill Fenner 	if (vflag > 1)
151a1c2090eSBill Fenner 		(void)printf("\n");
152a1c2090eSBill Fenner 	(void)printf(" Hold time: ");
153b0453382SBill Fenner 	relts_print(EXTRACT_16BITS(&bp[6]));
154a1c2090eSBill Fenner 	if (vflag < 2)
155a1c2090eSBill Fenner 		return;
156a1c2090eSBill Fenner 	bp += 8;
157a1c2090eSBill Fenner 	len -= 8;
158b0453382SBill Fenner 
159b0453382SBill Fenner 	TCHECK2(bp[0], 4);
160b0453382SBill Fenner 	maddrlen = bp[1];
161b0453382SBill Fenner 	addrlen = bp[2];
162b0453382SBill Fenner 	ngroups = bp[3];
163a1c2090eSBill Fenner 	bp += 4;
164a1c2090eSBill Fenner 	len -= 4;
165b0453382SBill Fenner 	while (ngroups--) {
16629292c17SSam Leffler 		/*
16729292c17SSam Leffler 		 * XXX - does the address have length "addrlen" and the
16829292c17SSam Leffler 		 * mask length "maddrlen"?
16929292c17SSam Leffler 		 */
170b0453382SBill Fenner 		TCHECK2(bp[0], 4);
171b0453382SBill Fenner 		(void)printf("\n\tGroup: %s", ipaddr_string(bp));
172cc391cceSBruce M Simpson 		TCHECK2(bp[4], 4);
173b0453382SBill Fenner 		if (EXTRACT_32BITS(&bp[4]) != 0xffffffff)
174b0453382SBill Fenner 			(void)printf("/%s", ipaddr_string(&bp[4]));
175b0453382SBill Fenner 		TCHECK2(bp[8], 4);
176b0453382SBill Fenner 		njoin = EXTRACT_16BITS(&bp[8]);
177b0453382SBill Fenner 		nprune = EXTRACT_16BITS(&bp[10]);
178b0453382SBill Fenner 		(void)printf(" joined: %d pruned: %d", njoin, nprune);
179a1c2090eSBill Fenner 		bp += 12;
180a1c2090eSBill Fenner 		len -= 12;
181b0453382SBill Fenner 		for (njp = 0; njp < (njoin + nprune); njp++) {
182cc391cceSBruce M Simpson 			const char *type;
183b0453382SBill Fenner 
184a1c2090eSBill Fenner 			if (njp < njoin)
185b0453382SBill Fenner 				type = "Join ";
186a1c2090eSBill Fenner 			else
187b0453382SBill Fenner 				type = "Prune";
188b0453382SBill Fenner 			TCHECK2(bp[0], 6);
189b0453382SBill Fenner 			(void)printf("\n\t%s %s%s%s%s/%d", type,
190b0453382SBill Fenner 			    (bp[0] & 0x01) ? "Sparse " : "Dense ",
191b0453382SBill Fenner 			    (bp[1] & 0x80) ? "WC " : "",
192b0453382SBill Fenner 			    (bp[1] & 0x40) ? "RP " : "SPT ",
193b0453382SBill Fenner 			ipaddr_string(&bp[2]), bp[1] & 0x3f);
194a1c2090eSBill Fenner 			bp += 6;
195a1c2090eSBill Fenner 			len -= 6;
196b0453382SBill Fenner 		}
197b0453382SBill Fenner 	}
198b0453382SBill Fenner 	return;
199b0453382SBill Fenner trunc:
200b0453382SBill Fenner 	(void)printf("[|pim]");
201b0453382SBill Fenner 	return;
202b0453382SBill Fenner }
2034edb46e9SPaul Traina 
2044edb46e9SPaul Traina void
205b0453382SBill Fenner pimv1_print(register const u_char *bp, register u_int len)
2064edb46e9SPaul Traina {
2074edb46e9SPaul Traina 	register const u_char *ep;
2084edb46e9SPaul Traina 	register u_char type;
2094edb46e9SPaul Traina 
2104edb46e9SPaul Traina 	ep = (const u_char *)snapend;
2114edb46e9SPaul Traina 	if (bp >= ep)
2124edb46e9SPaul Traina 		return;
2134edb46e9SPaul Traina 
214cc391cceSBruce M Simpson 	TCHECK(bp[1]);
2154edb46e9SPaul Traina 	type = bp[1];
2164edb46e9SPaul Traina 
2174edb46e9SPaul Traina 	switch (type) {
2184edb46e9SPaul Traina 	case 0:
2194edb46e9SPaul Traina 		(void)printf(" Query");
220b0453382SBill Fenner 		if (TTEST(bp[8])) {
221b0453382SBill Fenner 			switch (bp[8] >> 4) {
222a1c2090eSBill Fenner 			case 0:
223a1c2090eSBill Fenner 				(void)printf(" Dense-mode");
224b0453382SBill Fenner 				break;
225a1c2090eSBill Fenner 			case 1:
226a1c2090eSBill Fenner 				(void)printf(" Sparse-mode");
227b0453382SBill Fenner 				break;
228a1c2090eSBill Fenner 			case 2:
229a1c2090eSBill Fenner 				(void)printf(" Sparse-Dense-mode");
230b0453382SBill Fenner 				break;
231a1c2090eSBill Fenner 			default:
232a1c2090eSBill Fenner 				(void)printf(" mode-%d", bp[8] >> 4);
233b0453382SBill Fenner 				break;
234b0453382SBill Fenner 			}
235b0453382SBill Fenner 		}
236b0453382SBill Fenner 		if (vflag) {
237b0453382SBill Fenner 			TCHECK2(bp[10],2);
238b0453382SBill Fenner 			(void)printf(" (Hold-time ");
239b0453382SBill Fenner 			relts_print(EXTRACT_16BITS(&bp[10]));
240b0453382SBill Fenner 			(void)printf(")");
241b0453382SBill Fenner 		}
2424edb46e9SPaul Traina 		break;
2434edb46e9SPaul Traina 
2444edb46e9SPaul Traina 	case 1:
2454edb46e9SPaul Traina 		(void)printf(" Register");
246b0453382SBill Fenner 		TCHECK2(bp[8], 20);			/* ip header */
247b0453382SBill Fenner 		(void)printf(" for %s > %s", ipaddr_string(&bp[20]),
248b0453382SBill Fenner 		    ipaddr_string(&bp[24]));
2494edb46e9SPaul Traina 		break;
2504edb46e9SPaul Traina 	case 2:
2514edb46e9SPaul Traina 		(void)printf(" Register-Stop");
252b0453382SBill Fenner 		TCHECK2(bp[12], 4);
253b0453382SBill Fenner 		(void)printf(" for %s > %s", ipaddr_string(&bp[8]),
254b0453382SBill Fenner 		    ipaddr_string(&bp[12]));
2554edb46e9SPaul Traina 		break;
2564edb46e9SPaul Traina 	case 3:
2574edb46e9SPaul Traina 		(void)printf(" Join/Prune");
258a1c2090eSBill Fenner 		if (vflag)
259b0453382SBill Fenner 			pimv1_join_prune_print(&bp[8], len - 8);
2604edb46e9SPaul Traina 		break;
2614edb46e9SPaul Traina 	case 4:
2624edb46e9SPaul Traina 		(void)printf(" RP-reachable");
263b0453382SBill Fenner 		if (vflag) {
264b0453382SBill Fenner 			TCHECK2(bp[22], 2);
265b0453382SBill Fenner 			(void)printf(" group %s",
266b0453382SBill Fenner 			ipaddr_string(&bp[8]));
267b0453382SBill Fenner 			if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
268b0453382SBill Fenner 				(void)printf("/%s", ipaddr_string(&bp[12]));
269a1c2090eSBill Fenner 			(void)printf(" RP %s hold ", ipaddr_string(&bp[16]));
270b0453382SBill Fenner 			relts_print(EXTRACT_16BITS(&bp[22]));
271b0453382SBill Fenner 		}
2724edb46e9SPaul Traina 		break;
2734edb46e9SPaul Traina 	case 5:
2744edb46e9SPaul Traina 		(void)printf(" Assert");
275b0453382SBill Fenner 		TCHECK2(bp[16], 4);
276b0453382SBill Fenner 		(void)printf(" for %s > %s", ipaddr_string(&bp[16]),
277b0453382SBill Fenner 		    ipaddr_string(&bp[8]));
278b0453382SBill Fenner 		if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
279b0453382SBill Fenner 			(void)printf("/%s", ipaddr_string(&bp[12]));
280b0453382SBill Fenner 		TCHECK2(bp[24], 4);
281b0453382SBill Fenner 		(void)printf(" %s pref %d metric %d",
282b0453382SBill Fenner 		    (bp[20] & 0x80) ? "RP-tree" : "SPT",
283b0453382SBill Fenner 		EXTRACT_32BITS(&bp[20]) & 0x7fffffff,
284b0453382SBill Fenner 		EXTRACT_32BITS(&bp[24]));
2854edb46e9SPaul Traina 		break;
2864edb46e9SPaul Traina 	case 6:
2874edb46e9SPaul Traina 		(void)printf(" Graft");
288a1c2090eSBill Fenner 		if (vflag)
289b0453382SBill Fenner 			pimv1_join_prune_print(&bp[8], len - 8);
2904edb46e9SPaul Traina 		break;
2914edb46e9SPaul Traina 	case 7:
2924edb46e9SPaul Traina 		(void)printf(" Graft-ACK");
293a1c2090eSBill Fenner 		if (vflag)
294b0453382SBill Fenner 			pimv1_join_prune_print(&bp[8], len - 8);
2954edb46e9SPaul Traina 		break;
2964edb46e9SPaul Traina 	case 8:
2974edb46e9SPaul Traina 		(void)printf(" Mode");
2984edb46e9SPaul Traina 		break;
2994edb46e9SPaul Traina 	default:
3004edb46e9SPaul Traina 		(void)printf(" [type %d]", type);
3014edb46e9SPaul Traina 		break;
3024edb46e9SPaul Traina 	}
303b0453382SBill Fenner 	if ((bp[4] >> 4) != 1)
304b0453382SBill Fenner 		(void)printf(" [v%d]", bp[4] >> 4);
305b0453382SBill Fenner 	return;
306b0453382SBill Fenner 
307b0453382SBill Fenner trunc:
308b0453382SBill Fenner 	(void)printf("[|pim]");
309b0453382SBill Fenner 	return;
310b0453382SBill Fenner }
311b0453382SBill Fenner 
312b0453382SBill Fenner /*
313b0453382SBill Fenner  * auto-RP is a cisco protocol, documented at
314a1c2090eSBill Fenner  * ftp://ftpeng.cisco.com/ipmulticast/specs/pim-autorp-spec01.txt
315a1c2090eSBill Fenner  *
316a1c2090eSBill Fenner  * This implements version 1+, dated Sept 9, 1998.
317b0453382SBill Fenner  */
318b0453382SBill Fenner void
319b0453382SBill Fenner cisco_autorp_print(register const u_char *bp, register u_int len)
320b0453382SBill Fenner {
321b0453382SBill Fenner 	int type;
322b0453382SBill Fenner 	int numrps;
323b0453382SBill Fenner 	int hold;
324b0453382SBill Fenner 
325b0453382SBill Fenner 	TCHECK(bp[0]);
326b0453382SBill Fenner 	(void)printf(" auto-rp ");
327b0453382SBill Fenner 	type = bp[0];
328b0453382SBill Fenner 	switch (type) {
329b0453382SBill Fenner 	case 0x11:
330b0453382SBill Fenner 		(void)printf("candidate-advert");
331b0453382SBill Fenner 		break;
332b0453382SBill Fenner 	case 0x12:
333b0453382SBill Fenner 		(void)printf("mapping");
334b0453382SBill Fenner 		break;
335b0453382SBill Fenner 	default:
336b0453382SBill Fenner 		(void)printf("type-0x%02x", type);
337b0453382SBill Fenner 		break;
338b0453382SBill Fenner 	}
339b0453382SBill Fenner 
340b0453382SBill Fenner 	TCHECK(bp[1]);
341b0453382SBill Fenner 	numrps = bp[1];
342b0453382SBill Fenner 
343b0453382SBill Fenner 	TCHECK2(bp[2], 2);
344b0453382SBill Fenner 	(void)printf(" Hold ");
345b0453382SBill Fenner 	hold = EXTRACT_16BITS(&bp[2]);
346b0453382SBill Fenner 	if (hold)
347b0453382SBill Fenner 		relts_print(EXTRACT_16BITS(&bp[2]));
348b0453382SBill Fenner 	else
349b0453382SBill Fenner 		printf("FOREVER");
350b0453382SBill Fenner 
351b0453382SBill Fenner 	/* Next 4 bytes are reserved. */
352b0453382SBill Fenner 
353b0453382SBill Fenner 	bp += 8; len -= 8;
354b0453382SBill Fenner 
355b0453382SBill Fenner 	/*XXX skip unless -v? */
356b0453382SBill Fenner 
357b0453382SBill Fenner 	/*
358b0453382SBill Fenner 	 * Rest of packet:
359b0453382SBill Fenner 	 * numrps entries of the form:
360b0453382SBill Fenner 	 * 32 bits: RP
361b0453382SBill Fenner 	 * 6 bits: reserved
362b0453382SBill Fenner 	 * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
363b0453382SBill Fenner 	 * 8 bits: # of entries for this RP
364b0453382SBill Fenner 	 * each entry: 7 bits: reserved, 1 bit: negative,
365b0453382SBill Fenner 	 *	       8 bits: mask 32 bits: source
366b0453382SBill Fenner 	 * lather, rinse, repeat.
367b0453382SBill Fenner 	 */
368b0453382SBill Fenner 	while (numrps--) {
369b0453382SBill Fenner 		int nentries;
370b0453382SBill Fenner 		char s;
371b0453382SBill Fenner 
372b0453382SBill Fenner 		TCHECK2(bp[0], 4);
373b0453382SBill Fenner 		(void)printf(" RP %s", ipaddr_string(bp));
374b0453382SBill Fenner 		TCHECK(bp[4]);
375b0453382SBill Fenner 		switch (bp[4] & 0x3) {
376b0453382SBill Fenner 		case 0: printf(" PIMv?");
377b0453382SBill Fenner 			break;
378b0453382SBill Fenner 		case 1:	printf(" PIMv1");
379b0453382SBill Fenner 			break;
380b0453382SBill Fenner 		case 2:	printf(" PIMv2");
381b0453382SBill Fenner 			break;
382b0453382SBill Fenner 		case 3:	printf(" PIMv1+2");
383b0453382SBill Fenner 			break;
384b0453382SBill Fenner 		}
385a1c2090eSBill Fenner 		if (bp[4] & 0xfc)
386a1c2090eSBill Fenner 			(void)printf(" [rsvd=0x%02x]", bp[4] & 0xfc);
387b0453382SBill Fenner 		TCHECK(bp[5]);
388b0453382SBill Fenner 		nentries = bp[5];
389b0453382SBill Fenner 		bp += 6; len -= 6;
390b0453382SBill Fenner 		s = ' ';
391b0453382SBill Fenner 		for (; nentries; nentries--) {
392b0453382SBill Fenner 			TCHECK2(bp[0], 6);
393b0453382SBill Fenner 			(void)printf("%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
394b0453382SBill Fenner 			    ipaddr_string(&bp[2]), bp[1]);
395a1c2090eSBill Fenner 			if (bp[0] & 0xfe)
396a1c2090eSBill Fenner 				(void)printf("[rsvd=0x%02x]", bp[0] & 0xfe);
397b0453382SBill Fenner 			s = ',';
398b0453382SBill Fenner 			bp += 6; len -= 6;
399b0453382SBill Fenner 		}
400b0453382SBill Fenner 	}
401b0453382SBill Fenner 	return;
402b0453382SBill Fenner 
403b0453382SBill Fenner trunc:
404b0453382SBill Fenner 	(void)printf("[|autorp]");
405b0453382SBill Fenner 	return;
406b0453382SBill Fenner }
407b0453382SBill Fenner 
408b0453382SBill Fenner void
409b0453382SBill Fenner pim_print(register const u_char *bp, register u_int len)
410b0453382SBill Fenner {
411b0453382SBill Fenner 	register const u_char *ep;
412b0453382SBill Fenner 	register struct pim *pim = (struct pim *)bp;
413b0453382SBill Fenner 
414b0453382SBill Fenner 	ep = (const u_char *)snapend;
415b0453382SBill Fenner 	if (bp >= ep)
416b0453382SBill Fenner 		return;
417b0453382SBill Fenner #ifdef notyet			/* currently we see only version and type */
418b0453382SBill Fenner 	TCHECK(pim->pim_rsv);
419b0453382SBill Fenner #endif
420b0453382SBill Fenner 
421b0453382SBill Fenner 	switch (PIM_VER(pim->pim_typever)) {
422c1ad1296SSam Leffler 	case 2:
423c1ad1296SSam Leffler             if (!vflag) {
424c1ad1296SSam Leffler                 printf("PIMv%u, %s, length: %u",
425c1ad1296SSam Leffler                        PIM_VER(pim->pim_typever),
426c1ad1296SSam Leffler                        tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)),
427c1ad1296SSam Leffler                        len);
428c1ad1296SSam Leffler                 return;
429c1ad1296SSam Leffler             } else {
430c1ad1296SSam Leffler                 printf("PIMv%u, length: %u\n\t%s",
431c1ad1296SSam Leffler                        PIM_VER(pim->pim_typever),
432c1ad1296SSam Leffler                        len,
433c1ad1296SSam Leffler                        tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)));
434b0453382SBill Fenner                 pimv2_print(bp, len);
435c1ad1296SSam Leffler             }
436b0453382SBill Fenner             break;
437b0453382SBill Fenner 	default:
438c1ad1296SSam Leffler 		printf("PIMv%u, length: %u",
439c1ad1296SSam Leffler                        PIM_VER(pim->pim_typever),
440c1ad1296SSam Leffler                        len);
441b0453382SBill Fenner 		break;
442b0453382SBill Fenner 	}
443b0453382SBill Fenner 	return;
444b0453382SBill Fenner }
445b0453382SBill Fenner 
446b0453382SBill Fenner /*
447b0453382SBill Fenner  * PIMv2 uses encoded address representations.
448b0453382SBill Fenner  *
449b0453382SBill Fenner  * The last PIM-SM I-D before RFC2117 was published specified the
450b0453382SBill Fenner  * following representation for unicast addresses.  However, RFC2117
451b0453382SBill Fenner  * specified no encoding for unicast addresses with the unicast
452b0453382SBill Fenner  * address length specified in the header.  Therefore, we have to
453b0453382SBill Fenner  * guess which encoding is being used (Cisco's PIMv2 implementation
454b0453382SBill Fenner  * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
455b0453382SBill Fenner  * field into a 'unicast-address-length-in-bytes' field.  We guess
456b0453382SBill Fenner  * that it's the draft encoding if this reserved field is zero.
457b0453382SBill Fenner  *
458b0453382SBill Fenner  * RFC2362 goes back to the encoded format, and calls the addr length
459b0453382SBill Fenner  * field "reserved" again.
460b0453382SBill Fenner  *
461b0453382SBill Fenner  * The first byte is the address family, from:
462b0453382SBill Fenner  *
463b0453382SBill Fenner  *    0    Reserved
464b0453382SBill Fenner  *    1    IP (IP version 4)
465b0453382SBill Fenner  *    2    IP6 (IP version 6)
466b0453382SBill Fenner  *    3    NSAP
467b0453382SBill Fenner  *    4    HDLC (8-bit multidrop)
468b0453382SBill Fenner  *    5    BBN 1822
469b0453382SBill Fenner  *    6    802 (includes all 802 media plus Ethernet "canonical format")
470b0453382SBill Fenner  *    7    E.163
471b0453382SBill Fenner  *    8    E.164 (SMDS, Frame Relay, ATM)
472b0453382SBill Fenner  *    9    F.69 (Telex)
473b0453382SBill Fenner  *   10    X.121 (X.25, Frame Relay)
474b0453382SBill Fenner  *   11    IPX
475b0453382SBill Fenner  *   12    Appletalk
476b0453382SBill Fenner  *   13    Decnet IV
477b0453382SBill Fenner  *   14    Banyan Vines
478b0453382SBill Fenner  *   15    E.164 with NSAP format subaddress
479b0453382SBill Fenner  *
480b0453382SBill Fenner  * In addition, the second byte is an "Encoding".  0 is the default
481b0453382SBill Fenner  * encoding for the address family, and no other encodings are currently
482b0453382SBill Fenner  * specified.
483b0453382SBill Fenner  *
484b0453382SBill Fenner  */
485b0453382SBill Fenner 
486b0453382SBill Fenner static int pimv2_addr_len;
487b0453382SBill Fenner 
488b0453382SBill Fenner enum pimv2_addrtype {
489b0453382SBill Fenner 	pimv2_unicast, pimv2_group, pimv2_source
490b0453382SBill Fenner };
491b0453382SBill Fenner 
492b0453382SBill Fenner /*  0                   1                   2                   3
493b0453382SBill 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
494b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
495b0453382SBill Fenner  * | Addr Family   | Encoding Type |     Unicast Address           |
496b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
497b0453382SBill Fenner  *  0                   1                   2                   3
498b0453382SBill 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
499b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
500b0453382SBill Fenner  * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
501b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
502b0453382SBill Fenner  * |                Group multicast Address                        |
503b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
504b0453382SBill Fenner  *  0                   1                   2                   3
505b0453382SBill 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
506b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
507b0453382SBill Fenner  * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
508b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
509b0453382SBill Fenner  * |                        Source Address                         |
510b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
511b0453382SBill Fenner  */
512b0453382SBill Fenner static int
513b0453382SBill Fenner pimv2_addr_print(const u_char *bp, enum pimv2_addrtype at, int silent)
514b0453382SBill Fenner {
515b0453382SBill Fenner 	int af;
516b0453382SBill Fenner 	int len, hdrlen;
517b0453382SBill Fenner 
518b0453382SBill Fenner 	TCHECK(bp[0]);
519b0453382SBill Fenner 
520b0453382SBill Fenner 	if (pimv2_addr_len == 0) {
521b0453382SBill Fenner 		TCHECK(bp[1]);
522b0453382SBill Fenner 		switch (bp[0]) {
523b0453382SBill Fenner 		case 1:
524b0453382SBill Fenner 			af = AF_INET;
525b0453382SBill Fenner 			len = 4;
526b0453382SBill Fenner 			break;
527b0453382SBill Fenner #ifdef INET6
528b0453382SBill Fenner 		case 2:
529b0453382SBill Fenner 			af = AF_INET6;
530b0453382SBill Fenner 			len = 16;
531b0453382SBill Fenner 			break;
532b0453382SBill Fenner #endif
533b0453382SBill Fenner 		default:
534b0453382SBill Fenner 			return -1;
535b0453382SBill Fenner 		}
536b0453382SBill Fenner 		if (bp[1] != 0)
537b0453382SBill Fenner 			return -1;
538b0453382SBill Fenner 		hdrlen = 2;
539b0453382SBill Fenner 	} else {
540b0453382SBill Fenner 		switch (pimv2_addr_len) {
541b0453382SBill Fenner 		case 4:
542b0453382SBill Fenner 			af = AF_INET;
543b0453382SBill Fenner 			break;
544b0453382SBill Fenner #ifdef INET6
545b0453382SBill Fenner 		case 16:
546b0453382SBill Fenner 			af = AF_INET6;
547b0453382SBill Fenner 			break;
548b0453382SBill Fenner #endif
549b0453382SBill Fenner 		default:
550b0453382SBill Fenner 			return -1;
551b0453382SBill Fenner 			break;
552b0453382SBill Fenner 		}
553b0453382SBill Fenner 		len = pimv2_addr_len;
554b0453382SBill Fenner 		hdrlen = 0;
555b0453382SBill Fenner 	}
556b0453382SBill Fenner 
557b0453382SBill Fenner 	bp += hdrlen;
558b0453382SBill Fenner 	switch (at) {
559b0453382SBill Fenner 	case pimv2_unicast:
560b0453382SBill Fenner 		TCHECK2(bp[0], len);
561b0453382SBill Fenner 		if (af == AF_INET) {
562b0453382SBill Fenner 			if (!silent)
563b0453382SBill Fenner 				(void)printf("%s", ipaddr_string(bp));
564b0453382SBill Fenner 		}
565b0453382SBill Fenner #ifdef INET6
566b0453382SBill Fenner 		else if (af == AF_INET6) {
567b0453382SBill Fenner 			if (!silent)
568b0453382SBill Fenner 				(void)printf("%s", ip6addr_string(bp));
569b0453382SBill Fenner 		}
570b0453382SBill Fenner #endif
571b0453382SBill Fenner 		return hdrlen + len;
572b0453382SBill Fenner 	case pimv2_group:
573b0453382SBill Fenner 	case pimv2_source:
574b0453382SBill Fenner 		TCHECK2(bp[0], len + 2);
575b0453382SBill Fenner 		if (af == AF_INET) {
576b0453382SBill Fenner 			if (!silent) {
577b0453382SBill Fenner 				(void)printf("%s", ipaddr_string(bp + 2));
578b0453382SBill Fenner 				if (bp[1] != 32)
579b0453382SBill Fenner 					(void)printf("/%u", bp[1]);
580b0453382SBill Fenner 			}
581b0453382SBill Fenner 		}
582b0453382SBill Fenner #ifdef INET6
583b0453382SBill Fenner 		else if (af == AF_INET6) {
584b0453382SBill Fenner 			if (!silent) {
585b0453382SBill Fenner 				(void)printf("%s", ip6addr_string(bp + 2));
586b0453382SBill Fenner 				if (bp[1] != 128)
587b0453382SBill Fenner 					(void)printf("/%u", bp[1]);
588b0453382SBill Fenner 			}
589b0453382SBill Fenner 		}
590b0453382SBill Fenner #endif
591b0453382SBill Fenner 		if (bp[0] && !silent) {
592b0453382SBill Fenner 			if (at == pimv2_group) {
593b0453382SBill Fenner 				(void)printf("(0x%02x)", bp[0]);
594b0453382SBill Fenner 			} else {
595b0453382SBill Fenner 				(void)printf("(%s%s%s",
596b0453382SBill Fenner 					bp[0] & 0x04 ? "S" : "",
597b0453382SBill Fenner 					bp[0] & 0x02 ? "W" : "",
598b0453382SBill Fenner 					bp[0] & 0x01 ? "R" : "");
599b0453382SBill Fenner 				if (bp[0] & 0xf8) {
600b0453382SBill Fenner 					(void) printf("+0x%02x", bp[0] & 0xf8);
601b0453382SBill Fenner 				}
602b0453382SBill Fenner 				(void)printf(")");
603b0453382SBill Fenner 			}
604b0453382SBill Fenner 		}
605b0453382SBill Fenner 		return hdrlen + 2 + len;
606b0453382SBill Fenner 	default:
607b0453382SBill Fenner 		return -1;
608b0453382SBill Fenner 	}
609b0453382SBill Fenner trunc:
610b0453382SBill Fenner 	return -1;
611b0453382SBill Fenner }
612b0453382SBill Fenner 
613b0453382SBill Fenner static void
614b0453382SBill Fenner pimv2_print(register const u_char *bp, register u_int len)
615b0453382SBill Fenner {
616b0453382SBill Fenner 	register const u_char *ep;
617b0453382SBill Fenner 	register struct pim *pim = (struct pim *)bp;
618b0453382SBill Fenner 	int advance;
619b0453382SBill Fenner 
620b0453382SBill Fenner 	ep = (const u_char *)snapend;
621b0453382SBill Fenner 	if (bp >= ep)
622b0453382SBill Fenner 		return;
6239537d84eSBill Fenner 	if (ep > bp + len)
6249537d84eSBill Fenner 		ep = bp + len;
625b0453382SBill Fenner 	TCHECK(pim->pim_rsv);
626b0453382SBill Fenner 	pimv2_addr_len = pim->pim_rsv;
627b0453382SBill Fenner 	if (pimv2_addr_len != 0)
628c1ad1296SSam Leffler 		(void)printf(", RFC2117-encoding");
629b0453382SBill Fenner 
630b0453382SBill Fenner 	switch (PIM_TYPE(pim->pim_typever)) {
631c1ad1296SSam Leffler 	case PIMV2_TYPE_HELLO:
632b0453382SBill Fenner 	    {
633b0453382SBill Fenner 		u_int16_t otype, olen;
634b0453382SBill Fenner 		bp += 4;
635b0453382SBill Fenner 		while (bp < ep) {
636b0453382SBill Fenner 			TCHECK2(bp[0], 4);
637b0453382SBill Fenner 			otype = EXTRACT_16BITS(&bp[0]);
638b0453382SBill Fenner 			olen = EXTRACT_16BITS(&bp[2]);
639b0453382SBill Fenner 			TCHECK2(bp[0], 4 + olen);
640c1ad1296SSam Leffler 
641c1ad1296SSam Leffler                         printf("\n\t  %s Option (%u), length: %u, Value: ",
642c1ad1296SSam Leffler                                tok2str( pimv2_hello_option_values,"Unknown",otype),
643c1ad1296SSam Leffler                                otype,
644c1ad1296SSam Leffler                                olen);
645c1ad1296SSam Leffler 			bp += 4;
646c1ad1296SSam Leffler 
647b0453382SBill Fenner 			switch (otype) {
648c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_HOLDTIME:
649c1ad1296SSam Leffler                                 relts_print(EXTRACT_16BITS(bp));
650b0453382SBill Fenner                                 break;
651b0453382SBill Fenner 
652c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_LANPRUNEDELAY:
653cc391cceSBruce M Simpson 				if (olen != 4) {
654c1ad1296SSam Leffler 					(void)printf("ERROR: Option Lenght != 4 Bytes (%u)", olen);
655cc391cceSBruce M Simpson 				} else {
656cc391cceSBruce M Simpson 					char t_bit;
657cc391cceSBruce M Simpson 					u_int16_t lan_delay, override_interval;
658c1ad1296SSam Leffler 					lan_delay = EXTRACT_16BITS(bp);
659c1ad1296SSam Leffler 					override_interval = EXTRACT_16BITS(bp+2);
660cc391cceSBruce M Simpson 					t_bit = (lan_delay & 0x8000)? 1 : 0;
661cc391cceSBruce M Simpson 					lan_delay &= ~0x8000;
662c1ad1296SSam Leffler 					(void)printf("\n\t    T-bit=%d, LAN delay %dms, Override interval %dms",
663cc391cceSBruce M Simpson 					t_bit, lan_delay, override_interval);
664cc391cceSBruce M Simpson 				}
665cc391cceSBruce M Simpson 				break;
666cc391cceSBruce M Simpson 
667c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_DR_PRIORITY_OLD:
668c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_DR_PRIORITY:
669c1ad1296SSam Leffler                                 switch (olen) {
670c1ad1296SSam Leffler                                 case 0:
671c1ad1296SSam Leffler                                     printf("Bi-Directional Capability (Old)");
6720e0def19SBill Fenner                                     break;
673c1ad1296SSam Leffler                                 case 4:
674c1ad1296SSam Leffler                                     printf("%u", EXTRACT_32BITS(bp));
675c1ad1296SSam Leffler                                     break;
676c1ad1296SSam Leffler                                 default:
677c1ad1296SSam Leffler                                     printf("ERROR: Option Lenght != 4 Bytes (%u)", olen);
6780e0def19SBill Fenner                                     break;
6790e0def19SBill Fenner                                 }
680c1ad1296SSam Leffler                                 break;
681c1ad1296SSam Leffler 
682c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_GENID:
683c1ad1296SSam Leffler                                 (void)printf("0x%08x", EXTRACT_32BITS(bp));
684c1ad1296SSam Leffler 				break;
685c1ad1296SSam Leffler 
686c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_REFRESH_CAP:
687c1ad1296SSam Leffler                                 (void)printf("v%d", *bp);
688c1ad1296SSam Leffler 				if (*(bp+1) != 0) {
689c1ad1296SSam Leffler                                     (void)printf(", interval ");
690c1ad1296SSam Leffler                                     relts_print(*(bp+1));
691c1ad1296SSam Leffler 				}
692c1ad1296SSam Leffler 				if (EXTRACT_16BITS(bp+2) != 0) {
693c1ad1296SSam Leffler                                     (void)printf(" ?0x%04x?", EXTRACT_16BITS(bp+2));
694a1c2090eSBill Fenner 				}
695b0453382SBill Fenner 				break;
696b0453382SBill Fenner 
697c1ad1296SSam Leffler 			case  PIMV2_HELLO_OPTION_BIDIR_CAP:
698b0453382SBill Fenner 				break;
699b0453382SBill Fenner 
700c1ad1296SSam Leffler                         case PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD:
701c1ad1296SSam Leffler                         case PIMV2_HELLO_OPTION_ADDRESS_LIST:
702cc391cceSBruce M Simpson 				if (vflag > 1) {
703c1ad1296SSam Leffler 					const u_char *ptr = bp;
704c1ad1296SSam Leffler 					while (ptr < (bp+olen)) {
705cc391cceSBruce M Simpson 						int advance;
706cc391cceSBruce M Simpson 
707c1ad1296SSam Leffler 						printf("\n\t    ");
708cc391cceSBruce M Simpson 						advance = pimv2_addr_print(ptr, pimv2_unicast, 0);
709cc391cceSBruce M Simpson 						if (advance < 0) {
710cc391cceSBruce M Simpson 							printf("...");
711cc391cceSBruce M Simpson 							break;
712cc391cceSBruce M Simpson 						}
713cc391cceSBruce M Simpson 						ptr += advance;
714cc391cceSBruce M Simpson 					}
715cc391cceSBruce M Simpson 				}
716cc391cceSBruce M Simpson 				break;
717b0453382SBill Fenner 			default:
718c1ad1296SSam Leffler                                 if (vflag <= 1)
719c1ad1296SSam Leffler                                     print_unknown_data(bp,"\n\t    ",olen);
720c1ad1296SSam Leffler                                 break;
721b0453382SBill Fenner 			}
722c1ad1296SSam Leffler                         /* do we want to see an additionally hexdump ? */
723c1ad1296SSam Leffler                         if (vflag> 1)
724c1ad1296SSam Leffler                             print_unknown_data(bp,"\n\t    ",olen);
725c1ad1296SSam Leffler 			bp += olen;
726b0453382SBill Fenner 		}
727b0453382SBill Fenner 		break;
728b0453382SBill Fenner 	    }
729b0453382SBill Fenner 
730c1ad1296SSam Leffler 	case PIMV2_TYPE_REGISTER:
731b0453382SBill Fenner 	{
732b0453382SBill Fenner 		struct ip *ip;
733b0453382SBill Fenner 
734b0453382SBill Fenner 		if (vflag && bp + 8 <= ep) {
735b0453382SBill Fenner 			(void)printf(" %s%s", bp[4] & 0x80 ? "B" : "",
736b0453382SBill Fenner 				bp[4] & 0x40 ? "N" : "");
737b0453382SBill Fenner 		}
738b0453382SBill Fenner 		bp += 8; len -= 8;
739b0453382SBill Fenner 
740b0453382SBill Fenner 		/* encapsulated multicast packet */
741b0453382SBill Fenner 		if (bp >= ep)
742b0453382SBill Fenner 			break;
743b0453382SBill Fenner 		ip = (struct ip *)bp;
744943ee2b1SBill Fenner 		switch (IP_V(ip)) {
745b0453382SBill Fenner 		case 4:	/* IPv4 */
746b0453382SBill Fenner 			printf(" ");
747c1ad1296SSam Leffler 			ip_print(gndo, bp, len);
748b0453382SBill Fenner 			break;
749b0453382SBill Fenner #ifdef INET6
750b0453382SBill Fenner 		case 6:	/* IPv6 */
751b0453382SBill Fenner 			printf(" ");
752b0453382SBill Fenner 			ip6_print(bp, len);
753b0453382SBill Fenner 			break;
754b0453382SBill Fenner #endif
755b0453382SBill Fenner 		default:
756943ee2b1SBill Fenner 			(void)printf(" IP ver %d", IP_V(ip));
757b0453382SBill Fenner 			break;
758b0453382SBill Fenner 		}
759b0453382SBill Fenner 		break;
760b0453382SBill Fenner 	}
761b0453382SBill Fenner 
762c1ad1296SSam Leffler 	case PIMV2_TYPE_REGISTER_STOP:
763b0453382SBill Fenner 		bp += 4; len -= 4;
764b0453382SBill Fenner 		if (bp >= ep)
765b0453382SBill Fenner 			break;
766b0453382SBill Fenner 		(void)printf(" group=");
767b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
768b0453382SBill Fenner 			(void)printf("...");
769b0453382SBill Fenner 			break;
770b0453382SBill Fenner 		}
771b0453382SBill Fenner 		bp += advance; len -= advance;
772b0453382SBill Fenner 		if (bp >= ep)
773b0453382SBill Fenner 			break;
774b0453382SBill Fenner 		(void)printf(" source=");
775b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
776b0453382SBill Fenner 			(void)printf("...");
777b0453382SBill Fenner 			break;
778b0453382SBill Fenner 		}
779b0453382SBill Fenner 		bp += advance; len -= advance;
780b0453382SBill Fenner 		break;
781b0453382SBill Fenner 
782c1ad1296SSam Leffler 	case PIMV2_TYPE_JOIN_PRUNE:
783c1ad1296SSam Leffler 	case PIMV2_TYPE_GRAFT:
784c1ad1296SSam Leffler 	case PIMV2_TYPE_GRAFT_ACK:
785c1ad1296SSam Leffler 
786c1ad1296SSam Leffler 
787c1ad1296SSam Leffler         /*
788c1ad1296SSam Leffler          * 0                   1                   2                   3
789c1ad1296SSam Leffler          *   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
790c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
791c1ad1296SSam Leffler          *  |PIM Ver| Type  | Addr length   |           Checksum            |
792c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
793c1ad1296SSam Leffler          *  |             Unicast-Upstream Neighbor Address                 |
794c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
795c1ad1296SSam Leffler          *  |  Reserved     | Num groups    |          Holdtime             |
796c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
797c1ad1296SSam Leffler          *  |            Encoded-Multicast Group Address-1                  |
798c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
799c1ad1296SSam Leffler          *  |   Number of Joined  Sources   |   Number of Pruned Sources    |
800c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
801c1ad1296SSam Leffler          *  |               Encoded-Joined Source Address-1                 |
802c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
803c1ad1296SSam Leffler          *  |                             .                                 |
804c1ad1296SSam Leffler          *  |                             .                                 |
805c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
806c1ad1296SSam Leffler          *  |               Encoded-Joined Source Address-n                 |
807c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
808c1ad1296SSam Leffler          *  |               Encoded-Pruned Source Address-1                 |
809c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
810c1ad1296SSam Leffler          *  |                             .                                 |
811c1ad1296SSam Leffler          *  |                             .                                 |
812c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
813c1ad1296SSam Leffler          *  |               Encoded-Pruned Source Address-n                 |
814c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
815c1ad1296SSam Leffler          *  |                           .                                   |
816c1ad1296SSam Leffler          *  |                           .                                   |
817c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
818c1ad1296SSam Leffler          *  |                Encoded-Multicast Group Address-n              |
819c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
820c1ad1296SSam Leffler          */
821c1ad1296SSam Leffler 
822b0453382SBill Fenner 	    {
823b0453382SBill Fenner 		u_int8_t ngroup;
824b0453382SBill Fenner 		u_int16_t holdtime;
825b0453382SBill Fenner 		u_int16_t njoin;
826b0453382SBill Fenner 		u_int16_t nprune;
827b0453382SBill Fenner 		int i, j;
828b0453382SBill Fenner 
829b0453382SBill Fenner 		bp += 4; len -= 4;
830b0453382SBill Fenner 		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
831b0453382SBill Fenner 			if (bp >= ep)
832b0453382SBill Fenner 				break;
833c1ad1296SSam Leffler 			(void)printf(", upstream-neighbor: ");
834b0453382SBill Fenner 			if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
835b0453382SBill Fenner 				(void)printf("...");
836b0453382SBill Fenner 				break;
837b0453382SBill Fenner 			}
838b0453382SBill Fenner 			bp += advance; len -= advance;
839b0453382SBill Fenner 		}
840b0453382SBill Fenner 		if (bp + 4 > ep)
841b0453382SBill Fenner 			break;
842b0453382SBill Fenner 		ngroup = bp[1];
843b0453382SBill Fenner 		holdtime = EXTRACT_16BITS(&bp[2]);
844c1ad1296SSam Leffler 		(void)printf("\n\t  %u group(s)", ngroup);
845b0453382SBill Fenner 		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
846c1ad1296SSam Leffler 			(void)printf(", holdtime: ");
847b0453382SBill Fenner 			if (holdtime == 0xffff)
848c1ad1296SSam Leffler 				(void)printf("infinite");
849b0453382SBill Fenner 			else
850b0453382SBill Fenner 				relts_print(holdtime);
851b0453382SBill Fenner 		}
852b0453382SBill Fenner 		bp += 4; len -= 4;
853b0453382SBill Fenner 		for (i = 0; i < ngroup; i++) {
854b0453382SBill Fenner 			if (bp >= ep)
855b0453382SBill Fenner 				goto jp_done;
856c1ad1296SSam Leffler 			(void)printf("\n\t    group #%u: ", i+1);
857b0453382SBill Fenner 			if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
858b0453382SBill Fenner 				(void)printf("...)");
859b0453382SBill Fenner 				goto jp_done;
860b0453382SBill Fenner 			}
861b0453382SBill Fenner 			bp += advance; len -= advance;
862b0453382SBill Fenner 			if (bp + 4 > ep) {
863b0453382SBill Fenner 				(void)printf("...)");
864b0453382SBill Fenner 				goto jp_done;
865b0453382SBill Fenner 			}
866b0453382SBill Fenner 			njoin = EXTRACT_16BITS(&bp[0]);
867b0453382SBill Fenner 			nprune = EXTRACT_16BITS(&bp[2]);
868c1ad1296SSam Leffler 			(void)printf(", joined sources: %u, pruned sources: %u", njoin,nprune);
869b0453382SBill Fenner 			bp += 4; len -= 4;
870b0453382SBill Fenner 			for (j = 0; j < njoin; j++) {
871c1ad1296SSam Leffler 				(void)printf("\n\t      joined source #%u: ",j+1);
872b0453382SBill Fenner 				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
873b0453382SBill Fenner 					(void)printf("...)");
874b0453382SBill Fenner 					goto jp_done;
875b0453382SBill Fenner 				}
876b0453382SBill Fenner 				bp += advance; len -= advance;
877b0453382SBill Fenner 			}
878b0453382SBill Fenner 			for (j = 0; j < nprune; j++) {
879c1ad1296SSam Leffler 				(void)printf("\n\t      pruned source #%u: ",j+1);
880b0453382SBill Fenner 				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
881b0453382SBill Fenner 					(void)printf("...)");
882b0453382SBill Fenner 					goto jp_done;
883b0453382SBill Fenner 				}
884b0453382SBill Fenner 				bp += advance; len -= advance;
885b0453382SBill Fenner 			}
886b0453382SBill Fenner 		}
887b0453382SBill Fenner 	jp_done:
888b0453382SBill Fenner 		break;
889b0453382SBill Fenner 	    }
890b0453382SBill Fenner 
891c1ad1296SSam Leffler 	case PIMV2_TYPE_BOOTSTRAP:
892b0453382SBill Fenner 	{
893b0453382SBill Fenner 		int i, j, frpcnt;
894b0453382SBill Fenner 		bp += 4;
895b0453382SBill Fenner 
896b0453382SBill Fenner 		/* Fragment Tag, Hash Mask len, and BSR-priority */
897b0453382SBill Fenner 		if (bp + sizeof(u_int16_t) >= ep) break;
898b0453382SBill Fenner 		(void)printf(" tag=%x", EXTRACT_16BITS(bp));
899b0453382SBill Fenner 		bp += sizeof(u_int16_t);
900b0453382SBill Fenner 		if (bp >= ep) break;
901b0453382SBill Fenner 		(void)printf(" hashmlen=%d", bp[0]);
902b0453382SBill Fenner 		if (bp + 1 >= ep) break;
903b0453382SBill Fenner 		(void)printf(" BSRprio=%d", bp[1]);
904b0453382SBill Fenner 		bp += 2;
905b0453382SBill Fenner 
906b0453382SBill Fenner 		/* Encoded-Unicast-BSR-Address */
907b0453382SBill Fenner 		if (bp >= ep) break;
908b0453382SBill Fenner 		(void)printf(" BSR=");
909b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
910b0453382SBill Fenner 			(void)printf("...");
911b0453382SBill Fenner 			break;
912b0453382SBill Fenner 		}
913b0453382SBill Fenner 		bp += advance;
914b0453382SBill Fenner 
915b0453382SBill Fenner 		for (i = 0; bp < ep; i++) {
916b0453382SBill Fenner 			/* Encoded-Group Address */
917b0453382SBill Fenner 			(void)printf(" (group%d: ", i);
918b0453382SBill Fenner 			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
919b0453382SBill Fenner 			    < 0) {
920b0453382SBill Fenner 				(void)printf("...)");
921b0453382SBill Fenner 				goto bs_done;
922b0453382SBill Fenner 			}
923b0453382SBill Fenner 			bp += advance;
924b0453382SBill Fenner 
925b0453382SBill Fenner 			/* RP-Count, Frag RP-Cnt, and rsvd */
926b0453382SBill Fenner 			if (bp >= ep) {
927b0453382SBill Fenner 				(void)printf("...)");
928b0453382SBill Fenner 				goto bs_done;
929b0453382SBill Fenner 			}
930943ee2b1SBill Fenner 			(void)printf(" RPcnt=%d", bp[0]);
931b0453382SBill Fenner 			if (bp + 1 >= ep) {
932b0453382SBill Fenner 				(void)printf("...)");
933b0453382SBill Fenner 				goto bs_done;
934b0453382SBill Fenner 			}
935943ee2b1SBill Fenner 			(void)printf(" FRPcnt=%d", frpcnt = bp[1]);
936b0453382SBill Fenner 			bp += 4;
937b0453382SBill Fenner 
938b0453382SBill Fenner 			for (j = 0; j < frpcnt && bp < ep; j++) {
939b0453382SBill Fenner 				/* each RP info */
940b0453382SBill Fenner 				(void)printf(" RP%d=", j);
941b0453382SBill Fenner 				if ((advance = pimv2_addr_print(bp,
942b0453382SBill Fenner 								pimv2_unicast,
943b0453382SBill Fenner 								0)) < 0) {
944b0453382SBill Fenner 					(void)printf("...)");
945b0453382SBill Fenner 					goto bs_done;
946b0453382SBill Fenner 				}
947b0453382SBill Fenner 				bp += advance;
948b0453382SBill Fenner 
949b0453382SBill Fenner 				if (bp + 1 >= ep) {
950b0453382SBill Fenner 					(void)printf("...)");
951b0453382SBill Fenner 					goto bs_done;
952b0453382SBill Fenner 				}
953b0453382SBill Fenner 				(void)printf(",holdtime=");
954b0453382SBill Fenner 				relts_print(EXTRACT_16BITS(bp));
955b0453382SBill Fenner 				if (bp + 2 >= ep) {
956b0453382SBill Fenner 					(void)printf("...)");
957b0453382SBill Fenner 					goto bs_done;
958b0453382SBill Fenner 				}
959b0453382SBill Fenner 				(void)printf(",prio=%d", bp[2]);
960b0453382SBill Fenner 				bp += 4;
961b0453382SBill Fenner 			}
962b0453382SBill Fenner 			(void)printf(")");
963b0453382SBill Fenner 		}
964b0453382SBill Fenner 	   bs_done:
965b0453382SBill Fenner 		break;
966b0453382SBill Fenner 	}
967c1ad1296SSam Leffler 	case PIMV2_TYPE_ASSERT:
968b0453382SBill Fenner 		bp += 4; len -= 4;
969b0453382SBill Fenner 		if (bp >= ep)
970b0453382SBill Fenner 			break;
971b0453382SBill Fenner 		(void)printf(" group=");
972b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
973b0453382SBill Fenner 			(void)printf("...");
974b0453382SBill Fenner 			break;
975b0453382SBill Fenner 		}
976b0453382SBill Fenner 		bp += advance; len -= advance;
977b0453382SBill Fenner 		if (bp >= ep)
978b0453382SBill Fenner 			break;
979b0453382SBill Fenner 		(void)printf(" src=");
980b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
981b0453382SBill Fenner 			(void)printf("...");
982b0453382SBill Fenner 			break;
983b0453382SBill Fenner 		}
984b0453382SBill Fenner 		bp += advance; len -= advance;
985b0453382SBill Fenner 		if (bp + 8 > ep)
986b0453382SBill Fenner 			break;
987b0453382SBill Fenner 		if (bp[0] & 0x80)
988b0453382SBill Fenner 			(void)printf(" RPT");
989b0453382SBill Fenner 		(void)printf(" pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff);
990b0453382SBill Fenner 		(void)printf(" metric=%u", EXTRACT_32BITS(&bp[4]));
991b0453382SBill Fenner 		break;
992b0453382SBill Fenner 
993c1ad1296SSam Leffler 	case PIMV2_TYPE_CANDIDATE_RP:
994b0453382SBill Fenner 	{
995b0453382SBill Fenner 		int i, pfxcnt;
996b0453382SBill Fenner 		bp += 4;
997b0453382SBill Fenner 
998b0453382SBill Fenner 		/* Prefix-Cnt, Priority, and Holdtime */
999b0453382SBill Fenner 		if (bp >= ep) break;
1000b0453382SBill Fenner 		(void)printf(" prefix-cnt=%d", bp[0]);
1001b0453382SBill Fenner 		pfxcnt = bp[0];
1002b0453382SBill Fenner 		if (bp + 1 >= ep) break;
1003b0453382SBill Fenner 		(void)printf(" prio=%d", bp[1]);
1004b0453382SBill Fenner 		if (bp + 3 >= ep) break;
1005b0453382SBill Fenner 		(void)printf(" holdtime=");
1006b0453382SBill Fenner 		relts_print(EXTRACT_16BITS(&bp[2]));
1007b0453382SBill Fenner 		bp += 4;
1008b0453382SBill Fenner 
1009b0453382SBill Fenner 		/* Encoded-Unicast-RP-Address */
1010b0453382SBill Fenner 		if (bp >= ep) break;
1011b0453382SBill Fenner 		(void)printf(" RP=");
1012b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
1013b0453382SBill Fenner 			(void)printf("...");
1014b0453382SBill Fenner 			break;
1015b0453382SBill Fenner 		}
1016b0453382SBill Fenner 		bp += advance;
1017b0453382SBill Fenner 
1018b0453382SBill Fenner 		/* Encoded-Group Addresses */
1019b0453382SBill Fenner 		for (i = 0; i < pfxcnt && bp < ep; i++) {
1020b0453382SBill Fenner 			(void)printf(" Group%d=", i);
1021b0453382SBill Fenner 			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
1022b0453382SBill Fenner 			    < 0) {
1023b0453382SBill Fenner 				(void)printf("...");
1024b0453382SBill Fenner 				break;
1025b0453382SBill Fenner 			}
1026b0453382SBill Fenner 			bp += advance;
1027b0453382SBill Fenner 		}
1028b0453382SBill Fenner 		break;
1029b0453382SBill Fenner 	}
1030b0453382SBill Fenner 
1031c1ad1296SSam Leffler 	case PIMV2_TYPE_PRUNE_REFRESH:
1032b0453382SBill Fenner 		(void)printf(" src=");
1033b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
1034b0453382SBill Fenner 			(void)printf("...");
1035b0453382SBill Fenner 			break;
1036b0453382SBill Fenner 		}
1037b0453382SBill Fenner 		bp += advance;
1038b0453382SBill Fenner 		(void)printf(" grp=");
1039b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
1040b0453382SBill Fenner 			(void)printf("...");
1041b0453382SBill Fenner 			break;
1042b0453382SBill Fenner 		}
1043b0453382SBill Fenner 		bp += advance;
1044b0453382SBill Fenner 		(void)printf(" forwarder=");
1045b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
1046b0453382SBill Fenner 			(void)printf("...");
1047b0453382SBill Fenner 			break;
1048b0453382SBill Fenner 		}
1049b0453382SBill Fenner 		bp += advance;
1050b0453382SBill Fenner 		TCHECK2(bp[0], 2);
1051b0453382SBill Fenner 		(void)printf(" TUNR ");
1052b0453382SBill Fenner 		relts_print(EXTRACT_16BITS(bp));
1053b0453382SBill Fenner 		break;
1054b0453382SBill Fenner 
1055b0453382SBill Fenner 
1056b0453382SBill Fenner 	 default:
1057b0453382SBill Fenner 		(void)printf(" [type %d]", PIM_TYPE(pim->pim_typever));
1058b0453382SBill Fenner 		break;
1059b0453382SBill Fenner 	}
1060b0453382SBill Fenner 
1061b0453382SBill Fenner 	return;
1062b0453382SBill Fenner 
1063b0453382SBill Fenner trunc:
1064b0453382SBill Fenner 	(void)printf("[|pim]");
10654edb46e9SPaul Traina }
1066c1ad1296SSam Leffler 
1067c1ad1296SSam Leffler /*
1068c1ad1296SSam Leffler  * Local Variables:
1069c1ad1296SSam Leffler  * c-style: whitesmith
1070c1ad1296SSam Leffler  * c-basic-offset: 8
1071c1ad1296SSam Leffler  * End:
1072c1ad1296SSam Leffler  */
1073