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