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