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