print-pim.c revision 162021
11573Srgrimes/*
21849Swollman * Copyright (c) 1995, 1996
31849Swollman *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that: (1) source code distributions
71573Srgrimes * retain the above copyright notice and this paragraph in its entirety, (2)
81573Srgrimes * distributions including binary code include the above copyright notice and
91573Srgrimes * this paragraph in its entirety in the documentation or other materials
101573Srgrimes * provided with the distribution, and (3) all advertising materials mentioning
111573Srgrimes * features or use of this software display the following acknowledgement:
121573Srgrimes * ``This product includes software developed by the University of California,
131573Srgrimes * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
141573Srgrimes * the University nor the names of its contributors may be used to endorse
151573Srgrimes * or promote products derived from this software without specific prior
161573Srgrimes * written permission.
171573Srgrimes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
181573Srgrimes * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
191573Srgrimes * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
201573Srgrimes *
211573Srgrimes * $FreeBSD: head/contrib/tcpdump/print-pim.c 162021 2006-09-04 20:25:04Z sam $
221573Srgrimes */
231573Srgrimes
241573Srgrimes#ifndef lint
251573Srgrimesstatic const char rcsid[] _U_ =
261573Srgrimes    "@(#) $Header: /tcpdump/master/tcpdump/print-pim.c,v 1.45.2.3 2005/07/11 20:24:34 hannes Exp $ (LBL)";
271573Srgrimes#endif
281573Srgrimes
291573Srgrimes#ifdef HAVE_CONFIG_H
301573Srgrimes#include "config.h"
311573Srgrimes#endif
321573Srgrimes
331573Srgrimes#include <tcpdump-stdinc.h>
341573Srgrimes#include "interface.h"
351573Srgrimes
361849Swollman#define PIMV2_TYPE_HELLO         0
371849Swollman#define PIMV2_TYPE_REGISTER      1
3850476Speter#define PIMV2_TYPE_REGISTER_STOP 2
391573Srgrimes#define PIMV2_TYPE_JOIN_PRUNE    3
401573Srgrimes#define PIMV2_TYPE_BOOTSTRAP     4
411573Srgrimes#define PIMV2_TYPE_ASSERT        5
4285437Speter#define PIMV2_TYPE_GRAFT         6
431573Srgrimes#define PIMV2_TYPE_GRAFT_ACK     7
4456809Sjasone#define PIMV2_TYPE_CANDIDATE_RP  8
4571579Sdeischen#define PIMV2_TYPE_PRUNE_REFRESH 9
4671579Sdeischen
4771579Sdeischenstatic struct tok pimv2_type_values[] = {
4871579Sdeischen    { PIMV2_TYPE_HELLO,         "Hello" },
4971579Sdeischen    { PIMV2_TYPE_REGISTER,      "Register" },
5087006Sjhb    { PIMV2_TYPE_REGISTER_STOP, "Register Stop" },
5171579Sdeischen    { PIMV2_TYPE_JOIN_PRUNE,    "Join / Prune" },
5271770Sdeischen    { PIMV2_TYPE_BOOTSTRAP,     "Bootstrap" },
5371579Sdeischen    { PIMV2_TYPE_ASSERT,        "Assert" },
5471770Sdeischen    { PIMV2_TYPE_GRAFT,         "Graft" },
5571579Sdeischen    { PIMV2_TYPE_GRAFT_ACK,     "Graft Acknowledgement" },
5671579Sdeischen    { PIMV2_TYPE_CANDIDATE_RP,  "Candidate RP Advertisement" },
5787006Sjhb    { PIMV2_TYPE_PRUNE_REFRESH, "Prune Refresh" },
5815634Speter    { 0, NULL}
5971770Sdeischen};
6071770Sdeischen
6171770Sdeischen#define PIMV2_HELLO_OPTION_HOLDTIME             1
6215634Speter#define PIMV2_HELLO_OPTION_LANPRUNEDELAY        2
6315634Speter#define PIMV2_HELLO_OPTION_DR_PRIORITY_OLD     18
6415634Speter#define PIMV2_HELLO_OPTION_DR_PRIORITY         19
6515634Speter#define PIMV2_HELLO_OPTION_GENID               20
6615634Speter#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
71static 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
90struct 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
114static void pimv2_print(register const u_char *bp, register u_int len);
115
116static void
117pimv1_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;
199trunc:
200	(void)printf("[|pim]");
201	return;
202}
203
204void
205pimv1_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
307trunc:
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 */
318void
319cisco_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
403trunc:
404	(void)printf("[|autorp]");
405	return;
406}
407
408void
409pim_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
486static int pimv2_addr_len;
487
488enum 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 */
512static int
513pimv2_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	}
609trunc:
610	return -1;
611}
612
613static void
614pimv2_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
1063trunc:
1064	(void)printf("[|pim]");
1065}
1066
1067/*
1068 * Local Variables:
1069 * c-style: whitesmith
1070 * c-basic-offset: 8
1071 * End:
1072 */
1073