print-pim.c revision 214478
117680Spst/*
217680Spst * Copyright (c) 1995, 1996
317680Spst *	The Regents of the University of California.  All rights reserved.
417680Spst *
517680Spst * Redistribution and use in source and binary forms, with or without
617680Spst * modification, are permitted provided that: (1) source code distributions
717680Spst * retain the above copyright notice and this paragraph in its entirety, (2)
817680Spst * distributions including binary code include the above copyright notice and
917680Spst * this paragraph in its entirety in the documentation or other materials
1017680Spst * provided with the distribution, and (3) all advertising materials mentioning
1117680Spst * features or use of this software display the following acknowledgement:
1217680Spst * ``This product includes software developed by the University of California,
1317680Spst * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
1417680Spst * the University nor the names of its contributors may be used to endorse
1517680Spst * or promote products derived from this software without specific prior
1617680Spst * written permission.
1717680Spst * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
1817680Spst * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
1917680Spst * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2057278Sfenner *
2157278Sfenner * $FreeBSD: head/contrib/tcpdump/print-pim.c 214478 2010-10-28 19:06:17Z rpaulo $
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
25127675Sbmsstatic const char rcsid[] _U_ =
26190207Srpaulo    "@(#) $Header: /tcpdump/master/tcpdump/print-pim.c,v 1.49 2006-02-13 01:31:35 hannes Exp $ (LBL)";
2717680Spst#endif
2817680Spst
2956893Sfenner#ifdef HAVE_CONFIG_H
3056893Sfenner#include "config.h"
3156893Sfenner#endif
3256893Sfenner
33127675Sbms#include <tcpdump-stdinc.h>
34146778Ssam#include "interface.h"
3517680Spst
36146778Ssam#define PIMV2_TYPE_HELLO         0
37146778Ssam#define PIMV2_TYPE_REGISTER      1
38146778Ssam#define PIMV2_TYPE_REGISTER_STOP 2
39146778Ssam#define PIMV2_TYPE_JOIN_PRUNE    3
40146778Ssam#define PIMV2_TYPE_BOOTSTRAP     4
41146778Ssam#define PIMV2_TYPE_ASSERT        5
42146778Ssam#define PIMV2_TYPE_GRAFT         6
43146778Ssam#define PIMV2_TYPE_GRAFT_ACK     7
44146778Ssam#define PIMV2_TYPE_CANDIDATE_RP  8
45146778Ssam#define PIMV2_TYPE_PRUNE_REFRESH 9
46146778Ssam
47146778Ssamstatic struct tok pimv2_type_values[] = {
48146778Ssam    { PIMV2_TYPE_HELLO,         "Hello" },
49146778Ssam    { PIMV2_TYPE_REGISTER,      "Register" },
50146778Ssam    { PIMV2_TYPE_REGISTER_STOP, "Register Stop" },
51146778Ssam    { PIMV2_TYPE_JOIN_PRUNE,    "Join / Prune" },
52146778Ssam    { PIMV2_TYPE_BOOTSTRAP,     "Bootstrap" },
53146778Ssam    { PIMV2_TYPE_ASSERT,        "Assert" },
54146778Ssam    { PIMV2_TYPE_GRAFT,         "Graft" },
55146778Ssam    { PIMV2_TYPE_GRAFT_ACK,     "Graft Acknowledgement" },
56146778Ssam    { PIMV2_TYPE_CANDIDATE_RP,  "Candidate RP Advertisement" },
57146778Ssam    { PIMV2_TYPE_PRUNE_REFRESH, "Prune Refresh" },
58146778Ssam    { 0, NULL}
59146778Ssam};
60146778Ssam
61146778Ssam#define PIMV2_HELLO_OPTION_HOLDTIME             1
62146778Ssam#define PIMV2_HELLO_OPTION_LANPRUNEDELAY        2
63146778Ssam#define PIMV2_HELLO_OPTION_DR_PRIORITY_OLD     18
64146778Ssam#define PIMV2_HELLO_OPTION_DR_PRIORITY         19
65146778Ssam#define PIMV2_HELLO_OPTION_GENID               20
66146778Ssam#define PIMV2_HELLO_OPTION_REFRESH_CAP         21
67146778Ssam#define PIMV2_HELLO_OPTION_BIDIR_CAP           22
68146778Ssam#define PIMV2_HELLO_OPTION_ADDRESS_LIST        24
69146778Ssam#define PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD 65001
70146778Ssam
71146778Ssamstatic struct tok pimv2_hello_option_values[] = {
72146778Ssam    { PIMV2_HELLO_OPTION_HOLDTIME,         "Hold Time" },
73146778Ssam    { PIMV2_HELLO_OPTION_LANPRUNEDELAY,    "LAN Prune Delay" },
74146778Ssam    { PIMV2_HELLO_OPTION_DR_PRIORITY_OLD,  "DR Priority (Old)" },
75146778Ssam    { PIMV2_HELLO_OPTION_DR_PRIORITY,      "DR Priority" },
76146778Ssam    { PIMV2_HELLO_OPTION_GENID,            "Generation ID" },
77146778Ssam    { PIMV2_HELLO_OPTION_REFRESH_CAP,      "State Refresh Capability" },
78146778Ssam    { PIMV2_HELLO_OPTION_BIDIR_CAP,        "Bi-Directional Capability" },
79146778Ssam    { PIMV2_HELLO_OPTION_ADDRESS_LIST,     "Address List" },
80146778Ssam    { PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD, "Address List (Old)" },
81146778Ssam    { 0, NULL}
82146778Ssam};
83146778Ssam
84172686Smlaier#define PIMV2_REGISTER_FLAG_LEN      4
85172686Smlaier#define PIMV2_REGISTER_FLAG_BORDER 0x80000000
86172686Smlaier#define PIMV2_REGISTER_FLAG_NULL   0x40000000
87146778Ssam
88172686Smlaierstatic struct tok pimv2_register_flag_values[] = {
89172686Smlaier    { PIMV2_REGISTER_FLAG_BORDER, "Border" },
90172686Smlaier    { PIMV2_REGISTER_FLAG_NULL, "Null" },
91172686Smlaier    { 0, NULL}
92172686Smlaier};
93172686Smlaier
9456893Sfenner/*
9556893Sfenner * XXX: We consider a case where IPv6 is not ready yet for portability,
9656893Sfenner * but PIM dependent defintions should be independent of IPv6...
9756893Sfenner */
9856893Sfenner
9956893Sfennerstruct pim {
10056893Sfenner	u_int8_t pim_typever;
10157278Sfenner			/* upper 4bit: PIM version number; 2 for PIMv2 */
10257278Sfenner			/* lower 4bit: the PIM message type, currently they are:
10356893Sfenner			 * Hello, Register, Register-Stop, Join/Prune,
10456893Sfenner			 * Bootstrap, Assert, Graft (PIM-DM only),
10556893Sfenner			 * Graft-Ack (PIM-DM only), C-RP-Adv
10656893Sfenner			 */
10757278Sfenner#define PIM_VER(x)	(((x) & 0xf0) >> 4)
10857278Sfenner#define PIM_TYPE(x)	((x) & 0x0f)
10956893Sfenner	u_char  pim_rsv;	/* Reserved */
11056893Sfenner	u_short	pim_cksum;	/* IP style check sum */
11156893Sfenner};
11256893Sfenner
11356893Sfenner
11417680Spst#include <stdio.h>
11517680Spst#include <stdlib.h>
11617680Spst
11717680Spst#include "interface.h"
11817680Spst#include "addrtoname.h"
11956893Sfenner#include "extract.h"
12017680Spst
12175118Sfenner#include "ip.h"
12275118Sfenner
123214478Srpaulostatic void pimv2_print(register const u_char *bp, register u_int len, u_int cksum);
12456893Sfenner
12556893Sfennerstatic void
12656893Sfennerpimv1_join_prune_print(register const u_char *bp, register u_int len)
12756893Sfenner{
12898527Sfenner	int maddrlen, addrlen, ngroups, njoin, nprune;
12998527Sfenner	int njp;
13056893Sfenner
13198527Sfenner	/* If it's a single group and a single source, use 1-line output. */
13298527Sfenner	if (TTEST2(bp[0], 30) && bp[11] == 1 &&
13398527Sfenner	    ((njoin = EXTRACT_16BITS(&bp[20])) + EXTRACT_16BITS(&bp[22])) == 1) {
13498527Sfenner		int hold;
13556893Sfenner
13698527Sfenner		(void)printf(" RPF %s ", ipaddr_string(bp));
13798527Sfenner		hold = EXTRACT_16BITS(&bp[6]);
13898527Sfenner		if (hold != 180) {
13998527Sfenner			(void)printf("Hold ");
14098527Sfenner			relts_print(hold);
14198527Sfenner		}
14298527Sfenner		(void)printf("%s (%s/%d, %s", njoin ? "Join" : "Prune",
14398527Sfenner		ipaddr_string(&bp[26]), bp[25] & 0x3f,
14498527Sfenner		ipaddr_string(&bp[12]));
14598527Sfenner		if (EXTRACT_32BITS(&bp[16]) != 0xffffffff)
14698527Sfenner			(void)printf("/%s", ipaddr_string(&bp[16]));
14798527Sfenner		(void)printf(") %s%s %s",
14856893Sfenner		    (bp[24] & 0x01) ? "Sparse" : "Dense",
14956893Sfenner		    (bp[25] & 0x80) ? " WC" : "",
15056893Sfenner		    (bp[25] & 0x40) ? "RP" : "SPT");
15198527Sfenner		return;
15298527Sfenner	}
15356893Sfenner
154162021Ssam	TCHECK2(bp[0], sizeof(struct in_addr));
15598527Sfenner	if (vflag > 1)
15698527Sfenner		(void)printf("\n");
15798527Sfenner	(void)printf(" Upstream Nbr: %s", ipaddr_string(bp));
15898527Sfenner	TCHECK2(bp[6], 2);
15998527Sfenner	if (vflag > 1)
16098527Sfenner		(void)printf("\n");
16198527Sfenner	(void)printf(" Hold time: ");
16298527Sfenner	relts_print(EXTRACT_16BITS(&bp[6]));
16398527Sfenner	if (vflag < 2)
16498527Sfenner		return;
16598527Sfenner	bp += 8;
16698527Sfenner	len -= 8;
16756893Sfenner
16898527Sfenner	TCHECK2(bp[0], 4);
16998527Sfenner	maddrlen = bp[1];
17098527Sfenner	addrlen = bp[2];
17198527Sfenner	ngroups = bp[3];
17298527Sfenner	bp += 4;
17398527Sfenner	len -= 4;
17498527Sfenner	while (ngroups--) {
175147904Ssam		/*
176147904Ssam		 * XXX - does the address have length "addrlen" and the
177147904Ssam		 * mask length "maddrlen"?
178147904Ssam		 */
179162021Ssam		TCHECK2(bp[0], sizeof(struct in_addr));
18098527Sfenner		(void)printf("\n\tGroup: %s", ipaddr_string(bp));
181162021Ssam		TCHECK2(bp[4], sizeof(struct in_addr));
18298527Sfenner		if (EXTRACT_32BITS(&bp[4]) != 0xffffffff)
18398527Sfenner			(void)printf("/%s", ipaddr_string(&bp[4]));
18498527Sfenner		TCHECK2(bp[8], 4);
18598527Sfenner		njoin = EXTRACT_16BITS(&bp[8]);
18698527Sfenner		nprune = EXTRACT_16BITS(&bp[10]);
18798527Sfenner		(void)printf(" joined: %d pruned: %d", njoin, nprune);
18898527Sfenner		bp += 12;
18998527Sfenner		len -= 12;
19098527Sfenner		for (njp = 0; njp < (njoin + nprune); njp++) {
191127675Sbms			const char *type;
19298527Sfenner
19398527Sfenner			if (njp < njoin)
19498527Sfenner				type = "Join ";
19598527Sfenner			else
19698527Sfenner				type = "Prune";
19798527Sfenner			TCHECK2(bp[0], 6);
19898527Sfenner			(void)printf("\n\t%s %s%s%s%s/%d", type,
19956893Sfenner			    (bp[0] & 0x01) ? "Sparse " : "Dense ",
20056893Sfenner			    (bp[1] & 0x80) ? "WC " : "",
20156893Sfenner			    (bp[1] & 0x40) ? "RP " : "SPT ",
20298527Sfenner			ipaddr_string(&bp[2]), bp[1] & 0x3f);
20398527Sfenner			bp += 6;
20498527Sfenner			len -= 6;
20598527Sfenner		}
20656893Sfenner	}
20798527Sfenner	return;
20856893Sfennertrunc:
20998527Sfenner	(void)printf("[|pim]");
21098527Sfenner	return;
21156893Sfenner}
21256893Sfenner
21317680Spstvoid
21456893Sfennerpimv1_print(register const u_char *bp, register u_int len)
21517680Spst{
21698527Sfenner	register const u_char *ep;
21798527Sfenner	register u_char type;
21817680Spst
21998527Sfenner	ep = (const u_char *)snapend;
22098527Sfenner	if (bp >= ep)
22198527Sfenner		return;
22217680Spst
223127675Sbms	TCHECK(bp[1]);
22498527Sfenner	type = bp[1];
22517680Spst
22698527Sfenner	switch (type) {
22798527Sfenner	case 0:
22898527Sfenner		(void)printf(" Query");
22998527Sfenner		if (TTEST(bp[8])) {
23098527Sfenner			switch (bp[8] >> 4) {
23198527Sfenner			case 0:
23298527Sfenner				(void)printf(" Dense-mode");
23356893Sfenner				break;
23498527Sfenner			case 1:
23598527Sfenner				(void)printf(" Sparse-mode");
23656893Sfenner				break;
23798527Sfenner			case 2:
23898527Sfenner				(void)printf(" Sparse-Dense-mode");
23956893Sfenner				break;
24098527Sfenner			default:
24198527Sfenner				(void)printf(" mode-%d", bp[8] >> 4);
24256893Sfenner				break;
24398527Sfenner			}
24456893Sfenner		}
24598527Sfenner		if (vflag) {
24698527Sfenner			TCHECK2(bp[10],2);
24798527Sfenner			(void)printf(" (Hold-time ");
24898527Sfenner			relts_print(EXTRACT_16BITS(&bp[10]));
24998527Sfenner			(void)printf(")");
25098527Sfenner		}
25198527Sfenner		break;
25217680Spst
25398527Sfenner	case 1:
25498527Sfenner		(void)printf(" Register");
25598527Sfenner		TCHECK2(bp[8], 20);			/* ip header */
25698527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[20]),
25798527Sfenner		    ipaddr_string(&bp[24]));
25898527Sfenner		break;
25998527Sfenner	case 2:
26098527Sfenner		(void)printf(" Register-Stop");
261162021Ssam		TCHECK2(bp[12], sizeof(struct in_addr));
26298527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[8]),
26398527Sfenner		    ipaddr_string(&bp[12]));
26498527Sfenner		break;
26598527Sfenner	case 3:
26698527Sfenner		(void)printf(" Join/Prune");
26798527Sfenner		if (vflag)
26898527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
26998527Sfenner		break;
27098527Sfenner	case 4:
27198527Sfenner		(void)printf(" RP-reachable");
27298527Sfenner		if (vflag) {
27398527Sfenner			TCHECK2(bp[22], 2);
27498527Sfenner			(void)printf(" group %s",
27556893Sfenner			ipaddr_string(&bp[8]));
27698527Sfenner			if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
27798527Sfenner				(void)printf("/%s", ipaddr_string(&bp[12]));
27898527Sfenner			(void)printf(" RP %s hold ", ipaddr_string(&bp[16]));
27998527Sfenner			relts_print(EXTRACT_16BITS(&bp[22]));
28098527Sfenner		}
28198527Sfenner		break;
28298527Sfenner	case 5:
28398527Sfenner		(void)printf(" Assert");
284162021Ssam		TCHECK2(bp[16], sizeof(struct in_addr));
28598527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[16]),
28698527Sfenner		    ipaddr_string(&bp[8]));
28756893Sfenner		if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
28856893Sfenner			(void)printf("/%s", ipaddr_string(&bp[12]));
28998527Sfenner		TCHECK2(bp[24], 4);
29098527Sfenner		(void)printf(" %s pref %d metric %d",
29198527Sfenner		    (bp[20] & 0x80) ? "RP-tree" : "SPT",
29256893Sfenner		EXTRACT_32BITS(&bp[20]) & 0x7fffffff,
29356893Sfenner		EXTRACT_32BITS(&bp[24]));
29498527Sfenner		break;
29598527Sfenner	case 6:
29698527Sfenner		(void)printf(" Graft");
29798527Sfenner		if (vflag)
29898527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
29998527Sfenner		break;
30098527Sfenner	case 7:
30198527Sfenner		(void)printf(" Graft-ACK");
30298527Sfenner		if (vflag)
30398527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
30498527Sfenner		break;
30598527Sfenner	case 8:
30698527Sfenner		(void)printf(" Mode");
30798527Sfenner		break;
30898527Sfenner	default:
30998527Sfenner		(void)printf(" [type %d]", type);
31098527Sfenner		break;
31156893Sfenner	}
31298527Sfenner	if ((bp[4] >> 4) != 1)
31398527Sfenner		(void)printf(" [v%d]", bp[4] >> 4);
31498527Sfenner	return;
31517680Spst
31656893Sfennertrunc:
31798527Sfenner	(void)printf("[|pim]");
31898527Sfenner	return;
31917680Spst}
32056893Sfenner
32156893Sfenner/*
32256893Sfenner * auto-RP is a cisco protocol, documented at
32398527Sfenner * ftp://ftpeng.cisco.com/ipmulticast/specs/pim-autorp-spec01.txt
32498527Sfenner *
32598527Sfenner * This implements version 1+, dated Sept 9, 1998.
32656893Sfenner */
32756893Sfennervoid
32856893Sfennercisco_autorp_print(register const u_char *bp, register u_int len)
32956893Sfenner{
33098527Sfenner	int type;
33198527Sfenner	int numrps;
33298527Sfenner	int hold;
33356893Sfenner
33498527Sfenner	TCHECK(bp[0]);
33598527Sfenner	(void)printf(" auto-rp ");
33698527Sfenner	type = bp[0];
33798527Sfenner	switch (type) {
33898527Sfenner	case 0x11:
33998527Sfenner		(void)printf("candidate-advert");
34098527Sfenner		break;
34198527Sfenner	case 0x12:
34298527Sfenner		(void)printf("mapping");
34398527Sfenner		break;
34498527Sfenner	default:
34598527Sfenner		(void)printf("type-0x%02x", type);
34698527Sfenner		break;
34798527Sfenner	}
34856893Sfenner
34998527Sfenner	TCHECK(bp[1]);
35098527Sfenner	numrps = bp[1];
35156893Sfenner
35298527Sfenner	TCHECK2(bp[2], 2);
35398527Sfenner	(void)printf(" Hold ");
35498527Sfenner	hold = EXTRACT_16BITS(&bp[2]);
35598527Sfenner	if (hold)
35698527Sfenner		relts_print(EXTRACT_16BITS(&bp[2]));
35798527Sfenner	else
35898527Sfenner		printf("FOREVER");
35956893Sfenner
36098527Sfenner	/* Next 4 bytes are reserved. */
36156893Sfenner
36298527Sfenner	bp += 8; len -= 8;
36356893Sfenner
36498527Sfenner	/*XXX skip unless -v? */
36556893Sfenner
36698527Sfenner	/*
36798527Sfenner	 * Rest of packet:
36898527Sfenner	 * numrps entries of the form:
36998527Sfenner	 * 32 bits: RP
37098527Sfenner	 * 6 bits: reserved
37198527Sfenner	 * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
37298527Sfenner	 * 8 bits: # of entries for this RP
37398527Sfenner	 * each entry: 7 bits: reserved, 1 bit: negative,
37498527Sfenner	 *	       8 bits: mask 32 bits: source
37598527Sfenner	 * lather, rinse, repeat.
37698527Sfenner	 */
37798527Sfenner	while (numrps--) {
37898527Sfenner		int nentries;
37998527Sfenner		char s;
38056893Sfenner
38198527Sfenner		TCHECK2(bp[0], 4);
38298527Sfenner		(void)printf(" RP %s", ipaddr_string(bp));
38398527Sfenner		TCHECK(bp[4]);
38498527Sfenner		switch (bp[4] & 0x3) {
38598527Sfenner		case 0: printf(" PIMv?");
38698527Sfenner			break;
38798527Sfenner		case 1:	printf(" PIMv1");
38898527Sfenner			break;
38998527Sfenner		case 2:	printf(" PIMv2");
39098527Sfenner			break;
39198527Sfenner		case 3:	printf(" PIMv1+2");
39298527Sfenner			break;
39398527Sfenner		}
39498527Sfenner		if (bp[4] & 0xfc)
39598527Sfenner			(void)printf(" [rsvd=0x%02x]", bp[4] & 0xfc);
39698527Sfenner		TCHECK(bp[5]);
39798527Sfenner		nentries = bp[5];
39898527Sfenner		bp += 6; len -= 6;
39998527Sfenner		s = ' ';
40098527Sfenner		for (; nentries; nentries--) {
40198527Sfenner			TCHECK2(bp[0], 6);
40298527Sfenner			(void)printf("%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
40398527Sfenner			    ipaddr_string(&bp[2]), bp[1]);
40498527Sfenner			if (bp[0] & 0xfe)
40598527Sfenner				(void)printf("[rsvd=0x%02x]", bp[0] & 0xfe);
40698527Sfenner			s = ',';
40798527Sfenner			bp += 6; len -= 6;
40898527Sfenner		}
40956893Sfenner	}
41098527Sfenner	return;
41156893Sfenner
41256893Sfennertrunc:
41398527Sfenner	(void)printf("[|autorp]");
41498527Sfenner	return;
41556893Sfenner}
41656893Sfenner
41756893Sfennervoid
418214478Srpaulopim_print(register const u_char *bp, register u_int len, u_int cksum)
41956893Sfenner{
42056893Sfenner	register const u_char *ep;
42156893Sfenner	register struct pim *pim = (struct pim *)bp;
42256893Sfenner
42356893Sfenner	ep = (const u_char *)snapend;
42456893Sfenner	if (bp >= ep)
42556893Sfenner		return;
42656893Sfenner#ifdef notyet			/* currently we see only version and type */
42756893Sfenner	TCHECK(pim->pim_rsv);
42856893Sfenner#endif
42956893Sfenner
43075118Sfenner	switch (PIM_VER(pim->pim_typever)) {
431146778Ssam	case 2:
432146778Ssam            if (!vflag) {
433172686Smlaier                printf("PIMv%u, %s, length %u",
434146778Ssam                       PIM_VER(pim->pim_typever),
435146778Ssam                       tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)),
436146778Ssam                       len);
437146778Ssam                return;
438146778Ssam            } else {
439172686Smlaier                printf("PIMv%u, length %u\n\t%s",
440146778Ssam                       PIM_VER(pim->pim_typever),
441146778Ssam                       len,
442146778Ssam                       tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)));
443214478Srpaulo                pimv2_print(bp, len, cksum);
444146778Ssam            }
445146778Ssam            break;
44698527Sfenner	default:
447172686Smlaier		printf("PIMv%u, length %u",
448146778Ssam                       PIM_VER(pim->pim_typever),
449146778Ssam                       len);
45056893Sfenner		break;
45156893Sfenner	}
45256893Sfenner	return;
45356893Sfenner}
45456893Sfenner
45556893Sfenner/*
45656893Sfenner * PIMv2 uses encoded address representations.
45756893Sfenner *
45856893Sfenner * The last PIM-SM I-D before RFC2117 was published specified the
45956893Sfenner * following representation for unicast addresses.  However, RFC2117
46056893Sfenner * specified no encoding for unicast addresses with the unicast
46156893Sfenner * address length specified in the header.  Therefore, we have to
46256893Sfenner * guess which encoding is being used (Cisco's PIMv2 implementation
46356893Sfenner * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
46456893Sfenner * field into a 'unicast-address-length-in-bytes' field.  We guess
46556893Sfenner * that it's the draft encoding if this reserved field is zero.
46656893Sfenner *
46756893Sfenner * RFC2362 goes back to the encoded format, and calls the addr length
46856893Sfenner * field "reserved" again.
46956893Sfenner *
47056893Sfenner * The first byte is the address family, from:
47156893Sfenner *
47256893Sfenner *    0    Reserved
47356893Sfenner *    1    IP (IP version 4)
47456893Sfenner *    2    IP6 (IP version 6)
47556893Sfenner *    3    NSAP
47656893Sfenner *    4    HDLC (8-bit multidrop)
47756893Sfenner *    5    BBN 1822
47856893Sfenner *    6    802 (includes all 802 media plus Ethernet "canonical format")
47956893Sfenner *    7    E.163
48056893Sfenner *    8    E.164 (SMDS, Frame Relay, ATM)
48156893Sfenner *    9    F.69 (Telex)
48256893Sfenner *   10    X.121 (X.25, Frame Relay)
48356893Sfenner *   11    IPX
48456893Sfenner *   12    Appletalk
48556893Sfenner *   13    Decnet IV
48656893Sfenner *   14    Banyan Vines
48756893Sfenner *   15    E.164 with NSAP format subaddress
48856893Sfenner *
48956893Sfenner * In addition, the second byte is an "Encoding".  0 is the default
49056893Sfenner * encoding for the address family, and no other encodings are currently
49156893Sfenner * specified.
49256893Sfenner *
49356893Sfenner */
49456893Sfenner
49556893Sfennerstatic int pimv2_addr_len;
49656893Sfenner
49756893Sfennerenum pimv2_addrtype {
49856893Sfenner	pimv2_unicast, pimv2_group, pimv2_source
49956893Sfenner};
50056893Sfenner
50156893Sfenner/*  0                   1                   2                   3
50256893Sfenner *  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
50356893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50456893Sfenner * | Addr Family   | Encoding Type |     Unicast Address           |
50556893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
50656893Sfenner *  0                   1                   2                   3
50756893Sfenner *  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
50856893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50956893Sfenner * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
51056893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51156893Sfenner * |                Group multicast Address                        |
51256893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51356893Sfenner *  0                   1                   2                   3
51456893Sfenner *  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
51556893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51656893Sfenner * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
51756893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51856893Sfenner * |                        Source Address                         |
51956893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52056893Sfenner */
52156893Sfennerstatic int
52256893Sfennerpimv2_addr_print(const u_char *bp, enum pimv2_addrtype at, int silent)
52356893Sfenner{
52456893Sfenner	int af;
52556893Sfenner	int len, hdrlen;
52656893Sfenner
52756893Sfenner	TCHECK(bp[0]);
52856893Sfenner
52956893Sfenner	if (pimv2_addr_len == 0) {
53056893Sfenner		TCHECK(bp[1]);
53156893Sfenner		switch (bp[0]) {
53298527Sfenner		case 1:
53356893Sfenner			af = AF_INET;
534162021Ssam			len = sizeof(struct in_addr);
53556893Sfenner			break;
53656893Sfenner#ifdef INET6
53798527Sfenner		case 2:
53856893Sfenner			af = AF_INET6;
539162021Ssam			len = sizeof(struct in6_addr);
54056893Sfenner			break;
54156893Sfenner#endif
54298527Sfenner		default:
54356893Sfenner			return -1;
54456893Sfenner		}
54556893Sfenner		if (bp[1] != 0)
54656893Sfenner			return -1;
54756893Sfenner		hdrlen = 2;
54856893Sfenner	} else {
54956893Sfenner		switch (pimv2_addr_len) {
550162021Ssam		case sizeof(struct in_addr):
55156893Sfenner			af = AF_INET;
55256893Sfenner			break;
55356893Sfenner#ifdef INET6
554162021Ssam		case sizeof(struct in6_addr):
55556893Sfenner			af = AF_INET6;
55656893Sfenner			break;
55756893Sfenner#endif
55898527Sfenner		default:
55956893Sfenner			return -1;
56056893Sfenner			break;
56156893Sfenner		}
56256893Sfenner		len = pimv2_addr_len;
56356893Sfenner		hdrlen = 0;
56456893Sfenner	}
56556893Sfenner
56656893Sfenner	bp += hdrlen;
56756893Sfenner	switch (at) {
56898527Sfenner	case pimv2_unicast:
56956893Sfenner		TCHECK2(bp[0], len);
57056893Sfenner		if (af == AF_INET) {
57156893Sfenner			if (!silent)
57256893Sfenner				(void)printf("%s", ipaddr_string(bp));
57356893Sfenner		}
57456893Sfenner#ifdef INET6
57556893Sfenner		else if (af == AF_INET6) {
57656893Sfenner			if (!silent)
57756893Sfenner				(void)printf("%s", ip6addr_string(bp));
57856893Sfenner		}
57956893Sfenner#endif
58056893Sfenner		return hdrlen + len;
58198527Sfenner	case pimv2_group:
58298527Sfenner	case pimv2_source:
58356893Sfenner		TCHECK2(bp[0], len + 2);
58456893Sfenner		if (af == AF_INET) {
58556893Sfenner			if (!silent) {
58656893Sfenner				(void)printf("%s", ipaddr_string(bp + 2));
58756893Sfenner				if (bp[1] != 32)
58856893Sfenner					(void)printf("/%u", bp[1]);
58956893Sfenner			}
59056893Sfenner		}
59156893Sfenner#ifdef INET6
59256893Sfenner		else if (af == AF_INET6) {
59356893Sfenner			if (!silent) {
59456893Sfenner				(void)printf("%s", ip6addr_string(bp + 2));
59556893Sfenner				if (bp[1] != 128)
59656893Sfenner					(void)printf("/%u", bp[1]);
59756893Sfenner			}
59856893Sfenner		}
59956893Sfenner#endif
60056893Sfenner		if (bp[0] && !silent) {
60156893Sfenner			if (at == pimv2_group) {
60256893Sfenner				(void)printf("(0x%02x)", bp[0]);
60356893Sfenner			} else {
60456893Sfenner				(void)printf("(%s%s%s",
60556893Sfenner					bp[0] & 0x04 ? "S" : "",
60656893Sfenner					bp[0] & 0x02 ? "W" : "",
60756893Sfenner					bp[0] & 0x01 ? "R" : "");
60856893Sfenner				if (bp[0] & 0xf8) {
60956893Sfenner					(void) printf("+0x%02x", bp[0] & 0xf8);
61056893Sfenner				}
61156893Sfenner				(void)printf(")");
61256893Sfenner			}
61356893Sfenner		}
61456893Sfenner		return hdrlen + 2 + len;
61556893Sfenner	default:
61656893Sfenner		return -1;
61756893Sfenner	}
61856893Sfennertrunc:
61956893Sfenner	return -1;
62056893Sfenner}
62156893Sfenner
62256893Sfennerstatic void
623214478Srpaulopimv2_print(register const u_char *bp, register u_int len, u_int cksum)
62456893Sfenner{
62556893Sfenner	register const u_char *ep;
62656893Sfenner	register struct pim *pim = (struct pim *)bp;
62756893Sfenner	int advance;
62856893Sfenner
62956893Sfenner	ep = (const u_char *)snapend;
63056893Sfenner	if (bp >= ep)
63156893Sfenner		return;
63257278Sfenner	if (ep > bp + len)
63357278Sfenner		ep = bp + len;
63456893Sfenner	TCHECK(pim->pim_rsv);
63556893Sfenner	pimv2_addr_len = pim->pim_rsv;
63656893Sfenner	if (pimv2_addr_len != 0)
637146778Ssam		(void)printf(", RFC2117-encoding");
63856893Sfenner
639172686Smlaier        printf(", cksum 0x%04x ", EXTRACT_16BITS(&pim->pim_cksum));
640172686Smlaier        if (EXTRACT_16BITS(&pim->pim_cksum) == 0) {
641172686Smlaier                printf("(unverified)");
642172686Smlaier        } else {
643214478Srpaulo                printf("(%scorrect)", TTEST2(bp[0], len) && cksum ? "in" : "" );
644172686Smlaier        }
645172686Smlaier
64656893Sfenner	switch (PIM_TYPE(pim->pim_typever)) {
647146778Ssam	case PIMV2_TYPE_HELLO:
64856893Sfenner	    {
64956893Sfenner		u_int16_t otype, olen;
65056893Sfenner		bp += 4;
65156893Sfenner		while (bp < ep) {
65256893Sfenner			TCHECK2(bp[0], 4);
65356893Sfenner			otype = EXTRACT_16BITS(&bp[0]);
65456893Sfenner			olen = EXTRACT_16BITS(&bp[2]);
65556893Sfenner			TCHECK2(bp[0], 4 + olen);
656146778Ssam
657172686Smlaier                        printf("\n\t  %s Option (%u), length %u, Value: ",
658146778Ssam                               tok2str( pimv2_hello_option_values,"Unknown",otype),
659146778Ssam                               otype,
660146778Ssam                               olen);
661146778Ssam			bp += 4;
662146778Ssam
66356893Sfenner			switch (otype) {
664146778Ssam			case PIMV2_HELLO_OPTION_HOLDTIME:
665146778Ssam                                relts_print(EXTRACT_16BITS(bp));
666146778Ssam                                break;
66756893Sfenner
668146778Ssam			case PIMV2_HELLO_OPTION_LANPRUNEDELAY:
669127675Sbms				if (olen != 4) {
670146778Ssam					(void)printf("ERROR: Option Lenght != 4 Bytes (%u)", olen);
671127675Sbms				} else {
672127675Sbms					char t_bit;
673127675Sbms					u_int16_t lan_delay, override_interval;
674146778Ssam					lan_delay = EXTRACT_16BITS(bp);
675146778Ssam					override_interval = EXTRACT_16BITS(bp+2);
676127675Sbms					t_bit = (lan_delay & 0x8000)? 1 : 0;
677127675Sbms					lan_delay &= ~0x8000;
678146778Ssam					(void)printf("\n\t    T-bit=%d, LAN delay %dms, Override interval %dms",
679127675Sbms					t_bit, lan_delay, override_interval);
680127675Sbms				}
681127675Sbms				break;
682127675Sbms
683146778Ssam			case PIMV2_HELLO_OPTION_DR_PRIORITY_OLD:
684146778Ssam			case PIMV2_HELLO_OPTION_DR_PRIORITY:
685146778Ssam                                switch (olen) {
686146778Ssam                                case 0:
687146778Ssam                                    printf("Bi-Directional Capability (Old)");
688146778Ssam                                    break;
689146778Ssam                                case 4:
690146778Ssam                                    printf("%u", EXTRACT_32BITS(bp));
691146778Ssam                                    break;
692146778Ssam                                default:
693146778Ssam                                    printf("ERROR: Option Lenght != 4 Bytes (%u)", olen);
694146778Ssam                                    break;
695146778Ssam                                }
696146778Ssam                                break;
697111729Sfenner
698146778Ssam			case PIMV2_HELLO_OPTION_GENID:
699146778Ssam                                (void)printf("0x%08x", EXTRACT_32BITS(bp));
70056893Sfenner				break;
70156893Sfenner
702146778Ssam			case PIMV2_HELLO_OPTION_REFRESH_CAP:
703146778Ssam                                (void)printf("v%d", *bp);
704146778Ssam				if (*(bp+1) != 0) {
705146778Ssam                                    (void)printf(", interval ");
706146778Ssam                                    relts_print(*(bp+1));
70756893Sfenner				}
708146778Ssam				if (EXTRACT_16BITS(bp+2) != 0) {
709146778Ssam                                    (void)printf(" ?0x%04x?", EXTRACT_16BITS(bp+2));
71098527Sfenner				}
71156893Sfenner				break;
71256893Sfenner
713146778Ssam			case  PIMV2_HELLO_OPTION_BIDIR_CAP:
71498527Sfenner				break;
71598527Sfenner
716146778Ssam                        case PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD:
717146778Ssam                        case PIMV2_HELLO_OPTION_ADDRESS_LIST:
718127675Sbms				if (vflag > 1) {
719146778Ssam					const u_char *ptr = bp;
720146778Ssam					while (ptr < (bp+olen)) {
721127675Sbms						int advance;
722127675Sbms
723146778Ssam						printf("\n\t    ");
724127675Sbms						advance = pimv2_addr_print(ptr, pimv2_unicast, 0);
725127675Sbms						if (advance < 0) {
726127675Sbms							printf("...");
727127675Sbms							break;
728127675Sbms						}
729127675Sbms						ptr += advance;
730127675Sbms					}
731127675Sbms				}
732127675Sbms				break;
73356893Sfenner			default:
734146778Ssam                                if (vflag <= 1)
735146778Ssam                                    print_unknown_data(bp,"\n\t    ",olen);
736146778Ssam                                break;
73756893Sfenner			}
738146778Ssam                        /* do we want to see an additionally hexdump ? */
739146778Ssam                        if (vflag> 1)
740146778Ssam                            print_unknown_data(bp,"\n\t    ",olen);
741146778Ssam			bp += olen;
74256893Sfenner		}
74356893Sfenner		break;
74456893Sfenner	    }
74556893Sfenner
746146778Ssam	case PIMV2_TYPE_REGISTER:
74798527Sfenner	{
74856893Sfenner		struct ip *ip;
74956893Sfenner
750172686Smlaier                if (!TTEST2(*(bp+4), PIMV2_REGISTER_FLAG_LEN))
751172686Smlaier                        goto trunc;
752172686Smlaier
753172686Smlaier                printf(", Flags [ %s ]\n\t",
754172686Smlaier                       tok2str(pimv2_register_flag_values,
755172686Smlaier                               "none",
756172686Smlaier                               EXTRACT_32BITS(bp+4)));
757172686Smlaier
75856893Sfenner		bp += 8; len -= 8;
75956893Sfenner		/* encapsulated multicast packet */
76056893Sfenner		ip = (struct ip *)bp;
76175118Sfenner		switch (IP_V(ip)) {
762172686Smlaier                case 0: /* Null header */
763172686Smlaier			(void)printf("IP-Null-header %s > %s",
764172686Smlaier                                     ipaddr_string(&ip->ip_src),
765172686Smlaier                                     ipaddr_string(&ip->ip_dst));
766172686Smlaier			break;
767172686Smlaier
76898527Sfenner		case 4:	/* IPv4 */
769146778Ssam			ip_print(gndo, bp, len);
77056893Sfenner			break;
77156893Sfenner#ifdef INET6
77298527Sfenner		case 6:	/* IPv6 */
77356893Sfenner			ip6_print(bp, len);
77456893Sfenner			break;
77556893Sfenner#endif
776172686Smlaier                default:
777172686Smlaier                        (void)printf("IP ver %d", IP_V(ip));
778172686Smlaier                        break;
77956893Sfenner		}
78056893Sfenner		break;
78198527Sfenner	}
78256893Sfenner
783146778Ssam	case PIMV2_TYPE_REGISTER_STOP:
78456893Sfenner		bp += 4; len -= 4;
78556893Sfenner		if (bp >= ep)
78656893Sfenner			break;
78756893Sfenner		(void)printf(" group=");
78856893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
78956893Sfenner			(void)printf("...");
79056893Sfenner			break;
79156893Sfenner		}
79256893Sfenner		bp += advance; len -= advance;
79356893Sfenner		if (bp >= ep)
79456893Sfenner			break;
79556893Sfenner		(void)printf(" source=");
79656893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
79756893Sfenner			(void)printf("...");
79856893Sfenner			break;
79956893Sfenner		}
80056893Sfenner		bp += advance; len -= advance;
80156893Sfenner		break;
80256893Sfenner
803146778Ssam	case PIMV2_TYPE_JOIN_PRUNE:
804146778Ssam	case PIMV2_TYPE_GRAFT:
805146778Ssam	case PIMV2_TYPE_GRAFT_ACK:
806146778Ssam
807146778Ssam
808146778Ssam        /*
809146778Ssam         * 0                   1                   2                   3
810146778Ssam         *   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
811146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
812146778Ssam         *  |PIM Ver| Type  | Addr length   |           Checksum            |
813146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
814146778Ssam         *  |             Unicast-Upstream Neighbor Address                 |
815146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
816146778Ssam         *  |  Reserved     | Num groups    |          Holdtime             |
817146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
818146778Ssam         *  |            Encoded-Multicast Group Address-1                  |
819146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
820146778Ssam         *  |   Number of Joined  Sources   |   Number of Pruned Sources    |
821146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
822146778Ssam         *  |               Encoded-Joined Source Address-1                 |
823146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
824146778Ssam         *  |                             .                                 |
825146778Ssam         *  |                             .                                 |
826146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
827146778Ssam         *  |               Encoded-Joined Source Address-n                 |
828146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
829146778Ssam         *  |               Encoded-Pruned Source Address-1                 |
830146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
831146778Ssam         *  |                             .                                 |
832146778Ssam         *  |                             .                                 |
833146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
834146778Ssam         *  |               Encoded-Pruned Source Address-n                 |
835146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
836146778Ssam         *  |                           .                                   |
837146778Ssam         *  |                           .                                   |
838146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
839146778Ssam         *  |                Encoded-Multicast Group Address-n              |
840146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
841146778Ssam         */
842146778Ssam
84356893Sfenner	    {
84456893Sfenner		u_int8_t ngroup;
84556893Sfenner		u_int16_t holdtime;
84656893Sfenner		u_int16_t njoin;
84756893Sfenner		u_int16_t nprune;
84856893Sfenner		int i, j;
84956893Sfenner
85056893Sfenner		bp += 4; len -= 4;
85156893Sfenner		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
85256893Sfenner			if (bp >= ep)
85356893Sfenner				break;
854146778Ssam			(void)printf(", upstream-neighbor: ");
85556893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
85656893Sfenner				(void)printf("...");
85756893Sfenner				break;
85856893Sfenner			}
85956893Sfenner			bp += advance; len -= advance;
86056893Sfenner		}
86156893Sfenner		if (bp + 4 > ep)
86256893Sfenner			break;
86356893Sfenner		ngroup = bp[1];
86456893Sfenner		holdtime = EXTRACT_16BITS(&bp[2]);
865146778Ssam		(void)printf("\n\t  %u group(s)", ngroup);
86656893Sfenner		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
867146778Ssam			(void)printf(", holdtime: ");
86856893Sfenner			if (holdtime == 0xffff)
869146778Ssam				(void)printf("infinite");
87056893Sfenner			else
87156893Sfenner				relts_print(holdtime);
87256893Sfenner		}
87356893Sfenner		bp += 4; len -= 4;
87456893Sfenner		for (i = 0; i < ngroup; i++) {
87556893Sfenner			if (bp >= ep)
87656893Sfenner				goto jp_done;
877146778Ssam			(void)printf("\n\t    group #%u: ", i+1);
87856893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
87956893Sfenner				(void)printf("...)");
88056893Sfenner				goto jp_done;
88156893Sfenner			}
88256893Sfenner			bp += advance; len -= advance;
88356893Sfenner			if (bp + 4 > ep) {
88456893Sfenner				(void)printf("...)");
88556893Sfenner				goto jp_done;
88656893Sfenner			}
88756893Sfenner			njoin = EXTRACT_16BITS(&bp[0]);
88856893Sfenner			nprune = EXTRACT_16BITS(&bp[2]);
889146778Ssam			(void)printf(", joined sources: %u, pruned sources: %u", njoin,nprune);
89056893Sfenner			bp += 4; len -= 4;
89156893Sfenner			for (j = 0; j < njoin; j++) {
892146778Ssam				(void)printf("\n\t      joined source #%u: ",j+1);
89356893Sfenner				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
89456893Sfenner					(void)printf("...)");
89556893Sfenner					goto jp_done;
89656893Sfenner				}
89756893Sfenner				bp += advance; len -= advance;
89856893Sfenner			}
89956893Sfenner			for (j = 0; j < nprune; j++) {
900146778Ssam				(void)printf("\n\t      pruned source #%u: ",j+1);
90156893Sfenner				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
90256893Sfenner					(void)printf("...)");
90356893Sfenner					goto jp_done;
90456893Sfenner				}
90556893Sfenner				bp += advance; len -= advance;
90656893Sfenner			}
90756893Sfenner		}
90856893Sfenner	jp_done:
90956893Sfenner		break;
91056893Sfenner	    }
91156893Sfenner
912146778Ssam	case PIMV2_TYPE_BOOTSTRAP:
91398527Sfenner	{
91456893Sfenner		int i, j, frpcnt;
91556893Sfenner		bp += 4;
91656893Sfenner
91756893Sfenner		/* Fragment Tag, Hash Mask len, and BSR-priority */
91856893Sfenner		if (bp + sizeof(u_int16_t) >= ep) break;
91956893Sfenner		(void)printf(" tag=%x", EXTRACT_16BITS(bp));
92056893Sfenner		bp += sizeof(u_int16_t);
92156893Sfenner		if (bp >= ep) break;
92256893Sfenner		(void)printf(" hashmlen=%d", bp[0]);
92356893Sfenner		if (bp + 1 >= ep) break;
92456893Sfenner		(void)printf(" BSRprio=%d", bp[1]);
92556893Sfenner		bp += 2;
92656893Sfenner
92756893Sfenner		/* Encoded-Unicast-BSR-Address */
92856893Sfenner		if (bp >= ep) break;
92956893Sfenner		(void)printf(" BSR=");
93056893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
93156893Sfenner			(void)printf("...");
93256893Sfenner			break;
93356893Sfenner		}
93456893Sfenner		bp += advance;
93556893Sfenner
93656893Sfenner		for (i = 0; bp < ep; i++) {
93756893Sfenner			/* Encoded-Group Address */
93856893Sfenner			(void)printf(" (group%d: ", i);
93956893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
94056893Sfenner			    < 0) {
94156893Sfenner				(void)printf("...)");
94256893Sfenner				goto bs_done;
94356893Sfenner			}
94456893Sfenner			bp += advance;
94556893Sfenner
94656893Sfenner			/* RP-Count, Frag RP-Cnt, and rsvd */
94756893Sfenner			if (bp >= ep) {
94856893Sfenner				(void)printf("...)");
94956893Sfenner				goto bs_done;
95056893Sfenner			}
95175118Sfenner			(void)printf(" RPcnt=%d", bp[0]);
95256893Sfenner			if (bp + 1 >= ep) {
95356893Sfenner				(void)printf("...)");
95456893Sfenner				goto bs_done;
95556893Sfenner			}
95675118Sfenner			(void)printf(" FRPcnt=%d", frpcnt = bp[1]);
95756893Sfenner			bp += 4;
95856893Sfenner
95956893Sfenner			for (j = 0; j < frpcnt && bp < ep; j++) {
96056893Sfenner				/* each RP info */
96156893Sfenner				(void)printf(" RP%d=", j);
96256893Sfenner				if ((advance = pimv2_addr_print(bp,
96356893Sfenner								pimv2_unicast,
96456893Sfenner								0)) < 0) {
96556893Sfenner					(void)printf("...)");
96656893Sfenner					goto bs_done;
96756893Sfenner				}
96856893Sfenner				bp += advance;
96956893Sfenner
97056893Sfenner				if (bp + 1 >= ep) {
97156893Sfenner					(void)printf("...)");
97256893Sfenner					goto bs_done;
97356893Sfenner				}
97456893Sfenner				(void)printf(",holdtime=");
97556893Sfenner				relts_print(EXTRACT_16BITS(bp));
97656893Sfenner				if (bp + 2 >= ep) {
97756893Sfenner					(void)printf("...)");
97856893Sfenner					goto bs_done;
97956893Sfenner				}
98056893Sfenner				(void)printf(",prio=%d", bp[2]);
98156893Sfenner				bp += 4;
98256893Sfenner			}
98356893Sfenner			(void)printf(")");
98456893Sfenner		}
98556893Sfenner	   bs_done:
98656893Sfenner		break;
98798527Sfenner	}
988146778Ssam	case PIMV2_TYPE_ASSERT:
98956893Sfenner		bp += 4; len -= 4;
99056893Sfenner		if (bp >= ep)
99156893Sfenner			break;
99256893Sfenner		(void)printf(" group=");
99356893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
99456893Sfenner			(void)printf("...");
99556893Sfenner			break;
99656893Sfenner		}
99756893Sfenner		bp += advance; len -= advance;
99856893Sfenner		if (bp >= ep)
99956893Sfenner			break;
100056893Sfenner		(void)printf(" src=");
100156893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
100256893Sfenner			(void)printf("...");
100356893Sfenner			break;
100456893Sfenner		}
100556893Sfenner		bp += advance; len -= advance;
100656893Sfenner		if (bp + 8 > ep)
100756893Sfenner			break;
100856893Sfenner		if (bp[0] & 0x80)
100956893Sfenner			(void)printf(" RPT");
101056893Sfenner		(void)printf(" pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff);
101156893Sfenner		(void)printf(" metric=%u", EXTRACT_32BITS(&bp[4]));
101256893Sfenner		break;
101356893Sfenner
1014146778Ssam	case PIMV2_TYPE_CANDIDATE_RP:
101598527Sfenner	{
101656893Sfenner		int i, pfxcnt;
101756893Sfenner		bp += 4;
101856893Sfenner
101956893Sfenner		/* Prefix-Cnt, Priority, and Holdtime */
102056893Sfenner		if (bp >= ep) break;
102156893Sfenner		(void)printf(" prefix-cnt=%d", bp[0]);
102256893Sfenner		pfxcnt = bp[0];
102356893Sfenner		if (bp + 1 >= ep) break;
102456893Sfenner		(void)printf(" prio=%d", bp[1]);
102556893Sfenner		if (bp + 3 >= ep) break;
102656893Sfenner		(void)printf(" holdtime=");
102756893Sfenner		relts_print(EXTRACT_16BITS(&bp[2]));
102856893Sfenner		bp += 4;
102956893Sfenner
103056893Sfenner		/* Encoded-Unicast-RP-Address */
103156893Sfenner		if (bp >= ep) break;
103256893Sfenner		(void)printf(" RP=");
103356893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
103456893Sfenner			(void)printf("...");
103556893Sfenner			break;
103656893Sfenner		}
103756893Sfenner		bp += advance;
103856893Sfenner
103956893Sfenner		/* Encoded-Group Addresses */
104056893Sfenner		for (i = 0; i < pfxcnt && bp < ep; i++) {
104156893Sfenner			(void)printf(" Group%d=", i);
104256893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
104356893Sfenner			    < 0) {
104456893Sfenner				(void)printf("...");
104556893Sfenner				break;
104656893Sfenner			}
104756893Sfenner			bp += advance;
104856893Sfenner		}
104956893Sfenner		break;
105098527Sfenner	}
105156893Sfenner
1052146778Ssam	case PIMV2_TYPE_PRUNE_REFRESH:
105356893Sfenner		(void)printf(" src=");
105456893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
105556893Sfenner			(void)printf("...");
105656893Sfenner			break;
105756893Sfenner		}
105856893Sfenner		bp += advance;
105956893Sfenner		(void)printf(" grp=");
106056893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
106156893Sfenner			(void)printf("...");
106256893Sfenner			break;
106356893Sfenner		}
106456893Sfenner		bp += advance;
106556893Sfenner		(void)printf(" forwarder=");
106656893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
106756893Sfenner			(void)printf("...");
106856893Sfenner			break;
106956893Sfenner		}
107056893Sfenner		bp += advance;
107156893Sfenner		TCHECK2(bp[0], 2);
107256893Sfenner		(void)printf(" TUNR ");
107356893Sfenner		relts_print(EXTRACT_16BITS(bp));
107456893Sfenner		break;
107556893Sfenner
107656893Sfenner
107756893Sfenner	 default:
107856893Sfenner		(void)printf(" [type %d]", PIM_TYPE(pim->pim_typever));
107956893Sfenner		break;
108056893Sfenner	}
108156893Sfenner
108256893Sfenner	return;
108356893Sfenner
108456893Sfennertrunc:
108556893Sfenner	(void)printf("[|pim]");
108656893Sfenner}
1087146778Ssam
1088146778Ssam/*
1089146778Ssam * Local Variables:
1090146778Ssam * c-style: whitesmith
1091146778Ssam * c-basic-offset: 8
1092146778Ssam * End:
1093146778Ssam */
1094