xref: /freebsd/contrib/tcpdump/print-pim.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
14edb46e9SPaul Traina /*
24edb46e9SPaul Traina  * Copyright (c) 1995, 1996
34edb46e9SPaul Traina  *	The Regents of the University of California.  All rights reserved.
44edb46e9SPaul Traina  *
54edb46e9SPaul Traina  * Redistribution and use in source and binary forms, with or without
64edb46e9SPaul Traina  * modification, are permitted provided that: (1) source code distributions
74edb46e9SPaul Traina  * retain the above copyright notice and this paragraph in its entirety, (2)
84edb46e9SPaul Traina  * distributions including binary code include the above copyright notice and
94edb46e9SPaul Traina  * this paragraph in its entirety in the documentation or other materials
104edb46e9SPaul Traina  * provided with the distribution, and (3) all advertising materials mentioning
114edb46e9SPaul Traina  * features or use of this software display the following acknowledgement:
124edb46e9SPaul Traina  * ``This product includes software developed by the University of California,
134edb46e9SPaul Traina  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
144edb46e9SPaul Traina  * the University nor the names of its contributors may be used to endorse
154edb46e9SPaul Traina  * or promote products derived from this software without specific prior
164edb46e9SPaul Traina  * written permission.
174edb46e9SPaul Traina  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
184edb46e9SPaul Traina  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
194edb46e9SPaul Traina  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
204edb46e9SPaul Traina  */
214edb46e9SPaul Traina 
223340d773SGleb Smirnoff /* \summary: Protocol Independent Multicast (PIM) printer */
233340d773SGleb Smirnoff 
24ee67461eSJoseph Mingrone #include <config.h>
254edb46e9SPaul Traina 
26ee67461eSJoseph Mingrone #include "netdissect-stdinc.h"
27cac3dcd5SXin LI 
283340d773SGleb Smirnoff #include "netdissect.h"
29cac3dcd5SXin LI #include "addrtoname.h"
30cac3dcd5SXin LI #include "extract.h"
31cac3dcd5SXin LI 
32cac3dcd5SXin LI #include "ip.h"
333340d773SGleb Smirnoff #include "ip6.h"
343340d773SGleb Smirnoff #include "ipproto.h"
35c1ad1296SSam Leffler 
363c602fabSXin LI #define PIMV1_TYPE_QUERY           0
373c602fabSXin LI #define PIMV1_TYPE_REGISTER        1
383c602fabSXin LI #define PIMV1_TYPE_REGISTER_STOP   2
393c602fabSXin LI #define PIMV1_TYPE_JOIN_PRUNE      3
403c602fabSXin LI #define PIMV1_TYPE_RP_REACHABILITY 4
413c602fabSXin LI #define PIMV1_TYPE_ASSERT          5
423c602fabSXin LI #define PIMV1_TYPE_GRAFT           6
433c602fabSXin LI #define PIMV1_TYPE_GRAFT_ACK       7
443c602fabSXin LI 
453c602fabSXin LI static const struct tok pimv1_type_str[] = {
463c602fabSXin LI 	{ PIMV1_TYPE_QUERY,           "Query"         },
473c602fabSXin LI 	{ PIMV1_TYPE_REGISTER,        "Register"      },
483c602fabSXin LI 	{ PIMV1_TYPE_REGISTER_STOP,   "Register-Stop" },
493c602fabSXin LI 	{ PIMV1_TYPE_JOIN_PRUNE,      "Join/Prune"    },
503c602fabSXin LI 	{ PIMV1_TYPE_RP_REACHABILITY, "RP-reachable"  },
513c602fabSXin LI 	{ PIMV1_TYPE_ASSERT,          "Assert"        },
523c602fabSXin LI 	{ PIMV1_TYPE_GRAFT,           "Graft"         },
533c602fabSXin LI 	{ PIMV1_TYPE_GRAFT_ACK,       "Graft-ACK"     },
543c602fabSXin LI 	{ 0, NULL }
553c602fabSXin LI };
563c602fabSXin LI 
57c1ad1296SSam Leffler #define PIMV2_TYPE_HELLO         0
58c1ad1296SSam Leffler #define PIMV2_TYPE_REGISTER      1
59c1ad1296SSam Leffler #define PIMV2_TYPE_REGISTER_STOP 2
60c1ad1296SSam Leffler #define PIMV2_TYPE_JOIN_PRUNE    3
61c1ad1296SSam Leffler #define PIMV2_TYPE_BOOTSTRAP     4
62c1ad1296SSam Leffler #define PIMV2_TYPE_ASSERT        5
63c1ad1296SSam Leffler #define PIMV2_TYPE_GRAFT         6
64c1ad1296SSam Leffler #define PIMV2_TYPE_GRAFT_ACK     7
65c1ad1296SSam Leffler #define PIMV2_TYPE_CANDIDATE_RP  8
66c1ad1296SSam Leffler #define PIMV2_TYPE_PRUNE_REFRESH 9
673c602fabSXin LI #define PIMV2_TYPE_DF_ELECTION   10
683c602fabSXin LI #define PIMV2_TYPE_ECMP_REDIRECT 11
69c1ad1296SSam Leffler 
703c602fabSXin LI static const struct tok pimv2_type_values[] = {
71c1ad1296SSam Leffler     { PIMV2_TYPE_HELLO,         "Hello" },
72c1ad1296SSam Leffler     { PIMV2_TYPE_REGISTER,      "Register" },
73c1ad1296SSam Leffler     { PIMV2_TYPE_REGISTER_STOP, "Register Stop" },
74c1ad1296SSam Leffler     { PIMV2_TYPE_JOIN_PRUNE,    "Join / Prune" },
75c1ad1296SSam Leffler     { PIMV2_TYPE_BOOTSTRAP,     "Bootstrap" },
76c1ad1296SSam Leffler     { PIMV2_TYPE_ASSERT,        "Assert" },
77c1ad1296SSam Leffler     { PIMV2_TYPE_GRAFT,         "Graft" },
78c1ad1296SSam Leffler     { PIMV2_TYPE_GRAFT_ACK,     "Graft Acknowledgement" },
79c1ad1296SSam Leffler     { PIMV2_TYPE_CANDIDATE_RP,  "Candidate RP Advertisement" },
80c1ad1296SSam Leffler     { PIMV2_TYPE_PRUNE_REFRESH, "Prune Refresh" },
813c602fabSXin LI     { PIMV2_TYPE_DF_ELECTION,   "DF Election" },
823c602fabSXin LI     { PIMV2_TYPE_ECMP_REDIRECT, "ECMP Redirect" },
83c1ad1296SSam Leffler     { 0, NULL}
84c1ad1296SSam Leffler };
85c1ad1296SSam Leffler 
86c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_HOLDTIME             1
87c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_LANPRUNEDELAY        2
88c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_DR_PRIORITY_OLD     18
89c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_DR_PRIORITY         19
90c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_GENID               20
91c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_REFRESH_CAP         21
92c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_BIDIR_CAP           22
93c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_ADDRESS_LIST        24
94c1ad1296SSam Leffler #define PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD 65001
95c1ad1296SSam Leffler 
963c602fabSXin LI static const struct tok pimv2_hello_option_values[] = {
97c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_HOLDTIME,         "Hold Time" },
98c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_LANPRUNEDELAY,    "LAN Prune Delay" },
99c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_DR_PRIORITY_OLD,  "DR Priority (Old)" },
100c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_DR_PRIORITY,      "DR Priority" },
101c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_GENID,            "Generation ID" },
102c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_REFRESH_CAP,      "State Refresh Capability" },
103c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_BIDIR_CAP,        "Bi-Directional Capability" },
104c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_ADDRESS_LIST,     "Address List" },
105c1ad1296SSam Leffler     { PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD, "Address List (Old)" },
106c1ad1296SSam Leffler     { 0, NULL}
107c1ad1296SSam Leffler };
108c1ad1296SSam Leffler 
109abf25193SMax Laier #define PIMV2_REGISTER_FLAG_LEN      4
110abf25193SMax Laier #define PIMV2_REGISTER_FLAG_BORDER 0x80000000
111abf25193SMax Laier #define PIMV2_REGISTER_FLAG_NULL   0x40000000
112abf25193SMax Laier 
1133c602fabSXin LI static const struct tok pimv2_register_flag_values[] = {
114abf25193SMax Laier     { PIMV2_REGISTER_FLAG_BORDER, "Border" },
115abf25193SMax Laier     { PIMV2_REGISTER_FLAG_NULL, "Null" },
116abf25193SMax Laier     { 0, NULL}
117abf25193SMax Laier };
118b0453382SBill Fenner 
119ee67461eSJoseph Mingrone #define PIMV2_DF_ELECTION_OFFER                  1
120ee67461eSJoseph Mingrone #define PIMV2_DF_ELECTION_WINNER                 2
121ee67461eSJoseph Mingrone #define PIMV2_DF_ELECTION_BACKOFF                3
122ee67461eSJoseph Mingrone #define PIMV2_DF_ELECTION_PASS                   4
123ee67461eSJoseph Mingrone 
124ee67461eSJoseph Mingrone static const struct tok pimv2_df_election_flag_values[] = {
125ee67461eSJoseph Mingrone     { PIMV2_DF_ELECTION_OFFER, "Offer" },
126ee67461eSJoseph Mingrone     { PIMV2_DF_ELECTION_WINNER, "Winner" },
127ee67461eSJoseph Mingrone     { PIMV2_DF_ELECTION_BACKOFF, "Backoff" },
128ee67461eSJoseph Mingrone     { PIMV2_DF_ELECTION_PASS, "Pass" },
129ee67461eSJoseph Mingrone     { 0, NULL}
130ee67461eSJoseph Mingrone };
131ee67461eSJoseph Mingrone 
132ee67461eSJoseph Mingrone #define PIMV2_DF_ELECTION_PASS_BACKOFF_STR(x)   ( \
133ee67461eSJoseph Mingrone       x == PIMV2_DF_ELECTION_BACKOFF ? "offer" : "new winner" )
134ee67461eSJoseph Mingrone 
135ee67461eSJoseph Mingrone 
136b0453382SBill Fenner /*
137b0453382SBill Fenner  * XXX: We consider a case where IPv6 is not ready yet for portability,
138ee67461eSJoseph Mingrone  * but PIM dependent definitions should be independent of IPv6...
139b0453382SBill Fenner  */
140b0453382SBill Fenner 
141b0453382SBill Fenner struct pim {
142ee67461eSJoseph Mingrone 	nd_uint8_t	pim_typever;
1439537d84eSBill Fenner 			/* upper 4bit: PIM version number; 2 for PIMv2 */
1449537d84eSBill Fenner 			/* lower 4bit: the PIM message type, currently they are:
145b0453382SBill Fenner 			 * Hello, Register, Register-Stop, Join/Prune,
146b0453382SBill Fenner 			 * Bootstrap, Assert, Graft (PIM-DM only),
147b0453382SBill Fenner 			 * Graft-Ack (PIM-DM only), C-RP-Adv
148b0453382SBill Fenner 			 */
1499537d84eSBill Fenner #define PIM_VER(x)	(((x) & 0xf0) >> 4)
1509537d84eSBill Fenner #define PIM_TYPE(x)	((x) & 0x0f)
151ee67461eSJoseph Mingrone 	nd_uint8_t	pim_rsv;	/* Reserved in v1, subtype+address length in v2 */
152ee67461eSJoseph Mingrone #define PIM_SUBTYPE(x)  (((x) & 0xf0) >> 4)
153ee67461eSJoseph Mingrone 	nd_uint16_t	pim_cksum;	/* IP style check sum */
154b0453382SBill Fenner };
155b0453382SBill Fenner 
156ee67461eSJoseph Mingrone static void pimv2_print(netdissect_options *, const u_char *bp, u_int len, const u_char *);
157b0453382SBill Fenner 
158b0453382SBill Fenner static void
pimv1_join_prune_print(netdissect_options * ndo,const u_char * bp,u_int len)1593c602fabSXin LI pimv1_join_prune_print(netdissect_options *ndo,
160ee67461eSJoseph Mingrone                        const u_char *bp, u_int len)
161b0453382SBill Fenner {
162ee67461eSJoseph Mingrone 	u_int ngroups, njoin, nprune;
163ee67461eSJoseph Mingrone 	u_int njp;
164b0453382SBill Fenner 
165b0453382SBill Fenner 	/* If it's a single group and a single source, use 1-line output. */
166ee67461eSJoseph Mingrone 	if (ND_TTEST_LEN(bp, 30) && GET_U_1(bp + 11) == 1 &&
167ee67461eSJoseph Mingrone 	    ((njoin = GET_BE_U_2(bp + 20)) + GET_BE_U_2(bp + 22)) == 1) {
168ee67461eSJoseph Mingrone 		u_int hold;
169b0453382SBill Fenner 
170ee67461eSJoseph Mingrone 		ND_PRINT(" RPF %s ", GET_IPADDR_STRING(bp));
171ee67461eSJoseph Mingrone 		hold = GET_BE_U_2(bp + 6);
172b0453382SBill Fenner 		if (hold != 180) {
173ee67461eSJoseph Mingrone 			ND_PRINT("Hold ");
1743340d773SGleb Smirnoff 			unsigned_relts_print(ndo, hold);
175b0453382SBill Fenner 		}
176ee67461eSJoseph Mingrone 		ND_PRINT("%s (%s/%u, %s", njoin ? "Join" : "Prune",
177ee67461eSJoseph Mingrone 		GET_IPADDR_STRING(bp + 26), GET_U_1(bp + 25) & 0x3f,
178ee67461eSJoseph Mingrone 		GET_IPADDR_STRING(bp + 12));
179ee67461eSJoseph Mingrone 		if (GET_BE_U_4(bp + 16) != 0xffffffff)
180ee67461eSJoseph Mingrone 			ND_PRINT("/%s", GET_IPADDR_STRING(bp + 16));
181ee67461eSJoseph Mingrone 		ND_PRINT(") %s%s %s",
182ee67461eSJoseph Mingrone 		    (GET_U_1(bp + 24) & 0x01) ? "Sparse" : "Dense",
183ee67461eSJoseph Mingrone 		    (GET_U_1(bp + 25) & 0x80) ? " WC" : "",
184ee67461eSJoseph Mingrone 		    (GET_U_1(bp + 25) & 0x40) ? "RP" : "SPT");
185b0453382SBill Fenner 		return;
186b0453382SBill Fenner 	}
187b0453382SBill Fenner 
188ee67461eSJoseph Mingrone 	if (len < sizeof(nd_ipv4))
1890bff6a5aSEd Maste 		goto trunc;
1903c602fabSXin LI 	if (ndo->ndo_vflag > 1)
191ee67461eSJoseph Mingrone 		ND_PRINT("\n");
192ee67461eSJoseph Mingrone 	ND_PRINT(" Upstream Nbr: %s", GET_IPADDR_STRING(bp));
1930bff6a5aSEd Maste 	bp += 4;
1940bff6a5aSEd Maste 	len -= 4;
1950bff6a5aSEd Maste 	if (len < 4)
1960bff6a5aSEd Maste 		goto trunc;
1973c602fabSXin LI 	if (ndo->ndo_vflag > 1)
198ee67461eSJoseph Mingrone 		ND_PRINT("\n");
199ee67461eSJoseph Mingrone 	ND_PRINT(" Hold time: ");
200ee67461eSJoseph Mingrone 	unsigned_relts_print(ndo, GET_BE_U_2(bp + 2));
2013c602fabSXin LI 	if (ndo->ndo_vflag < 2)
202a1c2090eSBill Fenner 		return;
2030bff6a5aSEd Maste 	bp += 4;
2040bff6a5aSEd Maste 	len -= 4;
205b0453382SBill Fenner 
2060bff6a5aSEd Maste 	if (len < 4)
2070bff6a5aSEd Maste 		goto trunc;
208ee67461eSJoseph Mingrone 	ngroups = GET_U_1(bp + 3);
209a1c2090eSBill Fenner 	bp += 4;
210a1c2090eSBill Fenner 	len -= 4;
211ee67461eSJoseph Mingrone 	while (ngroups != 0) {
21229292c17SSam Leffler 		/*
21329292c17SSam Leffler 		 * XXX - does the address have length "addrlen" and the
21429292c17SSam Leffler 		 * mask length "maddrlen"?
21529292c17SSam Leffler 		 */
2160bff6a5aSEd Maste 		if (len < 4)
2170bff6a5aSEd Maste 			goto trunc;
218ee67461eSJoseph Mingrone 		ND_PRINT("\n\tGroup: %s", GET_IPADDR_STRING(bp));
2190bff6a5aSEd Maste 		bp += 4;
2200bff6a5aSEd Maste 		len -= 4;
2210bff6a5aSEd Maste 		if (len < 4)
2220bff6a5aSEd Maste 			goto trunc;
223ee67461eSJoseph Mingrone 		if (GET_BE_U_4(bp) != 0xffffffff)
224ee67461eSJoseph Mingrone 			ND_PRINT("/%s", GET_IPADDR_STRING(bp));
2250bff6a5aSEd Maste 		bp += 4;
2260bff6a5aSEd Maste 		len -= 4;
2270bff6a5aSEd Maste 		if (len < 4)
2280bff6a5aSEd Maste 			goto trunc;
229ee67461eSJoseph Mingrone 		njoin = GET_BE_U_2(bp);
230ee67461eSJoseph Mingrone 		nprune = GET_BE_U_2(bp + 2);
231ee67461eSJoseph Mingrone 		ND_PRINT(" joined: %u pruned: %u", njoin, nprune);
2320bff6a5aSEd Maste 		bp += 4;
2330bff6a5aSEd Maste 		len -= 4;
234b0453382SBill Fenner 		for (njp = 0; njp < (njoin + nprune); njp++) {
235cc391cceSBruce M Simpson 			const char *type;
236b0453382SBill Fenner 
237a1c2090eSBill Fenner 			if (njp < njoin)
238b0453382SBill Fenner 				type = "Join ";
239a1c2090eSBill Fenner 			else
240b0453382SBill Fenner 				type = "Prune";
2410bff6a5aSEd Maste 			if (len < 6)
2420bff6a5aSEd Maste 				goto trunc;
243ee67461eSJoseph Mingrone 			ND_PRINT("\n\t%s %s%s%s%s/%u", type,
244ee67461eSJoseph Mingrone 			    (GET_U_1(bp) & 0x01) ? "Sparse " : "Dense ",
245ee67461eSJoseph Mingrone 			    (GET_U_1(bp + 1) & 0x80) ? "WC " : "",
246ee67461eSJoseph Mingrone 			    (GET_U_1(bp + 1) & 0x40) ? "RP " : "SPT ",
247ee67461eSJoseph Mingrone 			    GET_IPADDR_STRING(bp + 2),
248ee67461eSJoseph Mingrone 			    GET_U_1(bp + 1) & 0x3f);
249a1c2090eSBill Fenner 			bp += 6;
250a1c2090eSBill Fenner 			len -= 6;
251b0453382SBill Fenner 		}
252ee67461eSJoseph Mingrone 		ngroups--;
253b0453382SBill Fenner 	}
254b0453382SBill Fenner 	return;
255b0453382SBill Fenner trunc:
256ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
257b0453382SBill Fenner }
2584edb46e9SPaul Traina 
2594edb46e9SPaul Traina void
pimv1_print(netdissect_options * ndo,const u_char * bp,u_int len)2603c602fabSXin LI pimv1_print(netdissect_options *ndo,
261ee67461eSJoseph Mingrone             const u_char *bp, u_int len)
2624edb46e9SPaul Traina {
263ee67461eSJoseph Mingrone 	u_char type;
2644edb46e9SPaul Traina 
265ee67461eSJoseph Mingrone 	ndo->ndo_protocol = "pimv1";
266ee67461eSJoseph Mingrone 	type = GET_U_1(bp + 1);
2674edb46e9SPaul Traina 
268ee67461eSJoseph Mingrone 	ND_PRINT(" %s", tok2str(pimv1_type_str, "[type %u]", type));
2694edb46e9SPaul Traina 	switch (type) {
2703c602fabSXin LI 	case PIMV1_TYPE_QUERY:
271ee67461eSJoseph Mingrone 		if (ND_TTEST_1(bp + 8)) {
272ee67461eSJoseph Mingrone 			switch (GET_U_1(bp + 8) >> 4) {
273a1c2090eSBill Fenner 			case 0:
274ee67461eSJoseph Mingrone 				ND_PRINT(" Dense-mode");
275b0453382SBill Fenner 				break;
276a1c2090eSBill Fenner 			case 1:
277ee67461eSJoseph Mingrone 				ND_PRINT(" Sparse-mode");
278b0453382SBill Fenner 				break;
279a1c2090eSBill Fenner 			case 2:
280ee67461eSJoseph Mingrone 				ND_PRINT(" Sparse-Dense-mode");
281b0453382SBill Fenner 				break;
282a1c2090eSBill Fenner 			default:
283ee67461eSJoseph Mingrone 				ND_PRINT(" mode-%u", GET_U_1(bp + 8) >> 4);
284b0453382SBill Fenner 				break;
285b0453382SBill Fenner 			}
286b0453382SBill Fenner 		}
2873c602fabSXin LI 		if (ndo->ndo_vflag) {
288ee67461eSJoseph Mingrone 			ND_PRINT(" (Hold-time ");
289ee67461eSJoseph Mingrone 			unsigned_relts_print(ndo, GET_BE_U_2(bp + 10));
290ee67461eSJoseph Mingrone 			ND_PRINT(")");
291b0453382SBill Fenner 		}
2924edb46e9SPaul Traina 		break;
2934edb46e9SPaul Traina 
2943c602fabSXin LI 	case PIMV1_TYPE_REGISTER:
295ee67461eSJoseph Mingrone 		ND_TCHECK_LEN(bp + 8, 20);			/* ip header */
296ee67461eSJoseph Mingrone 		ND_PRINT(" for %s > %s", GET_IPADDR_STRING(bp + 20),
297ee67461eSJoseph Mingrone 			  GET_IPADDR_STRING(bp + 24));
2984edb46e9SPaul Traina 		break;
2993c602fabSXin LI 	case PIMV1_TYPE_REGISTER_STOP:
300ee67461eSJoseph Mingrone 		ND_PRINT(" for %s > %s", GET_IPADDR_STRING(bp + 8),
301ee67461eSJoseph Mingrone 			  GET_IPADDR_STRING(bp + 12));
3024edb46e9SPaul Traina 		break;
3033c602fabSXin LI 	case PIMV1_TYPE_RP_REACHABILITY:
3043c602fabSXin LI 		if (ndo->ndo_vflag) {
305ee67461eSJoseph Mingrone 			ND_PRINT(" group %s", GET_IPADDR_STRING(bp + 8));
306ee67461eSJoseph Mingrone 			if (GET_BE_U_4(bp + 12) != 0xffffffff)
307ee67461eSJoseph Mingrone 				ND_PRINT("/%s", GET_IPADDR_STRING(bp + 12));
308ee67461eSJoseph Mingrone 			ND_PRINT(" RP %s hold ", GET_IPADDR_STRING(bp + 16));
309ee67461eSJoseph Mingrone 			unsigned_relts_print(ndo, GET_BE_U_2(bp + 22));
310b0453382SBill Fenner 		}
3114edb46e9SPaul Traina 		break;
3123c602fabSXin LI 	case PIMV1_TYPE_ASSERT:
313ee67461eSJoseph Mingrone 		ND_PRINT(" for %s > %s", GET_IPADDR_STRING(bp + 16),
314ee67461eSJoseph Mingrone 			  GET_IPADDR_STRING(bp + 8));
315ee67461eSJoseph Mingrone 		if (GET_BE_U_4(bp + 12) != 0xffffffff)
316ee67461eSJoseph Mingrone 			ND_PRINT("/%s", GET_IPADDR_STRING(bp + 12));
317ee67461eSJoseph Mingrone 		ND_PRINT(" %s pref %u metric %u",
318ee67461eSJoseph Mingrone 		    (GET_U_1(bp + 20) & 0x80) ? "RP-tree" : "SPT",
319ee67461eSJoseph Mingrone 		    GET_BE_U_4(bp + 20) & 0x7fffffff,
320ee67461eSJoseph Mingrone 		    GET_BE_U_4(bp + 24));
3214edb46e9SPaul Traina 		break;
3223c602fabSXin LI 	case PIMV1_TYPE_JOIN_PRUNE:
3233c602fabSXin LI 	case PIMV1_TYPE_GRAFT:
3243c602fabSXin LI 	case PIMV1_TYPE_GRAFT_ACK:
3250bff6a5aSEd Maste 		if (ndo->ndo_vflag) {
3260bff6a5aSEd Maste 			if (len < 8)
3270bff6a5aSEd Maste 				goto trunc;
328ee67461eSJoseph Mingrone 			pimv1_join_prune_print(ndo, bp + 8, len - 8);
3290bff6a5aSEd Maste 		}
3304edb46e9SPaul Traina 		break;
3314edb46e9SPaul Traina 	}
332ee67461eSJoseph Mingrone 	if ((GET_U_1(bp + 4) >> 4) != 1)
333ee67461eSJoseph Mingrone 		ND_PRINT(" [v%u]", GET_U_1(bp + 4) >> 4);
334b0453382SBill Fenner 	return;
335b0453382SBill Fenner 
336b0453382SBill Fenner trunc:
337ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
338b0453382SBill Fenner }
339b0453382SBill Fenner 
340b0453382SBill Fenner /*
341b0453382SBill Fenner  * auto-RP is a cisco protocol, documented at
342a1c2090eSBill Fenner  * ftp://ftpeng.cisco.com/ipmulticast/specs/pim-autorp-spec01.txt
343a1c2090eSBill Fenner  *
344a1c2090eSBill Fenner  * This implements version 1+, dated Sept 9, 1998.
345b0453382SBill Fenner  */
346b0453382SBill Fenner void
cisco_autorp_print(netdissect_options * ndo,const u_char * bp,u_int len)3473c602fabSXin LI cisco_autorp_print(netdissect_options *ndo,
348ee67461eSJoseph Mingrone                    const u_char *bp, u_int len)
349b0453382SBill Fenner {
350ee67461eSJoseph Mingrone 	u_int type;
351ee67461eSJoseph Mingrone 	u_int numrps;
352ee67461eSJoseph Mingrone 	u_int hold;
353b0453382SBill Fenner 
354ee67461eSJoseph Mingrone 	ndo->ndo_protocol = "cisco_autorp";
3550bff6a5aSEd Maste 	if (len < 8)
3560bff6a5aSEd Maste 		goto trunc;
357ee67461eSJoseph Mingrone 	ND_PRINT(" auto-rp ");
358ee67461eSJoseph Mingrone 	type = GET_U_1(bp);
359b0453382SBill Fenner 	switch (type) {
360b0453382SBill Fenner 	case 0x11:
361ee67461eSJoseph Mingrone 		ND_PRINT("candidate-advert");
362b0453382SBill Fenner 		break;
363b0453382SBill Fenner 	case 0x12:
364ee67461eSJoseph Mingrone 		ND_PRINT("mapping");
365b0453382SBill Fenner 		break;
366b0453382SBill Fenner 	default:
367ee67461eSJoseph Mingrone 		ND_PRINT("type-0x%02x", type);
368b0453382SBill Fenner 		break;
369b0453382SBill Fenner 	}
370b0453382SBill Fenner 
371ee67461eSJoseph Mingrone 	numrps = GET_U_1(bp + 1);
372b0453382SBill Fenner 
373ee67461eSJoseph Mingrone 	ND_PRINT(" Hold ");
374ee67461eSJoseph Mingrone 	hold = GET_BE_U_2(bp + 2);
375b0453382SBill Fenner 	if (hold)
376ee67461eSJoseph Mingrone 		unsigned_relts_print(ndo, GET_BE_U_2(bp + 2));
377b0453382SBill Fenner 	else
378ee67461eSJoseph Mingrone 		ND_PRINT("FOREVER");
379b0453382SBill Fenner 
380b0453382SBill Fenner 	/* Next 4 bytes are reserved. */
381b0453382SBill Fenner 
382b0453382SBill Fenner 	bp += 8; len -= 8;
383b0453382SBill Fenner 
384b0453382SBill Fenner 	/*XXX skip unless -v? */
385b0453382SBill Fenner 
386b0453382SBill Fenner 	/*
387b0453382SBill Fenner 	 * Rest of packet:
388b0453382SBill Fenner 	 * numrps entries of the form:
389b0453382SBill Fenner 	 * 32 bits: RP
390b0453382SBill Fenner 	 * 6 bits: reserved
391b0453382SBill Fenner 	 * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
392b0453382SBill Fenner 	 * 8 bits: # of entries for this RP
393b0453382SBill Fenner 	 * each entry: 7 bits: reserved, 1 bit: negative,
394b0453382SBill Fenner 	 *	       8 bits: mask 32 bits: source
395b0453382SBill Fenner 	 * lather, rinse, repeat.
396b0453382SBill Fenner 	 */
397ee67461eSJoseph Mingrone 	while (numrps != 0) {
398ee67461eSJoseph Mingrone 		u_int nentries;
399b0453382SBill Fenner 		char s;
400b0453382SBill Fenner 
4010bff6a5aSEd Maste 		if (len < 4)
4020bff6a5aSEd Maste 			goto trunc;
403ee67461eSJoseph Mingrone 		ND_PRINT(" RP %s", GET_IPADDR_STRING(bp));
4040bff6a5aSEd Maste 		bp += 4;
4050bff6a5aSEd Maste 		len -= 4;
4060bff6a5aSEd Maste 		if (len < 1)
4070bff6a5aSEd Maste 			goto trunc;
408ee67461eSJoseph Mingrone 		switch (GET_U_1(bp) & 0x3) {
409ee67461eSJoseph Mingrone 		case 0: ND_PRINT(" PIMv?");
410b0453382SBill Fenner 			break;
411ee67461eSJoseph Mingrone 		case 1:	ND_PRINT(" PIMv1");
412b0453382SBill Fenner 			break;
413ee67461eSJoseph Mingrone 		case 2:	ND_PRINT(" PIMv2");
414b0453382SBill Fenner 			break;
415ee67461eSJoseph Mingrone 		case 3:	ND_PRINT(" PIMv1+2");
416b0453382SBill Fenner 			break;
417b0453382SBill Fenner 		}
418ee67461eSJoseph Mingrone 		if (GET_U_1(bp) & 0xfc)
419ee67461eSJoseph Mingrone 			ND_PRINT(" [rsvd=0x%02x]", GET_U_1(bp) & 0xfc);
4200bff6a5aSEd Maste 		bp += 1;
4210bff6a5aSEd Maste 		len -= 1;
4220bff6a5aSEd Maste 		if (len < 1)
4230bff6a5aSEd Maste 			goto trunc;
424ee67461eSJoseph Mingrone 		nentries = GET_U_1(bp);
4250bff6a5aSEd Maste 		bp += 1;
4260bff6a5aSEd Maste 		len -= 1;
427b0453382SBill Fenner 		s = ' ';
428ee67461eSJoseph Mingrone 		while (nentries != 0) {
4290bff6a5aSEd Maste 			if (len < 6)
4300bff6a5aSEd Maste 				goto trunc;
431ee67461eSJoseph Mingrone 			ND_PRINT("%c%s%s/%u", s, GET_U_1(bp) & 1 ? "!" : "",
432ee67461eSJoseph Mingrone 			          GET_IPADDR_STRING(bp + 2), GET_U_1(bp + 1));
433ee67461eSJoseph Mingrone 			if (GET_U_1(bp) & 0x02) {
434ee67461eSJoseph Mingrone 				ND_PRINT(" bidir");
435cac3dcd5SXin LI 			}
436ee67461eSJoseph Mingrone 			if (GET_U_1(bp) & 0xfc) {
437ee67461eSJoseph Mingrone 				ND_PRINT("[rsvd=0x%02x]", GET_U_1(bp) & 0xfc);
438cac3dcd5SXin LI 			}
439b0453382SBill Fenner 			s = ',';
440b0453382SBill Fenner 			bp += 6; len -= 6;
441ee67461eSJoseph Mingrone 			nentries--;
442b0453382SBill Fenner 		}
443ee67461eSJoseph Mingrone 		numrps--;
444b0453382SBill Fenner 	}
445b0453382SBill Fenner 	return;
446b0453382SBill Fenner 
447b0453382SBill Fenner trunc:
448ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
449b0453382SBill Fenner }
450b0453382SBill Fenner 
451b0453382SBill Fenner void
pim_print(netdissect_options * ndo,const u_char * bp,u_int len,const u_char * bp2)4523c602fabSXin LI pim_print(netdissect_options *ndo,
453ee67461eSJoseph Mingrone           const u_char *bp, u_int len, const u_char *bp2)
454b0453382SBill Fenner {
455ee67461eSJoseph Mingrone 	const struct pim *pim = (const struct pim *)bp;
456ee67461eSJoseph Mingrone 	uint8_t pim_typever;
457b0453382SBill Fenner 
458ee67461eSJoseph Mingrone 	ndo->ndo_protocol = "pim";
459b0453382SBill Fenner 
460ee67461eSJoseph Mingrone 	pim_typever = GET_U_1(pim->pim_typever);
461ee67461eSJoseph Mingrone 	switch (PIM_VER(pim_typever)) {
462c1ad1296SSam Leffler 	case 2:
4633c602fabSXin LI 		if (!ndo->ndo_vflag) {
464ee67461eSJoseph Mingrone 			ND_PRINT("PIMv%u, %s, length %u",
465ee67461eSJoseph Mingrone 			          PIM_VER(pim_typever),
466ee67461eSJoseph Mingrone 			          tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim_typever)),
467ee67461eSJoseph Mingrone 			          len);
468c1ad1296SSam Leffler 			return;
469c1ad1296SSam Leffler 		} else {
470ee67461eSJoseph Mingrone 			ND_PRINT("PIMv%u, length %u\n\t%s",
471ee67461eSJoseph Mingrone 			          PIM_VER(pim_typever),
472c1ad1296SSam Leffler 			          len,
473ee67461eSJoseph Mingrone 			          tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim_typever)));
4743340d773SGleb Smirnoff 			pimv2_print(ndo, bp, len, bp2);
475c1ad1296SSam Leffler 		}
476b0453382SBill Fenner 		break;
477b0453382SBill Fenner 	default:
478ee67461eSJoseph Mingrone 		ND_PRINT("PIMv%u, length %u",
479ee67461eSJoseph Mingrone 		          PIM_VER(pim_typever),
480ee67461eSJoseph Mingrone 		          len);
481b0453382SBill Fenner 		break;
482b0453382SBill Fenner 	}
483b0453382SBill Fenner }
484b0453382SBill Fenner 
485b0453382SBill Fenner /*
486b0453382SBill Fenner  * PIMv2 uses encoded address representations.
487b0453382SBill Fenner  *
488b0453382SBill Fenner  * The last PIM-SM I-D before RFC2117 was published specified the
489b0453382SBill Fenner  * following representation for unicast addresses.  However, RFC2117
490b0453382SBill Fenner  * specified no encoding for unicast addresses with the unicast
491b0453382SBill Fenner  * address length specified in the header.  Therefore, we have to
492b0453382SBill Fenner  * guess which encoding is being used (Cisco's PIMv2 implementation
493b0453382SBill Fenner  * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
494b0453382SBill Fenner  * field into a 'unicast-address-length-in-bytes' field.  We guess
495b0453382SBill Fenner  * that it's the draft encoding if this reserved field is zero.
496b0453382SBill Fenner  *
497b0453382SBill Fenner  * RFC2362 goes back to the encoded format, and calls the addr length
498b0453382SBill Fenner  * field "reserved" again.
499b0453382SBill Fenner  *
500b0453382SBill Fenner  * The first byte is the address family, from:
501b0453382SBill Fenner  *
502b0453382SBill Fenner  *    0    Reserved
503b0453382SBill Fenner  *    1    IP (IP version 4)
504b0453382SBill Fenner  *    2    IP6 (IP version 6)
505b0453382SBill Fenner  *    3    NSAP
506b0453382SBill Fenner  *    4    HDLC (8-bit multidrop)
507b0453382SBill Fenner  *    5    BBN 1822
508b0453382SBill Fenner  *    6    802 (includes all 802 media plus Ethernet "canonical format")
509b0453382SBill Fenner  *    7    E.163
510b0453382SBill Fenner  *    8    E.164 (SMDS, Frame Relay, ATM)
511b0453382SBill Fenner  *    9    F.69 (Telex)
512b0453382SBill Fenner  *   10    X.121 (X.25, Frame Relay)
513b0453382SBill Fenner  *   11    IPX
514b0453382SBill Fenner  *   12    Appletalk
515b0453382SBill Fenner  *   13    Decnet IV
516b0453382SBill Fenner  *   14    Banyan Vines
517b0453382SBill Fenner  *   15    E.164 with NSAP format subaddress
518b0453382SBill Fenner  *
519b0453382SBill Fenner  * In addition, the second byte is an "Encoding".  0 is the default
520b0453382SBill Fenner  * encoding for the address family, and no other encodings are currently
521b0453382SBill Fenner  * specified.
522b0453382SBill Fenner  *
523b0453382SBill Fenner  */
524b0453382SBill Fenner 
525b0453382SBill Fenner enum pimv2_addrtype {
526b0453382SBill Fenner 	pimv2_unicast, pimv2_group, pimv2_source
527b0453382SBill Fenner };
528b0453382SBill Fenner 
529b0453382SBill Fenner /*  0                   1                   2                   3
530b0453382SBill 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
531b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
532b0453382SBill Fenner  * | Addr Family   | Encoding Type |     Unicast Address           |
533b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
534b0453382SBill Fenner  *  0                   1                   2                   3
535b0453382SBill 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
536b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
537b0453382SBill Fenner  * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
538b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539b0453382SBill Fenner  * |                Group multicast Address                        |
540b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
541b0453382SBill Fenner  *  0                   1                   2                   3
542b0453382SBill 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
543b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
544b0453382SBill Fenner  * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
545b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
546b0453382SBill Fenner  * |                        Source Address                         |
547b0453382SBill Fenner  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
548b0453382SBill Fenner  */
549b0453382SBill Fenner static int
pimv2_addr_print(netdissect_options * ndo,const u_char * bp,u_int len,enum pimv2_addrtype at,u_int addr_len,int silent)5503c602fabSXin LI pimv2_addr_print(netdissect_options *ndo,
5510bff6a5aSEd Maste                  const u_char *bp, u_int len, enum pimv2_addrtype at,
5520bff6a5aSEd Maste                  u_int addr_len, int silent)
553b0453382SBill Fenner {
554ee67461eSJoseph Mingrone 	u_int af;
5550bff6a5aSEd Maste 	int hdrlen;
556b0453382SBill Fenner 
5570bff6a5aSEd Maste 	if (addr_len == 0) {
5580bff6a5aSEd Maste 		if (len < 2)
5590bff6a5aSEd Maste 			goto trunc;
560ee67461eSJoseph Mingrone 		switch (GET_U_1(bp)) {
561b0453382SBill Fenner 		case 1:
562b0453382SBill Fenner 			af = AF_INET;
563ee67461eSJoseph Mingrone 			addr_len = (u_int)sizeof(nd_ipv4);
564b0453382SBill Fenner 			break;
565b0453382SBill Fenner 		case 2:
566b0453382SBill Fenner 			af = AF_INET6;
567ee67461eSJoseph Mingrone 			addr_len = (u_int)sizeof(nd_ipv6);
568b0453382SBill Fenner 			break;
569b0453382SBill Fenner 		default:
570b0453382SBill Fenner 			return -1;
571b0453382SBill Fenner 		}
572ee67461eSJoseph Mingrone 		if (GET_U_1(bp + 1) != 0)
573b0453382SBill Fenner 			return -1;
574b0453382SBill Fenner 		hdrlen = 2;
575b0453382SBill Fenner 	} else {
5760bff6a5aSEd Maste 		switch (addr_len) {
577ee67461eSJoseph Mingrone 		case sizeof(nd_ipv4):
578b0453382SBill Fenner 			af = AF_INET;
579b0453382SBill Fenner 			break;
580ee67461eSJoseph Mingrone 		case sizeof(nd_ipv6):
581b0453382SBill Fenner 			af = AF_INET6;
582b0453382SBill Fenner 			break;
583b0453382SBill Fenner 		default:
584b0453382SBill Fenner 			return -1;
585b0453382SBill Fenner 			break;
586b0453382SBill Fenner 		}
587b0453382SBill Fenner 		hdrlen = 0;
588b0453382SBill Fenner 	}
589b0453382SBill Fenner 
590b0453382SBill Fenner 	bp += hdrlen;
5910bff6a5aSEd Maste 	len -= hdrlen;
592b0453382SBill Fenner 	switch (at) {
593b0453382SBill Fenner 	case pimv2_unicast:
5940bff6a5aSEd Maste 		if (len < addr_len)
5950bff6a5aSEd Maste 			goto trunc;
596ee67461eSJoseph Mingrone 		ND_TCHECK_LEN(bp, addr_len);
597b0453382SBill Fenner 		if (af == AF_INET) {
598b0453382SBill Fenner 			if (!silent)
599ee67461eSJoseph Mingrone 				ND_PRINT("%s", GET_IPADDR_STRING(bp));
600*0a7e5f1fSJoseph Mingrone 		} else if (af == AF_INET6) {
601b0453382SBill Fenner 			if (!silent)
602ee67461eSJoseph Mingrone 				ND_PRINT("%s", GET_IP6ADDR_STRING(bp));
603b0453382SBill Fenner 		}
6040bff6a5aSEd Maste 		return hdrlen + addr_len;
605b0453382SBill Fenner 	case pimv2_group:
606b0453382SBill Fenner 	case pimv2_source:
6070bff6a5aSEd Maste 		if (len < addr_len + 2)
6080bff6a5aSEd Maste 			goto trunc;
609ee67461eSJoseph Mingrone 		ND_TCHECK_LEN(bp, addr_len + 2);
610b0453382SBill Fenner 		if (af == AF_INET) {
611b0453382SBill Fenner 			if (!silent) {
612ee67461eSJoseph Mingrone 				ND_PRINT("%s", GET_IPADDR_STRING(bp + 2));
613ee67461eSJoseph Mingrone 				if (GET_U_1(bp + 1) != 32)
614ee67461eSJoseph Mingrone 					ND_PRINT("/%u", GET_U_1(bp + 1));
615b0453382SBill Fenner 			}
616*0a7e5f1fSJoseph Mingrone 		} else if (af == AF_INET6) {
617b0453382SBill Fenner 			if (!silent) {
618ee67461eSJoseph Mingrone 				ND_PRINT("%s", GET_IP6ADDR_STRING(bp + 2));
619ee67461eSJoseph Mingrone 				if (GET_U_1(bp + 1) != 128)
620ee67461eSJoseph Mingrone 					ND_PRINT("/%u", GET_U_1(bp + 1));
621b0453382SBill Fenner 			}
622b0453382SBill Fenner 		}
623ee67461eSJoseph Mingrone 		if (GET_U_1(bp) && !silent) {
624b0453382SBill Fenner 			if (at == pimv2_group) {
625ee67461eSJoseph Mingrone 				ND_PRINT("(0x%02x)", GET_U_1(bp));
626b0453382SBill Fenner 			} else {
627ee67461eSJoseph Mingrone 				ND_PRINT("(%s%s%s",
628ee67461eSJoseph Mingrone 					GET_U_1(bp) & 0x04 ? "S" : "",
629ee67461eSJoseph Mingrone 					GET_U_1(bp) & 0x02 ? "W" : "",
630ee67461eSJoseph Mingrone 					GET_U_1(bp) & 0x01 ? "R" : "");
631ee67461eSJoseph Mingrone 				if (GET_U_1(bp) & 0xf8) {
632ee67461eSJoseph Mingrone 					ND_PRINT("+0x%02x",
633ee67461eSJoseph Mingrone 						 GET_U_1(bp) & 0xf8);
634b0453382SBill Fenner 				}
635ee67461eSJoseph Mingrone 				ND_PRINT(")");
636b0453382SBill Fenner 			}
637b0453382SBill Fenner 		}
6380bff6a5aSEd Maste 		return hdrlen + 2 + addr_len;
639b0453382SBill Fenner 	default:
640b0453382SBill Fenner 		return -1;
641b0453382SBill Fenner 	}
642b0453382SBill Fenner trunc:
643b0453382SBill Fenner 	return -1;
644b0453382SBill Fenner }
645b0453382SBill Fenner 
6463340d773SGleb Smirnoff enum checksum_status {
6473340d773SGleb Smirnoff 	CORRECT,
6483340d773SGleb Smirnoff 	INCORRECT,
6493340d773SGleb Smirnoff 	UNVERIFIED
6503340d773SGleb Smirnoff };
6513340d773SGleb Smirnoff 
6523340d773SGleb Smirnoff static enum checksum_status
pimv2_check_checksum(netdissect_options * ndo,const u_char * bp,const u_char * bp2,u_int len)6533340d773SGleb Smirnoff pimv2_check_checksum(netdissect_options *ndo, const u_char *bp,
6543340d773SGleb Smirnoff 		     const u_char *bp2, u_int len)
6553340d773SGleb Smirnoff {
6563340d773SGleb Smirnoff 	const struct ip *ip;
6573340d773SGleb Smirnoff 	u_int cksum;
6583340d773SGleb Smirnoff 
659ee67461eSJoseph Mingrone 	if (!ND_TTEST_LEN(bp, len)) {
6603340d773SGleb Smirnoff 		/* We don't have all the data. */
6613340d773SGleb Smirnoff 		return (UNVERIFIED);
6623340d773SGleb Smirnoff 	}
6633340d773SGleb Smirnoff 	ip = (const struct ip *)bp2;
6643340d773SGleb Smirnoff 	if (IP_V(ip) == 4) {
6653340d773SGleb Smirnoff 		struct cksum_vec vec[1];
6663340d773SGleb Smirnoff 
6673340d773SGleb Smirnoff 		vec[0].ptr = bp;
6683340d773SGleb Smirnoff 		vec[0].len = len;
6693340d773SGleb Smirnoff 		cksum = in_cksum(vec, 1);
6703340d773SGleb Smirnoff 		return (cksum ? INCORRECT : CORRECT);
6713340d773SGleb Smirnoff 	} else if (IP_V(ip) == 6) {
6723340d773SGleb Smirnoff 		const struct ip6_hdr *ip6;
6733340d773SGleb Smirnoff 
6743340d773SGleb Smirnoff 		ip6 = (const struct ip6_hdr *)bp2;
6753340d773SGleb Smirnoff 		cksum = nextproto6_cksum(ndo, ip6, bp, len, len, IPPROTO_PIM);
6763340d773SGleb Smirnoff 		return (cksum ? INCORRECT : CORRECT);
6773340d773SGleb Smirnoff 	} else {
6783340d773SGleb Smirnoff 		return (UNVERIFIED);
6793340d773SGleb Smirnoff 	}
6803340d773SGleb Smirnoff }
6813340d773SGleb Smirnoff 
682b0453382SBill Fenner static void
pimv2_print(netdissect_options * ndo,const u_char * bp,u_int len,const u_char * bp2)6833c602fabSXin LI pimv2_print(netdissect_options *ndo,
684ee67461eSJoseph Mingrone             const u_char *bp, u_int len, const u_char *bp2)
685b0453382SBill Fenner {
686ee67461eSJoseph Mingrone 	const struct pim *pim = (const struct pim *)bp;
687b0453382SBill Fenner 	int advance;
688ee67461eSJoseph Mingrone 	int subtype;
6893340d773SGleb Smirnoff 	enum checksum_status cksum_status;
690ee67461eSJoseph Mingrone 	u_int pim_typever;
691ee67461eSJoseph Mingrone 	u_int pimv2_addr_len;
692b0453382SBill Fenner 
693ee67461eSJoseph Mingrone 	ndo->ndo_protocol = "pimv2";
694ee67461eSJoseph Mingrone 	if (len < 2) {
695ee67461eSJoseph Mingrone 		ND_PRINT("[length %u < 2]", len);
696ee67461eSJoseph Mingrone 		nd_print_invalid(ndo);
697ee67461eSJoseph Mingrone 		return;
698ee67461eSJoseph Mingrone 	}
699ee67461eSJoseph Mingrone 	pim_typever = GET_U_1(pim->pim_typever);
700ee67461eSJoseph Mingrone 	/* RFC5015 allocates the high 4 bits of pim_rsv for "subtype". */
701ee67461eSJoseph Mingrone 	pimv2_addr_len = GET_U_1(pim->pim_rsv) & 0x0f;
702b0453382SBill Fenner 	if (pimv2_addr_len != 0)
703ee67461eSJoseph Mingrone 		ND_PRINT(", RFC2117-encoding");
704b0453382SBill Fenner 
705ee67461eSJoseph Mingrone 	if (len < 4) {
706ee67461eSJoseph Mingrone 		ND_PRINT("[length %u < 4]", len);
707ee67461eSJoseph Mingrone 		nd_print_invalid(ndo);
708ee67461eSJoseph Mingrone 		return;
709ee67461eSJoseph Mingrone 	}
710ee67461eSJoseph Mingrone 	ND_PRINT(", cksum 0x%04x ", GET_BE_U_2(pim->pim_cksum));
711ee67461eSJoseph Mingrone 	if (GET_BE_U_2(pim->pim_cksum) == 0) {
712ee67461eSJoseph Mingrone 		ND_PRINT("(unverified)");
713abf25193SMax Laier 	} else {
714ee67461eSJoseph Mingrone 		if (PIM_TYPE(pim_typever) == PIMV2_TYPE_REGISTER) {
7153340d773SGleb Smirnoff 			/*
7163340d773SGleb Smirnoff 			 * The checksum only covers the packet header,
7173340d773SGleb Smirnoff 			 * not the encapsulated packet.
7183340d773SGleb Smirnoff 			 */
7193340d773SGleb Smirnoff 			cksum_status = pimv2_check_checksum(ndo, bp, bp2, 8);
7203340d773SGleb Smirnoff 			if (cksum_status == INCORRECT) {
7213340d773SGleb Smirnoff 				/*
7223340d773SGleb Smirnoff 				 * To quote RFC 4601, "For interoperability
7233340d773SGleb Smirnoff 				 * reasons, a message carrying a checksum
7243340d773SGleb Smirnoff 				 * calculated over the entire PIM Register
7253340d773SGleb Smirnoff 				 * message should also be accepted."
7263340d773SGleb Smirnoff 				 */
7273340d773SGleb Smirnoff 				cksum_status = pimv2_check_checksum(ndo, bp, bp2, len);
7283340d773SGleb Smirnoff 			}
7293340d773SGleb Smirnoff 		} else {
7303340d773SGleb Smirnoff 			/*
7313340d773SGleb Smirnoff 			 * The checksum covers the entire packet.
7323340d773SGleb Smirnoff 			 */
7333340d773SGleb Smirnoff 			cksum_status = pimv2_check_checksum(ndo, bp, bp2, len);
7343340d773SGleb Smirnoff 		}
7353340d773SGleb Smirnoff 		switch (cksum_status) {
7363340d773SGleb Smirnoff 
7373340d773SGleb Smirnoff 		case CORRECT:
738ee67461eSJoseph Mingrone 			ND_PRINT("(correct)");
7393340d773SGleb Smirnoff 			break;
7403340d773SGleb Smirnoff 
7413340d773SGleb Smirnoff 		case INCORRECT:
742ee67461eSJoseph Mingrone 			ND_PRINT("(incorrect)");
7433340d773SGleb Smirnoff 			break;
7443340d773SGleb Smirnoff 
7453340d773SGleb Smirnoff 		case UNVERIFIED:
746ee67461eSJoseph Mingrone 			ND_PRINT("(unverified)");
7473340d773SGleb Smirnoff 			break;
7483340d773SGleb Smirnoff 		}
749abf25193SMax Laier 	}
7500bff6a5aSEd Maste 	bp += 4;
7510bff6a5aSEd Maste 	len -= 4;
752abf25193SMax Laier 
753ee67461eSJoseph Mingrone 	switch (PIM_TYPE(pim_typever)) {
754c1ad1296SSam Leffler 	case PIMV2_TYPE_HELLO:
755b0453382SBill Fenner 	    {
7563c602fabSXin LI 		uint16_t otype, olen;
7570bff6a5aSEd Maste 		while (len > 0) {
7580bff6a5aSEd Maste 			if (len < 4)
7590bff6a5aSEd Maste 				goto trunc;
760ee67461eSJoseph Mingrone 			otype = GET_BE_U_2(bp);
761ee67461eSJoseph Mingrone 			olen = GET_BE_U_2(bp + 2);
762ee67461eSJoseph Mingrone 			ND_PRINT("\n\t  %s Option (%u), length %u, Value: ",
763c1ad1296SSam Leffler 			          tok2str(pimv2_hello_option_values, "Unknown", otype),
764c1ad1296SSam Leffler 			          otype,
765ee67461eSJoseph Mingrone 			          olen);
766c1ad1296SSam Leffler 			bp += 4;
7670bff6a5aSEd Maste 			len -= 4;
768c1ad1296SSam Leffler 
7690bff6a5aSEd Maste 			if (len < olen)
7700bff6a5aSEd Maste 				goto trunc;
771ee67461eSJoseph Mingrone 			ND_TCHECK_LEN(bp, olen);
772b0453382SBill Fenner 			switch (otype) {
773c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_HOLDTIME:
7740bff6a5aSEd Maste 				if (olen != 2) {
775ee67461eSJoseph Mingrone 					ND_PRINT("[option length %u != 2]", olen);
776ee67461eSJoseph Mingrone 					nd_print_invalid(ndo);
777ee67461eSJoseph Mingrone 					return;
7780bff6a5aSEd Maste 				} else {
779ee67461eSJoseph Mingrone 					unsigned_relts_print(ndo,
780ee67461eSJoseph Mingrone 							     GET_BE_U_2(bp));
7810bff6a5aSEd Maste 				}
782b0453382SBill Fenner 				break;
783b0453382SBill Fenner 
784c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_LANPRUNEDELAY:
785cc391cceSBruce M Simpson 				if (olen != 4) {
786ee67461eSJoseph Mingrone 					ND_PRINT("[option length %u != 4]", olen);
787ee67461eSJoseph Mingrone 					nd_print_invalid(ndo);
788ee67461eSJoseph Mingrone 					return;
789cc391cceSBruce M Simpson 				} else {
790cc391cceSBruce M Simpson 					char t_bit;
7913c602fabSXin LI 					uint16_t lan_delay, override_interval;
792ee67461eSJoseph Mingrone 					lan_delay = GET_BE_U_2(bp);
793ee67461eSJoseph Mingrone 					override_interval = GET_BE_U_2(bp + 2);
794cc391cceSBruce M Simpson 					t_bit = (lan_delay & 0x8000)? 1 : 0;
795cc391cceSBruce M Simpson 					lan_delay &= ~0x8000;
796ee67461eSJoseph Mingrone 					ND_PRINT("\n\t    T-bit=%u, LAN delay %ums, Override interval %ums",
797ee67461eSJoseph Mingrone 					t_bit, lan_delay, override_interval);
798cc391cceSBruce M Simpson 				}
799cc391cceSBruce M Simpson 				break;
800cc391cceSBruce M Simpson 
801c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_DR_PRIORITY_OLD:
802c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_DR_PRIORITY:
803c1ad1296SSam Leffler 				switch (olen) {
804c1ad1296SSam Leffler 				case 0:
805ee67461eSJoseph Mingrone 					ND_PRINT("Bi-Directional Capability (Old)");
8060e0def19SBill Fenner 					break;
807c1ad1296SSam Leffler 				case 4:
808ee67461eSJoseph Mingrone 					ND_PRINT("%u", GET_BE_U_4(bp));
809c1ad1296SSam Leffler 					break;
810c1ad1296SSam Leffler 				default:
811ee67461eSJoseph Mingrone 					ND_PRINT("[option length %u != 4]", olen);
812ee67461eSJoseph Mingrone 					nd_print_invalid(ndo);
813ee67461eSJoseph Mingrone 					return;
8140e0def19SBill Fenner 					break;
8150e0def19SBill Fenner 				}
816c1ad1296SSam Leffler 				break;
817c1ad1296SSam Leffler 
818c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_GENID:
8190bff6a5aSEd Maste 				if (olen != 4) {
820ee67461eSJoseph Mingrone 					ND_PRINT("[option length %u != 4]", olen);
821ee67461eSJoseph Mingrone 					nd_print_invalid(ndo);
822ee67461eSJoseph Mingrone 					return;
8230bff6a5aSEd Maste 				} else {
824ee67461eSJoseph Mingrone 					ND_PRINT("0x%08x", GET_BE_U_4(bp));
8250bff6a5aSEd Maste 				}
826c1ad1296SSam Leffler 				break;
827c1ad1296SSam Leffler 
828c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_REFRESH_CAP:
8290bff6a5aSEd Maste 				if (olen != 4) {
830ee67461eSJoseph Mingrone 					ND_PRINT("[option length %u != 4]", olen);
831ee67461eSJoseph Mingrone 					nd_print_invalid(ndo);
832ee67461eSJoseph Mingrone 					return;
8330bff6a5aSEd Maste 				} else {
834ee67461eSJoseph Mingrone 					ND_PRINT("v%u", GET_U_1(bp));
835ee67461eSJoseph Mingrone 					if (GET_U_1(bp + 1) != 0) {
836ee67461eSJoseph Mingrone 						ND_PRINT(", interval ");
837ee67461eSJoseph Mingrone 						unsigned_relts_print(ndo,
838ee67461eSJoseph Mingrone 								     GET_U_1(bp + 1));
839c1ad1296SSam Leffler 					}
840ee67461eSJoseph Mingrone 					if (GET_BE_U_2(bp + 2) != 0) {
841ee67461eSJoseph Mingrone 						ND_PRINT(" ?0x%04x?",
842ee67461eSJoseph Mingrone 							 GET_BE_U_2(bp + 2));
843a1c2090eSBill Fenner 					}
8440bff6a5aSEd Maste 				}
845b0453382SBill Fenner 				break;
846b0453382SBill Fenner 
847c1ad1296SSam Leffler 			case  PIMV2_HELLO_OPTION_BIDIR_CAP:
848b0453382SBill Fenner 				break;
849b0453382SBill Fenner 
850c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD:
851c1ad1296SSam Leffler 			case PIMV2_HELLO_OPTION_ADDRESS_LIST:
8523c602fabSXin LI 				if (ndo->ndo_vflag > 1) {
853c1ad1296SSam Leffler 					const u_char *ptr = bp;
8540bff6a5aSEd Maste 					u_int plen = len;
855c1ad1296SSam Leffler 					while (ptr < (bp+olen)) {
856ee67461eSJoseph Mingrone 						ND_PRINT("\n\t    ");
8570bff6a5aSEd Maste 						advance = pimv2_addr_print(ndo, ptr, plen, pimv2_unicast, pimv2_addr_len, 0);
8580bff6a5aSEd Maste 						if (advance < 0)
8590bff6a5aSEd Maste 							goto trunc;
860cc391cceSBruce M Simpson 						ptr += advance;
8610bff6a5aSEd Maste 						plen -= advance;
862cc391cceSBruce M Simpson 					}
863cc391cceSBruce M Simpson 				}
864cc391cceSBruce M Simpson 				break;
865b0453382SBill Fenner 			default:
8663c602fabSXin LI 				if (ndo->ndo_vflag <= 1)
8673c602fabSXin LI 					print_unknown_data(ndo, bp, "\n\t    ", olen);
868c1ad1296SSam Leffler 				break;
869b0453382SBill Fenner 			}
870c1ad1296SSam Leffler 			/* do we want to see an additionally hexdump ? */
8713c602fabSXin LI 			if (ndo->ndo_vflag> 1)
8723c602fabSXin LI 				print_unknown_data(ndo, bp, "\n\t    ", olen);
873c1ad1296SSam Leffler 			bp += olen;
8740bff6a5aSEd Maste 			len -= olen;
875b0453382SBill Fenner 		}
876b0453382SBill Fenner 		break;
877b0453382SBill Fenner 	    }
878b0453382SBill Fenner 
879c1ad1296SSam Leffler 	case PIMV2_TYPE_REGISTER:
880b0453382SBill Fenner 	{
8813340d773SGleb Smirnoff 		const struct ip *ip;
882b0453382SBill Fenner 
8830bff6a5aSEd Maste 		if (len < 4)
8840bff6a5aSEd Maste 			goto trunc;
885ee67461eSJoseph Mingrone 		ND_TCHECK_LEN(bp, PIMV2_REGISTER_FLAG_LEN);
886b0453382SBill Fenner 
887ee67461eSJoseph Mingrone 		ND_PRINT(", Flags [ %s ]\n\t",
888abf25193SMax Laier 		          tok2str(pimv2_register_flag_values,
889abf25193SMax Laier 		          "none",
890ee67461eSJoseph Mingrone 		          GET_BE_U_4(bp)));
891abf25193SMax Laier 
8920bff6a5aSEd Maste 		bp += 4; len -= 4;
893b0453382SBill Fenner 		/* encapsulated multicast packet */
8940bff6a5aSEd Maste 		if (len == 0)
8950bff6a5aSEd Maste 			goto trunc;
8963340d773SGleb Smirnoff 		ip = (const struct ip *)bp;
897943ee2b1SBill Fenner 		switch (IP_V(ip)) {
898abf25193SMax Laier                 case 0: /* Null header */
899ee67461eSJoseph Mingrone 			ND_PRINT("IP-Null-header %s > %s",
900ee67461eSJoseph Mingrone 			          GET_IPADDR_STRING(ip->ip_src),
901ee67461eSJoseph Mingrone 			          GET_IPADDR_STRING(ip->ip_dst));
902abf25193SMax Laier 			break;
903abf25193SMax Laier 
904b0453382SBill Fenner 		case 4:	/* IPv4 */
9053c602fabSXin LI 			ip_print(ndo, bp, len);
906b0453382SBill Fenner 			break;
9078bdc5a62SPatrick Kelsey 
908b0453382SBill Fenner 		case 6:	/* IPv6 */
9093c602fabSXin LI 			ip6_print(ndo, bp, len);
910b0453382SBill Fenner 			break;
9118bdc5a62SPatrick Kelsey 
912b0453382SBill Fenner 		default:
913ee67461eSJoseph Mingrone 			ND_PRINT("IP ver %u", IP_V(ip));
914b0453382SBill Fenner 			break;
915b0453382SBill Fenner 		}
916b0453382SBill Fenner 		break;
917b0453382SBill Fenner 	}
918b0453382SBill Fenner 
919c1ad1296SSam Leffler 	case PIMV2_TYPE_REGISTER_STOP:
920ee67461eSJoseph Mingrone 		ND_PRINT(" group=");
9210bff6a5aSEd Maste 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
9220bff6a5aSEd Maste 			goto trunc;
923b0453382SBill Fenner 		bp += advance; len -= advance;
924ee67461eSJoseph Mingrone 		ND_PRINT(" source=");
9250bff6a5aSEd Maste 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
9260bff6a5aSEd Maste 			goto trunc;
927b0453382SBill Fenner 		bp += advance; len -= advance;
928b0453382SBill Fenner 		break;
929b0453382SBill Fenner 
930c1ad1296SSam Leffler 	case PIMV2_TYPE_JOIN_PRUNE:
931c1ad1296SSam Leffler 	case PIMV2_TYPE_GRAFT:
932c1ad1296SSam Leffler 	case PIMV2_TYPE_GRAFT_ACK:
933c1ad1296SSam Leffler 
934c1ad1296SSam Leffler 
935c1ad1296SSam Leffler         /*
936c1ad1296SSam Leffler          * 0                   1                   2                   3
937c1ad1296SSam 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
938c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
939c1ad1296SSam Leffler          *  |PIM Ver| Type  | Addr length   |           Checksum            |
940c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
941c1ad1296SSam Leffler          *  |             Unicast-Upstream Neighbor Address                 |
942c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
943c1ad1296SSam Leffler          *  |  Reserved     | Num groups    |          Holdtime             |
944c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
945c1ad1296SSam Leffler          *  |            Encoded-Multicast Group Address-1                  |
946c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
947c1ad1296SSam Leffler          *  |   Number of Joined  Sources   |   Number of Pruned Sources    |
948c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
949c1ad1296SSam Leffler          *  |               Encoded-Joined Source Address-1                 |
950c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
951c1ad1296SSam Leffler          *  |                             .                                 |
952c1ad1296SSam Leffler          *  |                             .                                 |
953c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
954c1ad1296SSam Leffler          *  |               Encoded-Joined Source Address-n                 |
955c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
956c1ad1296SSam Leffler          *  |               Encoded-Pruned Source Address-1                 |
957c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
958c1ad1296SSam Leffler          *  |                             .                                 |
959c1ad1296SSam Leffler          *  |                             .                                 |
960c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
961c1ad1296SSam Leffler          *  |               Encoded-Pruned Source Address-n                 |
962c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
963c1ad1296SSam Leffler          *  |                           .                                   |
964c1ad1296SSam Leffler          *  |                           .                                   |
965c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
966c1ad1296SSam Leffler          *  |                Encoded-Multicast Group Address-n              |
967c1ad1296SSam Leffler          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
968c1ad1296SSam Leffler          */
969c1ad1296SSam Leffler 
970b0453382SBill Fenner 	    {
9713c602fabSXin LI 		uint8_t ngroup;
9723c602fabSXin LI 		uint16_t holdtime;
9733c602fabSXin LI 		uint16_t njoin;
9743c602fabSXin LI 		uint16_t nprune;
975ee67461eSJoseph Mingrone 		u_int i, j;
976b0453382SBill Fenner 
977ee67461eSJoseph Mingrone 		if (PIM_TYPE(pim_typever) != 7) {	/*not for Graft-ACK*/
978ee67461eSJoseph Mingrone 			ND_PRINT(", upstream-neighbor: ");
9790bff6a5aSEd Maste 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
9800bff6a5aSEd Maste 				goto trunc;
981b0453382SBill Fenner 			bp += advance; len -= advance;
982b0453382SBill Fenner 		}
9830bff6a5aSEd Maste 		if (len < 4)
9840bff6a5aSEd Maste 			goto trunc;
985ee67461eSJoseph Mingrone 		ND_TCHECK_4(bp);
986ee67461eSJoseph Mingrone 		ngroup = GET_U_1(bp + 1);
987ee67461eSJoseph Mingrone 		holdtime = GET_BE_U_2(bp + 2);
988ee67461eSJoseph Mingrone 		ND_PRINT("\n\t  %u group(s)", ngroup);
989ee67461eSJoseph Mingrone 		if (PIM_TYPE(pim_typever) != 7) {	/*not for Graft-ACK*/
990ee67461eSJoseph Mingrone 			ND_PRINT(", holdtime: ");
991b0453382SBill Fenner 			if (holdtime == 0xffff)
992ee67461eSJoseph Mingrone 				ND_PRINT("infinite");
993b0453382SBill Fenner 			else
9943340d773SGleb Smirnoff 				unsigned_relts_print(ndo, holdtime);
995b0453382SBill Fenner 		}
996b0453382SBill Fenner 		bp += 4; len -= 4;
997b0453382SBill Fenner 		for (i = 0; i < ngroup; i++) {
998ee67461eSJoseph Mingrone 			ND_PRINT("\n\t    group #%u: ", i+1);
9990bff6a5aSEd Maste 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
10000bff6a5aSEd Maste 				goto trunc;
1001b0453382SBill Fenner 			bp += advance; len -= advance;
10020bff6a5aSEd Maste 			if (len < 4)
10030bff6a5aSEd Maste 				goto trunc;
1004ee67461eSJoseph Mingrone 			ND_TCHECK_4(bp);
1005ee67461eSJoseph Mingrone 			njoin = GET_BE_U_2(bp);
1006ee67461eSJoseph Mingrone 			nprune = GET_BE_U_2(bp + 2);
1007ee67461eSJoseph Mingrone 			ND_PRINT(", joined sources: %u, pruned sources: %u", njoin, nprune);
1008b0453382SBill Fenner 			bp += 4; len -= 4;
1009b0453382SBill Fenner 			for (j = 0; j < njoin; j++) {
1010ee67461eSJoseph Mingrone 				ND_PRINT("\n\t      joined source #%u: ", j+1);
10110bff6a5aSEd Maste 				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
10120bff6a5aSEd Maste 					goto trunc;
1013b0453382SBill Fenner 				bp += advance; len -= advance;
1014b0453382SBill Fenner 			}
1015b0453382SBill Fenner 			for (j = 0; j < nprune; j++) {
1016ee67461eSJoseph Mingrone 				ND_PRINT("\n\t      pruned source #%u: ", j+1);
10170bff6a5aSEd Maste 				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
10180bff6a5aSEd Maste 					goto trunc;
1019b0453382SBill Fenner 				bp += advance; len -= advance;
1020b0453382SBill Fenner 			}
1021b0453382SBill Fenner 		}
1022b0453382SBill Fenner 		break;
1023b0453382SBill Fenner 	    }
1024b0453382SBill Fenner 
1025c1ad1296SSam Leffler 	case PIMV2_TYPE_BOOTSTRAP:
1026b0453382SBill Fenner 	{
1027ee67461eSJoseph Mingrone 		u_int i, j, frpcnt;
1028b0453382SBill Fenner 
1029b0453382SBill Fenner 		/* Fragment Tag, Hash Mask len, and BSR-priority */
10300bff6a5aSEd Maste 		if (len < 2)
10310bff6a5aSEd Maste 			goto trunc;
1032ee67461eSJoseph Mingrone 		ND_PRINT(" tag=%x", GET_BE_U_2(bp));
10330bff6a5aSEd Maste 		bp += 2;
10340bff6a5aSEd Maste 		len -= 2;
10350bff6a5aSEd Maste 		if (len < 1)
10360bff6a5aSEd Maste 			goto trunc;
1037ee67461eSJoseph Mingrone 		ND_PRINT(" hashmlen=%u", GET_U_1(bp));
10380bff6a5aSEd Maste 		if (len < 2)
10390bff6a5aSEd Maste 			goto trunc;
1040ee67461eSJoseph Mingrone 		ND_TCHECK_1(bp + 2);
1041ee67461eSJoseph Mingrone 		ND_PRINT(" BSRprio=%u", GET_U_1(bp + 1));
1042b0453382SBill Fenner 		bp += 2;
10430bff6a5aSEd Maste 		len -= 2;
1044b0453382SBill Fenner 
1045b0453382SBill Fenner 		/* Encoded-Unicast-BSR-Address */
1046ee67461eSJoseph Mingrone 		ND_PRINT(" BSR=");
10470bff6a5aSEd Maste 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
10480bff6a5aSEd Maste 			goto trunc;
1049b0453382SBill Fenner 		bp += advance;
10500bff6a5aSEd Maste 		len -= advance;
1051b0453382SBill Fenner 
10520bff6a5aSEd Maste 		for (i = 0; len > 0; i++) {
1053b0453382SBill Fenner 			/* Encoded-Group Address */
1054ee67461eSJoseph Mingrone 			ND_PRINT(" (group%u: ", i);
10550bff6a5aSEd Maste 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
10560bff6a5aSEd Maste 				goto trunc;
1057b0453382SBill Fenner 			bp += advance;
10580bff6a5aSEd Maste 			len -= advance;
1059b0453382SBill Fenner 
1060b0453382SBill Fenner 			/* RP-Count, Frag RP-Cnt, and rsvd */
10610bff6a5aSEd Maste 			if (len < 1)
10620bff6a5aSEd Maste 				goto trunc;
1063ee67461eSJoseph Mingrone 			ND_PRINT(" RPcnt=%u", GET_U_1(bp));
10640bff6a5aSEd Maste 			if (len < 2)
10650bff6a5aSEd Maste 				goto trunc;
1066ee67461eSJoseph Mingrone 			frpcnt = GET_U_1(bp + 1);
1067ee67461eSJoseph Mingrone 			ND_PRINT(" FRPcnt=%u", frpcnt);
10680bff6a5aSEd Maste 			if (len < 4)
10690bff6a5aSEd Maste 				goto trunc;
1070b0453382SBill Fenner 			bp += 4;
10710bff6a5aSEd Maste 			len -= 4;
1072b0453382SBill Fenner 
10730bff6a5aSEd Maste 			for (j = 0; j < frpcnt && len > 0; j++) {
1074b0453382SBill Fenner 				/* each RP info */
1075ee67461eSJoseph Mingrone 				ND_PRINT(" RP%u=", j);
10760bff6a5aSEd Maste 				if ((advance = pimv2_addr_print(ndo, bp, len,
1077b0453382SBill Fenner 								pimv2_unicast,
10780bff6a5aSEd Maste 								pimv2_addr_len,
10790bff6a5aSEd Maste 								0)) < 0)
10800bff6a5aSEd Maste 					goto trunc;
1081b0453382SBill Fenner 				bp += advance;
10820bff6a5aSEd Maste 				len -= advance;
1083b0453382SBill Fenner 
10840bff6a5aSEd Maste 				if (len < 2)
10850bff6a5aSEd Maste 					goto trunc;
1086ee67461eSJoseph Mingrone 				ND_PRINT(",holdtime=");
1087ee67461eSJoseph Mingrone 				unsigned_relts_print(ndo,
1088ee67461eSJoseph Mingrone 						     GET_BE_U_2(bp));
10890bff6a5aSEd Maste 				if (len < 3)
10900bff6a5aSEd Maste 					goto trunc;
1091ee67461eSJoseph Mingrone 				ND_PRINT(",prio=%u", GET_U_1(bp + 2));
10920bff6a5aSEd Maste 				if (len < 4)
10930bff6a5aSEd Maste 					goto trunc;
1094b0453382SBill Fenner 				bp += 4;
10950bff6a5aSEd Maste 				len -= 4;
1096b0453382SBill Fenner 			}
1097ee67461eSJoseph Mingrone 			ND_PRINT(")");
1098b0453382SBill Fenner 		}
1099b0453382SBill Fenner 		break;
1100b0453382SBill Fenner 	}
1101c1ad1296SSam Leffler 	case PIMV2_TYPE_ASSERT:
1102ee67461eSJoseph Mingrone 		ND_PRINT(" group=");
11030bff6a5aSEd Maste 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
11040bff6a5aSEd Maste 			goto trunc;
1105b0453382SBill Fenner 		bp += advance; len -= advance;
1106ee67461eSJoseph Mingrone 		ND_PRINT(" src=");
11070bff6a5aSEd Maste 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
11080bff6a5aSEd Maste 			goto trunc;
1109b0453382SBill Fenner 		bp += advance; len -= advance;
11100bff6a5aSEd Maste 		if (len < 8)
11110bff6a5aSEd Maste 			goto trunc;
1112ee67461eSJoseph Mingrone 		ND_TCHECK_8(bp);
1113ee67461eSJoseph Mingrone 		if (GET_U_1(bp) & 0x80)
1114ee67461eSJoseph Mingrone 			ND_PRINT(" RPT");
1115ee67461eSJoseph Mingrone 		ND_PRINT(" pref=%u", GET_BE_U_4(bp) & 0x7fffffff);
1116ee67461eSJoseph Mingrone 		ND_PRINT(" metric=%u", GET_BE_U_4(bp + 4));
1117b0453382SBill Fenner 		break;
1118b0453382SBill Fenner 
1119c1ad1296SSam Leffler 	case PIMV2_TYPE_CANDIDATE_RP:
1120b0453382SBill Fenner 	{
1121ee67461eSJoseph Mingrone 		u_int i, pfxcnt;
1122b0453382SBill Fenner 
1123b0453382SBill Fenner 		/* Prefix-Cnt, Priority, and Holdtime */
11240bff6a5aSEd Maste 		if (len < 1)
11250bff6a5aSEd Maste 			goto trunc;
1126ee67461eSJoseph Mingrone 		ND_PRINT(" prefix-cnt=%u", GET_U_1(bp));
1127ee67461eSJoseph Mingrone 		pfxcnt = GET_U_1(bp);
11280bff6a5aSEd Maste 		if (len < 2)
11290bff6a5aSEd Maste 			goto trunc;
1130ee67461eSJoseph Mingrone 		ND_PRINT(" prio=%u", GET_U_1(bp + 1));
11310bff6a5aSEd Maste 		if (len < 4)
11320bff6a5aSEd Maste 			goto trunc;
1133ee67461eSJoseph Mingrone 		ND_PRINT(" holdtime=");
1134ee67461eSJoseph Mingrone 		unsigned_relts_print(ndo, GET_BE_U_2(bp + 2));
1135b0453382SBill Fenner 		bp += 4;
11360bff6a5aSEd Maste 		len -= 4;
1137b0453382SBill Fenner 
1138b0453382SBill Fenner 		/* Encoded-Unicast-RP-Address */
1139ee67461eSJoseph Mingrone 		ND_PRINT(" RP=");
11400bff6a5aSEd Maste 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
11410bff6a5aSEd Maste 			goto trunc;
1142b0453382SBill Fenner 		bp += advance;
11430bff6a5aSEd Maste 		len -= advance;
1144b0453382SBill Fenner 
1145b0453382SBill Fenner 		/* Encoded-Group Addresses */
11460bff6a5aSEd Maste 		for (i = 0; i < pfxcnt && len > 0; i++) {
1147ee67461eSJoseph Mingrone 			ND_PRINT(" Group%u=", i);
11480bff6a5aSEd Maste 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
11490bff6a5aSEd Maste 				goto trunc;
1150b0453382SBill Fenner 			bp += advance;
11510bff6a5aSEd Maste 			len -= advance;
1152b0453382SBill Fenner 		}
1153b0453382SBill Fenner 		break;
1154b0453382SBill Fenner 	}
1155b0453382SBill Fenner 
1156c1ad1296SSam Leffler 	case PIMV2_TYPE_PRUNE_REFRESH:
1157ee67461eSJoseph Mingrone 		ND_PRINT(" src=");
11580bff6a5aSEd Maste 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
11590bff6a5aSEd Maste 			goto trunc;
1160b0453382SBill Fenner 		bp += advance;
11610bff6a5aSEd Maste 		len -= advance;
1162ee67461eSJoseph Mingrone 		ND_PRINT(" grp=");
11630bff6a5aSEd Maste 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
11640bff6a5aSEd Maste 			goto trunc;
1165b0453382SBill Fenner 		bp += advance;
11660bff6a5aSEd Maste 		len -= advance;
1167ee67461eSJoseph Mingrone 		ND_PRINT(" forwarder=");
11680bff6a5aSEd Maste 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
11690bff6a5aSEd Maste 			goto trunc;
1170b0453382SBill Fenner 		bp += advance;
11710bff6a5aSEd Maste 		len -= advance;
11720bff6a5aSEd Maste 		if (len < 2)
11730bff6a5aSEd Maste 			goto trunc;
1174ee67461eSJoseph Mingrone 		ND_PRINT(" TUNR ");
1175ee67461eSJoseph Mingrone 		unsigned_relts_print(ndo, GET_BE_U_2(bp));
1176b0453382SBill Fenner 		break;
1177b0453382SBill Fenner 
1178ee67461eSJoseph Mingrone 	case PIMV2_TYPE_DF_ELECTION:
1179ee67461eSJoseph Mingrone 		subtype = PIM_SUBTYPE(GET_U_1(pim->pim_rsv));
1180ee67461eSJoseph Mingrone 		ND_PRINT("\n\t  %s,", tok2str( pimv2_df_election_flag_values,
1181ee67461eSJoseph Mingrone 			 "Unknown", subtype) );
1182ee67461eSJoseph Mingrone 
1183ee67461eSJoseph Mingrone 		ND_PRINT(" rpa=");
1184ee67461eSJoseph Mingrone 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0) {
1185ee67461eSJoseph Mingrone 			goto trunc;
1186ee67461eSJoseph Mingrone 		}
1187ee67461eSJoseph Mingrone 		bp += advance;
1188ee67461eSJoseph Mingrone 		len -= advance;
1189ee67461eSJoseph Mingrone 		ND_PRINT(" sender pref=%u", GET_BE_U_4(bp) );
1190ee67461eSJoseph Mingrone 		ND_PRINT(" sender metric=%u", GET_BE_U_4(bp + 4));
1191ee67461eSJoseph Mingrone 
1192ee67461eSJoseph Mingrone 		bp += 8;
1193ee67461eSJoseph Mingrone 		len -= 8;
1194ee67461eSJoseph Mingrone 
1195ee67461eSJoseph Mingrone 		switch (subtype) {
1196ee67461eSJoseph Mingrone 		case PIMV2_DF_ELECTION_BACKOFF:
1197ee67461eSJoseph Mingrone 		case PIMV2_DF_ELECTION_PASS:
1198ee67461eSJoseph Mingrone 			ND_PRINT("\n\t  %s addr=", PIMV2_DF_ELECTION_PASS_BACKOFF_STR(subtype));
1199ee67461eSJoseph Mingrone 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0) {
1200ee67461eSJoseph Mingrone 				goto trunc;
1201ee67461eSJoseph Mingrone 			}
1202ee67461eSJoseph Mingrone 			bp += advance;
1203ee67461eSJoseph Mingrone 			len -= advance;
1204ee67461eSJoseph Mingrone 
1205ee67461eSJoseph Mingrone 			ND_PRINT(" %s pref=%u", PIMV2_DF_ELECTION_PASS_BACKOFF_STR(subtype), GET_BE_U_4(bp) );
1206ee67461eSJoseph Mingrone 			ND_PRINT(" %s metric=%u", PIMV2_DF_ELECTION_PASS_BACKOFF_STR(subtype), GET_BE_U_4(bp + 4));
1207ee67461eSJoseph Mingrone 
1208ee67461eSJoseph Mingrone 			bp += 8;
1209ee67461eSJoseph Mingrone 			len -= 8;
1210ee67461eSJoseph Mingrone 
1211ee67461eSJoseph Mingrone 			if (subtype == PIMV2_DF_ELECTION_BACKOFF) {
1212ee67461eSJoseph Mingrone 				ND_PRINT(" interval %dms", GET_BE_U_2(bp));
1213ee67461eSJoseph Mingrone 			}
1214ee67461eSJoseph Mingrone 
1215ee67461eSJoseph Mingrone 			break;
1216ee67461eSJoseph Mingrone 		default:
1217ee67461eSJoseph Mingrone 			break;
1218ee67461eSJoseph Mingrone 		}
1219ee67461eSJoseph Mingrone 		break;
1220b0453382SBill Fenner 
1221b0453382SBill Fenner 	 default:
1222ee67461eSJoseph Mingrone 		ND_PRINT(" [type %u]", PIM_TYPE(pim_typever));
1223b0453382SBill Fenner 		break;
1224b0453382SBill Fenner 	}
1225b0453382SBill Fenner 
1226b0453382SBill Fenner 	return;
1227b0453382SBill Fenner 
1228b0453382SBill Fenner trunc:
1229ee67461eSJoseph Mingrone 	nd_print_trunc(ndo);
12304edb46e9SPaul Traina }
1231