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