xref: /freebsd/contrib/tcpdump/print-pim.c (revision 0a7e5f1f02aad2ff5fff1c60f44c6975fd07e1d9)
1 /*
2  * Copyright (c) 1995, 1996
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the University of California,
13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21 
22 /* \summary: Protocol Independent Multicast (PIM) printer */
23 
24 #include <config.h>
25 
26 #include "netdissect-stdinc.h"
27 
28 #include "netdissect.h"
29 #include "addrtoname.h"
30 #include "extract.h"
31 
32 #include "ip.h"
33 #include "ip6.h"
34 #include "ipproto.h"
35 
36 #define PIMV1_TYPE_QUERY           0
37 #define PIMV1_TYPE_REGISTER        1
38 #define PIMV1_TYPE_REGISTER_STOP   2
39 #define PIMV1_TYPE_JOIN_PRUNE      3
40 #define PIMV1_TYPE_RP_REACHABILITY 4
41 #define PIMV1_TYPE_ASSERT          5
42 #define PIMV1_TYPE_GRAFT           6
43 #define PIMV1_TYPE_GRAFT_ACK       7
44 
45 static const struct tok pimv1_type_str[] = {
46 	{ PIMV1_TYPE_QUERY,           "Query"         },
47 	{ PIMV1_TYPE_REGISTER,        "Register"      },
48 	{ PIMV1_TYPE_REGISTER_STOP,   "Register-Stop" },
49 	{ PIMV1_TYPE_JOIN_PRUNE,      "Join/Prune"    },
50 	{ PIMV1_TYPE_RP_REACHABILITY, "RP-reachable"  },
51 	{ PIMV1_TYPE_ASSERT,          "Assert"        },
52 	{ PIMV1_TYPE_GRAFT,           "Graft"         },
53 	{ PIMV1_TYPE_GRAFT_ACK,       "Graft-ACK"     },
54 	{ 0, NULL }
55 };
56 
57 #define PIMV2_TYPE_HELLO         0
58 #define PIMV2_TYPE_REGISTER      1
59 #define PIMV2_TYPE_REGISTER_STOP 2
60 #define PIMV2_TYPE_JOIN_PRUNE    3
61 #define PIMV2_TYPE_BOOTSTRAP     4
62 #define PIMV2_TYPE_ASSERT        5
63 #define PIMV2_TYPE_GRAFT         6
64 #define PIMV2_TYPE_GRAFT_ACK     7
65 #define PIMV2_TYPE_CANDIDATE_RP  8
66 #define PIMV2_TYPE_PRUNE_REFRESH 9
67 #define PIMV2_TYPE_DF_ELECTION   10
68 #define PIMV2_TYPE_ECMP_REDIRECT 11
69 
70 static const struct tok pimv2_type_values[] = {
71     { PIMV2_TYPE_HELLO,         "Hello" },
72     { PIMV2_TYPE_REGISTER,      "Register" },
73     { PIMV2_TYPE_REGISTER_STOP, "Register Stop" },
74     { PIMV2_TYPE_JOIN_PRUNE,    "Join / Prune" },
75     { PIMV2_TYPE_BOOTSTRAP,     "Bootstrap" },
76     { PIMV2_TYPE_ASSERT,        "Assert" },
77     { PIMV2_TYPE_GRAFT,         "Graft" },
78     { PIMV2_TYPE_GRAFT_ACK,     "Graft Acknowledgement" },
79     { PIMV2_TYPE_CANDIDATE_RP,  "Candidate RP Advertisement" },
80     { PIMV2_TYPE_PRUNE_REFRESH, "Prune Refresh" },
81     { PIMV2_TYPE_DF_ELECTION,   "DF Election" },
82     { PIMV2_TYPE_ECMP_REDIRECT, "ECMP Redirect" },
83     { 0, NULL}
84 };
85 
86 #define PIMV2_HELLO_OPTION_HOLDTIME             1
87 #define PIMV2_HELLO_OPTION_LANPRUNEDELAY        2
88 #define PIMV2_HELLO_OPTION_DR_PRIORITY_OLD     18
89 #define PIMV2_HELLO_OPTION_DR_PRIORITY         19
90 #define PIMV2_HELLO_OPTION_GENID               20
91 #define PIMV2_HELLO_OPTION_REFRESH_CAP         21
92 #define PIMV2_HELLO_OPTION_BIDIR_CAP           22
93 #define PIMV2_HELLO_OPTION_ADDRESS_LIST        24
94 #define PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD 65001
95 
96 static const struct tok pimv2_hello_option_values[] = {
97     { PIMV2_HELLO_OPTION_HOLDTIME,         "Hold Time" },
98     { PIMV2_HELLO_OPTION_LANPRUNEDELAY,    "LAN Prune Delay" },
99     { PIMV2_HELLO_OPTION_DR_PRIORITY_OLD,  "DR Priority (Old)" },
100     { PIMV2_HELLO_OPTION_DR_PRIORITY,      "DR Priority" },
101     { PIMV2_HELLO_OPTION_GENID,            "Generation ID" },
102     { PIMV2_HELLO_OPTION_REFRESH_CAP,      "State Refresh Capability" },
103     { PIMV2_HELLO_OPTION_BIDIR_CAP,        "Bi-Directional Capability" },
104     { PIMV2_HELLO_OPTION_ADDRESS_LIST,     "Address List" },
105     { PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD, "Address List (Old)" },
106     { 0, NULL}
107 };
108 
109 #define PIMV2_REGISTER_FLAG_LEN      4
110 #define PIMV2_REGISTER_FLAG_BORDER 0x80000000
111 #define PIMV2_REGISTER_FLAG_NULL   0x40000000
112 
113 static const struct tok pimv2_register_flag_values[] = {
114     { PIMV2_REGISTER_FLAG_BORDER, "Border" },
115     { PIMV2_REGISTER_FLAG_NULL, "Null" },
116     { 0, NULL}
117 };
118 
119 #define PIMV2_DF_ELECTION_OFFER                  1
120 #define PIMV2_DF_ELECTION_WINNER                 2
121 #define PIMV2_DF_ELECTION_BACKOFF                3
122 #define PIMV2_DF_ELECTION_PASS                   4
123 
124 static const struct tok pimv2_df_election_flag_values[] = {
125     { PIMV2_DF_ELECTION_OFFER, "Offer" },
126     { PIMV2_DF_ELECTION_WINNER, "Winner" },
127     { PIMV2_DF_ELECTION_BACKOFF, "Backoff" },
128     { PIMV2_DF_ELECTION_PASS, "Pass" },
129     { 0, NULL}
130 };
131 
132 #define PIMV2_DF_ELECTION_PASS_BACKOFF_STR(x)   ( \
133       x == PIMV2_DF_ELECTION_BACKOFF ? "offer" : "new winner" )
134 
135 
136 /*
137  * XXX: We consider a case where IPv6 is not ready yet for portability,
138  * but PIM dependent definitions should be independent of IPv6...
139  */
140 
141 struct pim {
142 	nd_uint8_t	pim_typever;
143 			/* upper 4bit: PIM version number; 2 for PIMv2 */
144 			/* lower 4bit: the PIM message type, currently they are:
145 			 * Hello, Register, Register-Stop, Join/Prune,
146 			 * Bootstrap, Assert, Graft (PIM-DM only),
147 			 * Graft-Ack (PIM-DM only), C-RP-Adv
148 			 */
149 #define PIM_VER(x)	(((x) & 0xf0) >> 4)
150 #define PIM_TYPE(x)	((x) & 0x0f)
151 	nd_uint8_t	pim_rsv;	/* Reserved in v1, subtype+address length in v2 */
152 #define PIM_SUBTYPE(x)  (((x) & 0xf0) >> 4)
153 	nd_uint16_t	pim_cksum;	/* IP style check sum */
154 };
155 
156 static void pimv2_print(netdissect_options *, const u_char *bp, u_int len, const u_char *);
157 
158 static void
pimv1_join_prune_print(netdissect_options * ndo,const u_char * bp,u_int len)159 pimv1_join_prune_print(netdissect_options *ndo,
160                        const u_char *bp, u_int len)
161 {
162 	u_int ngroups, njoin, nprune;
163 	u_int njp;
164 
165 	/* If it's a single group and a single source, use 1-line output. */
166 	if (ND_TTEST_LEN(bp, 30) && GET_U_1(bp + 11) == 1 &&
167 	    ((njoin = GET_BE_U_2(bp + 20)) + GET_BE_U_2(bp + 22)) == 1) {
168 		u_int hold;
169 
170 		ND_PRINT(" RPF %s ", GET_IPADDR_STRING(bp));
171 		hold = GET_BE_U_2(bp + 6);
172 		if (hold != 180) {
173 			ND_PRINT("Hold ");
174 			unsigned_relts_print(ndo, hold);
175 		}
176 		ND_PRINT("%s (%s/%u, %s", njoin ? "Join" : "Prune",
177 		GET_IPADDR_STRING(bp + 26), GET_U_1(bp + 25) & 0x3f,
178 		GET_IPADDR_STRING(bp + 12));
179 		if (GET_BE_U_4(bp + 16) != 0xffffffff)
180 			ND_PRINT("/%s", GET_IPADDR_STRING(bp + 16));
181 		ND_PRINT(") %s%s %s",
182 		    (GET_U_1(bp + 24) & 0x01) ? "Sparse" : "Dense",
183 		    (GET_U_1(bp + 25) & 0x80) ? " WC" : "",
184 		    (GET_U_1(bp + 25) & 0x40) ? "RP" : "SPT");
185 		return;
186 	}
187 
188 	if (len < sizeof(nd_ipv4))
189 		goto trunc;
190 	if (ndo->ndo_vflag > 1)
191 		ND_PRINT("\n");
192 	ND_PRINT(" Upstream Nbr: %s", GET_IPADDR_STRING(bp));
193 	bp += 4;
194 	len -= 4;
195 	if (len < 4)
196 		goto trunc;
197 	if (ndo->ndo_vflag > 1)
198 		ND_PRINT("\n");
199 	ND_PRINT(" Hold time: ");
200 	unsigned_relts_print(ndo, GET_BE_U_2(bp + 2));
201 	if (ndo->ndo_vflag < 2)
202 		return;
203 	bp += 4;
204 	len -= 4;
205 
206 	if (len < 4)
207 		goto trunc;
208 	ngroups = GET_U_1(bp + 3);
209 	bp += 4;
210 	len -= 4;
211 	while (ngroups != 0) {
212 		/*
213 		 * XXX - does the address have length "addrlen" and the
214 		 * mask length "maddrlen"?
215 		 */
216 		if (len < 4)
217 			goto trunc;
218 		ND_PRINT("\n\tGroup: %s", GET_IPADDR_STRING(bp));
219 		bp += 4;
220 		len -= 4;
221 		if (len < 4)
222 			goto trunc;
223 		if (GET_BE_U_4(bp) != 0xffffffff)
224 			ND_PRINT("/%s", GET_IPADDR_STRING(bp));
225 		bp += 4;
226 		len -= 4;
227 		if (len < 4)
228 			goto trunc;
229 		njoin = GET_BE_U_2(bp);
230 		nprune = GET_BE_U_2(bp + 2);
231 		ND_PRINT(" joined: %u pruned: %u", njoin, nprune);
232 		bp += 4;
233 		len -= 4;
234 		for (njp = 0; njp < (njoin + nprune); njp++) {
235 			const char *type;
236 
237 			if (njp < njoin)
238 				type = "Join ";
239 			else
240 				type = "Prune";
241 			if (len < 6)
242 				goto trunc;
243 			ND_PRINT("\n\t%s %s%s%s%s/%u", type,
244 			    (GET_U_1(bp) & 0x01) ? "Sparse " : "Dense ",
245 			    (GET_U_1(bp + 1) & 0x80) ? "WC " : "",
246 			    (GET_U_1(bp + 1) & 0x40) ? "RP " : "SPT ",
247 			    GET_IPADDR_STRING(bp + 2),
248 			    GET_U_1(bp + 1) & 0x3f);
249 			bp += 6;
250 			len -= 6;
251 		}
252 		ngroups--;
253 	}
254 	return;
255 trunc:
256 	nd_print_trunc(ndo);
257 }
258 
259 void
pimv1_print(netdissect_options * ndo,const u_char * bp,u_int len)260 pimv1_print(netdissect_options *ndo,
261             const u_char *bp, u_int len)
262 {
263 	u_char type;
264 
265 	ndo->ndo_protocol = "pimv1";
266 	type = GET_U_1(bp + 1);
267 
268 	ND_PRINT(" %s", tok2str(pimv1_type_str, "[type %u]", type));
269 	switch (type) {
270 	case PIMV1_TYPE_QUERY:
271 		if (ND_TTEST_1(bp + 8)) {
272 			switch (GET_U_1(bp + 8) >> 4) {
273 			case 0:
274 				ND_PRINT(" Dense-mode");
275 				break;
276 			case 1:
277 				ND_PRINT(" Sparse-mode");
278 				break;
279 			case 2:
280 				ND_PRINT(" Sparse-Dense-mode");
281 				break;
282 			default:
283 				ND_PRINT(" mode-%u", GET_U_1(bp + 8) >> 4);
284 				break;
285 			}
286 		}
287 		if (ndo->ndo_vflag) {
288 			ND_PRINT(" (Hold-time ");
289 			unsigned_relts_print(ndo, GET_BE_U_2(bp + 10));
290 			ND_PRINT(")");
291 		}
292 		break;
293 
294 	case PIMV1_TYPE_REGISTER:
295 		ND_TCHECK_LEN(bp + 8, 20);			/* ip header */
296 		ND_PRINT(" for %s > %s", GET_IPADDR_STRING(bp + 20),
297 			  GET_IPADDR_STRING(bp + 24));
298 		break;
299 	case PIMV1_TYPE_REGISTER_STOP:
300 		ND_PRINT(" for %s > %s", GET_IPADDR_STRING(bp + 8),
301 			  GET_IPADDR_STRING(bp + 12));
302 		break;
303 	case PIMV1_TYPE_RP_REACHABILITY:
304 		if (ndo->ndo_vflag) {
305 			ND_PRINT(" group %s", GET_IPADDR_STRING(bp + 8));
306 			if (GET_BE_U_4(bp + 12) != 0xffffffff)
307 				ND_PRINT("/%s", GET_IPADDR_STRING(bp + 12));
308 			ND_PRINT(" RP %s hold ", GET_IPADDR_STRING(bp + 16));
309 			unsigned_relts_print(ndo, GET_BE_U_2(bp + 22));
310 		}
311 		break;
312 	case PIMV1_TYPE_ASSERT:
313 		ND_PRINT(" for %s > %s", GET_IPADDR_STRING(bp + 16),
314 			  GET_IPADDR_STRING(bp + 8));
315 		if (GET_BE_U_4(bp + 12) != 0xffffffff)
316 			ND_PRINT("/%s", GET_IPADDR_STRING(bp + 12));
317 		ND_PRINT(" %s pref %u metric %u",
318 		    (GET_U_1(bp + 20) & 0x80) ? "RP-tree" : "SPT",
319 		    GET_BE_U_4(bp + 20) & 0x7fffffff,
320 		    GET_BE_U_4(bp + 24));
321 		break;
322 	case PIMV1_TYPE_JOIN_PRUNE:
323 	case PIMV1_TYPE_GRAFT:
324 	case PIMV1_TYPE_GRAFT_ACK:
325 		if (ndo->ndo_vflag) {
326 			if (len < 8)
327 				goto trunc;
328 			pimv1_join_prune_print(ndo, bp + 8, len - 8);
329 		}
330 		break;
331 	}
332 	if ((GET_U_1(bp + 4) >> 4) != 1)
333 		ND_PRINT(" [v%u]", GET_U_1(bp + 4) >> 4);
334 	return;
335 
336 trunc:
337 	nd_print_trunc(ndo);
338 }
339 
340 /*
341  * auto-RP is a cisco protocol, documented at
342  * ftp://ftpeng.cisco.com/ipmulticast/specs/pim-autorp-spec01.txt
343  *
344  * This implements version 1+, dated Sept 9, 1998.
345  */
346 void
cisco_autorp_print(netdissect_options * ndo,const u_char * bp,u_int len)347 cisco_autorp_print(netdissect_options *ndo,
348                    const u_char *bp, u_int len)
349 {
350 	u_int type;
351 	u_int numrps;
352 	u_int hold;
353 
354 	ndo->ndo_protocol = "cisco_autorp";
355 	if (len < 8)
356 		goto trunc;
357 	ND_PRINT(" auto-rp ");
358 	type = GET_U_1(bp);
359 	switch (type) {
360 	case 0x11:
361 		ND_PRINT("candidate-advert");
362 		break;
363 	case 0x12:
364 		ND_PRINT("mapping");
365 		break;
366 	default:
367 		ND_PRINT("type-0x%02x", type);
368 		break;
369 	}
370 
371 	numrps = GET_U_1(bp + 1);
372 
373 	ND_PRINT(" Hold ");
374 	hold = GET_BE_U_2(bp + 2);
375 	if (hold)
376 		unsigned_relts_print(ndo, GET_BE_U_2(bp + 2));
377 	else
378 		ND_PRINT("FOREVER");
379 
380 	/* Next 4 bytes are reserved. */
381 
382 	bp += 8; len -= 8;
383 
384 	/*XXX skip unless -v? */
385 
386 	/*
387 	 * Rest of packet:
388 	 * numrps entries of the form:
389 	 * 32 bits: RP
390 	 * 6 bits: reserved
391 	 * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
392 	 * 8 bits: # of entries for this RP
393 	 * each entry: 7 bits: reserved, 1 bit: negative,
394 	 *	       8 bits: mask 32 bits: source
395 	 * lather, rinse, repeat.
396 	 */
397 	while (numrps != 0) {
398 		u_int nentries;
399 		char s;
400 
401 		if (len < 4)
402 			goto trunc;
403 		ND_PRINT(" RP %s", GET_IPADDR_STRING(bp));
404 		bp += 4;
405 		len -= 4;
406 		if (len < 1)
407 			goto trunc;
408 		switch (GET_U_1(bp) & 0x3) {
409 		case 0: ND_PRINT(" PIMv?");
410 			break;
411 		case 1:	ND_PRINT(" PIMv1");
412 			break;
413 		case 2:	ND_PRINT(" PIMv2");
414 			break;
415 		case 3:	ND_PRINT(" PIMv1+2");
416 			break;
417 		}
418 		if (GET_U_1(bp) & 0xfc)
419 			ND_PRINT(" [rsvd=0x%02x]", GET_U_1(bp) & 0xfc);
420 		bp += 1;
421 		len -= 1;
422 		if (len < 1)
423 			goto trunc;
424 		nentries = GET_U_1(bp);
425 		bp += 1;
426 		len -= 1;
427 		s = ' ';
428 		while (nentries != 0) {
429 			if (len < 6)
430 				goto trunc;
431 			ND_PRINT("%c%s%s/%u", s, GET_U_1(bp) & 1 ? "!" : "",
432 			          GET_IPADDR_STRING(bp + 2), GET_U_1(bp + 1));
433 			if (GET_U_1(bp) & 0x02) {
434 				ND_PRINT(" bidir");
435 			}
436 			if (GET_U_1(bp) & 0xfc) {
437 				ND_PRINT("[rsvd=0x%02x]", GET_U_1(bp) & 0xfc);
438 			}
439 			s = ',';
440 			bp += 6; len -= 6;
441 			nentries--;
442 		}
443 		numrps--;
444 	}
445 	return;
446 
447 trunc:
448 	nd_print_trunc(ndo);
449 }
450 
451 void
pim_print(netdissect_options * ndo,const u_char * bp,u_int len,const u_char * bp2)452 pim_print(netdissect_options *ndo,
453           const u_char *bp, u_int len, const u_char *bp2)
454 {
455 	const struct pim *pim = (const struct pim *)bp;
456 	uint8_t pim_typever;
457 
458 	ndo->ndo_protocol = "pim";
459 
460 	pim_typever = GET_U_1(pim->pim_typever);
461 	switch (PIM_VER(pim_typever)) {
462 	case 2:
463 		if (!ndo->ndo_vflag) {
464 			ND_PRINT("PIMv%u, %s, length %u",
465 			          PIM_VER(pim_typever),
466 			          tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim_typever)),
467 			          len);
468 			return;
469 		} else {
470 			ND_PRINT("PIMv%u, length %u\n\t%s",
471 			          PIM_VER(pim_typever),
472 			          len,
473 			          tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim_typever)));
474 			pimv2_print(ndo, bp, len, bp2);
475 		}
476 		break;
477 	default:
478 		ND_PRINT("PIMv%u, length %u",
479 		          PIM_VER(pim_typever),
480 		          len);
481 		break;
482 	}
483 }
484 
485 /*
486  * PIMv2 uses encoded address representations.
487  *
488  * The last PIM-SM I-D before RFC2117 was published specified the
489  * following representation for unicast addresses.  However, RFC2117
490  * specified no encoding for unicast addresses with the unicast
491  * address length specified in the header.  Therefore, we have to
492  * guess which encoding is being used (Cisco's PIMv2 implementation
493  * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
494  * field into a 'unicast-address-length-in-bytes' field.  We guess
495  * that it's the draft encoding if this reserved field is zero.
496  *
497  * RFC2362 goes back to the encoded format, and calls the addr length
498  * field "reserved" again.
499  *
500  * The first byte is the address family, from:
501  *
502  *    0    Reserved
503  *    1    IP (IP version 4)
504  *    2    IP6 (IP version 6)
505  *    3    NSAP
506  *    4    HDLC (8-bit multidrop)
507  *    5    BBN 1822
508  *    6    802 (includes all 802 media plus Ethernet "canonical format")
509  *    7    E.163
510  *    8    E.164 (SMDS, Frame Relay, ATM)
511  *    9    F.69 (Telex)
512  *   10    X.121 (X.25, Frame Relay)
513  *   11    IPX
514  *   12    Appletalk
515  *   13    Decnet IV
516  *   14    Banyan Vines
517  *   15    E.164 with NSAP format subaddress
518  *
519  * In addition, the second byte is an "Encoding".  0 is the default
520  * encoding for the address family, and no other encodings are currently
521  * specified.
522  *
523  */
524 
525 enum pimv2_addrtype {
526 	pimv2_unicast, pimv2_group, pimv2_source
527 };
528 
529 /*  0                   1                   2                   3
530  *  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
531  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
532  * | Addr Family   | Encoding Type |     Unicast Address           |
533  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
534  *  0                   1                   2                   3
535  *  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
536  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
537  * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
538  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
539  * |                Group multicast Address                        |
540  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
541  *  0                   1                   2                   3
542  *  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
543  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
544  * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
545  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
546  * |                        Source Address                         |
547  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
548  */
549 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)550 pimv2_addr_print(netdissect_options *ndo,
551                  const u_char *bp, u_int len, enum pimv2_addrtype at,
552                  u_int addr_len, int silent)
553 {
554 	u_int af;
555 	int hdrlen;
556 
557 	if (addr_len == 0) {
558 		if (len < 2)
559 			goto trunc;
560 		switch (GET_U_1(bp)) {
561 		case 1:
562 			af = AF_INET;
563 			addr_len = (u_int)sizeof(nd_ipv4);
564 			break;
565 		case 2:
566 			af = AF_INET6;
567 			addr_len = (u_int)sizeof(nd_ipv6);
568 			break;
569 		default:
570 			return -1;
571 		}
572 		if (GET_U_1(bp + 1) != 0)
573 			return -1;
574 		hdrlen = 2;
575 	} else {
576 		switch (addr_len) {
577 		case sizeof(nd_ipv4):
578 			af = AF_INET;
579 			break;
580 		case sizeof(nd_ipv6):
581 			af = AF_INET6;
582 			break;
583 		default:
584 			return -1;
585 			break;
586 		}
587 		hdrlen = 0;
588 	}
589 
590 	bp += hdrlen;
591 	len -= hdrlen;
592 	switch (at) {
593 	case pimv2_unicast:
594 		if (len < addr_len)
595 			goto trunc;
596 		ND_TCHECK_LEN(bp, addr_len);
597 		if (af == AF_INET) {
598 			if (!silent)
599 				ND_PRINT("%s", GET_IPADDR_STRING(bp));
600 		} else if (af == AF_INET6) {
601 			if (!silent)
602 				ND_PRINT("%s", GET_IP6ADDR_STRING(bp));
603 		}
604 		return hdrlen + addr_len;
605 	case pimv2_group:
606 	case pimv2_source:
607 		if (len < addr_len + 2)
608 			goto trunc;
609 		ND_TCHECK_LEN(bp, addr_len + 2);
610 		if (af == AF_INET) {
611 			if (!silent) {
612 				ND_PRINT("%s", GET_IPADDR_STRING(bp + 2));
613 				if (GET_U_1(bp + 1) != 32)
614 					ND_PRINT("/%u", GET_U_1(bp + 1));
615 			}
616 		} else if (af == AF_INET6) {
617 			if (!silent) {
618 				ND_PRINT("%s", GET_IP6ADDR_STRING(bp + 2));
619 				if (GET_U_1(bp + 1) != 128)
620 					ND_PRINT("/%u", GET_U_1(bp + 1));
621 			}
622 		}
623 		if (GET_U_1(bp) && !silent) {
624 			if (at == pimv2_group) {
625 				ND_PRINT("(0x%02x)", GET_U_1(bp));
626 			} else {
627 				ND_PRINT("(%s%s%s",
628 					GET_U_1(bp) & 0x04 ? "S" : "",
629 					GET_U_1(bp) & 0x02 ? "W" : "",
630 					GET_U_1(bp) & 0x01 ? "R" : "");
631 				if (GET_U_1(bp) & 0xf8) {
632 					ND_PRINT("+0x%02x",
633 						 GET_U_1(bp) & 0xf8);
634 				}
635 				ND_PRINT(")");
636 			}
637 		}
638 		return hdrlen + 2 + addr_len;
639 	default:
640 		return -1;
641 	}
642 trunc:
643 	return -1;
644 }
645 
646 enum checksum_status {
647 	CORRECT,
648 	INCORRECT,
649 	UNVERIFIED
650 };
651 
652 static enum checksum_status
pimv2_check_checksum(netdissect_options * ndo,const u_char * bp,const u_char * bp2,u_int len)653 pimv2_check_checksum(netdissect_options *ndo, const u_char *bp,
654 		     const u_char *bp2, u_int len)
655 {
656 	const struct ip *ip;
657 	u_int cksum;
658 
659 	if (!ND_TTEST_LEN(bp, len)) {
660 		/* We don't have all the data. */
661 		return (UNVERIFIED);
662 	}
663 	ip = (const struct ip *)bp2;
664 	if (IP_V(ip) == 4) {
665 		struct cksum_vec vec[1];
666 
667 		vec[0].ptr = bp;
668 		vec[0].len = len;
669 		cksum = in_cksum(vec, 1);
670 		return (cksum ? INCORRECT : CORRECT);
671 	} else if (IP_V(ip) == 6) {
672 		const struct ip6_hdr *ip6;
673 
674 		ip6 = (const struct ip6_hdr *)bp2;
675 		cksum = nextproto6_cksum(ndo, ip6, bp, len, len, IPPROTO_PIM);
676 		return (cksum ? INCORRECT : CORRECT);
677 	} else {
678 		return (UNVERIFIED);
679 	}
680 }
681 
682 static void
pimv2_print(netdissect_options * ndo,const u_char * bp,u_int len,const u_char * bp2)683 pimv2_print(netdissect_options *ndo,
684             const u_char *bp, u_int len, const u_char *bp2)
685 {
686 	const struct pim *pim = (const struct pim *)bp;
687 	int advance;
688 	int subtype;
689 	enum checksum_status cksum_status;
690 	u_int pim_typever;
691 	u_int pimv2_addr_len;
692 
693 	ndo->ndo_protocol = "pimv2";
694 	if (len < 2) {
695 		ND_PRINT("[length %u < 2]", len);
696 		nd_print_invalid(ndo);
697 		return;
698 	}
699 	pim_typever = GET_U_1(pim->pim_typever);
700 	/* RFC5015 allocates the high 4 bits of pim_rsv for "subtype". */
701 	pimv2_addr_len = GET_U_1(pim->pim_rsv) & 0x0f;
702 	if (pimv2_addr_len != 0)
703 		ND_PRINT(", RFC2117-encoding");
704 
705 	if (len < 4) {
706 		ND_PRINT("[length %u < 4]", len);
707 		nd_print_invalid(ndo);
708 		return;
709 	}
710 	ND_PRINT(", cksum 0x%04x ", GET_BE_U_2(pim->pim_cksum));
711 	if (GET_BE_U_2(pim->pim_cksum) == 0) {
712 		ND_PRINT("(unverified)");
713 	} else {
714 		if (PIM_TYPE(pim_typever) == PIMV2_TYPE_REGISTER) {
715 			/*
716 			 * The checksum only covers the packet header,
717 			 * not the encapsulated packet.
718 			 */
719 			cksum_status = pimv2_check_checksum(ndo, bp, bp2, 8);
720 			if (cksum_status == INCORRECT) {
721 				/*
722 				 * To quote RFC 4601, "For interoperability
723 				 * reasons, a message carrying a checksum
724 				 * calculated over the entire PIM Register
725 				 * message should also be accepted."
726 				 */
727 				cksum_status = pimv2_check_checksum(ndo, bp, bp2, len);
728 			}
729 		} else {
730 			/*
731 			 * The checksum covers the entire packet.
732 			 */
733 			cksum_status = pimv2_check_checksum(ndo, bp, bp2, len);
734 		}
735 		switch (cksum_status) {
736 
737 		case CORRECT:
738 			ND_PRINT("(correct)");
739 			break;
740 
741 		case INCORRECT:
742 			ND_PRINT("(incorrect)");
743 			break;
744 
745 		case UNVERIFIED:
746 			ND_PRINT("(unverified)");
747 			break;
748 		}
749 	}
750 	bp += 4;
751 	len -= 4;
752 
753 	switch (PIM_TYPE(pim_typever)) {
754 	case PIMV2_TYPE_HELLO:
755 	    {
756 		uint16_t otype, olen;
757 		while (len > 0) {
758 			if (len < 4)
759 				goto trunc;
760 			otype = GET_BE_U_2(bp);
761 			olen = GET_BE_U_2(bp + 2);
762 			ND_PRINT("\n\t  %s Option (%u), length %u, Value: ",
763 			          tok2str(pimv2_hello_option_values, "Unknown", otype),
764 			          otype,
765 			          olen);
766 			bp += 4;
767 			len -= 4;
768 
769 			if (len < olen)
770 				goto trunc;
771 			ND_TCHECK_LEN(bp, olen);
772 			switch (otype) {
773 			case PIMV2_HELLO_OPTION_HOLDTIME:
774 				if (olen != 2) {
775 					ND_PRINT("[option length %u != 2]", olen);
776 					nd_print_invalid(ndo);
777 					return;
778 				} else {
779 					unsigned_relts_print(ndo,
780 							     GET_BE_U_2(bp));
781 				}
782 				break;
783 
784 			case PIMV2_HELLO_OPTION_LANPRUNEDELAY:
785 				if (olen != 4) {
786 					ND_PRINT("[option length %u != 4]", olen);
787 					nd_print_invalid(ndo);
788 					return;
789 				} else {
790 					char t_bit;
791 					uint16_t lan_delay, override_interval;
792 					lan_delay = GET_BE_U_2(bp);
793 					override_interval = GET_BE_U_2(bp + 2);
794 					t_bit = (lan_delay & 0x8000)? 1 : 0;
795 					lan_delay &= ~0x8000;
796 					ND_PRINT("\n\t    T-bit=%u, LAN delay %ums, Override interval %ums",
797 					t_bit, lan_delay, override_interval);
798 				}
799 				break;
800 
801 			case PIMV2_HELLO_OPTION_DR_PRIORITY_OLD:
802 			case PIMV2_HELLO_OPTION_DR_PRIORITY:
803 				switch (olen) {
804 				case 0:
805 					ND_PRINT("Bi-Directional Capability (Old)");
806 					break;
807 				case 4:
808 					ND_PRINT("%u", GET_BE_U_4(bp));
809 					break;
810 				default:
811 					ND_PRINT("[option length %u != 4]", olen);
812 					nd_print_invalid(ndo);
813 					return;
814 					break;
815 				}
816 				break;
817 
818 			case PIMV2_HELLO_OPTION_GENID:
819 				if (olen != 4) {
820 					ND_PRINT("[option length %u != 4]", olen);
821 					nd_print_invalid(ndo);
822 					return;
823 				} else {
824 					ND_PRINT("0x%08x", GET_BE_U_4(bp));
825 				}
826 				break;
827 
828 			case PIMV2_HELLO_OPTION_REFRESH_CAP:
829 				if (olen != 4) {
830 					ND_PRINT("[option length %u != 4]", olen);
831 					nd_print_invalid(ndo);
832 					return;
833 				} else {
834 					ND_PRINT("v%u", GET_U_1(bp));
835 					if (GET_U_1(bp + 1) != 0) {
836 						ND_PRINT(", interval ");
837 						unsigned_relts_print(ndo,
838 								     GET_U_1(bp + 1));
839 					}
840 					if (GET_BE_U_2(bp + 2) != 0) {
841 						ND_PRINT(" ?0x%04x?",
842 							 GET_BE_U_2(bp + 2));
843 					}
844 				}
845 				break;
846 
847 			case  PIMV2_HELLO_OPTION_BIDIR_CAP:
848 				break;
849 
850 			case PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD:
851 			case PIMV2_HELLO_OPTION_ADDRESS_LIST:
852 				if (ndo->ndo_vflag > 1) {
853 					const u_char *ptr = bp;
854 					u_int plen = len;
855 					while (ptr < (bp+olen)) {
856 						ND_PRINT("\n\t    ");
857 						advance = pimv2_addr_print(ndo, ptr, plen, pimv2_unicast, pimv2_addr_len, 0);
858 						if (advance < 0)
859 							goto trunc;
860 						ptr += advance;
861 						plen -= advance;
862 					}
863 				}
864 				break;
865 			default:
866 				if (ndo->ndo_vflag <= 1)
867 					print_unknown_data(ndo, bp, "\n\t    ", olen);
868 				break;
869 			}
870 			/* do we want to see an additionally hexdump ? */
871 			if (ndo->ndo_vflag> 1)
872 				print_unknown_data(ndo, bp, "\n\t    ", olen);
873 			bp += olen;
874 			len -= olen;
875 		}
876 		break;
877 	    }
878 
879 	case PIMV2_TYPE_REGISTER:
880 	{
881 		const struct ip *ip;
882 
883 		if (len < 4)
884 			goto trunc;
885 		ND_TCHECK_LEN(bp, PIMV2_REGISTER_FLAG_LEN);
886 
887 		ND_PRINT(", Flags [ %s ]\n\t",
888 		          tok2str(pimv2_register_flag_values,
889 		          "none",
890 		          GET_BE_U_4(bp)));
891 
892 		bp += 4; len -= 4;
893 		/* encapsulated multicast packet */
894 		if (len == 0)
895 			goto trunc;
896 		ip = (const struct ip *)bp;
897 		switch (IP_V(ip)) {
898                 case 0: /* Null header */
899 			ND_PRINT("IP-Null-header %s > %s",
900 			          GET_IPADDR_STRING(ip->ip_src),
901 			          GET_IPADDR_STRING(ip->ip_dst));
902 			break;
903 
904 		case 4:	/* IPv4 */
905 			ip_print(ndo, bp, len);
906 			break;
907 
908 		case 6:	/* IPv6 */
909 			ip6_print(ndo, bp, len);
910 			break;
911 
912 		default:
913 			ND_PRINT("IP ver %u", IP_V(ip));
914 			break;
915 		}
916 		break;
917 	}
918 
919 	case PIMV2_TYPE_REGISTER_STOP:
920 		ND_PRINT(" group=");
921 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
922 			goto trunc;
923 		bp += advance; len -= advance;
924 		ND_PRINT(" source=");
925 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
926 			goto trunc;
927 		bp += advance; len -= advance;
928 		break;
929 
930 	case PIMV2_TYPE_JOIN_PRUNE:
931 	case PIMV2_TYPE_GRAFT:
932 	case PIMV2_TYPE_GRAFT_ACK:
933 
934 
935         /*
936          * 0                   1                   2                   3
937          *   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
938          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
939          *  |PIM Ver| Type  | Addr length   |           Checksum            |
940          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
941          *  |             Unicast-Upstream Neighbor Address                 |
942          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
943          *  |  Reserved     | Num groups    |          Holdtime             |
944          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
945          *  |            Encoded-Multicast Group Address-1                  |
946          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
947          *  |   Number of Joined  Sources   |   Number of Pruned Sources    |
948          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
949          *  |               Encoded-Joined Source Address-1                 |
950          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
951          *  |                             .                                 |
952          *  |                             .                                 |
953          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
954          *  |               Encoded-Joined Source Address-n                 |
955          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
956          *  |               Encoded-Pruned Source Address-1                 |
957          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
958          *  |                             .                                 |
959          *  |                             .                                 |
960          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
961          *  |               Encoded-Pruned Source Address-n                 |
962          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
963          *  |                           .                                   |
964          *  |                           .                                   |
965          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
966          *  |                Encoded-Multicast Group Address-n              |
967          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
968          */
969 
970 	    {
971 		uint8_t ngroup;
972 		uint16_t holdtime;
973 		uint16_t njoin;
974 		uint16_t nprune;
975 		u_int i, j;
976 
977 		if (PIM_TYPE(pim_typever) != 7) {	/*not for Graft-ACK*/
978 			ND_PRINT(", upstream-neighbor: ");
979 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
980 				goto trunc;
981 			bp += advance; len -= advance;
982 		}
983 		if (len < 4)
984 			goto trunc;
985 		ND_TCHECK_4(bp);
986 		ngroup = GET_U_1(bp + 1);
987 		holdtime = GET_BE_U_2(bp + 2);
988 		ND_PRINT("\n\t  %u group(s)", ngroup);
989 		if (PIM_TYPE(pim_typever) != 7) {	/*not for Graft-ACK*/
990 			ND_PRINT(", holdtime: ");
991 			if (holdtime == 0xffff)
992 				ND_PRINT("infinite");
993 			else
994 				unsigned_relts_print(ndo, holdtime);
995 		}
996 		bp += 4; len -= 4;
997 		for (i = 0; i < ngroup; i++) {
998 			ND_PRINT("\n\t    group #%u: ", i+1);
999 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
1000 				goto trunc;
1001 			bp += advance; len -= advance;
1002 			if (len < 4)
1003 				goto trunc;
1004 			ND_TCHECK_4(bp);
1005 			njoin = GET_BE_U_2(bp);
1006 			nprune = GET_BE_U_2(bp + 2);
1007 			ND_PRINT(", joined sources: %u, pruned sources: %u", njoin, nprune);
1008 			bp += 4; len -= 4;
1009 			for (j = 0; j < njoin; j++) {
1010 				ND_PRINT("\n\t      joined source #%u: ", j+1);
1011 				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
1012 					goto trunc;
1013 				bp += advance; len -= advance;
1014 			}
1015 			for (j = 0; j < nprune; j++) {
1016 				ND_PRINT("\n\t      pruned source #%u: ", j+1);
1017 				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
1018 					goto trunc;
1019 				bp += advance; len -= advance;
1020 			}
1021 		}
1022 		break;
1023 	    }
1024 
1025 	case PIMV2_TYPE_BOOTSTRAP:
1026 	{
1027 		u_int i, j, frpcnt;
1028 
1029 		/* Fragment Tag, Hash Mask len, and BSR-priority */
1030 		if (len < 2)
1031 			goto trunc;
1032 		ND_PRINT(" tag=%x", GET_BE_U_2(bp));
1033 		bp += 2;
1034 		len -= 2;
1035 		if (len < 1)
1036 			goto trunc;
1037 		ND_PRINT(" hashmlen=%u", GET_U_1(bp));
1038 		if (len < 2)
1039 			goto trunc;
1040 		ND_TCHECK_1(bp + 2);
1041 		ND_PRINT(" BSRprio=%u", GET_U_1(bp + 1));
1042 		bp += 2;
1043 		len -= 2;
1044 
1045 		/* Encoded-Unicast-BSR-Address */
1046 		ND_PRINT(" BSR=");
1047 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
1048 			goto trunc;
1049 		bp += advance;
1050 		len -= advance;
1051 
1052 		for (i = 0; len > 0; i++) {
1053 			/* Encoded-Group Address */
1054 			ND_PRINT(" (group%u: ", i);
1055 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
1056 				goto trunc;
1057 			bp += advance;
1058 			len -= advance;
1059 
1060 			/* RP-Count, Frag RP-Cnt, and rsvd */
1061 			if (len < 1)
1062 				goto trunc;
1063 			ND_PRINT(" RPcnt=%u", GET_U_1(bp));
1064 			if (len < 2)
1065 				goto trunc;
1066 			frpcnt = GET_U_1(bp + 1);
1067 			ND_PRINT(" FRPcnt=%u", frpcnt);
1068 			if (len < 4)
1069 				goto trunc;
1070 			bp += 4;
1071 			len -= 4;
1072 
1073 			for (j = 0; j < frpcnt && len > 0; j++) {
1074 				/* each RP info */
1075 				ND_PRINT(" RP%u=", j);
1076 				if ((advance = pimv2_addr_print(ndo, bp, len,
1077 								pimv2_unicast,
1078 								pimv2_addr_len,
1079 								0)) < 0)
1080 					goto trunc;
1081 				bp += advance;
1082 				len -= advance;
1083 
1084 				if (len < 2)
1085 					goto trunc;
1086 				ND_PRINT(",holdtime=");
1087 				unsigned_relts_print(ndo,
1088 						     GET_BE_U_2(bp));
1089 				if (len < 3)
1090 					goto trunc;
1091 				ND_PRINT(",prio=%u", GET_U_1(bp + 2));
1092 				if (len < 4)
1093 					goto trunc;
1094 				bp += 4;
1095 				len -= 4;
1096 			}
1097 			ND_PRINT(")");
1098 		}
1099 		break;
1100 	}
1101 	case PIMV2_TYPE_ASSERT:
1102 		ND_PRINT(" group=");
1103 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
1104 			goto trunc;
1105 		bp += advance; len -= advance;
1106 		ND_PRINT(" src=");
1107 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
1108 			goto trunc;
1109 		bp += advance; len -= advance;
1110 		if (len < 8)
1111 			goto trunc;
1112 		ND_TCHECK_8(bp);
1113 		if (GET_U_1(bp) & 0x80)
1114 			ND_PRINT(" RPT");
1115 		ND_PRINT(" pref=%u", GET_BE_U_4(bp) & 0x7fffffff);
1116 		ND_PRINT(" metric=%u", GET_BE_U_4(bp + 4));
1117 		break;
1118 
1119 	case PIMV2_TYPE_CANDIDATE_RP:
1120 	{
1121 		u_int i, pfxcnt;
1122 
1123 		/* Prefix-Cnt, Priority, and Holdtime */
1124 		if (len < 1)
1125 			goto trunc;
1126 		ND_PRINT(" prefix-cnt=%u", GET_U_1(bp));
1127 		pfxcnt = GET_U_1(bp);
1128 		if (len < 2)
1129 			goto trunc;
1130 		ND_PRINT(" prio=%u", GET_U_1(bp + 1));
1131 		if (len < 4)
1132 			goto trunc;
1133 		ND_PRINT(" holdtime=");
1134 		unsigned_relts_print(ndo, GET_BE_U_2(bp + 2));
1135 		bp += 4;
1136 		len -= 4;
1137 
1138 		/* Encoded-Unicast-RP-Address */
1139 		ND_PRINT(" RP=");
1140 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
1141 			goto trunc;
1142 		bp += advance;
1143 		len -= advance;
1144 
1145 		/* Encoded-Group Addresses */
1146 		for (i = 0; i < pfxcnt && len > 0; i++) {
1147 			ND_PRINT(" Group%u=", i);
1148 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
1149 				goto trunc;
1150 			bp += advance;
1151 			len -= advance;
1152 		}
1153 		break;
1154 	}
1155 
1156 	case PIMV2_TYPE_PRUNE_REFRESH:
1157 		ND_PRINT(" src=");
1158 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
1159 			goto trunc;
1160 		bp += advance;
1161 		len -= advance;
1162 		ND_PRINT(" grp=");
1163 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
1164 			goto trunc;
1165 		bp += advance;
1166 		len -= advance;
1167 		ND_PRINT(" forwarder=");
1168 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
1169 			goto trunc;
1170 		bp += advance;
1171 		len -= advance;
1172 		if (len < 2)
1173 			goto trunc;
1174 		ND_PRINT(" TUNR ");
1175 		unsigned_relts_print(ndo, GET_BE_U_2(bp));
1176 		break;
1177 
1178 	case PIMV2_TYPE_DF_ELECTION:
1179 		subtype = PIM_SUBTYPE(GET_U_1(pim->pim_rsv));
1180 		ND_PRINT("\n\t  %s,", tok2str( pimv2_df_election_flag_values,
1181 			 "Unknown", subtype) );
1182 
1183 		ND_PRINT(" rpa=");
1184 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0) {
1185 			goto trunc;
1186 		}
1187 		bp += advance;
1188 		len -= advance;
1189 		ND_PRINT(" sender pref=%u", GET_BE_U_4(bp) );
1190 		ND_PRINT(" sender metric=%u", GET_BE_U_4(bp + 4));
1191 
1192 		bp += 8;
1193 		len -= 8;
1194 
1195 		switch (subtype) {
1196 		case PIMV2_DF_ELECTION_BACKOFF:
1197 		case PIMV2_DF_ELECTION_PASS:
1198 			ND_PRINT("\n\t  %s addr=", PIMV2_DF_ELECTION_PASS_BACKOFF_STR(subtype));
1199 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0) {
1200 				goto trunc;
1201 			}
1202 			bp += advance;
1203 			len -= advance;
1204 
1205 			ND_PRINT(" %s pref=%u", PIMV2_DF_ELECTION_PASS_BACKOFF_STR(subtype), GET_BE_U_4(bp) );
1206 			ND_PRINT(" %s metric=%u", PIMV2_DF_ELECTION_PASS_BACKOFF_STR(subtype), GET_BE_U_4(bp + 4));
1207 
1208 			bp += 8;
1209 			len -= 8;
1210 
1211 			if (subtype == PIMV2_DF_ELECTION_BACKOFF) {
1212 				ND_PRINT(" interval %dms", GET_BE_U_2(bp));
1213 			}
1214 
1215 			break;
1216 		default:
1217 			break;
1218 		}
1219 		break;
1220 
1221 	 default:
1222 		ND_PRINT(" [type %u]", PIM_TYPE(pim_typever));
1223 		break;
1224 	}
1225 
1226 	return;
1227 
1228 trunc:
1229 	nd_print_trunc(ndo);
1230 }
1231