xref: /freebsd/contrib/tcpdump/print-pim.c (revision c1ad1296ec82096c8c861fcc68d08493af59a029)
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_ =
26c1ad1296SSam Leffler     "@(#) $Header: /tcpdump/master/tcpdump/print-pim.c,v 1.45 2005/04/06 21:32:42 mcr 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--) {
166b0453382SBill Fenner 		TCHECK2(bp[0], 4);
167b0453382SBill Fenner 		(void)printf("\n\tGroup: %s", ipaddr_string(bp));
168cc391cceSBruce M Simpson 		TCHECK2(bp[4], 4);
169b0453382SBill Fenner 		if (EXTRACT_32BITS(&bp[4]) != 0xffffffff)
170b0453382SBill Fenner 			(void)printf("/%s", ipaddr_string(&bp[4]));
171b0453382SBill Fenner 		TCHECK2(bp[8], 4);
172b0453382SBill Fenner 		njoin = EXTRACT_16BITS(&bp[8]);
173b0453382SBill Fenner 		nprune = EXTRACT_16BITS(&bp[10]);
174b0453382SBill Fenner 		(void)printf(" joined: %d pruned: %d", njoin, nprune);
175a1c2090eSBill Fenner 		bp += 12;
176a1c2090eSBill Fenner 		len -= 12;
177b0453382SBill Fenner 		for (njp = 0; njp < (njoin + nprune); njp++) {
178cc391cceSBruce M Simpson 			const char *type;
179b0453382SBill Fenner 
180a1c2090eSBill Fenner 			if (njp < njoin)
181b0453382SBill Fenner 				type = "Join ";
182a1c2090eSBill Fenner 			else
183b0453382SBill Fenner 				type = "Prune";
184b0453382SBill Fenner 			TCHECK2(bp[0], 6);
185b0453382SBill Fenner 			(void)printf("\n\t%s %s%s%s%s/%d", type,
186b0453382SBill Fenner 			    (bp[0] & 0x01) ? "Sparse " : "Dense ",
187b0453382SBill Fenner 			    (bp[1] & 0x80) ? "WC " : "",
188b0453382SBill Fenner 			    (bp[1] & 0x40) ? "RP " : "SPT ",
189b0453382SBill Fenner 			ipaddr_string(&bp[2]), bp[1] & 0x3f);
190a1c2090eSBill Fenner 			bp += 6;
191a1c2090eSBill Fenner 			len -= 6;
192b0453382SBill Fenner 		}
193b0453382SBill Fenner 	}
194b0453382SBill Fenner 	return;
195b0453382SBill Fenner trunc:
196b0453382SBill Fenner 	(void)printf("[|pim]");
197b0453382SBill Fenner 	return;
198b0453382SBill Fenner }
1994edb46e9SPaul Traina 
2004edb46e9SPaul Traina void
201b0453382SBill Fenner pimv1_print(register const u_char *bp, register u_int len)
2024edb46e9SPaul Traina {
2034edb46e9SPaul Traina 	register const u_char *ep;
2044edb46e9SPaul Traina 	register u_char type;
2054edb46e9SPaul Traina 
2064edb46e9SPaul Traina 	ep = (const u_char *)snapend;
2074edb46e9SPaul Traina 	if (bp >= ep)
2084edb46e9SPaul Traina 		return;
2094edb46e9SPaul Traina 
210cc391cceSBruce M Simpson 	TCHECK(bp[1]);
2114edb46e9SPaul Traina 	type = bp[1];
2124edb46e9SPaul Traina 
2134edb46e9SPaul Traina 	switch (type) {
2144edb46e9SPaul Traina 	case 0:
2154edb46e9SPaul Traina 		(void)printf(" Query");
216b0453382SBill Fenner 		if (TTEST(bp[8])) {
217b0453382SBill Fenner 			switch (bp[8] >> 4) {
218a1c2090eSBill Fenner 			case 0:
219a1c2090eSBill Fenner 				(void)printf(" Dense-mode");
220b0453382SBill Fenner 				break;
221a1c2090eSBill Fenner 			case 1:
222a1c2090eSBill Fenner 				(void)printf(" Sparse-mode");
223b0453382SBill Fenner 				break;
224a1c2090eSBill Fenner 			case 2:
225a1c2090eSBill Fenner 				(void)printf(" Sparse-Dense-mode");
226b0453382SBill Fenner 				break;
227a1c2090eSBill Fenner 			default:
228a1c2090eSBill Fenner 				(void)printf(" mode-%d", bp[8] >> 4);
229b0453382SBill Fenner 				break;
230b0453382SBill Fenner 			}
231b0453382SBill Fenner 		}
232b0453382SBill Fenner 		if (vflag) {
233b0453382SBill Fenner 			TCHECK2(bp[10],2);
234b0453382SBill Fenner 			(void)printf(" (Hold-time ");
235b0453382SBill Fenner 			relts_print(EXTRACT_16BITS(&bp[10]));
236b0453382SBill Fenner 			(void)printf(")");
237b0453382SBill Fenner 		}
2384edb46e9SPaul Traina 		break;
2394edb46e9SPaul Traina 
2404edb46e9SPaul Traina 	case 1:
2414edb46e9SPaul Traina 		(void)printf(" Register");
242b0453382SBill Fenner 		TCHECK2(bp[8], 20);			/* ip header */
243b0453382SBill Fenner 		(void)printf(" for %s > %s", ipaddr_string(&bp[20]),
244b0453382SBill Fenner 		    ipaddr_string(&bp[24]));
2454edb46e9SPaul Traina 		break;
2464edb46e9SPaul Traina 	case 2:
2474edb46e9SPaul Traina 		(void)printf(" Register-Stop");
248b0453382SBill Fenner 		TCHECK2(bp[12], 4);
249b0453382SBill Fenner 		(void)printf(" for %s > %s", ipaddr_string(&bp[8]),
250b0453382SBill Fenner 		    ipaddr_string(&bp[12]));
2514edb46e9SPaul Traina 		break;
2524edb46e9SPaul Traina 	case 3:
2534edb46e9SPaul Traina 		(void)printf(" Join/Prune");
254a1c2090eSBill Fenner 		if (vflag)
255b0453382SBill Fenner 			pimv1_join_prune_print(&bp[8], len - 8);
2564edb46e9SPaul Traina 		break;
2574edb46e9SPaul Traina 	case 4:
2584edb46e9SPaul Traina 		(void)printf(" RP-reachable");
259b0453382SBill Fenner 		if (vflag) {
260b0453382SBill Fenner 			TCHECK2(bp[22], 2);
261b0453382SBill Fenner 			(void)printf(" group %s",
262b0453382SBill Fenner 			ipaddr_string(&bp[8]));
263b0453382SBill Fenner 			if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
264b0453382SBill Fenner 				(void)printf("/%s", ipaddr_string(&bp[12]));
265a1c2090eSBill Fenner 			(void)printf(" RP %s hold ", ipaddr_string(&bp[16]));
266b0453382SBill Fenner 			relts_print(EXTRACT_16BITS(&bp[22]));
267b0453382SBill Fenner 		}
2684edb46e9SPaul Traina 		break;
2694edb46e9SPaul Traina 	case 5:
2704edb46e9SPaul Traina 		(void)printf(" Assert");
271b0453382SBill Fenner 		TCHECK2(bp[16], 4);
272b0453382SBill Fenner 		(void)printf(" for %s > %s", ipaddr_string(&bp[16]),
273b0453382SBill Fenner 		    ipaddr_string(&bp[8]));
274b0453382SBill Fenner 		if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
275b0453382SBill Fenner 			(void)printf("/%s", ipaddr_string(&bp[12]));
276b0453382SBill Fenner 		TCHECK2(bp[24], 4);
277b0453382SBill Fenner 		(void)printf(" %s pref %d metric %d",
278b0453382SBill Fenner 		    (bp[20] & 0x80) ? "RP-tree" : "SPT",
279b0453382SBill Fenner 		EXTRACT_32BITS(&bp[20]) & 0x7fffffff,
280b0453382SBill Fenner 		EXTRACT_32BITS(&bp[24]));
2814edb46e9SPaul Traina 		break;
2824edb46e9SPaul Traina 	case 6:
2834edb46e9SPaul Traina 		(void)printf(" Graft");
284a1c2090eSBill Fenner 		if (vflag)
285b0453382SBill Fenner 			pimv1_join_prune_print(&bp[8], len - 8);
2864edb46e9SPaul Traina 		break;
2874edb46e9SPaul Traina 	case 7:
2884edb46e9SPaul Traina 		(void)printf(" Graft-ACK");
289a1c2090eSBill Fenner 		if (vflag)
290b0453382SBill Fenner 			pimv1_join_prune_print(&bp[8], len - 8);
2914edb46e9SPaul Traina 		break;
2924edb46e9SPaul Traina 	case 8:
2934edb46e9SPaul Traina 		(void)printf(" Mode");
2944edb46e9SPaul Traina 		break;
2954edb46e9SPaul Traina 	default:
2964edb46e9SPaul Traina 		(void)printf(" [type %d]", type);
2974edb46e9SPaul Traina 		break;
2984edb46e9SPaul Traina 	}
299b0453382SBill Fenner 	if ((bp[4] >> 4) != 1)
300b0453382SBill Fenner 		(void)printf(" [v%d]", bp[4] >> 4);
301b0453382SBill Fenner 	return;
302b0453382SBill Fenner 
303b0453382SBill Fenner trunc:
304b0453382SBill Fenner 	(void)printf("[|pim]");
305b0453382SBill Fenner 	return;
306b0453382SBill Fenner }
307b0453382SBill Fenner 
308b0453382SBill Fenner /*
309b0453382SBill Fenner  * auto-RP is a cisco protocol, documented at
310a1c2090eSBill Fenner  * ftp://ftpeng.cisco.com/ipmulticast/specs/pim-autorp-spec01.txt
311a1c2090eSBill Fenner  *
312a1c2090eSBill Fenner  * This implements version 1+, dated Sept 9, 1998.
313b0453382SBill Fenner  */
314b0453382SBill Fenner void
315b0453382SBill Fenner cisco_autorp_print(register const u_char *bp, register u_int len)
316b0453382SBill Fenner {
317b0453382SBill Fenner 	int type;
318b0453382SBill Fenner 	int numrps;
319b0453382SBill Fenner 	int hold;
320b0453382SBill Fenner 
321b0453382SBill Fenner 	TCHECK(bp[0]);
322b0453382SBill Fenner 	(void)printf(" auto-rp ");
323b0453382SBill Fenner 	type = bp[0];
324b0453382SBill Fenner 	switch (type) {
325b0453382SBill Fenner 	case 0x11:
326b0453382SBill Fenner 		(void)printf("candidate-advert");
327b0453382SBill Fenner 		break;
328b0453382SBill Fenner 	case 0x12:
329b0453382SBill Fenner 		(void)printf("mapping");
330b0453382SBill Fenner 		break;
331b0453382SBill Fenner 	default:
332b0453382SBill Fenner 		(void)printf("type-0x%02x", type);
333b0453382SBill Fenner 		break;
334b0453382SBill Fenner 	}
335b0453382SBill Fenner 
336b0453382SBill Fenner 	TCHECK(bp[1]);
337b0453382SBill Fenner 	numrps = bp[1];
338b0453382SBill Fenner 
339b0453382SBill Fenner 	TCHECK2(bp[2], 2);
340b0453382SBill Fenner 	(void)printf(" Hold ");
341b0453382SBill Fenner 	hold = EXTRACT_16BITS(&bp[2]);
342b0453382SBill Fenner 	if (hold)
343b0453382SBill Fenner 		relts_print(EXTRACT_16BITS(&bp[2]));
344b0453382SBill Fenner 	else
345b0453382SBill Fenner 		printf("FOREVER");
346b0453382SBill Fenner 
347b0453382SBill Fenner 	/* Next 4 bytes are reserved. */
348b0453382SBill Fenner 
349b0453382SBill Fenner 	bp += 8; len -= 8;
350b0453382SBill Fenner 
351b0453382SBill Fenner 	/*XXX skip unless -v? */
352b0453382SBill Fenner 
353b0453382SBill Fenner 	/*
354b0453382SBill Fenner 	 * Rest of packet:
355b0453382SBill Fenner 	 * numrps entries of the form:
356b0453382SBill Fenner 	 * 32 bits: RP
357b0453382SBill Fenner 	 * 6 bits: reserved
358b0453382SBill Fenner 	 * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
359b0453382SBill Fenner 	 * 8 bits: # of entries for this RP
360b0453382SBill Fenner 	 * each entry: 7 bits: reserved, 1 bit: negative,
361b0453382SBill Fenner 	 *	       8 bits: mask 32 bits: source
362b0453382SBill Fenner 	 * lather, rinse, repeat.
363b0453382SBill Fenner 	 */
364b0453382SBill Fenner 	while (numrps--) {
365b0453382SBill Fenner 		int nentries;
366b0453382SBill Fenner 		char s;
367b0453382SBill Fenner 
368b0453382SBill Fenner 		TCHECK2(bp[0], 4);
369b0453382SBill Fenner 		(void)printf(" RP %s", ipaddr_string(bp));
370b0453382SBill Fenner 		TCHECK(bp[4]);
371b0453382SBill Fenner 		switch (bp[4] & 0x3) {
372b0453382SBill Fenner 		case 0: printf(" PIMv?");
373b0453382SBill Fenner 			break;
374b0453382SBill Fenner 		case 1:	printf(" PIMv1");
375b0453382SBill Fenner 			break;
376b0453382SBill Fenner 		case 2:	printf(" PIMv2");
377b0453382SBill Fenner 			break;
378b0453382SBill Fenner 		case 3:	printf(" PIMv1+2");
379b0453382SBill Fenner 			break;
380b0453382SBill Fenner 		}
381a1c2090eSBill Fenner 		if (bp[4] & 0xfc)
382a1c2090eSBill Fenner 			(void)printf(" [rsvd=0x%02x]", bp[4] & 0xfc);
383b0453382SBill Fenner 		TCHECK(bp[5]);
384b0453382SBill Fenner 		nentries = bp[5];
385b0453382SBill Fenner 		bp += 6; len -= 6;
386b0453382SBill Fenner 		s = ' ';
387b0453382SBill Fenner 		for (; nentries; nentries--) {
388b0453382SBill Fenner 			TCHECK2(bp[0], 6);
389b0453382SBill Fenner 			(void)printf("%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
390b0453382SBill Fenner 			    ipaddr_string(&bp[2]), bp[1]);
391a1c2090eSBill Fenner 			if (bp[0] & 0xfe)
392a1c2090eSBill Fenner 				(void)printf("[rsvd=0x%02x]", bp[0] & 0xfe);
393b0453382SBill Fenner 			s = ',';
394b0453382SBill Fenner 			bp += 6; len -= 6;
395b0453382SBill Fenner 		}
396b0453382SBill Fenner 	}
397b0453382SBill Fenner 	return;
398b0453382SBill Fenner 
399b0453382SBill Fenner trunc:
400b0453382SBill Fenner 	(void)printf("[|autorp]");
401b0453382SBill Fenner 	return;
402b0453382SBill Fenner }
403b0453382SBill Fenner 
404b0453382SBill Fenner void
405b0453382SBill Fenner pim_print(register const u_char *bp, register u_int len)
406b0453382SBill Fenner {
407b0453382SBill Fenner 	register const u_char *ep;
408b0453382SBill Fenner 	register struct pim *pim = (struct pim *)bp;
409b0453382SBill Fenner 
410b0453382SBill Fenner 	ep = (const u_char *)snapend;
411b0453382SBill Fenner 	if (bp >= ep)
412b0453382SBill Fenner 		return;
413b0453382SBill Fenner #ifdef notyet			/* currently we see only version and type */
414b0453382SBill Fenner 	TCHECK(pim->pim_rsv);
415b0453382SBill Fenner #endif
416b0453382SBill Fenner 
417b0453382SBill Fenner 	switch (PIM_VER(pim->pim_typever)) {
418c1ad1296SSam Leffler 	case 2:
419c1ad1296SSam Leffler             if (!vflag) {
420c1ad1296SSam Leffler                 printf("PIMv%u, %s, length: %u",
421c1ad1296SSam Leffler                        PIM_VER(pim->pim_typever),
422c1ad1296SSam Leffler                        tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)),
423c1ad1296SSam Leffler                        len);
424c1ad1296SSam Leffler                 return;
425c1ad1296SSam Leffler             } else {
426c1ad1296SSam Leffler                 printf("PIMv%u, length: %u\n\t%s",
427c1ad1296SSam Leffler                        PIM_VER(pim->pim_typever),
428c1ad1296SSam Leffler                        len,
429c1ad1296SSam Leffler                        tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)));
430b0453382SBill Fenner                 pimv2_print(bp, len);
431c1ad1296SSam Leffler             }
432b0453382SBill Fenner             break;
433b0453382SBill Fenner 	default:
434c1ad1296SSam Leffler 		printf("PIMv%u, length: %u",
435c1ad1296SSam Leffler                        PIM_VER(pim->pim_typever),
436c1ad1296SSam Leffler                        len);
437b0453382SBill Fenner 		break;
438b0453382SBill Fenner 	}
439b0453382SBill Fenner 	return;
440b0453382SBill Fenner }
441b0453382SBill Fenner 
442b0453382SBill Fenner /*
443b0453382SBill Fenner  * PIMv2 uses encoded address representations.
444b0453382SBill Fenner  *
445b0453382SBill Fenner  * The last PIM-SM I-D before RFC2117 was published specified the
446b0453382SBill Fenner  * following representation for unicast addresses.  However, RFC2117
447b0453382SBill Fenner  * specified no encoding for unicast addresses with the unicast
448b0453382SBill Fenner  * address length specified in the header.  Therefore, we have to
449b0453382SBill Fenner  * guess which encoding is being used (Cisco's PIMv2 implementation
450b0453382SBill Fenner  * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
451b0453382SBill Fenner  * field into a 'unicast-address-length-in-bytes' field.  We guess
452b0453382SBill Fenner  * that it's the draft encoding if this reserved field is zero.
453b0453382SBill Fenner  *
454b0453382SBill Fenner  * RFC2362 goes back to the encoded format, and calls the addr length
455b0453382SBill Fenner  * field "reserved" again.
456b0453382SBill Fenner  *
457b0453382SBill Fenner  * The first byte is the address family, from:
458b0453382SBill Fenner  *
459b0453382SBill Fenner  *    0    Reserved
460b0453382SBill Fenner  *    1    IP (IP version 4)
461b0453382SBill Fenner  *    2    IP6 (IP version 6)
462b0453382SBill Fenner  *    3    NSAP
463b0453382SBill Fenner  *    4    HDLC (8-bit multidrop)
464b0453382SBill Fenner  *    5    BBN 1822
465b0453382SBill Fenner  *    6    802 (includes all 802 media plus Ethernet "canonical format")
466b0453382SBill Fenner  *    7    E.163
467b0453382SBill Fenner  *    8    E.164 (SMDS, Frame Relay, ATM)
468b0453382SBill Fenner  *    9    F.69 (Telex)
469b0453382SBill Fenner  *   10    X.121 (X.25, Frame Relay)
470b0453382SBill Fenner  *   11    IPX
471b0453382SBill Fenner  *   12    Appletalk
472b0453382SBill Fenner  *   13    Decnet IV
473b0453382SBill Fenner  *   14    Banyan Vines
474b0453382SBill Fenner  *   15    E.164 with NSAP format subaddress
475b0453382SBill Fenner  *
476b0453382SBill Fenner  * In addition, the second byte is an "Encoding".  0 is the default
477b0453382SBill Fenner  * encoding for the address family, and no other encodings are currently
478b0453382SBill Fenner  * specified.
479b0453382SBill Fenner  *
480b0453382SBill Fenner  */
481b0453382SBill Fenner 
482b0453382SBill Fenner static int pimv2_addr_len;
483b0453382SBill Fenner 
484b0453382SBill Fenner enum pimv2_addrtype {
485b0453382SBill Fenner 	pimv2_unicast, pimv2_group, pimv2_source
486b0453382SBill Fenner };
487b0453382SBill Fenner 
488b0453382SBill Fenner /*  0                   1                   2                   3
489b0453382SBill 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
490b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
491b0453382SBill Fenner  * | Addr Family   | Encoding Type |     Unicast Address           |
492b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
493b0453382SBill Fenner  *  0                   1                   2                   3
494b0453382SBill 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
495b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
496b0453382SBill Fenner  * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
497b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
498b0453382SBill Fenner  * |                Group multicast Address                        |
499b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
500b0453382SBill Fenner  *  0                   1                   2                   3
501b0453382SBill 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
502b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
503b0453382SBill Fenner  * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
504b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
505b0453382SBill Fenner  * |                        Source Address                         |
506b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
507b0453382SBill Fenner  */
508b0453382SBill Fenner static int
509b0453382SBill Fenner pimv2_addr_print(const u_char *bp, enum pimv2_addrtype at, int silent)
510b0453382SBill Fenner {
511b0453382SBill Fenner 	int af;
512cc391cceSBruce M Simpson 	const char *afstr;
513b0453382SBill Fenner 	int len, hdrlen;
514b0453382SBill Fenner 
515b0453382SBill Fenner 	TCHECK(bp[0]);
516b0453382SBill Fenner 
517b0453382SBill Fenner 	if (pimv2_addr_len == 0) {
518b0453382SBill Fenner 		TCHECK(bp[1]);
519b0453382SBill Fenner 		switch (bp[0]) {
520b0453382SBill Fenner 		case 1:
521b0453382SBill Fenner 			af = AF_INET;
522b0453382SBill Fenner 			afstr = "IPv4";
523b0453382SBill Fenner 			len = 4;
524b0453382SBill Fenner 			break;
525b0453382SBill Fenner #ifdef INET6
526b0453382SBill Fenner 		case 2:
527b0453382SBill Fenner 			af = AF_INET6;
528b0453382SBill Fenner 			afstr = "IPv6";
529b0453382SBill Fenner 			len = 16;
530b0453382SBill Fenner 			break;
531b0453382SBill Fenner #endif
532b0453382SBill Fenner 		default:
533b0453382SBill Fenner 			return -1;
534b0453382SBill Fenner 		}
535b0453382SBill Fenner 		if (bp[1] != 0)
536b0453382SBill Fenner 			return -1;
537b0453382SBill Fenner 		hdrlen = 2;
538b0453382SBill Fenner 	} else {
539b0453382SBill Fenner 		switch (pimv2_addr_len) {
540b0453382SBill Fenner 		case 4:
541b0453382SBill Fenner 			af = AF_INET;
542b0453382SBill Fenner 			afstr = "IPv4";
543b0453382SBill Fenner 			break;
544b0453382SBill Fenner #ifdef INET6
545b0453382SBill Fenner 		case 16:
546b0453382SBill Fenner 			af = AF_INET6;
547b0453382SBill Fenner 			afstr = "IPv6";
548b0453382SBill Fenner 			break;
549b0453382SBill Fenner #endif
550b0453382SBill Fenner 		default:
551b0453382SBill Fenner 			return -1;
552b0453382SBill Fenner 			break;
553b0453382SBill Fenner 		}
554b0453382SBill Fenner 		len = pimv2_addr_len;
555b0453382SBill Fenner 		hdrlen = 0;
556b0453382SBill Fenner 	}
557b0453382SBill Fenner 
558b0453382SBill Fenner 	bp += hdrlen;
559b0453382SBill Fenner 	switch (at) {
560b0453382SBill Fenner 	case pimv2_unicast:
561b0453382SBill Fenner 		TCHECK2(bp[0], len);
562b0453382SBill Fenner 		if (af == AF_INET) {
563b0453382SBill Fenner 			if (!silent)
564b0453382SBill Fenner 				(void)printf("%s", ipaddr_string(bp));
565b0453382SBill Fenner 		}
566b0453382SBill Fenner #ifdef INET6
567b0453382SBill Fenner 		else if (af == AF_INET6) {
568b0453382SBill Fenner 			if (!silent)
569b0453382SBill Fenner 				(void)printf("%s", ip6addr_string(bp));
570b0453382SBill Fenner 		}
571b0453382SBill Fenner #endif
572b0453382SBill Fenner 		return hdrlen + len;
573b0453382SBill Fenner 	case pimv2_group:
574b0453382SBill Fenner 	case pimv2_source:
575b0453382SBill Fenner 		TCHECK2(bp[0], len + 2);
576b0453382SBill Fenner 		if (af == AF_INET) {
577b0453382SBill Fenner 			if (!silent) {
578b0453382SBill Fenner 				(void)printf("%s", ipaddr_string(bp + 2));
579b0453382SBill Fenner 				if (bp[1] != 32)
580b0453382SBill Fenner 					(void)printf("/%u", bp[1]);
581b0453382SBill Fenner 			}
582b0453382SBill Fenner 		}
583b0453382SBill Fenner #ifdef INET6
584b0453382SBill Fenner 		else if (af == AF_INET6) {
585b0453382SBill Fenner 			if (!silent) {
586b0453382SBill Fenner 				(void)printf("%s", ip6addr_string(bp + 2));
587b0453382SBill Fenner 				if (bp[1] != 128)
588b0453382SBill Fenner 					(void)printf("/%u", bp[1]);
589b0453382SBill Fenner 			}
590b0453382SBill Fenner 		}
591b0453382SBill Fenner #endif
592b0453382SBill Fenner 		if (bp[0] && !silent) {
593b0453382SBill Fenner 			if (at == pimv2_group) {
594b0453382SBill Fenner 				(void)printf("(0x%02x)", bp[0]);
595b0453382SBill Fenner 			} else {
596b0453382SBill Fenner 				(void)printf("(%s%s%s",
597b0453382SBill Fenner 					bp[0] & 0x04 ? "S" : "",
598b0453382SBill Fenner 					bp[0] & 0x02 ? "W" : "",
599b0453382SBill Fenner 					bp[0] & 0x01 ? "R" : "");
600b0453382SBill Fenner 				if (bp[0] & 0xf8) {
601b0453382SBill Fenner 					(void) printf("+0x%02x", bp[0] & 0xf8);
602b0453382SBill Fenner 				}
603b0453382SBill Fenner 				(void)printf(")");
604b0453382SBill Fenner 			}
605b0453382SBill Fenner 		}
606b0453382SBill Fenner 		return hdrlen + 2 + len;
607b0453382SBill Fenner 	default:
608b0453382SBill Fenner 		return -1;
609b0453382SBill Fenner 	}
610b0453382SBill Fenner trunc:
611b0453382SBill Fenner 	return -1;
612b0453382SBill Fenner }
613b0453382SBill Fenner 
614b0453382SBill Fenner static void
615b0453382SBill Fenner pimv2_print(register const u_char *bp, register u_int len)
616b0453382SBill Fenner {
617b0453382SBill Fenner 	register const u_char *ep;
618b0453382SBill Fenner 	register struct pim *pim = (struct pim *)bp;
619b0453382SBill Fenner 	int advance;
620b0453382SBill Fenner 
621b0453382SBill Fenner 	ep = (const u_char *)snapend;
622b0453382SBill Fenner 	if (bp >= ep)
623b0453382SBill Fenner 		return;
6249537d84eSBill Fenner 	if (ep > bp + len)
6259537d84eSBill Fenner 		ep = bp + len;
626b0453382SBill Fenner 	TCHECK(pim->pim_rsv);
627b0453382SBill Fenner 	pimv2_addr_len = pim->pim_rsv;
628b0453382SBill Fenner 	if (pimv2_addr_len != 0)
629c1ad1296SSam Leffler 		(void)printf(", RFC2117-encoding");
630b0453382SBill Fenner 
631b0453382SBill Fenner 	switch (PIM_TYPE(pim->pim_typever)) {
632c1ad1296SSam Leffler 	case PIMV2_TYPE_HELLO:
633b0453382SBill Fenner 	    {
634b0453382SBill Fenner 		u_int16_t otype, olen;
635b0453382SBill Fenner 		bp += 4;
636b0453382SBill Fenner 		while (bp < ep) {
637b0453382SBill Fenner 			TCHECK2(bp[0], 4);
638b0453382SBill Fenner 			otype = EXTRACT_16BITS(&bp[0]);
639b0453382SBill Fenner 			olen = EXTRACT_16BITS(&bp[2]);
640b0453382SBill Fenner 			TCHECK2(bp[0], 4 + olen);
641c1ad1296SSam Leffler 
642c1ad1296SSam Leffler                         printf("\n\t  %s Option (%u), length: %u, Value: ",
643c1ad1296SSam Leffler                                tok2str( pimv2_hello_option_values,"Unknown",otype),
644c1ad1296SSam Leffler                                otype,
645c1ad1296SSam Leffler                                olen);
646c1ad1296SSam Leffler 			bp += 4;
647c1ad1296SSam Leffler 
648b0453382SBill Fenner 			switch (otype) {
649c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_HOLDTIME:
650c1ad1296SSam Leffler                                 relts_print(EXTRACT_16BITS(bp));
651b0453382SBill Fenner                                 break;
652b0453382SBill Fenner 
653c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_LANPRUNEDELAY:
654cc391cceSBruce M Simpson 				if (olen != 4) {
655c1ad1296SSam Leffler 					(void)printf("ERROR: Option Lenght != 4 Bytes (%u)", olen);
656cc391cceSBruce M Simpson 				} else {
657cc391cceSBruce M Simpson 					char t_bit;
658cc391cceSBruce M Simpson 					u_int16_t lan_delay, override_interval;
659c1ad1296SSam Leffler 					lan_delay = EXTRACT_16BITS(bp);
660c1ad1296SSam Leffler 					override_interval = EXTRACT_16BITS(bp+2);
661cc391cceSBruce M Simpson 					t_bit = (lan_delay & 0x8000)? 1 : 0;
662cc391cceSBruce M Simpson 					lan_delay &= ~0x8000;
663c1ad1296SSam Leffler 					(void)printf("\n\t    T-bit=%d, LAN delay %dms, Override interval %dms",
664cc391cceSBruce M Simpson 					t_bit, lan_delay, override_interval);
665cc391cceSBruce M Simpson 				}
666cc391cceSBruce M Simpson 				break;
667cc391cceSBruce M Simpson 
668c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_DR_PRIORITY_OLD:
669c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_DR_PRIORITY:
670c1ad1296SSam Leffler                                 switch (olen) {
671c1ad1296SSam Leffler                                 case 0:
672c1ad1296SSam Leffler                                     printf("Bi-Directional Capability (Old)");
6730e0def19SBill Fenner                                     break;
674c1ad1296SSam Leffler                                 case 4:
675c1ad1296SSam Leffler                                     printf("%u", EXTRACT_32BITS(bp));
676c1ad1296SSam Leffler                                     break;
677c1ad1296SSam Leffler                                 default:
678c1ad1296SSam Leffler                                     printf("ERROR: Option Lenght != 4 Bytes (%u)", olen);
6790e0def19SBill Fenner                                     break;
6800e0def19SBill Fenner                                 }
681c1ad1296SSam Leffler                                 break;
682c1ad1296SSam Leffler 
683c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_GENID:
684c1ad1296SSam Leffler                                 (void)printf("0x%08x", EXTRACT_32BITS(bp));
685c1ad1296SSam Leffler 				break;
686c1ad1296SSam Leffler 
687c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_REFRESH_CAP:
688c1ad1296SSam Leffler                                 (void)printf("v%d", *bp);
689c1ad1296SSam Leffler 				if (*(bp+1) != 0) {
690c1ad1296SSam Leffler                                     (void)printf(", interval ");
691c1ad1296SSam Leffler                                     relts_print(*(bp+1));
692c1ad1296SSam Leffler 				}
693c1ad1296SSam Leffler 				if (EXTRACT_16BITS(bp+2) != 0) {
694c1ad1296SSam Leffler                                     (void)printf(" ?0x%04x?", EXTRACT_16BITS(bp+2));
695a1c2090eSBill Fenner 				}
696b0453382SBill Fenner 				break;
697b0453382SBill Fenner 
698c1ad1296SSam Leffler 			case  PIMV2_HELLO_OPTION_BIDIR_CAP:
699b0453382SBill Fenner 				break;
700b0453382SBill Fenner 
701c1ad1296SSam Leffler                         case PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD:
702c1ad1296SSam Leffler                         case PIMV2_HELLO_OPTION_ADDRESS_LIST:
703cc391cceSBruce M Simpson 				if (vflag > 1) {
704c1ad1296SSam Leffler 					const u_char *ptr = bp;
705c1ad1296SSam Leffler 					while (ptr < (bp+olen)) {
706cc391cceSBruce M Simpson 						int advance;
707cc391cceSBruce M Simpson 
708c1ad1296SSam Leffler 						printf("\n\t    ");
709cc391cceSBruce M Simpson 						advance = pimv2_addr_print(ptr, pimv2_unicast, 0);
710cc391cceSBruce M Simpson 						if (advance < 0) {
711cc391cceSBruce M Simpson 							printf("...");
712cc391cceSBruce M Simpson 							break;
713cc391cceSBruce M Simpson 						}
714cc391cceSBruce M Simpson 						ptr += advance;
715cc391cceSBruce M Simpson 					}
716cc391cceSBruce M Simpson 				}
717cc391cceSBruce M Simpson 				break;
718b0453382SBill Fenner 			default:
719c1ad1296SSam Leffler                                 if (vflag <= 1)
720c1ad1296SSam Leffler                                     print_unknown_data(bp,"\n\t    ",olen);
721c1ad1296SSam Leffler                                 break;
722b0453382SBill Fenner 			}
723c1ad1296SSam Leffler                         /* do we want to see an additionally hexdump ? */
724c1ad1296SSam Leffler                         if (vflag> 1)
725c1ad1296SSam Leffler                             print_unknown_data(bp,"\n\t    ",olen);
726c1ad1296SSam Leffler 			bp += olen;
727b0453382SBill Fenner 		}
728b0453382SBill Fenner 		break;
729b0453382SBill Fenner 	    }
730b0453382SBill Fenner 
731c1ad1296SSam Leffler 	case PIMV2_TYPE_REGISTER:
732b0453382SBill Fenner 	{
733b0453382SBill Fenner 		struct ip *ip;
734b0453382SBill Fenner 
735b0453382SBill Fenner 		if (vflag && bp + 8 <= ep) {
736b0453382SBill Fenner 			(void)printf(" %s%s", bp[4] & 0x80 ? "B" : "",
737b0453382SBill Fenner 				bp[4] & 0x40 ? "N" : "");
738b0453382SBill Fenner 		}
739b0453382SBill Fenner 		bp += 8; len -= 8;
740b0453382SBill Fenner 
741b0453382SBill Fenner 		/* encapsulated multicast packet */
742b0453382SBill Fenner 		if (bp >= ep)
743b0453382SBill Fenner 			break;
744b0453382SBill Fenner 		ip = (struct ip *)bp;
745943ee2b1SBill Fenner 		switch (IP_V(ip)) {
746b0453382SBill Fenner 		case 4:	/* IPv4 */
747b0453382SBill Fenner 			printf(" ");
748c1ad1296SSam Leffler 			ip_print(gndo, bp, len);
749b0453382SBill Fenner 			break;
750b0453382SBill Fenner #ifdef INET6
751b0453382SBill Fenner 		case 6:	/* IPv6 */
752b0453382SBill Fenner 			printf(" ");
753b0453382SBill Fenner 			ip6_print(bp, len);
754b0453382SBill Fenner 			break;
755b0453382SBill Fenner #endif
756b0453382SBill Fenner 		default:
757943ee2b1SBill Fenner 			(void)printf(" IP ver %d", IP_V(ip));
758b0453382SBill Fenner 			break;
759b0453382SBill Fenner 		}
760b0453382SBill Fenner 		break;
761b0453382SBill Fenner 	}
762b0453382SBill Fenner 
763c1ad1296SSam Leffler 	case PIMV2_TYPE_REGISTER_STOP:
764b0453382SBill Fenner 		bp += 4; len -= 4;
765b0453382SBill Fenner 		if (bp >= ep)
766b0453382SBill Fenner 			break;
767b0453382SBill Fenner 		(void)printf(" group=");
768b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
769b0453382SBill Fenner 			(void)printf("...");
770b0453382SBill Fenner 			break;
771b0453382SBill Fenner 		}
772b0453382SBill Fenner 		bp += advance; len -= advance;
773b0453382SBill Fenner 		if (bp >= ep)
774b0453382SBill Fenner 			break;
775b0453382SBill Fenner 		(void)printf(" source=");
776b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
777b0453382SBill Fenner 			(void)printf("...");
778b0453382SBill Fenner 			break;
779b0453382SBill Fenner 		}
780b0453382SBill Fenner 		bp += advance; len -= advance;
781b0453382SBill Fenner 		break;
782b0453382SBill Fenner 
783c1ad1296SSam Leffler 	case PIMV2_TYPE_JOIN_PRUNE:
784c1ad1296SSam Leffler 	case PIMV2_TYPE_GRAFT:
785c1ad1296SSam Leffler 	case PIMV2_TYPE_GRAFT_ACK:
786c1ad1296SSam Leffler 
787c1ad1296SSam Leffler 
788c1ad1296SSam Leffler         /*
789c1ad1296SSam Leffler          * 0                   1                   2                   3
790c1ad1296SSam 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
791c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
792c1ad1296SSam Leffler          *  |PIM Ver| Type  | Addr length   |           Checksum            |
793c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
794c1ad1296SSam Leffler          *  |             Unicast-Upstream Neighbor Address                 |
795c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
796c1ad1296SSam Leffler          *  |  Reserved     | Num groups    |          Holdtime             |
797c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
798c1ad1296SSam Leffler          *  |            Encoded-Multicast Group Address-1                  |
799c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
800c1ad1296SSam Leffler          *  |   Number of Joined  Sources   |   Number of Pruned Sources    |
801c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
802c1ad1296SSam Leffler          *  |               Encoded-Joined Source Address-1                 |
803c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
804c1ad1296SSam Leffler          *  |                             .                                 |
805c1ad1296SSam Leffler          *  |                             .                                 |
806c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
807c1ad1296SSam Leffler          *  |               Encoded-Joined Source Address-n                 |
808c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
809c1ad1296SSam Leffler          *  |               Encoded-Pruned Source Address-1                 |
810c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
811c1ad1296SSam Leffler          *  |                             .                                 |
812c1ad1296SSam Leffler          *  |                             .                                 |
813c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
814c1ad1296SSam Leffler          *  |               Encoded-Pruned Source Address-n                 |
815c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
816c1ad1296SSam Leffler          *  |                           .                                   |
817c1ad1296SSam Leffler          *  |                           .                                   |
818c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
819c1ad1296SSam Leffler          *  |                Encoded-Multicast Group Address-n              |
820c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
821c1ad1296SSam Leffler          */
822c1ad1296SSam Leffler 
823b0453382SBill Fenner 	    {
824b0453382SBill Fenner 		u_int8_t ngroup;
825b0453382SBill Fenner 		u_int16_t holdtime;
826b0453382SBill Fenner 		u_int16_t njoin;
827b0453382SBill Fenner 		u_int16_t nprune;
828b0453382SBill Fenner 		int i, j;
829b0453382SBill Fenner 
830b0453382SBill Fenner 		bp += 4; len -= 4;
831b0453382SBill Fenner 		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
832b0453382SBill Fenner 			if (bp >= ep)
833b0453382SBill Fenner 				break;
834c1ad1296SSam Leffler 			(void)printf(", upstream-neighbor: ");
835b0453382SBill Fenner 			if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
836b0453382SBill Fenner 				(void)printf("...");
837b0453382SBill Fenner 				break;
838b0453382SBill Fenner 			}
839b0453382SBill Fenner 			bp += advance; len -= advance;
840b0453382SBill Fenner 		}
841b0453382SBill Fenner 		if (bp + 4 > ep)
842b0453382SBill Fenner 			break;
843b0453382SBill Fenner 		ngroup = bp[1];
844b0453382SBill Fenner 		holdtime = EXTRACT_16BITS(&bp[2]);
845c1ad1296SSam Leffler 		(void)printf("\n\t  %u group(s)", ngroup);
846b0453382SBill Fenner 		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
847c1ad1296SSam Leffler 			(void)printf(", holdtime: ");
848b0453382SBill Fenner 			if (holdtime == 0xffff)
849c1ad1296SSam Leffler 				(void)printf("infinite");
850b0453382SBill Fenner 			else
851b0453382SBill Fenner 				relts_print(holdtime);
852b0453382SBill Fenner 		}
853b0453382SBill Fenner 		bp += 4; len -= 4;
854b0453382SBill Fenner 		for (i = 0; i < ngroup; i++) {
855b0453382SBill Fenner 			if (bp >= ep)
856b0453382SBill Fenner 				goto jp_done;
857c1ad1296SSam Leffler 			(void)printf("\n\t    group #%u: ", i+1);
858b0453382SBill Fenner 			if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
859b0453382SBill Fenner 				(void)printf("...)");
860b0453382SBill Fenner 				goto jp_done;
861b0453382SBill Fenner 			}
862b0453382SBill Fenner 			bp += advance; len -= advance;
863b0453382SBill Fenner 			if (bp + 4 > ep) {
864b0453382SBill Fenner 				(void)printf("...)");
865b0453382SBill Fenner 				goto jp_done;
866b0453382SBill Fenner 			}
867b0453382SBill Fenner 			njoin = EXTRACT_16BITS(&bp[0]);
868b0453382SBill Fenner 			nprune = EXTRACT_16BITS(&bp[2]);
869c1ad1296SSam Leffler 			(void)printf(", joined sources: %u, pruned sources: %u", njoin,nprune);
870b0453382SBill Fenner 			bp += 4; len -= 4;
871b0453382SBill Fenner 			for (j = 0; j < njoin; j++) {
872c1ad1296SSam Leffler 				(void)printf("\n\t      joined source #%u: ",j+1);
873b0453382SBill Fenner 				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
874b0453382SBill Fenner 					(void)printf("...)");
875b0453382SBill Fenner 					goto jp_done;
876b0453382SBill Fenner 				}
877b0453382SBill Fenner 				bp += advance; len -= advance;
878b0453382SBill Fenner 			}
879b0453382SBill Fenner 			for (j = 0; j < nprune; j++) {
880c1ad1296SSam Leffler 				(void)printf("\n\t      pruned source #%u: ",j+1);
881b0453382SBill Fenner 				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
882b0453382SBill Fenner 					(void)printf("...)");
883b0453382SBill Fenner 					goto jp_done;
884b0453382SBill Fenner 				}
885b0453382SBill Fenner 				bp += advance; len -= advance;
886b0453382SBill Fenner 			}
887b0453382SBill Fenner 		}
888b0453382SBill Fenner 	jp_done:
889b0453382SBill Fenner 		break;
890b0453382SBill Fenner 	    }
891b0453382SBill Fenner 
892c1ad1296SSam Leffler 	case PIMV2_TYPE_BOOTSTRAP:
893b0453382SBill Fenner 	{
894b0453382SBill Fenner 		int i, j, frpcnt;
895b0453382SBill Fenner 		bp += 4;
896b0453382SBill Fenner 
897b0453382SBill Fenner 		/* Fragment Tag, Hash Mask len, and BSR-priority */
898b0453382SBill Fenner 		if (bp + sizeof(u_int16_t) >= ep) break;
899b0453382SBill Fenner 		(void)printf(" tag=%x", EXTRACT_16BITS(bp));
900b0453382SBill Fenner 		bp += sizeof(u_int16_t);
901b0453382SBill Fenner 		if (bp >= ep) break;
902b0453382SBill Fenner 		(void)printf(" hashmlen=%d", bp[0]);
903b0453382SBill Fenner 		if (bp + 1 >= ep) break;
904b0453382SBill Fenner 		(void)printf(" BSRprio=%d", bp[1]);
905b0453382SBill Fenner 		bp += 2;
906b0453382SBill Fenner 
907b0453382SBill Fenner 		/* Encoded-Unicast-BSR-Address */
908b0453382SBill Fenner 		if (bp >= ep) break;
909b0453382SBill Fenner 		(void)printf(" BSR=");
910b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
911b0453382SBill Fenner 			(void)printf("...");
912b0453382SBill Fenner 			break;
913b0453382SBill Fenner 		}
914b0453382SBill Fenner 		bp += advance;
915b0453382SBill Fenner 
916b0453382SBill Fenner 		for (i = 0; bp < ep; i++) {
917b0453382SBill Fenner 			/* Encoded-Group Address */
918b0453382SBill Fenner 			(void)printf(" (group%d: ", i);
919b0453382SBill Fenner 			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
920b0453382SBill Fenner 			    < 0) {
921b0453382SBill Fenner 				(void)printf("...)");
922b0453382SBill Fenner 				goto bs_done;
923b0453382SBill Fenner 			}
924b0453382SBill Fenner 			bp += advance;
925b0453382SBill Fenner 
926b0453382SBill Fenner 			/* RP-Count, Frag RP-Cnt, and rsvd */
927b0453382SBill Fenner 			if (bp >= ep) {
928b0453382SBill Fenner 				(void)printf("...)");
929b0453382SBill Fenner 				goto bs_done;
930b0453382SBill Fenner 			}
931943ee2b1SBill Fenner 			(void)printf(" RPcnt=%d", bp[0]);
932b0453382SBill Fenner 			if (bp + 1 >= ep) {
933b0453382SBill Fenner 				(void)printf("...)");
934b0453382SBill Fenner 				goto bs_done;
935b0453382SBill Fenner 			}
936943ee2b1SBill Fenner 			(void)printf(" FRPcnt=%d", frpcnt = bp[1]);
937b0453382SBill Fenner 			bp += 4;
938b0453382SBill Fenner 
939b0453382SBill Fenner 			for (j = 0; j < frpcnt && bp < ep; j++) {
940b0453382SBill Fenner 				/* each RP info */
941b0453382SBill Fenner 				(void)printf(" RP%d=", j);
942b0453382SBill Fenner 				if ((advance = pimv2_addr_print(bp,
943b0453382SBill Fenner 								pimv2_unicast,
944b0453382SBill Fenner 								0)) < 0) {
945b0453382SBill Fenner 					(void)printf("...)");
946b0453382SBill Fenner 					goto bs_done;
947b0453382SBill Fenner 				}
948b0453382SBill Fenner 				bp += advance;
949b0453382SBill Fenner 
950b0453382SBill Fenner 				if (bp + 1 >= ep) {
951b0453382SBill Fenner 					(void)printf("...)");
952b0453382SBill Fenner 					goto bs_done;
953b0453382SBill Fenner 				}
954b0453382SBill Fenner 				(void)printf(",holdtime=");
955b0453382SBill Fenner 				relts_print(EXTRACT_16BITS(bp));
956b0453382SBill Fenner 				if (bp + 2 >= ep) {
957b0453382SBill Fenner 					(void)printf("...)");
958b0453382SBill Fenner 					goto bs_done;
959b0453382SBill Fenner 				}
960b0453382SBill Fenner 				(void)printf(",prio=%d", bp[2]);
961b0453382SBill Fenner 				bp += 4;
962b0453382SBill Fenner 			}
963b0453382SBill Fenner 			(void)printf(")");
964b0453382SBill Fenner 		}
965b0453382SBill Fenner 	   bs_done:
966b0453382SBill Fenner 		break;
967b0453382SBill Fenner 	}
968c1ad1296SSam Leffler 	case PIMV2_TYPE_ASSERT:
969b0453382SBill Fenner 		bp += 4; len -= 4;
970b0453382SBill Fenner 		if (bp >= ep)
971b0453382SBill Fenner 			break;
972b0453382SBill Fenner 		(void)printf(" group=");
973b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
974b0453382SBill Fenner 			(void)printf("...");
975b0453382SBill Fenner 			break;
976b0453382SBill Fenner 		}
977b0453382SBill Fenner 		bp += advance; len -= advance;
978b0453382SBill Fenner 		if (bp >= ep)
979b0453382SBill Fenner 			break;
980b0453382SBill Fenner 		(void)printf(" src=");
981b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
982b0453382SBill Fenner 			(void)printf("...");
983b0453382SBill Fenner 			break;
984b0453382SBill Fenner 		}
985b0453382SBill Fenner 		bp += advance; len -= advance;
986b0453382SBill Fenner 		if (bp + 8 > ep)
987b0453382SBill Fenner 			break;
988b0453382SBill Fenner 		if (bp[0] & 0x80)
989b0453382SBill Fenner 			(void)printf(" RPT");
990b0453382SBill Fenner 		(void)printf(" pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff);
991b0453382SBill Fenner 		(void)printf(" metric=%u", EXTRACT_32BITS(&bp[4]));
992b0453382SBill Fenner 		break;
993b0453382SBill Fenner 
994c1ad1296SSam Leffler 	case PIMV2_TYPE_CANDIDATE_RP:
995b0453382SBill Fenner 	{
996b0453382SBill Fenner 		int i, pfxcnt;
997b0453382SBill Fenner 		bp += 4;
998b0453382SBill Fenner 
999b0453382SBill Fenner 		/* Prefix-Cnt, Priority, and Holdtime */
1000b0453382SBill Fenner 		if (bp >= ep) break;
1001b0453382SBill Fenner 		(void)printf(" prefix-cnt=%d", bp[0]);
1002b0453382SBill Fenner 		pfxcnt = bp[0];
1003b0453382SBill Fenner 		if (bp + 1 >= ep) break;
1004b0453382SBill Fenner 		(void)printf(" prio=%d", bp[1]);
1005b0453382SBill Fenner 		if (bp + 3 >= ep) break;
1006b0453382SBill Fenner 		(void)printf(" holdtime=");
1007b0453382SBill Fenner 		relts_print(EXTRACT_16BITS(&bp[2]));
1008b0453382SBill Fenner 		bp += 4;
1009b0453382SBill Fenner 
1010b0453382SBill Fenner 		/* Encoded-Unicast-RP-Address */
1011b0453382SBill Fenner 		if (bp >= ep) break;
1012b0453382SBill Fenner 		(void)printf(" RP=");
1013b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
1014b0453382SBill Fenner 			(void)printf("...");
1015b0453382SBill Fenner 			break;
1016b0453382SBill Fenner 		}
1017b0453382SBill Fenner 		bp += advance;
1018b0453382SBill Fenner 
1019b0453382SBill Fenner 		/* Encoded-Group Addresses */
1020b0453382SBill Fenner 		for (i = 0; i < pfxcnt && bp < ep; i++) {
1021b0453382SBill Fenner 			(void)printf(" Group%d=", i);
1022b0453382SBill Fenner 			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
1023b0453382SBill Fenner 			    < 0) {
1024b0453382SBill Fenner 				(void)printf("...");
1025b0453382SBill Fenner 				break;
1026b0453382SBill Fenner 			}
1027b0453382SBill Fenner 			bp += advance;
1028b0453382SBill Fenner 		}
1029b0453382SBill Fenner 		break;
1030b0453382SBill Fenner 	}
1031b0453382SBill Fenner 
1032c1ad1296SSam Leffler 	case PIMV2_TYPE_PRUNE_REFRESH:
1033b0453382SBill Fenner 		(void)printf(" src=");
1034b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
1035b0453382SBill Fenner 			(void)printf("...");
1036b0453382SBill Fenner 			break;
1037b0453382SBill Fenner 		}
1038b0453382SBill Fenner 		bp += advance;
1039b0453382SBill Fenner 		(void)printf(" grp=");
1040b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
1041b0453382SBill Fenner 			(void)printf("...");
1042b0453382SBill Fenner 			break;
1043b0453382SBill Fenner 		}
1044b0453382SBill Fenner 		bp += advance;
1045b0453382SBill Fenner 		(void)printf(" forwarder=");
1046b0453382SBill Fenner 		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
1047b0453382SBill Fenner 			(void)printf("...");
1048b0453382SBill Fenner 			break;
1049b0453382SBill Fenner 		}
1050b0453382SBill Fenner 		bp += advance;
1051b0453382SBill Fenner 		TCHECK2(bp[0], 2);
1052b0453382SBill Fenner 		(void)printf(" TUNR ");
1053b0453382SBill Fenner 		relts_print(EXTRACT_16BITS(bp));
1054b0453382SBill Fenner 		break;
1055b0453382SBill Fenner 
1056b0453382SBill Fenner 
1057b0453382SBill Fenner 	 default:
1058b0453382SBill Fenner 		(void)printf(" [type %d]", PIM_TYPE(pim->pim_typever));
1059b0453382SBill Fenner 		break;
1060b0453382SBill Fenner 	}
1061b0453382SBill Fenner 
1062b0453382SBill Fenner 	return;
1063b0453382SBill Fenner 
1064b0453382SBill Fenner trunc:
1065b0453382SBill Fenner 	(void)printf("[|pim]");
10664edb46e9SPaul Traina }
1067c1ad1296SSam Leffler 
1068c1ad1296SSam Leffler /*
1069c1ad1296SSam Leffler  * Local Variables:
1070c1ad1296SSam Leffler  * c-style: whitesmith
1071c1ad1296SSam Leffler  * c-basic-offset: 8
1072c1ad1296SSam Leffler  * End:
1073c1ad1296SSam Leffler  */
1074