print-pim.c revision 162021
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 162021 2006-09-04 20:25:04Z sam $
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
25127675Sbmsstatic const char rcsid[] _U_ =
26162021Ssam    "@(#) $Header: /tcpdump/master/tcpdump/print-pim.c,v 1.45.2.3 2005/07/11 20:24:34 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
84146778Ssam
8556893Sfenner/*
8656893Sfenner * XXX: We consider a case where IPv6 is not ready yet for portability,
8756893Sfenner * but PIM dependent defintions should be independent of IPv6...
8856893Sfenner */
8956893Sfenner
9056893Sfennerstruct pim {
9156893Sfenner	u_int8_t pim_typever;
9257278Sfenner			/* upper 4bit: PIM version number; 2 for PIMv2 */
9357278Sfenner			/* lower 4bit: the PIM message type, currently they are:
9456893Sfenner			 * Hello, Register, Register-Stop, Join/Prune,
9556893Sfenner			 * Bootstrap, Assert, Graft (PIM-DM only),
9656893Sfenner			 * Graft-Ack (PIM-DM only), C-RP-Adv
9756893Sfenner			 */
9857278Sfenner#define PIM_VER(x)	(((x) & 0xf0) >> 4)
9957278Sfenner#define PIM_TYPE(x)	((x) & 0x0f)
10056893Sfenner	u_char  pim_rsv;	/* Reserved */
10156893Sfenner	u_short	pim_cksum;	/* IP style check sum */
10256893Sfenner};
10356893Sfenner
10456893Sfenner
10517680Spst#include <stdio.h>
10617680Spst#include <stdlib.h>
10717680Spst
10817680Spst#include "interface.h"
10917680Spst#include "addrtoname.h"
11056893Sfenner#include "extract.h"
11117680Spst
11275118Sfenner#include "ip.h"
11375118Sfenner
11456893Sfennerstatic void pimv2_print(register const u_char *bp, register u_int len);
11556893Sfenner
11656893Sfennerstatic void
11756893Sfennerpimv1_join_prune_print(register const u_char *bp, register u_int len)
11856893Sfenner{
11998527Sfenner	int maddrlen, addrlen, ngroups, njoin, nprune;
12098527Sfenner	int njp;
12156893Sfenner
12298527Sfenner	/* If it's a single group and a single source, use 1-line output. */
12398527Sfenner	if (TTEST2(bp[0], 30) && bp[11] == 1 &&
12498527Sfenner	    ((njoin = EXTRACT_16BITS(&bp[20])) + EXTRACT_16BITS(&bp[22])) == 1) {
12598527Sfenner		int hold;
12656893Sfenner
12798527Sfenner		(void)printf(" RPF %s ", ipaddr_string(bp));
12898527Sfenner		hold = EXTRACT_16BITS(&bp[6]);
12998527Sfenner		if (hold != 180) {
13098527Sfenner			(void)printf("Hold ");
13198527Sfenner			relts_print(hold);
13298527Sfenner		}
13398527Sfenner		(void)printf("%s (%s/%d, %s", njoin ? "Join" : "Prune",
13498527Sfenner		ipaddr_string(&bp[26]), bp[25] & 0x3f,
13598527Sfenner		ipaddr_string(&bp[12]));
13698527Sfenner		if (EXTRACT_32BITS(&bp[16]) != 0xffffffff)
13798527Sfenner			(void)printf("/%s", ipaddr_string(&bp[16]));
13898527Sfenner		(void)printf(") %s%s %s",
13956893Sfenner		    (bp[24] & 0x01) ? "Sparse" : "Dense",
14056893Sfenner		    (bp[25] & 0x80) ? " WC" : "",
14156893Sfenner		    (bp[25] & 0x40) ? "RP" : "SPT");
14298527Sfenner		return;
14398527Sfenner	}
14456893Sfenner
145162021Ssam	TCHECK2(bp[0], sizeof(struct in_addr));
14698527Sfenner	if (vflag > 1)
14798527Sfenner		(void)printf("\n");
14898527Sfenner	(void)printf(" Upstream Nbr: %s", ipaddr_string(bp));
14998527Sfenner	TCHECK2(bp[6], 2);
15098527Sfenner	if (vflag > 1)
15198527Sfenner		(void)printf("\n");
15298527Sfenner	(void)printf(" Hold time: ");
15398527Sfenner	relts_print(EXTRACT_16BITS(&bp[6]));
15498527Sfenner	if (vflag < 2)
15598527Sfenner		return;
15698527Sfenner	bp += 8;
15798527Sfenner	len -= 8;
15856893Sfenner
15998527Sfenner	TCHECK2(bp[0], 4);
16098527Sfenner	maddrlen = bp[1];
16198527Sfenner	addrlen = bp[2];
16298527Sfenner	ngroups = bp[3];
16398527Sfenner	bp += 4;
16498527Sfenner	len -= 4;
16598527Sfenner	while (ngroups--) {
166147904Ssam		/*
167147904Ssam		 * XXX - does the address have length "addrlen" and the
168147904Ssam		 * mask length "maddrlen"?
169147904Ssam		 */
170162021Ssam		TCHECK2(bp[0], sizeof(struct in_addr));
17198527Sfenner		(void)printf("\n\tGroup: %s", ipaddr_string(bp));
172162021Ssam		TCHECK2(bp[4], sizeof(struct in_addr));
17398527Sfenner		if (EXTRACT_32BITS(&bp[4]) != 0xffffffff)
17498527Sfenner			(void)printf("/%s", ipaddr_string(&bp[4]));
17598527Sfenner		TCHECK2(bp[8], 4);
17698527Sfenner		njoin = EXTRACT_16BITS(&bp[8]);
17798527Sfenner		nprune = EXTRACT_16BITS(&bp[10]);
17898527Sfenner		(void)printf(" joined: %d pruned: %d", njoin, nprune);
17998527Sfenner		bp += 12;
18098527Sfenner		len -= 12;
18198527Sfenner		for (njp = 0; njp < (njoin + nprune); njp++) {
182127675Sbms			const char *type;
18398527Sfenner
18498527Sfenner			if (njp < njoin)
18598527Sfenner				type = "Join ";
18698527Sfenner			else
18798527Sfenner				type = "Prune";
18898527Sfenner			TCHECK2(bp[0], 6);
18998527Sfenner			(void)printf("\n\t%s %s%s%s%s/%d", type,
19056893Sfenner			    (bp[0] & 0x01) ? "Sparse " : "Dense ",
19156893Sfenner			    (bp[1] & 0x80) ? "WC " : "",
19256893Sfenner			    (bp[1] & 0x40) ? "RP " : "SPT ",
19398527Sfenner			ipaddr_string(&bp[2]), bp[1] & 0x3f);
19498527Sfenner			bp += 6;
19598527Sfenner			len -= 6;
19698527Sfenner		}
19756893Sfenner	}
19898527Sfenner	return;
19956893Sfennertrunc:
20098527Sfenner	(void)printf("[|pim]");
20198527Sfenner	return;
20256893Sfenner}
20356893Sfenner
20417680Spstvoid
20556893Sfennerpimv1_print(register const u_char *bp, register u_int len)
20617680Spst{
20798527Sfenner	register const u_char *ep;
20898527Sfenner	register u_char type;
20917680Spst
21098527Sfenner	ep = (const u_char *)snapend;
21198527Sfenner	if (bp >= ep)
21298527Sfenner		return;
21317680Spst
214127675Sbms	TCHECK(bp[1]);
21598527Sfenner	type = bp[1];
21617680Spst
21798527Sfenner	switch (type) {
21898527Sfenner	case 0:
21998527Sfenner		(void)printf(" Query");
22098527Sfenner		if (TTEST(bp[8])) {
22198527Sfenner			switch (bp[8] >> 4) {
22298527Sfenner			case 0:
22398527Sfenner				(void)printf(" Dense-mode");
22456893Sfenner				break;
22598527Sfenner			case 1:
22698527Sfenner				(void)printf(" Sparse-mode");
22756893Sfenner				break;
22898527Sfenner			case 2:
22998527Sfenner				(void)printf(" Sparse-Dense-mode");
23056893Sfenner				break;
23198527Sfenner			default:
23298527Sfenner				(void)printf(" mode-%d", bp[8] >> 4);
23356893Sfenner				break;
23498527Sfenner			}
23556893Sfenner		}
23698527Sfenner		if (vflag) {
23798527Sfenner			TCHECK2(bp[10],2);
23898527Sfenner			(void)printf(" (Hold-time ");
23998527Sfenner			relts_print(EXTRACT_16BITS(&bp[10]));
24098527Sfenner			(void)printf(")");
24198527Sfenner		}
24298527Sfenner		break;
24317680Spst
24498527Sfenner	case 1:
24598527Sfenner		(void)printf(" Register");
24698527Sfenner		TCHECK2(bp[8], 20);			/* ip header */
24798527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[20]),
24898527Sfenner		    ipaddr_string(&bp[24]));
24998527Sfenner		break;
25098527Sfenner	case 2:
25198527Sfenner		(void)printf(" Register-Stop");
252162021Ssam		TCHECK2(bp[12], sizeof(struct in_addr));
25398527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[8]),
25498527Sfenner		    ipaddr_string(&bp[12]));
25598527Sfenner		break;
25698527Sfenner	case 3:
25798527Sfenner		(void)printf(" Join/Prune");
25898527Sfenner		if (vflag)
25998527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
26098527Sfenner		break;
26198527Sfenner	case 4:
26298527Sfenner		(void)printf(" RP-reachable");
26398527Sfenner		if (vflag) {
26498527Sfenner			TCHECK2(bp[22], 2);
26598527Sfenner			(void)printf(" group %s",
26656893Sfenner			ipaddr_string(&bp[8]));
26798527Sfenner			if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
26898527Sfenner				(void)printf("/%s", ipaddr_string(&bp[12]));
26998527Sfenner			(void)printf(" RP %s hold ", ipaddr_string(&bp[16]));
27098527Sfenner			relts_print(EXTRACT_16BITS(&bp[22]));
27198527Sfenner		}
27298527Sfenner		break;
27398527Sfenner	case 5:
27498527Sfenner		(void)printf(" Assert");
275162021Ssam		TCHECK2(bp[16], sizeof(struct in_addr));
27698527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[16]),
27798527Sfenner		    ipaddr_string(&bp[8]));
27856893Sfenner		if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
27956893Sfenner			(void)printf("/%s", ipaddr_string(&bp[12]));
28098527Sfenner		TCHECK2(bp[24], 4);
28198527Sfenner		(void)printf(" %s pref %d metric %d",
28298527Sfenner		    (bp[20] & 0x80) ? "RP-tree" : "SPT",
28356893Sfenner		EXTRACT_32BITS(&bp[20]) & 0x7fffffff,
28456893Sfenner		EXTRACT_32BITS(&bp[24]));
28598527Sfenner		break;
28698527Sfenner	case 6:
28798527Sfenner		(void)printf(" Graft");
28898527Sfenner		if (vflag)
28998527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
29098527Sfenner		break;
29198527Sfenner	case 7:
29298527Sfenner		(void)printf(" Graft-ACK");
29398527Sfenner		if (vflag)
29498527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
29598527Sfenner		break;
29698527Sfenner	case 8:
29798527Sfenner		(void)printf(" Mode");
29898527Sfenner		break;
29998527Sfenner	default:
30098527Sfenner		(void)printf(" [type %d]", type);
30198527Sfenner		break;
30256893Sfenner	}
30398527Sfenner	if ((bp[4] >> 4) != 1)
30498527Sfenner		(void)printf(" [v%d]", bp[4] >> 4);
30598527Sfenner	return;
30617680Spst
30756893Sfennertrunc:
30898527Sfenner	(void)printf("[|pim]");
30998527Sfenner	return;
31017680Spst}
31156893Sfenner
31256893Sfenner/*
31356893Sfenner * auto-RP is a cisco protocol, documented at
31498527Sfenner * ftp://ftpeng.cisco.com/ipmulticast/specs/pim-autorp-spec01.txt
31598527Sfenner *
31698527Sfenner * This implements version 1+, dated Sept 9, 1998.
31756893Sfenner */
31856893Sfennervoid
31956893Sfennercisco_autorp_print(register const u_char *bp, register u_int len)
32056893Sfenner{
32198527Sfenner	int type;
32298527Sfenner	int numrps;
32398527Sfenner	int hold;
32456893Sfenner
32598527Sfenner	TCHECK(bp[0]);
32698527Sfenner	(void)printf(" auto-rp ");
32798527Sfenner	type = bp[0];
32898527Sfenner	switch (type) {
32998527Sfenner	case 0x11:
33098527Sfenner		(void)printf("candidate-advert");
33198527Sfenner		break;
33298527Sfenner	case 0x12:
33398527Sfenner		(void)printf("mapping");
33498527Sfenner		break;
33598527Sfenner	default:
33698527Sfenner		(void)printf("type-0x%02x", type);
33798527Sfenner		break;
33898527Sfenner	}
33956893Sfenner
34098527Sfenner	TCHECK(bp[1]);
34198527Sfenner	numrps = bp[1];
34256893Sfenner
34398527Sfenner	TCHECK2(bp[2], 2);
34498527Sfenner	(void)printf(" Hold ");
34598527Sfenner	hold = EXTRACT_16BITS(&bp[2]);
34698527Sfenner	if (hold)
34798527Sfenner		relts_print(EXTRACT_16BITS(&bp[2]));
34898527Sfenner	else
34998527Sfenner		printf("FOREVER");
35056893Sfenner
35198527Sfenner	/* Next 4 bytes are reserved. */
35256893Sfenner
35398527Sfenner	bp += 8; len -= 8;
35456893Sfenner
35598527Sfenner	/*XXX skip unless -v? */
35656893Sfenner
35798527Sfenner	/*
35898527Sfenner	 * Rest of packet:
35998527Sfenner	 * numrps entries of the form:
36098527Sfenner	 * 32 bits: RP
36198527Sfenner	 * 6 bits: reserved
36298527Sfenner	 * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
36398527Sfenner	 * 8 bits: # of entries for this RP
36498527Sfenner	 * each entry: 7 bits: reserved, 1 bit: negative,
36598527Sfenner	 *	       8 bits: mask 32 bits: source
36698527Sfenner	 * lather, rinse, repeat.
36798527Sfenner	 */
36898527Sfenner	while (numrps--) {
36998527Sfenner		int nentries;
37098527Sfenner		char s;
37156893Sfenner
37298527Sfenner		TCHECK2(bp[0], 4);
37398527Sfenner		(void)printf(" RP %s", ipaddr_string(bp));
37498527Sfenner		TCHECK(bp[4]);
37598527Sfenner		switch (bp[4] & 0x3) {
37698527Sfenner		case 0: printf(" PIMv?");
37798527Sfenner			break;
37898527Sfenner		case 1:	printf(" PIMv1");
37998527Sfenner			break;
38098527Sfenner		case 2:	printf(" PIMv2");
38198527Sfenner			break;
38298527Sfenner		case 3:	printf(" PIMv1+2");
38398527Sfenner			break;
38498527Sfenner		}
38598527Sfenner		if (bp[4] & 0xfc)
38698527Sfenner			(void)printf(" [rsvd=0x%02x]", bp[4] & 0xfc);
38798527Sfenner		TCHECK(bp[5]);
38898527Sfenner		nentries = bp[5];
38998527Sfenner		bp += 6; len -= 6;
39098527Sfenner		s = ' ';
39198527Sfenner		for (; nentries; nentries--) {
39298527Sfenner			TCHECK2(bp[0], 6);
39398527Sfenner			(void)printf("%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
39498527Sfenner			    ipaddr_string(&bp[2]), bp[1]);
39598527Sfenner			if (bp[0] & 0xfe)
39698527Sfenner				(void)printf("[rsvd=0x%02x]", bp[0] & 0xfe);
39798527Sfenner			s = ',';
39898527Sfenner			bp += 6; len -= 6;
39998527Sfenner		}
40056893Sfenner	}
40198527Sfenner	return;
40256893Sfenner
40356893Sfennertrunc:
40498527Sfenner	(void)printf("[|autorp]");
40598527Sfenner	return;
40656893Sfenner}
40756893Sfenner
40856893Sfennervoid
40956893Sfennerpim_print(register const u_char *bp, register u_int len)
41056893Sfenner{
41156893Sfenner	register const u_char *ep;
41256893Sfenner	register struct pim *pim = (struct pim *)bp;
41356893Sfenner
41456893Sfenner	ep = (const u_char *)snapend;
41556893Sfenner	if (bp >= ep)
41656893Sfenner		return;
41756893Sfenner#ifdef notyet			/* currently we see only version and type */
41856893Sfenner	TCHECK(pim->pim_rsv);
41956893Sfenner#endif
42056893Sfenner
42175118Sfenner	switch (PIM_VER(pim->pim_typever)) {
422146778Ssam	case 2:
423146778Ssam            if (!vflag) {
424146778Ssam                printf("PIMv%u, %s, length: %u",
425146778Ssam                       PIM_VER(pim->pim_typever),
426146778Ssam                       tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)),
427146778Ssam                       len);
428146778Ssam                return;
429146778Ssam            } else {
430146778Ssam                printf("PIMv%u, length: %u\n\t%s",
431146778Ssam                       PIM_VER(pim->pim_typever),
432146778Ssam                       len,
433146778Ssam                       tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)));
434146778Ssam                pimv2_print(bp, len);
435146778Ssam            }
436146778Ssam            break;
43798527Sfenner	default:
438146778Ssam		printf("PIMv%u, length: %u",
439146778Ssam                       PIM_VER(pim->pim_typever),
440146778Ssam                       len);
44156893Sfenner		break;
44256893Sfenner	}
44356893Sfenner	return;
44456893Sfenner}
44556893Sfenner
44656893Sfenner/*
44756893Sfenner * PIMv2 uses encoded address representations.
44856893Sfenner *
44956893Sfenner * The last PIM-SM I-D before RFC2117 was published specified the
45056893Sfenner * following representation for unicast addresses.  However, RFC2117
45156893Sfenner * specified no encoding for unicast addresses with the unicast
45256893Sfenner * address length specified in the header.  Therefore, we have to
45356893Sfenner * guess which encoding is being used (Cisco's PIMv2 implementation
45456893Sfenner * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
45556893Sfenner * field into a 'unicast-address-length-in-bytes' field.  We guess
45656893Sfenner * that it's the draft encoding if this reserved field is zero.
45756893Sfenner *
45856893Sfenner * RFC2362 goes back to the encoded format, and calls the addr length
45956893Sfenner * field "reserved" again.
46056893Sfenner *
46156893Sfenner * The first byte is the address family, from:
46256893Sfenner *
46356893Sfenner *    0    Reserved
46456893Sfenner *    1    IP (IP version 4)
46556893Sfenner *    2    IP6 (IP version 6)
46656893Sfenner *    3    NSAP
46756893Sfenner *    4    HDLC (8-bit multidrop)
46856893Sfenner *    5    BBN 1822
46956893Sfenner *    6    802 (includes all 802 media plus Ethernet "canonical format")
47056893Sfenner *    7    E.163
47156893Sfenner *    8    E.164 (SMDS, Frame Relay, ATM)
47256893Sfenner *    9    F.69 (Telex)
47356893Sfenner *   10    X.121 (X.25, Frame Relay)
47456893Sfenner *   11    IPX
47556893Sfenner *   12    Appletalk
47656893Sfenner *   13    Decnet IV
47756893Sfenner *   14    Banyan Vines
47856893Sfenner *   15    E.164 with NSAP format subaddress
47956893Sfenner *
48056893Sfenner * In addition, the second byte is an "Encoding".  0 is the default
48156893Sfenner * encoding for the address family, and no other encodings are currently
48256893Sfenner * specified.
48356893Sfenner *
48456893Sfenner */
48556893Sfenner
48656893Sfennerstatic int pimv2_addr_len;
48756893Sfenner
48856893Sfennerenum pimv2_addrtype {
48956893Sfenner	pimv2_unicast, pimv2_group, pimv2_source
49056893Sfenner};
49156893Sfenner
49256893Sfenner/*  0                   1                   2                   3
49356893Sfenner *  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
49456893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
49556893Sfenner * | Addr Family   | Encoding Type |     Unicast Address           |
49656893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
49756893Sfenner *  0                   1                   2                   3
49856893Sfenner *  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
49956893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50056893Sfenner * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
50156893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50256893Sfenner * |                Group multicast Address                        |
50356893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50456893Sfenner *  0                   1                   2                   3
50556893Sfenner *  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
50656893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50756893Sfenner * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
50856893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
50956893Sfenner * |                        Source Address                         |
51056893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51156893Sfenner */
51256893Sfennerstatic int
51356893Sfennerpimv2_addr_print(const u_char *bp, enum pimv2_addrtype at, int silent)
51456893Sfenner{
51556893Sfenner	int af;
51656893Sfenner	int len, hdrlen;
51756893Sfenner
51856893Sfenner	TCHECK(bp[0]);
51956893Sfenner
52056893Sfenner	if (pimv2_addr_len == 0) {
52156893Sfenner		TCHECK(bp[1]);
52256893Sfenner		switch (bp[0]) {
52398527Sfenner		case 1:
52456893Sfenner			af = AF_INET;
525162021Ssam			len = sizeof(struct in_addr);
52656893Sfenner			break;
52756893Sfenner#ifdef INET6
52898527Sfenner		case 2:
52956893Sfenner			af = AF_INET6;
530162021Ssam			len = sizeof(struct in6_addr);
53156893Sfenner			break;
53256893Sfenner#endif
53398527Sfenner		default:
53456893Sfenner			return -1;
53556893Sfenner		}
53656893Sfenner		if (bp[1] != 0)
53756893Sfenner			return -1;
53856893Sfenner		hdrlen = 2;
53956893Sfenner	} else {
54056893Sfenner		switch (pimv2_addr_len) {
541162021Ssam		case sizeof(struct in_addr):
54256893Sfenner			af = AF_INET;
54356893Sfenner			break;
54456893Sfenner#ifdef INET6
545162021Ssam		case sizeof(struct in6_addr):
54656893Sfenner			af = AF_INET6;
54756893Sfenner			break;
54856893Sfenner#endif
54998527Sfenner		default:
55056893Sfenner			return -1;
55156893Sfenner			break;
55256893Sfenner		}
55356893Sfenner		len = pimv2_addr_len;
55456893Sfenner		hdrlen = 0;
55556893Sfenner	}
55656893Sfenner
55756893Sfenner	bp += hdrlen;
55856893Sfenner	switch (at) {
55998527Sfenner	case pimv2_unicast:
56056893Sfenner		TCHECK2(bp[0], len);
56156893Sfenner		if (af == AF_INET) {
56256893Sfenner			if (!silent)
56356893Sfenner				(void)printf("%s", ipaddr_string(bp));
56456893Sfenner		}
56556893Sfenner#ifdef INET6
56656893Sfenner		else if (af == AF_INET6) {
56756893Sfenner			if (!silent)
56856893Sfenner				(void)printf("%s", ip6addr_string(bp));
56956893Sfenner		}
57056893Sfenner#endif
57156893Sfenner		return hdrlen + len;
57298527Sfenner	case pimv2_group:
57398527Sfenner	case pimv2_source:
57456893Sfenner		TCHECK2(bp[0], len + 2);
57556893Sfenner		if (af == AF_INET) {
57656893Sfenner			if (!silent) {
57756893Sfenner				(void)printf("%s", ipaddr_string(bp + 2));
57856893Sfenner				if (bp[1] != 32)
57956893Sfenner					(void)printf("/%u", bp[1]);
58056893Sfenner			}
58156893Sfenner		}
58256893Sfenner#ifdef INET6
58356893Sfenner		else if (af == AF_INET6) {
58456893Sfenner			if (!silent) {
58556893Sfenner				(void)printf("%s", ip6addr_string(bp + 2));
58656893Sfenner				if (bp[1] != 128)
58756893Sfenner					(void)printf("/%u", bp[1]);
58856893Sfenner			}
58956893Sfenner		}
59056893Sfenner#endif
59156893Sfenner		if (bp[0] && !silent) {
59256893Sfenner			if (at == pimv2_group) {
59356893Sfenner				(void)printf("(0x%02x)", bp[0]);
59456893Sfenner			} else {
59556893Sfenner				(void)printf("(%s%s%s",
59656893Sfenner					bp[0] & 0x04 ? "S" : "",
59756893Sfenner					bp[0] & 0x02 ? "W" : "",
59856893Sfenner					bp[0] & 0x01 ? "R" : "");
59956893Sfenner				if (bp[0] & 0xf8) {
60056893Sfenner					(void) printf("+0x%02x", bp[0] & 0xf8);
60156893Sfenner				}
60256893Sfenner				(void)printf(")");
60356893Sfenner			}
60456893Sfenner		}
60556893Sfenner		return hdrlen + 2 + len;
60656893Sfenner	default:
60756893Sfenner		return -1;
60856893Sfenner	}
60956893Sfennertrunc:
61056893Sfenner	return -1;
61156893Sfenner}
61256893Sfenner
61356893Sfennerstatic void
61456893Sfennerpimv2_print(register const u_char *bp, register u_int len)
61556893Sfenner{
61656893Sfenner	register const u_char *ep;
61756893Sfenner	register struct pim *pim = (struct pim *)bp;
61856893Sfenner	int advance;
61956893Sfenner
62056893Sfenner	ep = (const u_char *)snapend;
62156893Sfenner	if (bp >= ep)
62256893Sfenner		return;
62357278Sfenner	if (ep > bp + len)
62457278Sfenner		ep = bp + len;
62556893Sfenner	TCHECK(pim->pim_rsv);
62656893Sfenner	pimv2_addr_len = pim->pim_rsv;
62756893Sfenner	if (pimv2_addr_len != 0)
628146778Ssam		(void)printf(", RFC2117-encoding");
62956893Sfenner
63056893Sfenner	switch (PIM_TYPE(pim->pim_typever)) {
631146778Ssam	case PIMV2_TYPE_HELLO:
63256893Sfenner	    {
63356893Sfenner		u_int16_t otype, olen;
63456893Sfenner		bp += 4;
63556893Sfenner		while (bp < ep) {
63656893Sfenner			TCHECK2(bp[0], 4);
63756893Sfenner			otype = EXTRACT_16BITS(&bp[0]);
63856893Sfenner			olen = EXTRACT_16BITS(&bp[2]);
63956893Sfenner			TCHECK2(bp[0], 4 + olen);
640146778Ssam
641146778Ssam                        printf("\n\t  %s Option (%u), length: %u, Value: ",
642146778Ssam                               tok2str( pimv2_hello_option_values,"Unknown",otype),
643146778Ssam                               otype,
644146778Ssam                               olen);
645146778Ssam			bp += 4;
646146778Ssam
64756893Sfenner			switch (otype) {
648146778Ssam			case PIMV2_HELLO_OPTION_HOLDTIME:
649146778Ssam                                relts_print(EXTRACT_16BITS(bp));
650146778Ssam                                break;
65156893Sfenner
652146778Ssam			case PIMV2_HELLO_OPTION_LANPRUNEDELAY:
653127675Sbms				if (olen != 4) {
654146778Ssam					(void)printf("ERROR: Option Lenght != 4 Bytes (%u)", olen);
655127675Sbms				} else {
656127675Sbms					char t_bit;
657127675Sbms					u_int16_t lan_delay, override_interval;
658146778Ssam					lan_delay = EXTRACT_16BITS(bp);
659146778Ssam					override_interval = EXTRACT_16BITS(bp+2);
660127675Sbms					t_bit = (lan_delay & 0x8000)? 1 : 0;
661127675Sbms					lan_delay &= ~0x8000;
662146778Ssam					(void)printf("\n\t    T-bit=%d, LAN delay %dms, Override interval %dms",
663127675Sbms					t_bit, lan_delay, override_interval);
664127675Sbms				}
665127675Sbms				break;
666127675Sbms
667146778Ssam			case PIMV2_HELLO_OPTION_DR_PRIORITY_OLD:
668146778Ssam			case PIMV2_HELLO_OPTION_DR_PRIORITY:
669146778Ssam                                switch (olen) {
670146778Ssam                                case 0:
671146778Ssam                                    printf("Bi-Directional Capability (Old)");
672146778Ssam                                    break;
673146778Ssam                                case 4:
674146778Ssam                                    printf("%u", EXTRACT_32BITS(bp));
675146778Ssam                                    break;
676146778Ssam                                default:
677146778Ssam                                    printf("ERROR: Option Lenght != 4 Bytes (%u)", olen);
678146778Ssam                                    break;
679146778Ssam                                }
680146778Ssam                                break;
681111729Sfenner
682146778Ssam			case PIMV2_HELLO_OPTION_GENID:
683146778Ssam                                (void)printf("0x%08x", EXTRACT_32BITS(bp));
68456893Sfenner				break;
68556893Sfenner
686146778Ssam			case PIMV2_HELLO_OPTION_REFRESH_CAP:
687146778Ssam                                (void)printf("v%d", *bp);
688146778Ssam				if (*(bp+1) != 0) {
689146778Ssam                                    (void)printf(", interval ");
690146778Ssam                                    relts_print(*(bp+1));
69156893Sfenner				}
692146778Ssam				if (EXTRACT_16BITS(bp+2) != 0) {
693146778Ssam                                    (void)printf(" ?0x%04x?", EXTRACT_16BITS(bp+2));
69498527Sfenner				}
69556893Sfenner				break;
69656893Sfenner
697146778Ssam			case  PIMV2_HELLO_OPTION_BIDIR_CAP:
69898527Sfenner				break;
69998527Sfenner
700146778Ssam                        case PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD:
701146778Ssam                        case PIMV2_HELLO_OPTION_ADDRESS_LIST:
702127675Sbms				if (vflag > 1) {
703146778Ssam					const u_char *ptr = bp;
704146778Ssam					while (ptr < (bp+olen)) {
705127675Sbms						int advance;
706127675Sbms
707146778Ssam						printf("\n\t    ");
708127675Sbms						advance = pimv2_addr_print(ptr, pimv2_unicast, 0);
709127675Sbms						if (advance < 0) {
710127675Sbms							printf("...");
711127675Sbms							break;
712127675Sbms						}
713127675Sbms						ptr += advance;
714127675Sbms					}
715127675Sbms				}
716127675Sbms				break;
71756893Sfenner			default:
718146778Ssam                                if (vflag <= 1)
719146778Ssam                                    print_unknown_data(bp,"\n\t    ",olen);
720146778Ssam                                break;
72156893Sfenner			}
722146778Ssam                        /* do we want to see an additionally hexdump ? */
723146778Ssam                        if (vflag> 1)
724146778Ssam                            print_unknown_data(bp,"\n\t    ",olen);
725146778Ssam			bp += olen;
72656893Sfenner		}
72756893Sfenner		break;
72856893Sfenner	    }
72956893Sfenner
730146778Ssam	case PIMV2_TYPE_REGISTER:
73198527Sfenner	{
73256893Sfenner		struct ip *ip;
73356893Sfenner
73456893Sfenner		if (vflag && bp + 8 <= ep) {
73556893Sfenner			(void)printf(" %s%s", bp[4] & 0x80 ? "B" : "",
73656893Sfenner				bp[4] & 0x40 ? "N" : "");
73756893Sfenner		}
73856893Sfenner		bp += 8; len -= 8;
73956893Sfenner
74056893Sfenner		/* encapsulated multicast packet */
74156893Sfenner		if (bp >= ep)
74256893Sfenner			break;
74356893Sfenner		ip = (struct ip *)bp;
74475118Sfenner		switch (IP_V(ip)) {
74598527Sfenner		case 4:	/* IPv4 */
74656893Sfenner			printf(" ");
747146778Ssam			ip_print(gndo, bp, len);
74856893Sfenner			break;
74956893Sfenner#ifdef INET6
75098527Sfenner		case 6:	/* IPv6 */
75156893Sfenner			printf(" ");
75256893Sfenner			ip6_print(bp, len);
75356893Sfenner			break;
75456893Sfenner#endif
75598527Sfenner		default:
75675118Sfenner			(void)printf(" IP ver %d", IP_V(ip));
75756893Sfenner			break;
75856893Sfenner		}
75956893Sfenner		break;
76098527Sfenner	}
76156893Sfenner
762146778Ssam	case PIMV2_TYPE_REGISTER_STOP:
76356893Sfenner		bp += 4; len -= 4;
76456893Sfenner		if (bp >= ep)
76556893Sfenner			break;
76656893Sfenner		(void)printf(" group=");
76756893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
76856893Sfenner			(void)printf("...");
76956893Sfenner			break;
77056893Sfenner		}
77156893Sfenner		bp += advance; len -= advance;
77256893Sfenner		if (bp >= ep)
77356893Sfenner			break;
77456893Sfenner		(void)printf(" source=");
77556893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
77656893Sfenner			(void)printf("...");
77756893Sfenner			break;
77856893Sfenner		}
77956893Sfenner		bp += advance; len -= advance;
78056893Sfenner		break;
78156893Sfenner
782146778Ssam	case PIMV2_TYPE_JOIN_PRUNE:
783146778Ssam	case PIMV2_TYPE_GRAFT:
784146778Ssam	case PIMV2_TYPE_GRAFT_ACK:
785146778Ssam
786146778Ssam
787146778Ssam        /*
788146778Ssam         * 0                   1                   2                   3
789146778Ssam         *   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
790146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
791146778Ssam         *  |PIM Ver| Type  | Addr length   |           Checksum            |
792146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
793146778Ssam         *  |             Unicast-Upstream Neighbor Address                 |
794146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
795146778Ssam         *  |  Reserved     | Num groups    |          Holdtime             |
796146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
797146778Ssam         *  |            Encoded-Multicast Group Address-1                  |
798146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
799146778Ssam         *  |   Number of Joined  Sources   |   Number of Pruned Sources    |
800146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
801146778Ssam         *  |               Encoded-Joined Source Address-1                 |
802146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
803146778Ssam         *  |                             .                                 |
804146778Ssam         *  |                             .                                 |
805146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
806146778Ssam         *  |               Encoded-Joined Source Address-n                 |
807146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
808146778Ssam         *  |               Encoded-Pruned Source Address-1                 |
809146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
810146778Ssam         *  |                             .                                 |
811146778Ssam         *  |                             .                                 |
812146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
813146778Ssam         *  |               Encoded-Pruned Source Address-n                 |
814146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
815146778Ssam         *  |                           .                                   |
816146778Ssam         *  |                           .                                   |
817146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
818146778Ssam         *  |                Encoded-Multicast Group Address-n              |
819146778Ssam         *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
820146778Ssam         */
821146778Ssam
82256893Sfenner	    {
82356893Sfenner		u_int8_t ngroup;
82456893Sfenner		u_int16_t holdtime;
82556893Sfenner		u_int16_t njoin;
82656893Sfenner		u_int16_t nprune;
82756893Sfenner		int i, j;
82856893Sfenner
82956893Sfenner		bp += 4; len -= 4;
83056893Sfenner		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
83156893Sfenner			if (bp >= ep)
83256893Sfenner				break;
833146778Ssam			(void)printf(", upstream-neighbor: ");
83456893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
83556893Sfenner				(void)printf("...");
83656893Sfenner				break;
83756893Sfenner			}
83856893Sfenner			bp += advance; len -= advance;
83956893Sfenner		}
84056893Sfenner		if (bp + 4 > ep)
84156893Sfenner			break;
84256893Sfenner		ngroup = bp[1];
84356893Sfenner		holdtime = EXTRACT_16BITS(&bp[2]);
844146778Ssam		(void)printf("\n\t  %u group(s)", ngroup);
84556893Sfenner		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
846146778Ssam			(void)printf(", holdtime: ");
84756893Sfenner			if (holdtime == 0xffff)
848146778Ssam				(void)printf("infinite");
84956893Sfenner			else
85056893Sfenner				relts_print(holdtime);
85156893Sfenner		}
85256893Sfenner		bp += 4; len -= 4;
85356893Sfenner		for (i = 0; i < ngroup; i++) {
85456893Sfenner			if (bp >= ep)
85556893Sfenner				goto jp_done;
856146778Ssam			(void)printf("\n\t    group #%u: ", i+1);
85756893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
85856893Sfenner				(void)printf("...)");
85956893Sfenner				goto jp_done;
86056893Sfenner			}
86156893Sfenner			bp += advance; len -= advance;
86256893Sfenner			if (bp + 4 > ep) {
86356893Sfenner				(void)printf("...)");
86456893Sfenner				goto jp_done;
86556893Sfenner			}
86656893Sfenner			njoin = EXTRACT_16BITS(&bp[0]);
86756893Sfenner			nprune = EXTRACT_16BITS(&bp[2]);
868146778Ssam			(void)printf(", joined sources: %u, pruned sources: %u", njoin,nprune);
86956893Sfenner			bp += 4; len -= 4;
87056893Sfenner			for (j = 0; j < njoin; j++) {
871146778Ssam				(void)printf("\n\t      joined source #%u: ",j+1);
87256893Sfenner				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
87356893Sfenner					(void)printf("...)");
87456893Sfenner					goto jp_done;
87556893Sfenner				}
87656893Sfenner				bp += advance; len -= advance;
87756893Sfenner			}
87856893Sfenner			for (j = 0; j < nprune; j++) {
879146778Ssam				(void)printf("\n\t      pruned source #%u: ",j+1);
88056893Sfenner				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
88156893Sfenner					(void)printf("...)");
88256893Sfenner					goto jp_done;
88356893Sfenner				}
88456893Sfenner				bp += advance; len -= advance;
88556893Sfenner			}
88656893Sfenner		}
88756893Sfenner	jp_done:
88856893Sfenner		break;
88956893Sfenner	    }
89056893Sfenner
891146778Ssam	case PIMV2_TYPE_BOOTSTRAP:
89298527Sfenner	{
89356893Sfenner		int i, j, frpcnt;
89456893Sfenner		bp += 4;
89556893Sfenner
89656893Sfenner		/* Fragment Tag, Hash Mask len, and BSR-priority */
89756893Sfenner		if (bp + sizeof(u_int16_t) >= ep) break;
89856893Sfenner		(void)printf(" tag=%x", EXTRACT_16BITS(bp));
89956893Sfenner		bp += sizeof(u_int16_t);
90056893Sfenner		if (bp >= ep) break;
90156893Sfenner		(void)printf(" hashmlen=%d", bp[0]);
90256893Sfenner		if (bp + 1 >= ep) break;
90356893Sfenner		(void)printf(" BSRprio=%d", bp[1]);
90456893Sfenner		bp += 2;
90556893Sfenner
90656893Sfenner		/* Encoded-Unicast-BSR-Address */
90756893Sfenner		if (bp >= ep) break;
90856893Sfenner		(void)printf(" BSR=");
90956893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
91056893Sfenner			(void)printf("...");
91156893Sfenner			break;
91256893Sfenner		}
91356893Sfenner		bp += advance;
91456893Sfenner
91556893Sfenner		for (i = 0; bp < ep; i++) {
91656893Sfenner			/* Encoded-Group Address */
91756893Sfenner			(void)printf(" (group%d: ", i);
91856893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
91956893Sfenner			    < 0) {
92056893Sfenner				(void)printf("...)");
92156893Sfenner				goto bs_done;
92256893Sfenner			}
92356893Sfenner			bp += advance;
92456893Sfenner
92556893Sfenner			/* RP-Count, Frag RP-Cnt, and rsvd */
92656893Sfenner			if (bp >= ep) {
92756893Sfenner				(void)printf("...)");
92856893Sfenner				goto bs_done;
92956893Sfenner			}
93075118Sfenner			(void)printf(" RPcnt=%d", bp[0]);
93156893Sfenner			if (bp + 1 >= ep) {
93256893Sfenner				(void)printf("...)");
93356893Sfenner				goto bs_done;
93456893Sfenner			}
93575118Sfenner			(void)printf(" FRPcnt=%d", frpcnt = bp[1]);
93656893Sfenner			bp += 4;
93756893Sfenner
93856893Sfenner			for (j = 0; j < frpcnt && bp < ep; j++) {
93956893Sfenner				/* each RP info */
94056893Sfenner				(void)printf(" RP%d=", j);
94156893Sfenner				if ((advance = pimv2_addr_print(bp,
94256893Sfenner								pimv2_unicast,
94356893Sfenner								0)) < 0) {
94456893Sfenner					(void)printf("...)");
94556893Sfenner					goto bs_done;
94656893Sfenner				}
94756893Sfenner				bp += advance;
94856893Sfenner
94956893Sfenner				if (bp + 1 >= ep) {
95056893Sfenner					(void)printf("...)");
95156893Sfenner					goto bs_done;
95256893Sfenner				}
95356893Sfenner				(void)printf(",holdtime=");
95456893Sfenner				relts_print(EXTRACT_16BITS(bp));
95556893Sfenner				if (bp + 2 >= ep) {
95656893Sfenner					(void)printf("...)");
95756893Sfenner					goto bs_done;
95856893Sfenner				}
95956893Sfenner				(void)printf(",prio=%d", bp[2]);
96056893Sfenner				bp += 4;
96156893Sfenner			}
96256893Sfenner			(void)printf(")");
96356893Sfenner		}
96456893Sfenner	   bs_done:
96556893Sfenner		break;
96698527Sfenner	}
967146778Ssam	case PIMV2_TYPE_ASSERT:
96856893Sfenner		bp += 4; len -= 4;
96956893Sfenner		if (bp >= ep)
97056893Sfenner			break;
97156893Sfenner		(void)printf(" group=");
97256893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
97356893Sfenner			(void)printf("...");
97456893Sfenner			break;
97556893Sfenner		}
97656893Sfenner		bp += advance; len -= advance;
97756893Sfenner		if (bp >= ep)
97856893Sfenner			break;
97956893Sfenner		(void)printf(" src=");
98056893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
98156893Sfenner			(void)printf("...");
98256893Sfenner			break;
98356893Sfenner		}
98456893Sfenner		bp += advance; len -= advance;
98556893Sfenner		if (bp + 8 > ep)
98656893Sfenner			break;
98756893Sfenner		if (bp[0] & 0x80)
98856893Sfenner			(void)printf(" RPT");
98956893Sfenner		(void)printf(" pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff);
99056893Sfenner		(void)printf(" metric=%u", EXTRACT_32BITS(&bp[4]));
99156893Sfenner		break;
99256893Sfenner
993146778Ssam	case PIMV2_TYPE_CANDIDATE_RP:
99498527Sfenner	{
99556893Sfenner		int i, pfxcnt;
99656893Sfenner		bp += 4;
99756893Sfenner
99856893Sfenner		/* Prefix-Cnt, Priority, and Holdtime */
99956893Sfenner		if (bp >= ep) break;
100056893Sfenner		(void)printf(" prefix-cnt=%d", bp[0]);
100156893Sfenner		pfxcnt = bp[0];
100256893Sfenner		if (bp + 1 >= ep) break;
100356893Sfenner		(void)printf(" prio=%d", bp[1]);
100456893Sfenner		if (bp + 3 >= ep) break;
100556893Sfenner		(void)printf(" holdtime=");
100656893Sfenner		relts_print(EXTRACT_16BITS(&bp[2]));
100756893Sfenner		bp += 4;
100856893Sfenner
100956893Sfenner		/* Encoded-Unicast-RP-Address */
101056893Sfenner		if (bp >= ep) break;
101156893Sfenner		(void)printf(" RP=");
101256893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
101356893Sfenner			(void)printf("...");
101456893Sfenner			break;
101556893Sfenner		}
101656893Sfenner		bp += advance;
101756893Sfenner
101856893Sfenner		/* Encoded-Group Addresses */
101956893Sfenner		for (i = 0; i < pfxcnt && bp < ep; i++) {
102056893Sfenner			(void)printf(" Group%d=", i);
102156893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
102256893Sfenner			    < 0) {
102356893Sfenner				(void)printf("...");
102456893Sfenner				break;
102556893Sfenner			}
102656893Sfenner			bp += advance;
102756893Sfenner		}
102856893Sfenner		break;
102998527Sfenner	}
103056893Sfenner
1031146778Ssam	case PIMV2_TYPE_PRUNE_REFRESH:
103256893Sfenner		(void)printf(" src=");
103356893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
103456893Sfenner			(void)printf("...");
103556893Sfenner			break;
103656893Sfenner		}
103756893Sfenner		bp += advance;
103856893Sfenner		(void)printf(" grp=");
103956893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
104056893Sfenner			(void)printf("...");
104156893Sfenner			break;
104256893Sfenner		}
104356893Sfenner		bp += advance;
104456893Sfenner		(void)printf(" forwarder=");
104556893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
104656893Sfenner			(void)printf("...");
104756893Sfenner			break;
104856893Sfenner		}
104956893Sfenner		bp += advance;
105056893Sfenner		TCHECK2(bp[0], 2);
105156893Sfenner		(void)printf(" TUNR ");
105256893Sfenner		relts_print(EXTRACT_16BITS(bp));
105356893Sfenner		break;
105456893Sfenner
105556893Sfenner
105656893Sfenner	 default:
105756893Sfenner		(void)printf(" [type %d]", PIM_TYPE(pim->pim_typever));
105856893Sfenner		break;
105956893Sfenner	}
106056893Sfenner
106156893Sfenner	return;
106256893Sfenner
106356893Sfennertrunc:
106456893Sfenner	(void)printf("[|pim]");
106556893Sfenner}
1066146778Ssam
1067146778Ssam/*
1068146778Ssam * Local Variables:
1069146778Ssam * c-style: whitesmith
1070146778Ssam * c-basic-offset: 8
1071146778Ssam * End:
1072146778Ssam */
1073