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$
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>
34236192Sdelphij
35236192Sdelphij#include <stdio.h>
36236192Sdelphij#include <stdlib.h>
37236192Sdelphij
38146778Ssam#include "interface.h"
39236192Sdelphij#include "addrtoname.h"
40236192Sdelphij#include "extract.h"
4117680Spst
42236192Sdelphij#include "ip.h"
43236192Sdelphij
44146778Ssam#define PIMV2_TYPE_HELLO         0
45146778Ssam#define PIMV2_TYPE_REGISTER      1
46146778Ssam#define PIMV2_TYPE_REGISTER_STOP 2
47146778Ssam#define PIMV2_TYPE_JOIN_PRUNE    3
48146778Ssam#define PIMV2_TYPE_BOOTSTRAP     4
49146778Ssam#define PIMV2_TYPE_ASSERT        5
50146778Ssam#define PIMV2_TYPE_GRAFT         6
51146778Ssam#define PIMV2_TYPE_GRAFT_ACK     7
52146778Ssam#define PIMV2_TYPE_CANDIDATE_RP  8
53146778Ssam#define PIMV2_TYPE_PRUNE_REFRESH 9
54146778Ssam
55146778Ssamstatic struct tok pimv2_type_values[] = {
56146778Ssam    { PIMV2_TYPE_HELLO,         "Hello" },
57146778Ssam    { PIMV2_TYPE_REGISTER,      "Register" },
58146778Ssam    { PIMV2_TYPE_REGISTER_STOP, "Register Stop" },
59146778Ssam    { PIMV2_TYPE_JOIN_PRUNE,    "Join / Prune" },
60146778Ssam    { PIMV2_TYPE_BOOTSTRAP,     "Bootstrap" },
61146778Ssam    { PIMV2_TYPE_ASSERT,        "Assert" },
62146778Ssam    { PIMV2_TYPE_GRAFT,         "Graft" },
63146778Ssam    { PIMV2_TYPE_GRAFT_ACK,     "Graft Acknowledgement" },
64146778Ssam    { PIMV2_TYPE_CANDIDATE_RP,  "Candidate RP Advertisement" },
65146778Ssam    { PIMV2_TYPE_PRUNE_REFRESH, "Prune Refresh" },
66146778Ssam    { 0, NULL}
67146778Ssam};
68146778Ssam
69146778Ssam#define PIMV2_HELLO_OPTION_HOLDTIME             1
70146778Ssam#define PIMV2_HELLO_OPTION_LANPRUNEDELAY        2
71146778Ssam#define PIMV2_HELLO_OPTION_DR_PRIORITY_OLD     18
72146778Ssam#define PIMV2_HELLO_OPTION_DR_PRIORITY         19
73146778Ssam#define PIMV2_HELLO_OPTION_GENID               20
74146778Ssam#define PIMV2_HELLO_OPTION_REFRESH_CAP         21
75146778Ssam#define PIMV2_HELLO_OPTION_BIDIR_CAP           22
76146778Ssam#define PIMV2_HELLO_OPTION_ADDRESS_LIST        24
77146778Ssam#define PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD 65001
78146778Ssam
79146778Ssamstatic struct tok pimv2_hello_option_values[] = {
80146778Ssam    { PIMV2_HELLO_OPTION_HOLDTIME,         "Hold Time" },
81146778Ssam    { PIMV2_HELLO_OPTION_LANPRUNEDELAY,    "LAN Prune Delay" },
82146778Ssam    { PIMV2_HELLO_OPTION_DR_PRIORITY_OLD,  "DR Priority (Old)" },
83146778Ssam    { PIMV2_HELLO_OPTION_DR_PRIORITY,      "DR Priority" },
84146778Ssam    { PIMV2_HELLO_OPTION_GENID,            "Generation ID" },
85146778Ssam    { PIMV2_HELLO_OPTION_REFRESH_CAP,      "State Refresh Capability" },
86146778Ssam    { PIMV2_HELLO_OPTION_BIDIR_CAP,        "Bi-Directional Capability" },
87146778Ssam    { PIMV2_HELLO_OPTION_ADDRESS_LIST,     "Address List" },
88146778Ssam    { PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD, "Address List (Old)" },
89146778Ssam    { 0, NULL}
90146778Ssam};
91146778Ssam
92172686Smlaier#define PIMV2_REGISTER_FLAG_LEN      4
93172686Smlaier#define PIMV2_REGISTER_FLAG_BORDER 0x80000000
94172686Smlaier#define PIMV2_REGISTER_FLAG_NULL   0x40000000
95146778Ssam
96172686Smlaierstatic struct tok pimv2_register_flag_values[] = {
97172686Smlaier    { PIMV2_REGISTER_FLAG_BORDER, "Border" },
98172686Smlaier    { PIMV2_REGISTER_FLAG_NULL, "Null" },
99172686Smlaier    { 0, NULL}
100172686Smlaier};
101172686Smlaier
10256893Sfenner/*
10356893Sfenner * XXX: We consider a case where IPv6 is not ready yet for portability,
10456893Sfenner * but PIM dependent defintions should be independent of IPv6...
10556893Sfenner */
10656893Sfenner
10756893Sfennerstruct pim {
10856893Sfenner	u_int8_t pim_typever;
10957278Sfenner			/* upper 4bit: PIM version number; 2 for PIMv2 */
11057278Sfenner			/* lower 4bit: the PIM message type, currently they are:
11156893Sfenner			 * Hello, Register, Register-Stop, Join/Prune,
11256893Sfenner			 * Bootstrap, Assert, Graft (PIM-DM only),
11356893Sfenner			 * Graft-Ack (PIM-DM only), C-RP-Adv
11456893Sfenner			 */
11557278Sfenner#define PIM_VER(x)	(((x) & 0xf0) >> 4)
11657278Sfenner#define PIM_TYPE(x)	((x) & 0x0f)
11756893Sfenner	u_char  pim_rsv;	/* Reserved */
11856893Sfenner	u_short	pim_cksum;	/* IP style check sum */
11956893Sfenner};
12056893Sfenner
121214478Srpaulostatic void pimv2_print(register const u_char *bp, register u_int len, u_int cksum);
12256893Sfenner
12356893Sfennerstatic void
12456893Sfennerpimv1_join_prune_print(register const u_char *bp, register u_int len)
12556893Sfenner{
12698527Sfenner	int maddrlen, addrlen, ngroups, njoin, nprune;
12798527Sfenner	int njp;
12856893Sfenner
12998527Sfenner	/* If it's a single group and a single source, use 1-line output. */
13098527Sfenner	if (TTEST2(bp[0], 30) && bp[11] == 1 &&
13198527Sfenner	    ((njoin = EXTRACT_16BITS(&bp[20])) + EXTRACT_16BITS(&bp[22])) == 1) {
13298527Sfenner		int hold;
13356893Sfenner
13498527Sfenner		(void)printf(" RPF %s ", ipaddr_string(bp));
13598527Sfenner		hold = EXTRACT_16BITS(&bp[6]);
13698527Sfenner		if (hold != 180) {
13798527Sfenner			(void)printf("Hold ");
13898527Sfenner			relts_print(hold);
13998527Sfenner		}
14098527Sfenner		(void)printf("%s (%s/%d, %s", njoin ? "Join" : "Prune",
14198527Sfenner		ipaddr_string(&bp[26]), bp[25] & 0x3f,
14298527Sfenner		ipaddr_string(&bp[12]));
14398527Sfenner		if (EXTRACT_32BITS(&bp[16]) != 0xffffffff)
14498527Sfenner			(void)printf("/%s", ipaddr_string(&bp[16]));
14598527Sfenner		(void)printf(") %s%s %s",
14656893Sfenner		    (bp[24] & 0x01) ? "Sparse" : "Dense",
14756893Sfenner		    (bp[25] & 0x80) ? " WC" : "",
14856893Sfenner		    (bp[25] & 0x40) ? "RP" : "SPT");
14998527Sfenner		return;
15098527Sfenner	}
15156893Sfenner
152162021Ssam	TCHECK2(bp[0], sizeof(struct in_addr));
15398527Sfenner	if (vflag > 1)
15498527Sfenner		(void)printf("\n");
15598527Sfenner	(void)printf(" Upstream Nbr: %s", ipaddr_string(bp));
15698527Sfenner	TCHECK2(bp[6], 2);
15798527Sfenner	if (vflag > 1)
15898527Sfenner		(void)printf("\n");
15998527Sfenner	(void)printf(" Hold time: ");
16098527Sfenner	relts_print(EXTRACT_16BITS(&bp[6]));
16198527Sfenner	if (vflag < 2)
16298527Sfenner		return;
16398527Sfenner	bp += 8;
16498527Sfenner	len -= 8;
16556893Sfenner
16698527Sfenner	TCHECK2(bp[0], 4);
16798527Sfenner	maddrlen = bp[1];
16898527Sfenner	addrlen = bp[2];
16998527Sfenner	ngroups = bp[3];
17098527Sfenner	bp += 4;
17198527Sfenner	len -= 4;
17298527Sfenner	while (ngroups--) {
173147904Ssam		/*
174147904Ssam		 * XXX - does the address have length "addrlen" and the
175147904Ssam		 * mask length "maddrlen"?
176147904Ssam		 */
177162021Ssam		TCHECK2(bp[0], sizeof(struct in_addr));
17898527Sfenner		(void)printf("\n\tGroup: %s", ipaddr_string(bp));
179162021Ssam		TCHECK2(bp[4], sizeof(struct in_addr));
18098527Sfenner		if (EXTRACT_32BITS(&bp[4]) != 0xffffffff)
18198527Sfenner			(void)printf("/%s", ipaddr_string(&bp[4]));
18298527Sfenner		TCHECK2(bp[8], 4);
18398527Sfenner		njoin = EXTRACT_16BITS(&bp[8]);
18498527Sfenner		nprune = EXTRACT_16BITS(&bp[10]);
18598527Sfenner		(void)printf(" joined: %d pruned: %d", njoin, nprune);
18698527Sfenner		bp += 12;
18798527Sfenner		len -= 12;
18898527Sfenner		for (njp = 0; njp < (njoin + nprune); njp++) {
189127675Sbms			const char *type;
19098527Sfenner
19198527Sfenner			if (njp < njoin)
19298527Sfenner				type = "Join ";
19398527Sfenner			else
19498527Sfenner				type = "Prune";
19598527Sfenner			TCHECK2(bp[0], 6);
19698527Sfenner			(void)printf("\n\t%s %s%s%s%s/%d", type,
19756893Sfenner			    (bp[0] & 0x01) ? "Sparse " : "Dense ",
19856893Sfenner			    (bp[1] & 0x80) ? "WC " : "",
19956893Sfenner			    (bp[1] & 0x40) ? "RP " : "SPT ",
20098527Sfenner			ipaddr_string(&bp[2]), bp[1] & 0x3f);
20198527Sfenner			bp += 6;
20298527Sfenner			len -= 6;
20398527Sfenner		}
20456893Sfenner	}
20598527Sfenner	return;
20656893Sfennertrunc:
20798527Sfenner	(void)printf("[|pim]");
20898527Sfenner	return;
20956893Sfenner}
21056893Sfenner
21117680Spstvoid
21256893Sfennerpimv1_print(register const u_char *bp, register u_int len)
21317680Spst{
21498527Sfenner	register const u_char *ep;
21598527Sfenner	register u_char type;
21617680Spst
21798527Sfenner	ep = (const u_char *)snapend;
21898527Sfenner	if (bp >= ep)
21998527Sfenner		return;
22017680Spst
221127675Sbms	TCHECK(bp[1]);
22298527Sfenner	type = bp[1];
22317680Spst
22498527Sfenner	switch (type) {
22598527Sfenner	case 0:
22698527Sfenner		(void)printf(" Query");
22798527Sfenner		if (TTEST(bp[8])) {
22898527Sfenner			switch (bp[8] >> 4) {
22998527Sfenner			case 0:
23098527Sfenner				(void)printf(" Dense-mode");
23156893Sfenner				break;
23298527Sfenner			case 1:
23398527Sfenner				(void)printf(" Sparse-mode");
23456893Sfenner				break;
23598527Sfenner			case 2:
23698527Sfenner				(void)printf(" Sparse-Dense-mode");
23756893Sfenner				break;
23898527Sfenner			default:
23998527Sfenner				(void)printf(" mode-%d", bp[8] >> 4);
24056893Sfenner				break;
24198527Sfenner			}
24256893Sfenner		}
24398527Sfenner		if (vflag) {
24498527Sfenner			TCHECK2(bp[10],2);
24598527Sfenner			(void)printf(" (Hold-time ");
24698527Sfenner			relts_print(EXTRACT_16BITS(&bp[10]));
24798527Sfenner			(void)printf(")");
24898527Sfenner		}
24998527Sfenner		break;
25017680Spst
25198527Sfenner	case 1:
25298527Sfenner		(void)printf(" Register");
25398527Sfenner		TCHECK2(bp[8], 20);			/* ip header */
25498527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[20]),
25598527Sfenner		    ipaddr_string(&bp[24]));
25698527Sfenner		break;
25798527Sfenner	case 2:
25898527Sfenner		(void)printf(" Register-Stop");
259162021Ssam		TCHECK2(bp[12], sizeof(struct in_addr));
26098527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[8]),
26198527Sfenner		    ipaddr_string(&bp[12]));
26298527Sfenner		break;
26398527Sfenner	case 3:
26498527Sfenner		(void)printf(" Join/Prune");
26598527Sfenner		if (vflag)
26698527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
26798527Sfenner		break;
26898527Sfenner	case 4:
26998527Sfenner		(void)printf(" RP-reachable");
27098527Sfenner		if (vflag) {
27198527Sfenner			TCHECK2(bp[22], 2);
27298527Sfenner			(void)printf(" group %s",
27356893Sfenner			ipaddr_string(&bp[8]));
27498527Sfenner			if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
27598527Sfenner				(void)printf("/%s", ipaddr_string(&bp[12]));
27698527Sfenner			(void)printf(" RP %s hold ", ipaddr_string(&bp[16]));
27798527Sfenner			relts_print(EXTRACT_16BITS(&bp[22]));
27898527Sfenner		}
27998527Sfenner		break;
28098527Sfenner	case 5:
28198527Sfenner		(void)printf(" Assert");
282162021Ssam		TCHECK2(bp[16], sizeof(struct in_addr));
28398527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[16]),
28498527Sfenner		    ipaddr_string(&bp[8]));
28556893Sfenner		if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
28656893Sfenner			(void)printf("/%s", ipaddr_string(&bp[12]));
28798527Sfenner		TCHECK2(bp[24], 4);
28898527Sfenner		(void)printf(" %s pref %d metric %d",
28998527Sfenner		    (bp[20] & 0x80) ? "RP-tree" : "SPT",
29056893Sfenner		EXTRACT_32BITS(&bp[20]) & 0x7fffffff,
29156893Sfenner		EXTRACT_32BITS(&bp[24]));
29298527Sfenner		break;
29398527Sfenner	case 6:
29498527Sfenner		(void)printf(" Graft");
29598527Sfenner		if (vflag)
29698527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
29798527Sfenner		break;
29898527Sfenner	case 7:
29998527Sfenner		(void)printf(" Graft-ACK");
30098527Sfenner		if (vflag)
30198527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
30298527Sfenner		break;
30398527Sfenner	case 8:
30498527Sfenner		(void)printf(" Mode");
30598527Sfenner		break;
30698527Sfenner	default:
30798527Sfenner		(void)printf(" [type %d]", type);
30898527Sfenner		break;
30956893Sfenner	}
31098527Sfenner	if ((bp[4] >> 4) != 1)
31198527Sfenner		(void)printf(" [v%d]", bp[4] >> 4);
31298527Sfenner	return;
31317680Spst
31456893Sfennertrunc:
31598527Sfenner	(void)printf("[|pim]");
31698527Sfenner	return;
31717680Spst}
31856893Sfenner
31956893Sfenner/*
32056893Sfenner * auto-RP is a cisco protocol, documented at
32198527Sfenner * ftp://ftpeng.cisco.com/ipmulticast/specs/pim-autorp-spec01.txt
32298527Sfenner *
32398527Sfenner * This implements version 1+, dated Sept 9, 1998.
32456893Sfenner */
32556893Sfennervoid
32656893Sfennercisco_autorp_print(register const u_char *bp, register u_int len)
32756893Sfenner{
32898527Sfenner	int type;
32998527Sfenner	int numrps;
33098527Sfenner	int hold;
33156893Sfenner
33298527Sfenner	TCHECK(bp[0]);
33398527Sfenner	(void)printf(" auto-rp ");
33498527Sfenner	type = bp[0];
33598527Sfenner	switch (type) {
33698527Sfenner	case 0x11:
33798527Sfenner		(void)printf("candidate-advert");
33898527Sfenner		break;
33998527Sfenner	case 0x12:
34098527Sfenner		(void)printf("mapping");
34198527Sfenner		break;
34298527Sfenner	default:
34398527Sfenner		(void)printf("type-0x%02x", type);
34498527Sfenner		break;
34598527Sfenner	}
34656893Sfenner
34798527Sfenner	TCHECK(bp[1]);
34898527Sfenner	numrps = bp[1];
34956893Sfenner
35098527Sfenner	TCHECK2(bp[2], 2);
35198527Sfenner	(void)printf(" Hold ");
35298527Sfenner	hold = EXTRACT_16BITS(&bp[2]);
35398527Sfenner	if (hold)
35498527Sfenner		relts_print(EXTRACT_16BITS(&bp[2]));
35598527Sfenner	else
35698527Sfenner		printf("FOREVER");
35756893Sfenner
35898527Sfenner	/* Next 4 bytes are reserved. */
35956893Sfenner
36098527Sfenner	bp += 8; len -= 8;
36156893Sfenner
36298527Sfenner	/*XXX skip unless -v? */
36356893Sfenner
36498527Sfenner	/*
36598527Sfenner	 * Rest of packet:
36698527Sfenner	 * numrps entries of the form:
36798527Sfenner	 * 32 bits: RP
36898527Sfenner	 * 6 bits: reserved
36998527Sfenner	 * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
37098527Sfenner	 * 8 bits: # of entries for this RP
37198527Sfenner	 * each entry: 7 bits: reserved, 1 bit: negative,
37298527Sfenner	 *	       8 bits: mask 32 bits: source
37398527Sfenner	 * lather, rinse, repeat.
37498527Sfenner	 */
37598527Sfenner	while (numrps--) {
37698527Sfenner		int nentries;
37798527Sfenner		char s;
37856893Sfenner
37998527Sfenner		TCHECK2(bp[0], 4);
38098527Sfenner		(void)printf(" RP %s", ipaddr_string(bp));
38198527Sfenner		TCHECK(bp[4]);
38298527Sfenner		switch (bp[4] & 0x3) {
38398527Sfenner		case 0: printf(" PIMv?");
38498527Sfenner			break;
38598527Sfenner		case 1:	printf(" PIMv1");
38698527Sfenner			break;
38798527Sfenner		case 2:	printf(" PIMv2");
38898527Sfenner			break;
38998527Sfenner		case 3:	printf(" PIMv1+2");
39098527Sfenner			break;
39198527Sfenner		}
39298527Sfenner		if (bp[4] & 0xfc)
39398527Sfenner			(void)printf(" [rsvd=0x%02x]", bp[4] & 0xfc);
39498527Sfenner		TCHECK(bp[5]);
39598527Sfenner		nentries = bp[5];
39698527Sfenner		bp += 6; len -= 6;
39798527Sfenner		s = ' ';
39898527Sfenner		for (; nentries; nentries--) {
39998527Sfenner			TCHECK2(bp[0], 6);
40098527Sfenner			(void)printf("%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
40198527Sfenner			    ipaddr_string(&bp[2]), bp[1]);
402236192Sdelphij			if (bp[0] & 0x02) {
403236192Sdelphij			    (void)printf(" bidir");
404236192Sdelphij			}
405236192Sdelphij			if (bp[0] & 0xfc) {
406236192Sdelphij			    (void)printf("[rsvd=0x%02x]", bp[0] & 0xfc);
407236192Sdelphij			}
40898527Sfenner			s = ',';
40998527Sfenner			bp += 6; len -= 6;
41098527Sfenner		}
41156893Sfenner	}
41298527Sfenner	return;
41356893Sfenner
41456893Sfennertrunc:
41598527Sfenner	(void)printf("[|autorp]");
41698527Sfenner	return;
41756893Sfenner}
41856893Sfenner
41956893Sfennervoid
420214478Srpaulopim_print(register const u_char *bp, register u_int len, u_int cksum)
42156893Sfenner{
42256893Sfenner	register const u_char *ep;
42356893Sfenner	register struct pim *pim = (struct pim *)bp;
42456893Sfenner
42556893Sfenner	ep = (const u_char *)snapend;
42656893Sfenner	if (bp >= ep)
42756893Sfenner		return;
42856893Sfenner#ifdef notyet			/* currently we see only version and type */
42956893Sfenner	TCHECK(pim->pim_rsv);
43056893Sfenner#endif
43156893Sfenner
43275118Sfenner	switch (PIM_VER(pim->pim_typever)) {
433146778Ssam	case 2:
434146778Ssam            if (!vflag) {
435172686Smlaier                printf("PIMv%u, %s, length %u",
436146778Ssam                       PIM_VER(pim->pim_typever),
437146778Ssam                       tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)),
438146778Ssam                       len);
439146778Ssam                return;
440146778Ssam            } else {
441172686Smlaier                printf("PIMv%u, length %u\n\t%s",
442146778Ssam                       PIM_VER(pim->pim_typever),
443146778Ssam                       len,
444146778Ssam                       tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)));
445214478Srpaulo                pimv2_print(bp, len, cksum);
446146778Ssam            }
447146778Ssam            break;
44898527Sfenner	default:
449172686Smlaier		printf("PIMv%u, length %u",
450146778Ssam                       PIM_VER(pim->pim_typever),
451146778Ssam                       len);
45256893Sfenner		break;
45356893Sfenner	}
45456893Sfenner	return;
45556893Sfenner}
45656893Sfenner
45756893Sfenner/*
45856893Sfenner * PIMv2 uses encoded address representations.
45956893Sfenner *
46056893Sfenner * The last PIM-SM I-D before RFC2117 was published specified the
46156893Sfenner * following representation for unicast addresses.  However, RFC2117
46256893Sfenner * specified no encoding for unicast addresses with the unicast
46356893Sfenner * address length specified in the header.  Therefore, we have to
46456893Sfenner * guess which encoding is being used (Cisco's PIMv2 implementation
46556893Sfenner * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
46656893Sfenner * field into a 'unicast-address-length-in-bytes' field.  We guess
46756893Sfenner * that it's the draft encoding if this reserved field is zero.
46856893Sfenner *
46956893Sfenner * RFC2362 goes back to the encoded format, and calls the addr length
47056893Sfenner * field "reserved" again.
47156893Sfenner *
47256893Sfenner * The first byte is the address family, from:
47356893Sfenner *
47456893Sfenner *    0    Reserved
47556893Sfenner *    1    IP (IP version 4)
47656893Sfenner *    2    IP6 (IP version 6)
47756893Sfenner *    3    NSAP
47856893Sfenner *    4    HDLC (8-bit multidrop)
47956893Sfenner *    5    BBN 1822
48056893Sfenner *    6    802 (includes all 802 media plus Ethernet "canonical format")
48156893Sfenner *    7    E.163
48256893Sfenner *    8    E.164 (SMDS, Frame Relay, ATM)
48356893Sfenner *    9    F.69 (Telex)
48456893Sfenner *   10    X.121 (X.25, Frame Relay)
48556893Sfenner *   11    IPX
48656893Sfenner *   12    Appletalk
48756893Sfenner *   13    Decnet IV
48856893Sfenner *   14    Banyan Vines
48956893Sfenner *   15    E.164 with NSAP format subaddress
49056893Sfenner *
49156893Sfenner * In addition, the second byte is an "Encoding".  0 is the default
49256893Sfenner * encoding for the address family, and no other encodings are currently
49356893Sfenner * specified.
49456893Sfenner *
49556893Sfenner */
49656893Sfenner
49756893Sfennerstatic int pimv2_addr_len;
49856893Sfenner
49956893Sfennerenum pimv2_addrtype {
50056893Sfenner	pimv2_unicast, pimv2_group, pimv2_source
50156893Sfenner};
50256893Sfenner
50356893Sfenner/*  0                   1                   2                   3
50456893Sfenner *  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
50556893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50656893Sfenner * | Addr Family   | Encoding Type |     Unicast Address           |
50756893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
50856893Sfenner *  0                   1                   2                   3
50956893Sfenner *  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
51056893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51156893Sfenner * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
51256893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51356893Sfenner * |                Group multicast Address                        |
51456893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51556893Sfenner *  0                   1                   2                   3
51656893Sfenner *  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
51756893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51856893Sfenner * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
51956893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52056893Sfenner * |                        Source Address                         |
52156893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
52256893Sfenner */
52356893Sfennerstatic int
52456893Sfennerpimv2_addr_print(const u_char *bp, enum pimv2_addrtype at, int silent)
52556893Sfenner{
52656893Sfenner	int af;
52756893Sfenner	int len, hdrlen;
52856893Sfenner
52956893Sfenner	TCHECK(bp[0]);
53056893Sfenner
53156893Sfenner	if (pimv2_addr_len == 0) {
53256893Sfenner		TCHECK(bp[1]);
53356893Sfenner		switch (bp[0]) {
53498527Sfenner		case 1:
53556893Sfenner			af = AF_INET;
536162021Ssam			len = sizeof(struct in_addr);
53756893Sfenner			break;
53856893Sfenner#ifdef INET6
53998527Sfenner		case 2:
54056893Sfenner			af = AF_INET6;
541162021Ssam			len = sizeof(struct in6_addr);
54256893Sfenner			break;
54356893Sfenner#endif
54498527Sfenner		default:
54556893Sfenner			return -1;
54656893Sfenner		}
54756893Sfenner		if (bp[1] != 0)
54856893Sfenner			return -1;
54956893Sfenner		hdrlen = 2;
55056893Sfenner	} else {
55156893Sfenner		switch (pimv2_addr_len) {
552162021Ssam		case sizeof(struct in_addr):
55356893Sfenner			af = AF_INET;
55456893Sfenner			break;
55556893Sfenner#ifdef INET6
556162021Ssam		case sizeof(struct in6_addr):
55756893Sfenner			af = AF_INET6;
55856893Sfenner			break;
55956893Sfenner#endif
56098527Sfenner		default:
56156893Sfenner			return -1;
56256893Sfenner			break;
56356893Sfenner		}
56456893Sfenner		len = pimv2_addr_len;
56556893Sfenner		hdrlen = 0;
56656893Sfenner	}
56756893Sfenner
56856893Sfenner	bp += hdrlen;
56956893Sfenner	switch (at) {
57098527Sfenner	case pimv2_unicast:
57156893Sfenner		TCHECK2(bp[0], len);
57256893Sfenner		if (af == AF_INET) {
57356893Sfenner			if (!silent)
57456893Sfenner				(void)printf("%s", ipaddr_string(bp));
57556893Sfenner		}
57656893Sfenner#ifdef INET6
57756893Sfenner		else if (af == AF_INET6) {
57856893Sfenner			if (!silent)
57956893Sfenner				(void)printf("%s", ip6addr_string(bp));
58056893Sfenner		}
58156893Sfenner#endif
58256893Sfenner		return hdrlen + len;
58398527Sfenner	case pimv2_group:
58498527Sfenner	case pimv2_source:
58556893Sfenner		TCHECK2(bp[0], len + 2);
58656893Sfenner		if (af == AF_INET) {
58756893Sfenner			if (!silent) {
58856893Sfenner				(void)printf("%s", ipaddr_string(bp + 2));
58956893Sfenner				if (bp[1] != 32)
59056893Sfenner					(void)printf("/%u", bp[1]);
59156893Sfenner			}
59256893Sfenner		}
59356893Sfenner#ifdef INET6
59456893Sfenner		else if (af == AF_INET6) {
59556893Sfenner			if (!silent) {
59656893Sfenner				(void)printf("%s", ip6addr_string(bp + 2));
59756893Sfenner				if (bp[1] != 128)
59856893Sfenner					(void)printf("/%u", bp[1]);
59956893Sfenner			}
60056893Sfenner		}
60156893Sfenner#endif
60256893Sfenner		if (bp[0] && !silent) {
60356893Sfenner			if (at == pimv2_group) {
60456893Sfenner				(void)printf("(0x%02x)", bp[0]);
60556893Sfenner			} else {
60656893Sfenner				(void)printf("(%s%s%s",
60756893Sfenner					bp[0] & 0x04 ? "S" : "",
60856893Sfenner					bp[0] & 0x02 ? "W" : "",
60956893Sfenner					bp[0] & 0x01 ? "R" : "");
61056893Sfenner				if (bp[0] & 0xf8) {
61156893Sfenner					(void) printf("+0x%02x", bp[0] & 0xf8);
61256893Sfenner				}
61356893Sfenner				(void)printf(")");
61456893Sfenner			}
61556893Sfenner		}
61656893Sfenner		return hdrlen + 2 + len;
61756893Sfenner	default:
61856893Sfenner		return -1;
61956893Sfenner	}
62056893Sfennertrunc:
62156893Sfenner	return -1;
62256893Sfenner}
62356893Sfenner
62456893Sfennerstatic void
625214478Srpaulopimv2_print(register const u_char *bp, register u_int len, u_int cksum)
62656893Sfenner{
62756893Sfenner	register const u_char *ep;
62856893Sfenner	register struct pim *pim = (struct pim *)bp;
62956893Sfenner	int advance;
63056893Sfenner
63156893Sfenner	ep = (const u_char *)snapend;
63256893Sfenner	if (bp >= ep)
63356893Sfenner		return;
63457278Sfenner	if (ep > bp + len)
63557278Sfenner		ep = bp + len;
63656893Sfenner	TCHECK(pim->pim_rsv);
63756893Sfenner	pimv2_addr_len = pim->pim_rsv;
63856893Sfenner	if (pimv2_addr_len != 0)
639146778Ssam		(void)printf(", RFC2117-encoding");
64056893Sfenner
641172686Smlaier        printf(", cksum 0x%04x ", EXTRACT_16BITS(&pim->pim_cksum));
642172686Smlaier        if (EXTRACT_16BITS(&pim->pim_cksum) == 0) {
643172686Smlaier                printf("(unverified)");
644172686Smlaier        } else {
645214478Srpaulo                printf("(%scorrect)", TTEST2(bp[0], len) && cksum ? "in" : "" );
646172686Smlaier        }
647172686Smlaier
64856893Sfenner	switch (PIM_TYPE(pim->pim_typever)) {
649146778Ssam	case PIMV2_TYPE_HELLO:
65056893Sfenner	    {
65156893Sfenner		u_int16_t otype, olen;
65256893Sfenner		bp += 4;
65356893Sfenner		while (bp < ep) {
65456893Sfenner			TCHECK2(bp[0], 4);
65556893Sfenner			otype = EXTRACT_16BITS(&bp[0]);
65656893Sfenner			olen = EXTRACT_16BITS(&bp[2]);
65756893Sfenner			TCHECK2(bp[0], 4 + olen);
658146778Ssam
659172686Smlaier                        printf("\n\t  %s Option (%u), length %u, Value: ",
660146778Ssam                               tok2str( pimv2_hello_option_values,"Unknown",otype),
661146778Ssam                               otype,
662146778Ssam                               olen);
663146778Ssam			bp += 4;
664146778Ssam
66556893Sfenner			switch (otype) {
666146778Ssam			case PIMV2_HELLO_OPTION_HOLDTIME:
667146778Ssam                                relts_print(EXTRACT_16BITS(bp));
668146778Ssam                                break;
66956893Sfenner
670146778Ssam			case PIMV2_HELLO_OPTION_LANPRUNEDELAY:
671127675Sbms				if (olen != 4) {
672242485Sdelphij					(void)printf("ERROR: Option Length != 4 Bytes (%u)", olen);
673127675Sbms				} else {
674127675Sbms					char t_bit;
675127675Sbms					u_int16_t lan_delay, override_interval;
676146778Ssam					lan_delay = EXTRACT_16BITS(bp);
677146778Ssam					override_interval = EXTRACT_16BITS(bp+2);
678127675Sbms					t_bit = (lan_delay & 0x8000)? 1 : 0;
679127675Sbms					lan_delay &= ~0x8000;
680146778Ssam					(void)printf("\n\t    T-bit=%d, LAN delay %dms, Override interval %dms",
681127675Sbms					t_bit, lan_delay, override_interval);
682127675Sbms				}
683127675Sbms				break;
684127675Sbms
685146778Ssam			case PIMV2_HELLO_OPTION_DR_PRIORITY_OLD:
686146778Ssam			case PIMV2_HELLO_OPTION_DR_PRIORITY:
687146778Ssam                                switch (olen) {
688146778Ssam                                case 0:
689146778Ssam                                    printf("Bi-Directional Capability (Old)");
690146778Ssam                                    break;
691146778Ssam                                case 4:
692146778Ssam                                    printf("%u", EXTRACT_32BITS(bp));
693146778Ssam                                    break;
694146778Ssam                                default:
695242485Sdelphij                                    printf("ERROR: Option Length != 4 Bytes (%u)", olen);
696146778Ssam                                    break;
697146778Ssam                                }
698146778Ssam                                break;
699111729Sfenner
700146778Ssam			case PIMV2_HELLO_OPTION_GENID:
701146778Ssam                                (void)printf("0x%08x", EXTRACT_32BITS(bp));
70256893Sfenner				break;
70356893Sfenner
704146778Ssam			case PIMV2_HELLO_OPTION_REFRESH_CAP:
705146778Ssam                                (void)printf("v%d", *bp);
706146778Ssam				if (*(bp+1) != 0) {
707146778Ssam                                    (void)printf(", interval ");
708146778Ssam                                    relts_print(*(bp+1));
70956893Sfenner				}
710146778Ssam				if (EXTRACT_16BITS(bp+2) != 0) {
711146778Ssam                                    (void)printf(" ?0x%04x?", EXTRACT_16BITS(bp+2));
71298527Sfenner				}
71356893Sfenner				break;
71456893Sfenner
715146778Ssam			case  PIMV2_HELLO_OPTION_BIDIR_CAP:
71698527Sfenner				break;
71798527Sfenner
718146778Ssam                        case PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD:
719146778Ssam                        case PIMV2_HELLO_OPTION_ADDRESS_LIST:
720127675Sbms				if (vflag > 1) {
721146778Ssam					const u_char *ptr = bp;
722146778Ssam					while (ptr < (bp+olen)) {
723127675Sbms						int advance;
724127675Sbms
725146778Ssam						printf("\n\t    ");
726127675Sbms						advance = pimv2_addr_print(ptr, pimv2_unicast, 0);
727127675Sbms						if (advance < 0) {
728127675Sbms							printf("...");
729127675Sbms							break;
730127675Sbms						}
731127675Sbms						ptr += advance;
732127675Sbms					}
733127675Sbms				}
734127675Sbms				break;
73556893Sfenner			default:
736146778Ssam                                if (vflag <= 1)
737146778Ssam                                    print_unknown_data(bp,"\n\t    ",olen);
738146778Ssam                                break;
73956893Sfenner			}
740146778Ssam                        /* do we want to see an additionally hexdump ? */
741146778Ssam                        if (vflag> 1)
742146778Ssam                            print_unknown_data(bp,"\n\t    ",olen);
743146778Ssam			bp += olen;
74456893Sfenner		}
74556893Sfenner		break;
74656893Sfenner	    }
74756893Sfenner
748146778Ssam	case PIMV2_TYPE_REGISTER:
74998527Sfenner	{
75056893Sfenner		struct ip *ip;
75156893Sfenner
752172686Smlaier                if (!TTEST2(*(bp+4), PIMV2_REGISTER_FLAG_LEN))
753172686Smlaier                        goto trunc;
754172686Smlaier
755172686Smlaier                printf(", Flags [ %s ]\n\t",
756172686Smlaier                       tok2str(pimv2_register_flag_values,
757172686Smlaier                               "none",
758172686Smlaier                               EXTRACT_32BITS(bp+4)));
759172686Smlaier
76056893Sfenner		bp += 8; len -= 8;
76156893Sfenner		/* encapsulated multicast packet */
76256893Sfenner		ip = (struct ip *)bp;
76375118Sfenner		switch (IP_V(ip)) {
764172686Smlaier                case 0: /* Null header */
765172686Smlaier			(void)printf("IP-Null-header %s > %s",
766172686Smlaier                                     ipaddr_string(&ip->ip_src),
767172686Smlaier                                     ipaddr_string(&ip->ip_dst));
768172686Smlaier			break;
769172686Smlaier
77098527Sfenner		case 4:	/* IPv4 */
771146778Ssam			ip_print(gndo, bp, len);
77256893Sfenner			break;
77356893Sfenner#ifdef INET6
77498527Sfenner		case 6:	/* IPv6 */
775236192Sdelphij			ip6_print(gndo, bp, len);
77656893Sfenner			break;
77756893Sfenner#endif
778172686Smlaier                default:
779172686Smlaier                        (void)printf("IP ver %d", IP_V(ip));
780172686Smlaier                        break;
78156893Sfenner		}
78256893Sfenner		break;
78398527Sfenner	}
78456893Sfenner
785146778Ssam	case PIMV2_TYPE_REGISTER_STOP:
78656893Sfenner		bp += 4; len -= 4;
78756893Sfenner		if (bp >= ep)
78856893Sfenner			break;
78956893Sfenner		(void)printf(" group=");
79056893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
79156893Sfenner			(void)printf("...");
79256893Sfenner			break;
79356893Sfenner		}
79456893Sfenner		bp += advance; len -= advance;
79556893Sfenner		if (bp >= ep)
79656893Sfenner			break;
79756893Sfenner		(void)printf(" source=");
79856893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
79956893Sfenner			(void)printf("...");
80056893Sfenner			break;
80156893Sfenner		}
80256893Sfenner		bp += advance; len -= advance;
80356893Sfenner		break;
80456893Sfenner
805146778Ssam	case PIMV2_TYPE_JOIN_PRUNE:
806146778Ssam	case PIMV2_TYPE_GRAFT:
807146778Ssam	case PIMV2_TYPE_GRAFT_ACK:
808146778Ssam
809146778Ssam
810146778Ssam        /*
811146778Ssam         * 0                   1                   2                   3
812146778Ssam         *   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
813146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
814146778Ssam         *  |PIM Ver| Type  | Addr length   |           Checksum            |
815146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
816146778Ssam         *  |             Unicast-Upstream Neighbor Address                 |
817146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
818146778Ssam         *  |  Reserved     | Num groups    |          Holdtime             |
819146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
820146778Ssam         *  |            Encoded-Multicast Group Address-1                  |
821146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
822146778Ssam         *  |   Number of Joined  Sources   |   Number of Pruned Sources    |
823146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
824146778Ssam         *  |               Encoded-Joined Source Address-1                 |
825146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
826146778Ssam         *  |                             .                                 |
827146778Ssam         *  |                             .                                 |
828146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
829146778Ssam         *  |               Encoded-Joined Source Address-n                 |
830146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
831146778Ssam         *  |               Encoded-Pruned Source Address-1                 |
832146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
833146778Ssam         *  |                             .                                 |
834146778Ssam         *  |                             .                                 |
835146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
836146778Ssam         *  |               Encoded-Pruned Source Address-n                 |
837146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
838146778Ssam         *  |                           .                                   |
839146778Ssam         *  |                           .                                   |
840146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
841146778Ssam         *  |                Encoded-Multicast Group Address-n              |
842146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
843146778Ssam         */
844146778Ssam
84556893Sfenner	    {
84656893Sfenner		u_int8_t ngroup;
84756893Sfenner		u_int16_t holdtime;
84856893Sfenner		u_int16_t njoin;
84956893Sfenner		u_int16_t nprune;
85056893Sfenner		int i, j;
85156893Sfenner
85256893Sfenner		bp += 4; len -= 4;
85356893Sfenner		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
85456893Sfenner			if (bp >= ep)
85556893Sfenner				break;
856146778Ssam			(void)printf(", upstream-neighbor: ");
85756893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
85856893Sfenner				(void)printf("...");
85956893Sfenner				break;
86056893Sfenner			}
86156893Sfenner			bp += advance; len -= advance;
86256893Sfenner		}
86356893Sfenner		if (bp + 4 > ep)
86456893Sfenner			break;
86556893Sfenner		ngroup = bp[1];
86656893Sfenner		holdtime = EXTRACT_16BITS(&bp[2]);
867146778Ssam		(void)printf("\n\t  %u group(s)", ngroup);
86856893Sfenner		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
869146778Ssam			(void)printf(", holdtime: ");
87056893Sfenner			if (holdtime == 0xffff)
871146778Ssam				(void)printf("infinite");
87256893Sfenner			else
87356893Sfenner				relts_print(holdtime);
87456893Sfenner		}
87556893Sfenner		bp += 4; len -= 4;
87656893Sfenner		for (i = 0; i < ngroup; i++) {
87756893Sfenner			if (bp >= ep)
87856893Sfenner				goto jp_done;
879146778Ssam			(void)printf("\n\t    group #%u: ", i+1);
88056893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
88156893Sfenner				(void)printf("...)");
88256893Sfenner				goto jp_done;
88356893Sfenner			}
88456893Sfenner			bp += advance; len -= advance;
88556893Sfenner			if (bp + 4 > ep) {
88656893Sfenner				(void)printf("...)");
88756893Sfenner				goto jp_done;
88856893Sfenner			}
88956893Sfenner			njoin = EXTRACT_16BITS(&bp[0]);
89056893Sfenner			nprune = EXTRACT_16BITS(&bp[2]);
891146778Ssam			(void)printf(", joined sources: %u, pruned sources: %u", njoin,nprune);
89256893Sfenner			bp += 4; len -= 4;
89356893Sfenner			for (j = 0; j < njoin; j++) {
894146778Ssam				(void)printf("\n\t      joined source #%u: ",j+1);
89556893Sfenner				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
89656893Sfenner					(void)printf("...)");
89756893Sfenner					goto jp_done;
89856893Sfenner				}
89956893Sfenner				bp += advance; len -= advance;
90056893Sfenner			}
90156893Sfenner			for (j = 0; j < nprune; j++) {
902146778Ssam				(void)printf("\n\t      pruned source #%u: ",j+1);
90356893Sfenner				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
90456893Sfenner					(void)printf("...)");
90556893Sfenner					goto jp_done;
90656893Sfenner				}
90756893Sfenner				bp += advance; len -= advance;
90856893Sfenner			}
90956893Sfenner		}
91056893Sfenner	jp_done:
91156893Sfenner		break;
91256893Sfenner	    }
91356893Sfenner
914146778Ssam	case PIMV2_TYPE_BOOTSTRAP:
91598527Sfenner	{
91656893Sfenner		int i, j, frpcnt;
91756893Sfenner		bp += 4;
91856893Sfenner
91956893Sfenner		/* Fragment Tag, Hash Mask len, and BSR-priority */
92056893Sfenner		if (bp + sizeof(u_int16_t) >= ep) break;
92156893Sfenner		(void)printf(" tag=%x", EXTRACT_16BITS(bp));
92256893Sfenner		bp += sizeof(u_int16_t);
92356893Sfenner		if (bp >= ep) break;
92456893Sfenner		(void)printf(" hashmlen=%d", bp[0]);
92556893Sfenner		if (bp + 1 >= ep) break;
92656893Sfenner		(void)printf(" BSRprio=%d", bp[1]);
92756893Sfenner		bp += 2;
92856893Sfenner
92956893Sfenner		/* Encoded-Unicast-BSR-Address */
93056893Sfenner		if (bp >= ep) break;
93156893Sfenner		(void)printf(" BSR=");
93256893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
93356893Sfenner			(void)printf("...");
93456893Sfenner			break;
93556893Sfenner		}
93656893Sfenner		bp += advance;
93756893Sfenner
93856893Sfenner		for (i = 0; bp < ep; i++) {
93956893Sfenner			/* Encoded-Group Address */
94056893Sfenner			(void)printf(" (group%d: ", i);
94156893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
94256893Sfenner			    < 0) {
94356893Sfenner				(void)printf("...)");
94456893Sfenner				goto bs_done;
94556893Sfenner			}
94656893Sfenner			bp += advance;
94756893Sfenner
94856893Sfenner			/* RP-Count, Frag RP-Cnt, and rsvd */
94956893Sfenner			if (bp >= ep) {
95056893Sfenner				(void)printf("...)");
95156893Sfenner				goto bs_done;
95256893Sfenner			}
95375118Sfenner			(void)printf(" RPcnt=%d", bp[0]);
95456893Sfenner			if (bp + 1 >= ep) {
95556893Sfenner				(void)printf("...)");
95656893Sfenner				goto bs_done;
95756893Sfenner			}
95875118Sfenner			(void)printf(" FRPcnt=%d", frpcnt = bp[1]);
95956893Sfenner			bp += 4;
96056893Sfenner
96156893Sfenner			for (j = 0; j < frpcnt && bp < ep; j++) {
96256893Sfenner				/* each RP info */
96356893Sfenner				(void)printf(" RP%d=", j);
96456893Sfenner				if ((advance = pimv2_addr_print(bp,
96556893Sfenner								pimv2_unicast,
96656893Sfenner								0)) < 0) {
96756893Sfenner					(void)printf("...)");
96856893Sfenner					goto bs_done;
96956893Sfenner				}
97056893Sfenner				bp += advance;
97156893Sfenner
97256893Sfenner				if (bp + 1 >= ep) {
97356893Sfenner					(void)printf("...)");
97456893Sfenner					goto bs_done;
97556893Sfenner				}
97656893Sfenner				(void)printf(",holdtime=");
97756893Sfenner				relts_print(EXTRACT_16BITS(bp));
97856893Sfenner				if (bp + 2 >= ep) {
97956893Sfenner					(void)printf("...)");
98056893Sfenner					goto bs_done;
98156893Sfenner				}
98256893Sfenner				(void)printf(",prio=%d", bp[2]);
98356893Sfenner				bp += 4;
98456893Sfenner			}
98556893Sfenner			(void)printf(")");
98656893Sfenner		}
98756893Sfenner	   bs_done:
98856893Sfenner		break;
98998527Sfenner	}
990146778Ssam	case PIMV2_TYPE_ASSERT:
99156893Sfenner		bp += 4; len -= 4;
99256893Sfenner		if (bp >= ep)
99356893Sfenner			break;
99456893Sfenner		(void)printf(" group=");
99556893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
99656893Sfenner			(void)printf("...");
99756893Sfenner			break;
99856893Sfenner		}
99956893Sfenner		bp += advance; len -= advance;
100056893Sfenner		if (bp >= ep)
100156893Sfenner			break;
100256893Sfenner		(void)printf(" src=");
100356893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
100456893Sfenner			(void)printf("...");
100556893Sfenner			break;
100656893Sfenner		}
100756893Sfenner		bp += advance; len -= advance;
100856893Sfenner		if (bp + 8 > ep)
100956893Sfenner			break;
101056893Sfenner		if (bp[0] & 0x80)
101156893Sfenner			(void)printf(" RPT");
101256893Sfenner		(void)printf(" pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff);
101356893Sfenner		(void)printf(" metric=%u", EXTRACT_32BITS(&bp[4]));
101456893Sfenner		break;
101556893Sfenner
1016146778Ssam	case PIMV2_TYPE_CANDIDATE_RP:
101798527Sfenner	{
101856893Sfenner		int i, pfxcnt;
101956893Sfenner		bp += 4;
102056893Sfenner
102156893Sfenner		/* Prefix-Cnt, Priority, and Holdtime */
102256893Sfenner		if (bp >= ep) break;
102356893Sfenner		(void)printf(" prefix-cnt=%d", bp[0]);
102456893Sfenner		pfxcnt = bp[0];
102556893Sfenner		if (bp + 1 >= ep) break;
102656893Sfenner		(void)printf(" prio=%d", bp[1]);
102756893Sfenner		if (bp + 3 >= ep) break;
102856893Sfenner		(void)printf(" holdtime=");
102956893Sfenner		relts_print(EXTRACT_16BITS(&bp[2]));
103056893Sfenner		bp += 4;
103156893Sfenner
103256893Sfenner		/* Encoded-Unicast-RP-Address */
103356893Sfenner		if (bp >= ep) break;
103456893Sfenner		(void)printf(" RP=");
103556893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
103656893Sfenner			(void)printf("...");
103756893Sfenner			break;
103856893Sfenner		}
103956893Sfenner		bp += advance;
104056893Sfenner
104156893Sfenner		/* Encoded-Group Addresses */
104256893Sfenner		for (i = 0; i < pfxcnt && bp < ep; i++) {
104356893Sfenner			(void)printf(" Group%d=", i);
104456893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
104556893Sfenner			    < 0) {
104656893Sfenner				(void)printf("...");
104756893Sfenner				break;
104856893Sfenner			}
104956893Sfenner			bp += advance;
105056893Sfenner		}
105156893Sfenner		break;
105298527Sfenner	}
105356893Sfenner
1054146778Ssam	case PIMV2_TYPE_PRUNE_REFRESH:
105556893Sfenner		(void)printf(" src=");
105656893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
105756893Sfenner			(void)printf("...");
105856893Sfenner			break;
105956893Sfenner		}
106056893Sfenner		bp += advance;
106156893Sfenner		(void)printf(" grp=");
106256893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
106356893Sfenner			(void)printf("...");
106456893Sfenner			break;
106556893Sfenner		}
106656893Sfenner		bp += advance;
106756893Sfenner		(void)printf(" forwarder=");
106856893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
106956893Sfenner			(void)printf("...");
107056893Sfenner			break;
107156893Sfenner		}
107256893Sfenner		bp += advance;
107356893Sfenner		TCHECK2(bp[0], 2);
107456893Sfenner		(void)printf(" TUNR ");
107556893Sfenner		relts_print(EXTRACT_16BITS(bp));
107656893Sfenner		break;
107756893Sfenner
107856893Sfenner
107956893Sfenner	 default:
108056893Sfenner		(void)printf(" [type %d]", PIM_TYPE(pim->pim_typever));
108156893Sfenner		break;
108256893Sfenner	}
108356893Sfenner
108456893Sfenner	return;
108556893Sfenner
108656893Sfennertrunc:
108756893Sfenner	(void)printf("[|pim]");
108856893Sfenner}
1089146778Ssam
1090146778Ssam/*
1091146778Ssam * Local Variables:
1092146778Ssam * c-style: whitesmith
1093146778Ssam * c-basic-offset: 8
1094146778Ssam * End:
1095146778Ssam */
1096