print-pim.c revision 111729
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 111729 2003-03-02 08:25:48Z fenner $
2217680Spst */
2317680Spst
2417680Spst#ifndef lint
2526180Sfennerstatic const char rcsid[] =
26111729Sfenner    "@(#) $Header: /tcpdump/master/tcpdump/print-pim.c,v 1.29.4.1 2002/05/07 18:30:19 fenner Exp $ (LBL)";
2717680Spst#endif
2817680Spst
2956893Sfenner#ifdef HAVE_CONFIG_H
3056893Sfenner#include "config.h"
3156893Sfenner#endif
3256893Sfenner
3317680Spst#include <sys/param.h>
3417680Spst#include <sys/time.h>
3517680Spst#include <sys/socket.h>
3617680Spst
3717680Spst#include <netinet/in.h>
3817680Spst
3956893Sfenner/*
4056893Sfenner * XXX: We consider a case where IPv6 is not ready yet for portability,
4156893Sfenner * but PIM dependent defintions should be independent of IPv6...
4256893Sfenner */
4356893Sfenner
4456893Sfennerstruct pim {
4556893Sfenner	u_int8_t pim_typever;
4657278Sfenner			/* upper 4bit: PIM version number; 2 for PIMv2 */
4757278Sfenner			/* lower 4bit: the PIM message type, currently they are:
4856893Sfenner			 * Hello, Register, Register-Stop, Join/Prune,
4956893Sfenner			 * Bootstrap, Assert, Graft (PIM-DM only),
5056893Sfenner			 * Graft-Ack (PIM-DM only), C-RP-Adv
5156893Sfenner			 */
5257278Sfenner#define PIM_VER(x)	(((x) & 0xf0) >> 4)
5357278Sfenner#define PIM_TYPE(x)	((x) & 0x0f)
5456893Sfenner	u_char  pim_rsv;	/* Reserved */
5556893Sfenner	u_short	pim_cksum;	/* IP style check sum */
5656893Sfenner};
5756893Sfenner
5856893Sfenner
5917680Spst#include <stdio.h>
6017680Spst#include <stdlib.h>
6117680Spst#include <unistd.h>
6217680Spst
6317680Spst#include "interface.h"
6417680Spst#include "addrtoname.h"
6556893Sfenner#include "extract.h"
6617680Spst
6775118Sfenner#include "ip.h"
6875118Sfenner
6956893Sfennerstatic void pimv2_print(register const u_char *bp, register u_int len);
7056893Sfenner
7156893Sfennerstatic void
7256893Sfennerpimv1_join_prune_print(register const u_char *bp, register u_int len)
7356893Sfenner{
7498527Sfenner	int maddrlen, addrlen, ngroups, njoin, nprune;
7598527Sfenner	int njp;
7656893Sfenner
7798527Sfenner	/* If it's a single group and a single source, use 1-line output. */
7898527Sfenner	if (TTEST2(bp[0], 30) && bp[11] == 1 &&
7998527Sfenner	    ((njoin = EXTRACT_16BITS(&bp[20])) + EXTRACT_16BITS(&bp[22])) == 1) {
8098527Sfenner		int hold;
8156893Sfenner
8298527Sfenner		(void)printf(" RPF %s ", ipaddr_string(bp));
8398527Sfenner		hold = EXTRACT_16BITS(&bp[6]);
8498527Sfenner		if (hold != 180) {
8598527Sfenner			(void)printf("Hold ");
8698527Sfenner			relts_print(hold);
8798527Sfenner		}
8898527Sfenner		(void)printf("%s (%s/%d, %s", njoin ? "Join" : "Prune",
8998527Sfenner		ipaddr_string(&bp[26]), bp[25] & 0x3f,
9098527Sfenner		ipaddr_string(&bp[12]));
9198527Sfenner		if (EXTRACT_32BITS(&bp[16]) != 0xffffffff)
9298527Sfenner			(void)printf("/%s", ipaddr_string(&bp[16]));
9398527Sfenner		(void)printf(") %s%s %s",
9456893Sfenner		    (bp[24] & 0x01) ? "Sparse" : "Dense",
9556893Sfenner		    (bp[25] & 0x80) ? " WC" : "",
9656893Sfenner		    (bp[25] & 0x40) ? "RP" : "SPT");
9798527Sfenner		return;
9898527Sfenner	}
9956893Sfenner
10056893Sfenner	TCHECK2(bp[0], 4);
10198527Sfenner	if (vflag > 1)
10298527Sfenner		(void)printf("\n");
10398527Sfenner	(void)printf(" Upstream Nbr: %s", ipaddr_string(bp));
10498527Sfenner	TCHECK2(bp[6], 2);
10598527Sfenner	if (vflag > 1)
10698527Sfenner		(void)printf("\n");
10798527Sfenner	(void)printf(" Hold time: ");
10898527Sfenner	relts_print(EXTRACT_16BITS(&bp[6]));
10998527Sfenner	if (vflag < 2)
11098527Sfenner		return;
11198527Sfenner	bp += 8;
11298527Sfenner	len -= 8;
11356893Sfenner
11498527Sfenner	TCHECK2(bp[0], 4);
11598527Sfenner	maddrlen = bp[1];
11698527Sfenner	addrlen = bp[2];
11798527Sfenner	ngroups = bp[3];
11898527Sfenner	bp += 4;
11998527Sfenner	len -= 4;
12098527Sfenner	while (ngroups--) {
12198527Sfenner		TCHECK2(bp[0], 4);
12298527Sfenner		(void)printf("\n\tGroup: %s", ipaddr_string(bp));
12398527Sfenner		if (EXTRACT_32BITS(&bp[4]) != 0xffffffff)
12498527Sfenner			(void)printf("/%s", ipaddr_string(&bp[4]));
12598527Sfenner		TCHECK2(bp[8], 4);
12698527Sfenner		njoin = EXTRACT_16BITS(&bp[8]);
12798527Sfenner		nprune = EXTRACT_16BITS(&bp[10]);
12898527Sfenner		(void)printf(" joined: %d pruned: %d", njoin, nprune);
12998527Sfenner		bp += 12;
13098527Sfenner		len -= 12;
13198527Sfenner		for (njp = 0; njp < (njoin + nprune); njp++) {
13298527Sfenner			char *type;
13398527Sfenner
13498527Sfenner			if (njp < njoin)
13598527Sfenner				type = "Join ";
13698527Sfenner			else
13798527Sfenner				type = "Prune";
13898527Sfenner			TCHECK2(bp[0], 6);
13998527Sfenner			(void)printf("\n\t%s %s%s%s%s/%d", type,
14056893Sfenner			    (bp[0] & 0x01) ? "Sparse " : "Dense ",
14156893Sfenner			    (bp[1] & 0x80) ? "WC " : "",
14256893Sfenner			    (bp[1] & 0x40) ? "RP " : "SPT ",
14398527Sfenner			ipaddr_string(&bp[2]), bp[1] & 0x3f);
14498527Sfenner			bp += 6;
14598527Sfenner			len -= 6;
14698527Sfenner		}
14756893Sfenner	}
14898527Sfenner	return;
14956893Sfennertrunc:
15098527Sfenner	(void)printf("[|pim]");
15198527Sfenner	return;
15256893Sfenner}
15356893Sfenner
15417680Spstvoid
15556893Sfennerpimv1_print(register const u_char *bp, register u_int len)
15617680Spst{
15798527Sfenner	register const u_char *ep;
15898527Sfenner	register u_char type;
15917680Spst
16098527Sfenner	ep = (const u_char *)snapend;
16198527Sfenner	if (bp >= ep)
16298527Sfenner		return;
16317680Spst
16498527Sfenner	type = bp[1];
16517680Spst
16698527Sfenner	switch (type) {
16798527Sfenner	case 0:
16898527Sfenner		(void)printf(" Query");
16998527Sfenner		if (TTEST(bp[8])) {
17098527Sfenner			switch (bp[8] >> 4) {
17198527Sfenner			case 0:
17298527Sfenner				(void)printf(" Dense-mode");
17356893Sfenner				break;
17498527Sfenner			case 1:
17598527Sfenner				(void)printf(" Sparse-mode");
17656893Sfenner				break;
17798527Sfenner			case 2:
17898527Sfenner				(void)printf(" Sparse-Dense-mode");
17956893Sfenner				break;
18098527Sfenner			default:
18198527Sfenner				(void)printf(" mode-%d", bp[8] >> 4);
18256893Sfenner				break;
18398527Sfenner			}
18456893Sfenner		}
18598527Sfenner		if (vflag) {
18698527Sfenner			TCHECK2(bp[10],2);
18798527Sfenner			(void)printf(" (Hold-time ");
18898527Sfenner			relts_print(EXTRACT_16BITS(&bp[10]));
18998527Sfenner			(void)printf(")");
19098527Sfenner		}
19198527Sfenner		break;
19217680Spst
19398527Sfenner	case 1:
19498527Sfenner		(void)printf(" Register");
19598527Sfenner		TCHECK2(bp[8], 20);			/* ip header */
19698527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[20]),
19798527Sfenner		    ipaddr_string(&bp[24]));
19898527Sfenner		break;
19998527Sfenner	case 2:
20098527Sfenner		(void)printf(" Register-Stop");
20198527Sfenner		TCHECK2(bp[12], 4);
20298527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[8]),
20398527Sfenner		    ipaddr_string(&bp[12]));
20498527Sfenner		break;
20598527Sfenner	case 3:
20698527Sfenner		(void)printf(" Join/Prune");
20798527Sfenner		if (vflag)
20898527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
20998527Sfenner		break;
21098527Sfenner	case 4:
21198527Sfenner		(void)printf(" RP-reachable");
21298527Sfenner		if (vflag) {
21398527Sfenner			TCHECK2(bp[22], 2);
21498527Sfenner			(void)printf(" group %s",
21556893Sfenner			ipaddr_string(&bp[8]));
21698527Sfenner			if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
21798527Sfenner				(void)printf("/%s", ipaddr_string(&bp[12]));
21898527Sfenner			(void)printf(" RP %s hold ", ipaddr_string(&bp[16]));
21998527Sfenner			relts_print(EXTRACT_16BITS(&bp[22]));
22098527Sfenner		}
22198527Sfenner		break;
22298527Sfenner	case 5:
22398527Sfenner		(void)printf(" Assert");
22498527Sfenner		TCHECK2(bp[16], 4);
22598527Sfenner		(void)printf(" for %s > %s", ipaddr_string(&bp[16]),
22698527Sfenner		    ipaddr_string(&bp[8]));
22756893Sfenner		if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
22856893Sfenner			(void)printf("/%s", ipaddr_string(&bp[12]));
22998527Sfenner		TCHECK2(bp[24], 4);
23098527Sfenner		(void)printf(" %s pref %d metric %d",
23198527Sfenner		    (bp[20] & 0x80) ? "RP-tree" : "SPT",
23256893Sfenner		EXTRACT_32BITS(&bp[20]) & 0x7fffffff,
23356893Sfenner		EXTRACT_32BITS(&bp[24]));
23498527Sfenner		break;
23598527Sfenner	case 6:
23698527Sfenner		(void)printf(" Graft");
23798527Sfenner		if (vflag)
23898527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
23998527Sfenner		break;
24098527Sfenner	case 7:
24198527Sfenner		(void)printf(" Graft-ACK");
24298527Sfenner		if (vflag)
24398527Sfenner			pimv1_join_prune_print(&bp[8], len - 8);
24498527Sfenner		break;
24598527Sfenner	case 8:
24698527Sfenner		(void)printf(" Mode");
24798527Sfenner		break;
24898527Sfenner	default:
24998527Sfenner		(void)printf(" [type %d]", type);
25098527Sfenner		break;
25156893Sfenner	}
25298527Sfenner	if ((bp[4] >> 4) != 1)
25398527Sfenner		(void)printf(" [v%d]", bp[4] >> 4);
25498527Sfenner	return;
25517680Spst
25656893Sfennertrunc:
25798527Sfenner	(void)printf("[|pim]");
25898527Sfenner	return;
25917680Spst}
26056893Sfenner
26156893Sfenner/*
26256893Sfenner * auto-RP is a cisco protocol, documented at
26398527Sfenner * ftp://ftpeng.cisco.com/ipmulticast/specs/pim-autorp-spec01.txt
26498527Sfenner *
26598527Sfenner * This implements version 1+, dated Sept 9, 1998.
26656893Sfenner */
26756893Sfennervoid
26856893Sfennercisco_autorp_print(register const u_char *bp, register u_int len)
26956893Sfenner{
27098527Sfenner	int type;
27198527Sfenner	int numrps;
27298527Sfenner	int hold;
27356893Sfenner
27498527Sfenner	TCHECK(bp[0]);
27598527Sfenner	(void)printf(" auto-rp ");
27698527Sfenner	type = bp[0];
27798527Sfenner	switch (type) {
27898527Sfenner	case 0x11:
27998527Sfenner		(void)printf("candidate-advert");
28098527Sfenner		break;
28198527Sfenner	case 0x12:
28298527Sfenner		(void)printf("mapping");
28398527Sfenner		break;
28498527Sfenner	default:
28598527Sfenner		(void)printf("type-0x%02x", type);
28698527Sfenner		break;
28798527Sfenner	}
28856893Sfenner
28998527Sfenner	TCHECK(bp[1]);
29098527Sfenner	numrps = bp[1];
29156893Sfenner
29298527Sfenner	TCHECK2(bp[2], 2);
29398527Sfenner	(void)printf(" Hold ");
29498527Sfenner	hold = EXTRACT_16BITS(&bp[2]);
29598527Sfenner	if (hold)
29698527Sfenner		relts_print(EXTRACT_16BITS(&bp[2]));
29798527Sfenner	else
29898527Sfenner		printf("FOREVER");
29956893Sfenner
30098527Sfenner	/* Next 4 bytes are reserved. */
30156893Sfenner
30298527Sfenner	bp += 8; len -= 8;
30356893Sfenner
30498527Sfenner	/*XXX skip unless -v? */
30556893Sfenner
30698527Sfenner	/*
30798527Sfenner	 * Rest of packet:
30898527Sfenner	 * numrps entries of the form:
30998527Sfenner	 * 32 bits: RP
31098527Sfenner	 * 6 bits: reserved
31198527Sfenner	 * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
31298527Sfenner	 * 8 bits: # of entries for this RP
31398527Sfenner	 * each entry: 7 bits: reserved, 1 bit: negative,
31498527Sfenner	 *	       8 bits: mask 32 bits: source
31598527Sfenner	 * lather, rinse, repeat.
31698527Sfenner	 */
31798527Sfenner	while (numrps--) {
31898527Sfenner		int nentries;
31998527Sfenner		char s;
32056893Sfenner
32198527Sfenner		TCHECK2(bp[0], 4);
32298527Sfenner		(void)printf(" RP %s", ipaddr_string(bp));
32398527Sfenner		TCHECK(bp[4]);
32498527Sfenner		switch (bp[4] & 0x3) {
32598527Sfenner		case 0: printf(" PIMv?");
32698527Sfenner			break;
32798527Sfenner		case 1:	printf(" PIMv1");
32898527Sfenner			break;
32998527Sfenner		case 2:	printf(" PIMv2");
33098527Sfenner			break;
33198527Sfenner		case 3:	printf(" PIMv1+2");
33298527Sfenner			break;
33398527Sfenner		}
33498527Sfenner		if (bp[4] & 0xfc)
33598527Sfenner			(void)printf(" [rsvd=0x%02x]", bp[4] & 0xfc);
33698527Sfenner		TCHECK(bp[5]);
33798527Sfenner		nentries = bp[5];
33898527Sfenner		bp += 6; len -= 6;
33998527Sfenner		s = ' ';
34098527Sfenner		for (; nentries; nentries--) {
34198527Sfenner			TCHECK2(bp[0], 6);
34298527Sfenner			(void)printf("%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
34398527Sfenner			    ipaddr_string(&bp[2]), bp[1]);
34498527Sfenner			if (bp[0] & 0xfe)
34598527Sfenner				(void)printf("[rsvd=0x%02x]", bp[0] & 0xfe);
34698527Sfenner			s = ',';
34798527Sfenner			bp += 6; len -= 6;
34898527Sfenner		}
34956893Sfenner	}
35098527Sfenner	return;
35156893Sfenner
35256893Sfennertrunc:
35398527Sfenner	(void)printf("[|autorp]");
35498527Sfenner	return;
35556893Sfenner}
35656893Sfenner
35756893Sfennervoid
35856893Sfennerpim_print(register const u_char *bp, register u_int len)
35956893Sfenner{
36056893Sfenner	register const u_char *ep;
36156893Sfenner	register struct pim *pim = (struct pim *)bp;
36256893Sfenner
36356893Sfenner	ep = (const u_char *)snapend;
36456893Sfenner	if (bp >= ep)
36556893Sfenner		return;
36656893Sfenner#ifdef notyet			/* currently we see only version and type */
36756893Sfenner	TCHECK(pim->pim_rsv);
36856893Sfenner#endif
36956893Sfenner
37075118Sfenner	switch (PIM_VER(pim->pim_typever)) {
37198527Sfenner	case 2:		/* avoid hardcoding? */
37257278Sfenner		(void)printf("pim v2");
37356893Sfenner		pimv2_print(bp, len);
37456893Sfenner		break;
37598527Sfenner	default:
37657278Sfenner		(void)printf("pim v%d", PIM_VER(pim->pim_typever));
37756893Sfenner		break;
37856893Sfenner	}
37956893Sfenner	return;
38056893Sfenner}
38156893Sfenner
38256893Sfenner/*
38356893Sfenner * PIMv2 uses encoded address representations.
38456893Sfenner *
38556893Sfenner * The last PIM-SM I-D before RFC2117 was published specified the
38656893Sfenner * following representation for unicast addresses.  However, RFC2117
38756893Sfenner * specified no encoding for unicast addresses with the unicast
38856893Sfenner * address length specified in the header.  Therefore, we have to
38956893Sfenner * guess which encoding is being used (Cisco's PIMv2 implementation
39056893Sfenner * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
39156893Sfenner * field into a 'unicast-address-length-in-bytes' field.  We guess
39256893Sfenner * that it's the draft encoding if this reserved field is zero.
39356893Sfenner *
39456893Sfenner * RFC2362 goes back to the encoded format, and calls the addr length
39556893Sfenner * field "reserved" again.
39656893Sfenner *
39756893Sfenner * The first byte is the address family, from:
39856893Sfenner *
39956893Sfenner *    0    Reserved
40056893Sfenner *    1    IP (IP version 4)
40156893Sfenner *    2    IP6 (IP version 6)
40256893Sfenner *    3    NSAP
40356893Sfenner *    4    HDLC (8-bit multidrop)
40456893Sfenner *    5    BBN 1822
40556893Sfenner *    6    802 (includes all 802 media plus Ethernet "canonical format")
40656893Sfenner *    7    E.163
40756893Sfenner *    8    E.164 (SMDS, Frame Relay, ATM)
40856893Sfenner *    9    F.69 (Telex)
40956893Sfenner *   10    X.121 (X.25, Frame Relay)
41056893Sfenner *   11    IPX
41156893Sfenner *   12    Appletalk
41256893Sfenner *   13    Decnet IV
41356893Sfenner *   14    Banyan Vines
41456893Sfenner *   15    E.164 with NSAP format subaddress
41556893Sfenner *
41656893Sfenner * In addition, the second byte is an "Encoding".  0 is the default
41756893Sfenner * encoding for the address family, and no other encodings are currently
41856893Sfenner * specified.
41956893Sfenner *
42056893Sfenner */
42156893Sfenner
42256893Sfennerstatic int pimv2_addr_len;
42356893Sfenner
42456893Sfennerenum pimv2_addrtype {
42556893Sfenner	pimv2_unicast, pimv2_group, pimv2_source
42656893Sfenner};
42756893Sfenner
42856893Sfenner/*  0                   1                   2                   3
42956893Sfenner *  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
43056893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43156893Sfenner * | Addr Family   | Encoding Type |     Unicast Address           |
43256893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
43356893Sfenner *  0                   1                   2                   3
43456893Sfenner *  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
43556893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43656893Sfenner * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
43756893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43856893Sfenner * |                Group multicast Address                        |
43956893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44056893Sfenner *  0                   1                   2                   3
44156893Sfenner *  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
44256893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44356893Sfenner * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
44456893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44556893Sfenner * |                        Source Address                         |
44656893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44756893Sfenner */
44856893Sfennerstatic int
44956893Sfennerpimv2_addr_print(const u_char *bp, enum pimv2_addrtype at, int silent)
45056893Sfenner{
45156893Sfenner	int af;
45256893Sfenner	char *afstr;
45356893Sfenner	int len, hdrlen;
45456893Sfenner
45556893Sfenner	TCHECK(bp[0]);
45656893Sfenner
45756893Sfenner	if (pimv2_addr_len == 0) {
45856893Sfenner		TCHECK(bp[1]);
45956893Sfenner		switch (bp[0]) {
46098527Sfenner		case 1:
46156893Sfenner			af = AF_INET;
46256893Sfenner			afstr = "IPv4";
46356893Sfenner			len = 4;
46456893Sfenner			break;
46556893Sfenner#ifdef INET6
46698527Sfenner		case 2:
46756893Sfenner			af = AF_INET6;
46856893Sfenner			afstr = "IPv6";
46956893Sfenner			len = 16;
47056893Sfenner			break;
47156893Sfenner#endif
47298527Sfenner		default:
47356893Sfenner			return -1;
47456893Sfenner		}
47556893Sfenner		if (bp[1] != 0)
47656893Sfenner			return -1;
47756893Sfenner		hdrlen = 2;
47856893Sfenner	} else {
47956893Sfenner		switch (pimv2_addr_len) {
48098527Sfenner		case 4:
48156893Sfenner			af = AF_INET;
48256893Sfenner			afstr = "IPv4";
48356893Sfenner			break;
48456893Sfenner#ifdef INET6
48598527Sfenner		case 16:
48656893Sfenner			af = AF_INET6;
48756893Sfenner			afstr = "IPv6";
48856893Sfenner			break;
48956893Sfenner#endif
49098527Sfenner		default:
49156893Sfenner			return -1;
49256893Sfenner			break;
49356893Sfenner		}
49456893Sfenner		len = pimv2_addr_len;
49556893Sfenner		hdrlen = 0;
49656893Sfenner	}
49756893Sfenner
49856893Sfenner	bp += hdrlen;
49956893Sfenner	switch (at) {
50098527Sfenner	case pimv2_unicast:
50156893Sfenner		TCHECK2(bp[0], len);
50256893Sfenner		if (af == AF_INET) {
50356893Sfenner			if (!silent)
50456893Sfenner				(void)printf("%s", ipaddr_string(bp));
50556893Sfenner		}
50656893Sfenner#ifdef INET6
50756893Sfenner		else if (af == AF_INET6) {
50856893Sfenner			if (!silent)
50956893Sfenner				(void)printf("%s", ip6addr_string(bp));
51056893Sfenner		}
51156893Sfenner#endif
51256893Sfenner		return hdrlen + len;
51398527Sfenner	case pimv2_group:
51498527Sfenner	case pimv2_source:
51556893Sfenner		TCHECK2(bp[0], len + 2);
51656893Sfenner		if (af == AF_INET) {
51756893Sfenner			if (!silent) {
51856893Sfenner				(void)printf("%s", ipaddr_string(bp + 2));
51956893Sfenner				if (bp[1] != 32)
52056893Sfenner					(void)printf("/%u", bp[1]);
52156893Sfenner			}
52256893Sfenner		}
52356893Sfenner#ifdef INET6
52456893Sfenner		else if (af == AF_INET6) {
52556893Sfenner			if (!silent) {
52656893Sfenner				(void)printf("%s", ip6addr_string(bp + 2));
52756893Sfenner				if (bp[1] != 128)
52856893Sfenner					(void)printf("/%u", bp[1]);
52956893Sfenner			}
53056893Sfenner		}
53156893Sfenner#endif
53256893Sfenner		if (bp[0] && !silent) {
53356893Sfenner			if (at == pimv2_group) {
53456893Sfenner				(void)printf("(0x%02x)", bp[0]);
53556893Sfenner			} else {
53656893Sfenner				(void)printf("(%s%s%s",
53756893Sfenner					bp[0] & 0x04 ? "S" : "",
53856893Sfenner					bp[0] & 0x02 ? "W" : "",
53956893Sfenner					bp[0] & 0x01 ? "R" : "");
54056893Sfenner				if (bp[0] & 0xf8) {
54156893Sfenner					(void) printf("+0x%02x", bp[0] & 0xf8);
54256893Sfenner				}
54356893Sfenner				(void)printf(")");
54456893Sfenner			}
54556893Sfenner		}
54656893Sfenner		return hdrlen + 2 + len;
54756893Sfenner	default:
54856893Sfenner		return -1;
54956893Sfenner	}
55056893Sfennertrunc:
55156893Sfenner	return -1;
55256893Sfenner}
55356893Sfenner
55456893Sfennerstatic void
55556893Sfennerpimv2_print(register const u_char *bp, register u_int len)
55656893Sfenner{
55756893Sfenner	register const u_char *ep;
55856893Sfenner	register struct pim *pim = (struct pim *)bp;
55956893Sfenner	int advance;
56056893Sfenner
56156893Sfenner	ep = (const u_char *)snapend;
56256893Sfenner	if (bp >= ep)
56356893Sfenner		return;
56457278Sfenner	if (ep > bp + len)
56557278Sfenner		ep = bp + len;
56656893Sfenner	TCHECK(pim->pim_rsv);
56756893Sfenner	pimv2_addr_len = pim->pim_rsv;
56856893Sfenner	if (pimv2_addr_len != 0)
56956893Sfenner		(void)printf("[RFC2117-encoding] ");
57056893Sfenner
57156893Sfenner	switch (PIM_TYPE(pim->pim_typever)) {
57298527Sfenner	case 0:
57356893Sfenner	    {
57456893Sfenner		u_int16_t otype, olen;
57556893Sfenner		(void)printf(" Hello");
57656893Sfenner		bp += 4;
57756893Sfenner		while (bp < ep) {
57856893Sfenner			TCHECK2(bp[0], 4);
57956893Sfenner			otype = EXTRACT_16BITS(&bp[0]);
58056893Sfenner			olen = EXTRACT_16BITS(&bp[2]);
58156893Sfenner			TCHECK2(bp[0], 4 + olen);
58256893Sfenner			switch (otype) {
58356893Sfenner			case 1:		/* Hold time */
58456893Sfenner				(void)printf(" (Hold-time ");
58556893Sfenner				relts_print(EXTRACT_16BITS(&bp[4]));
58656893Sfenner				(void)printf(")");
58756893Sfenner				break;
58856893Sfenner
589111729Sfenner			case 18:	/* Old DR-Priority */
590111729Sfenner				if (olen == 4)
591111729Sfenner					(void)printf(" (OLD-DR-Priority: %d)",
592111729Sfenner							EXTRACT_32BITS(&bp[4]));
593111729Sfenner				else
594111729Sfenner					goto unknown;
595111729Sfenner				break;
596111729Sfenner
597111729Sfenner
59898527Sfenner			case 19:	/* DR-Priority */
599111729Sfenner				if (olen == 0) {
600111729Sfenner					(void)printf(" (OLD-bidir-capable)");
601111729Sfenner					break;
602111729Sfenner				}
60398527Sfenner				(void)printf(" (DR-Priority: ");
60498527Sfenner				if (olen != 4) {
60598527Sfenner					(void)printf("!olen=%d!)", olen);
60698527Sfenner				} else {
60798527Sfenner					(void)printf("%d)", EXTRACT_32BITS(&bp[4]));
60898527Sfenner				}
60956893Sfenner				break;
61056893Sfenner
61156893Sfenner			case 20:
61256893Sfenner				(void)printf(" (Genid: 0x%08x)", EXTRACT_32BITS(&bp[4]));
61356893Sfenner				break;
61456893Sfenner
61556893Sfenner			case 21:
61698527Sfenner				(void)printf(" (State Refresh Capable; v%d", bp[4]);
61798527Sfenner				if (bp[5] != 0) {
61898527Sfenner					(void)printf(" interval ");
61998527Sfenner					relts_print(bp[5]);
62056893Sfenner				}
62198527Sfenner				if (EXTRACT_16BITS(&bp[6]) != 0) {
62298527Sfenner					(void)printf(" ?0x%04x?", EXTRACT_16BITS(&bp[6]));
62398527Sfenner				}
62456893Sfenner				(void)printf(")");
62556893Sfenner				break;
62656893Sfenner
62798527Sfenner			case 22:	/* Bidir-Capable */
62898527Sfenner				(void)printf(" (bidir-capable)");
62998527Sfenner				break;
63098527Sfenner
63156893Sfenner			default:
632111729Sfenner			unknown:
63356893Sfenner				if (vflag)
63456893Sfenner					(void)printf(" [Hello option %d]", otype);
63556893Sfenner			}
63656893Sfenner			bp += 4 + olen;
63756893Sfenner		}
63856893Sfenner		break;
63956893Sfenner	    }
64056893Sfenner
64198527Sfenner	case 1:
64298527Sfenner	{
64356893Sfenner		struct ip *ip;
64456893Sfenner
64556893Sfenner		(void)printf(" Register");
64656893Sfenner		if (vflag && bp + 8 <= ep) {
64756893Sfenner			(void)printf(" %s%s", bp[4] & 0x80 ? "B" : "",
64856893Sfenner				bp[4] & 0x40 ? "N" : "");
64956893Sfenner		}
65056893Sfenner		bp += 8; len -= 8;
65156893Sfenner
65256893Sfenner		/* encapsulated multicast packet */
65356893Sfenner		if (bp >= ep)
65456893Sfenner			break;
65556893Sfenner		ip = (struct ip *)bp;
65675118Sfenner		switch (IP_V(ip)) {
65798527Sfenner		case 4:	/* IPv4 */
65856893Sfenner			printf(" ");
65956893Sfenner			ip_print(bp, len);
66056893Sfenner			break;
66156893Sfenner#ifdef INET6
66298527Sfenner		case 6:	/* IPv6 */
66356893Sfenner			printf(" ");
66456893Sfenner			ip6_print(bp, len);
66556893Sfenner			break;
66656893Sfenner#endif
66798527Sfenner		default:
66875118Sfenner			(void)printf(" IP ver %d", IP_V(ip));
66956893Sfenner			break;
67056893Sfenner		}
67156893Sfenner		break;
67298527Sfenner	}
67356893Sfenner
67498527Sfenner	case 2:
67556893Sfenner		(void)printf(" Register-Stop");
67656893Sfenner		bp += 4; len -= 4;
67756893Sfenner		if (bp >= ep)
67856893Sfenner			break;
67956893Sfenner		(void)printf(" group=");
68056893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
68156893Sfenner			(void)printf("...");
68256893Sfenner			break;
68356893Sfenner		}
68456893Sfenner		bp += advance; len -= advance;
68556893Sfenner		if (bp >= ep)
68656893Sfenner			break;
68756893Sfenner		(void)printf(" source=");
68856893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
68956893Sfenner			(void)printf("...");
69056893Sfenner			break;
69156893Sfenner		}
69256893Sfenner		bp += advance; len -= advance;
69356893Sfenner		break;
69456893Sfenner
69598527Sfenner	case 3:
69698527Sfenner	case 6:
69798527Sfenner	case 7:
69856893Sfenner	    {
69956893Sfenner		u_int8_t ngroup;
70056893Sfenner		u_int16_t holdtime;
70156893Sfenner		u_int16_t njoin;
70256893Sfenner		u_int16_t nprune;
70356893Sfenner		int i, j;
70456893Sfenner
70556893Sfenner		switch (PIM_TYPE(pim->pim_typever)) {
70698527Sfenner		case 3:
70756893Sfenner			(void)printf(" Join/Prune");
70856893Sfenner			break;
70998527Sfenner		case 6:
71056893Sfenner			(void)printf(" Graft");
71156893Sfenner			break;
71298527Sfenner		case 7:
71356893Sfenner			(void)printf(" Graft-ACK");
71456893Sfenner			break;
71556893Sfenner		}
71656893Sfenner		bp += 4; len -= 4;
71756893Sfenner		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
71856893Sfenner			if (bp >= ep)
71956893Sfenner				break;
72056893Sfenner			(void)printf(" upstream-neighbor=");
72156893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
72256893Sfenner				(void)printf("...");
72356893Sfenner				break;
72456893Sfenner			}
72556893Sfenner			bp += advance; len -= advance;
72656893Sfenner		}
72756893Sfenner		if (bp + 4 > ep)
72856893Sfenner			break;
72956893Sfenner		ngroup = bp[1];
73056893Sfenner		holdtime = EXTRACT_16BITS(&bp[2]);
73156893Sfenner		(void)printf(" groups=%u", ngroup);
73256893Sfenner		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
73356893Sfenner			(void)printf(" holdtime=");
73456893Sfenner			if (holdtime == 0xffff)
73556893Sfenner				(void)printf("infty");
73656893Sfenner			else
73756893Sfenner				relts_print(holdtime);
73856893Sfenner		}
73956893Sfenner		bp += 4; len -= 4;
74056893Sfenner		for (i = 0; i < ngroup; i++) {
74156893Sfenner			if (bp >= ep)
74256893Sfenner				goto jp_done;
74356893Sfenner			(void)printf(" (group%d: ", i);
74456893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
74556893Sfenner				(void)printf("...)");
74656893Sfenner				goto jp_done;
74756893Sfenner			}
74856893Sfenner			bp += advance; len -= advance;
74956893Sfenner			if (bp + 4 > ep) {
75056893Sfenner				(void)printf("...)");
75156893Sfenner				goto jp_done;
75256893Sfenner			}
75356893Sfenner			njoin = EXTRACT_16BITS(&bp[0]);
75456893Sfenner			nprune = EXTRACT_16BITS(&bp[2]);
75556893Sfenner			(void)printf(" join=%u", njoin);
75656893Sfenner			bp += 4; len -= 4;
75756893Sfenner			for (j = 0; j < njoin; j++) {
75856893Sfenner				(void)printf(" ");
75956893Sfenner				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
76056893Sfenner					(void)printf("...)");
76156893Sfenner					goto jp_done;
76256893Sfenner				}
76356893Sfenner				bp += advance; len -= advance;
76456893Sfenner			}
76556893Sfenner			(void)printf(" prune=%u", nprune);
76656893Sfenner			for (j = 0; j < nprune; j++) {
76756893Sfenner				(void)printf(" ");
76856893Sfenner				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
76956893Sfenner					(void)printf("...)");
77056893Sfenner					goto jp_done;
77156893Sfenner				}
77256893Sfenner				bp += advance; len -= advance;
77356893Sfenner			}
77456893Sfenner			(void)printf(")");
77556893Sfenner		}
77656893Sfenner	jp_done:
77756893Sfenner		break;
77856893Sfenner	    }
77956893Sfenner
78098527Sfenner	case 4:
78198527Sfenner	{
78256893Sfenner		int i, j, frpcnt;
78356893Sfenner
78456893Sfenner		(void)printf(" Bootstrap");
78556893Sfenner		bp += 4;
78656893Sfenner
78756893Sfenner		/* Fragment Tag, Hash Mask len, and BSR-priority */
78856893Sfenner		if (bp + sizeof(u_int16_t) >= ep) break;
78956893Sfenner		(void)printf(" tag=%x", EXTRACT_16BITS(bp));
79056893Sfenner		bp += sizeof(u_int16_t);
79156893Sfenner		if (bp >= ep) break;
79256893Sfenner		(void)printf(" hashmlen=%d", bp[0]);
79356893Sfenner		if (bp + 1 >= ep) break;
79456893Sfenner		(void)printf(" BSRprio=%d", bp[1]);
79556893Sfenner		bp += 2;
79656893Sfenner
79756893Sfenner		/* Encoded-Unicast-BSR-Address */
79856893Sfenner		if (bp >= ep) break;
79956893Sfenner		(void)printf(" BSR=");
80056893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
80156893Sfenner			(void)printf("...");
80256893Sfenner			break;
80356893Sfenner		}
80456893Sfenner		bp += advance;
80556893Sfenner
80656893Sfenner		for (i = 0; bp < ep; i++) {
80756893Sfenner			/* Encoded-Group Address */
80856893Sfenner			(void)printf(" (group%d: ", i);
80956893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
81056893Sfenner			    < 0) {
81156893Sfenner				(void)printf("...)");
81256893Sfenner				goto bs_done;
81356893Sfenner			}
81456893Sfenner			bp += advance;
81556893Sfenner
81656893Sfenner			/* RP-Count, Frag RP-Cnt, and rsvd */
81756893Sfenner			if (bp >= ep) {
81856893Sfenner				(void)printf("...)");
81956893Sfenner				goto bs_done;
82056893Sfenner			}
82175118Sfenner			(void)printf(" RPcnt=%d", bp[0]);
82256893Sfenner			if (bp + 1 >= ep) {
82356893Sfenner				(void)printf("...)");
82456893Sfenner				goto bs_done;
82556893Sfenner			}
82675118Sfenner			(void)printf(" FRPcnt=%d", frpcnt = bp[1]);
82756893Sfenner			bp += 4;
82856893Sfenner
82956893Sfenner			for (j = 0; j < frpcnt && bp < ep; j++) {
83056893Sfenner				/* each RP info */
83156893Sfenner				(void)printf(" RP%d=", j);
83256893Sfenner				if ((advance = pimv2_addr_print(bp,
83356893Sfenner								pimv2_unicast,
83456893Sfenner								0)) < 0) {
83556893Sfenner					(void)printf("...)");
83656893Sfenner					goto bs_done;
83756893Sfenner				}
83856893Sfenner				bp += advance;
83956893Sfenner
84056893Sfenner				if (bp + 1 >= ep) {
84156893Sfenner					(void)printf("...)");
84256893Sfenner					goto bs_done;
84356893Sfenner				}
84456893Sfenner				(void)printf(",holdtime=");
84556893Sfenner				relts_print(EXTRACT_16BITS(bp));
84656893Sfenner				if (bp + 2 >= ep) {
84756893Sfenner					(void)printf("...)");
84856893Sfenner					goto bs_done;
84956893Sfenner				}
85056893Sfenner				(void)printf(",prio=%d", bp[2]);
85156893Sfenner				bp += 4;
85256893Sfenner			}
85356893Sfenner			(void)printf(")");
85456893Sfenner		}
85556893Sfenner	   bs_done:
85656893Sfenner		break;
85798527Sfenner	}
85898527Sfenner	case 5:
85956893Sfenner		(void)printf(" Assert");
86056893Sfenner		bp += 4; len -= 4;
86156893Sfenner		if (bp >= ep)
86256893Sfenner			break;
86356893Sfenner		(void)printf(" group=");
86456893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
86556893Sfenner			(void)printf("...");
86656893Sfenner			break;
86756893Sfenner		}
86856893Sfenner		bp += advance; len -= advance;
86956893Sfenner		if (bp >= ep)
87056893Sfenner			break;
87156893Sfenner		(void)printf(" src=");
87256893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
87356893Sfenner			(void)printf("...");
87456893Sfenner			break;
87556893Sfenner		}
87656893Sfenner		bp += advance; len -= advance;
87756893Sfenner		if (bp + 8 > ep)
87856893Sfenner			break;
87956893Sfenner		if (bp[0] & 0x80)
88056893Sfenner			(void)printf(" RPT");
88156893Sfenner		(void)printf(" pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff);
88256893Sfenner		(void)printf(" metric=%u", EXTRACT_32BITS(&bp[4]));
88356893Sfenner		break;
88456893Sfenner
88598527Sfenner	case 8:
88698527Sfenner	{
88756893Sfenner		int i, pfxcnt;
88856893Sfenner
88956893Sfenner		(void)printf(" Candidate-RP-Advertisement");
89056893Sfenner		bp += 4;
89156893Sfenner
89256893Sfenner		/* Prefix-Cnt, Priority, and Holdtime */
89356893Sfenner		if (bp >= ep) break;
89456893Sfenner		(void)printf(" prefix-cnt=%d", bp[0]);
89556893Sfenner		pfxcnt = bp[0];
89656893Sfenner		if (bp + 1 >= ep) break;
89756893Sfenner		(void)printf(" prio=%d", bp[1]);
89856893Sfenner		if (bp + 3 >= ep) break;
89956893Sfenner		(void)printf(" holdtime=");
90056893Sfenner		relts_print(EXTRACT_16BITS(&bp[2]));
90156893Sfenner		bp += 4;
90256893Sfenner
90356893Sfenner		/* Encoded-Unicast-RP-Address */
90456893Sfenner		if (bp >= ep) break;
90556893Sfenner		(void)printf(" RP=");
90656893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
90756893Sfenner			(void)printf("...");
90856893Sfenner			break;
90956893Sfenner		}
91056893Sfenner		bp += advance;
91156893Sfenner
91256893Sfenner		/* Encoded-Group Addresses */
91356893Sfenner		for (i = 0; i < pfxcnt && bp < ep; i++) {
91456893Sfenner			(void)printf(" Group%d=", i);
91556893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
91656893Sfenner			    < 0) {
91756893Sfenner				(void)printf("...");
91856893Sfenner				break;
91956893Sfenner			}
92056893Sfenner			bp += advance;
92156893Sfenner		}
92256893Sfenner		break;
92398527Sfenner	}
92456893Sfenner
92598527Sfenner	case 9:
92656893Sfenner		(void)printf(" Prune-Refresh");
92756893Sfenner		(void)printf(" src=");
92856893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
92956893Sfenner			(void)printf("...");
93056893Sfenner			break;
93156893Sfenner		}
93256893Sfenner		bp += advance;
93356893Sfenner		(void)printf(" grp=");
93456893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
93556893Sfenner			(void)printf("...");
93656893Sfenner			break;
93756893Sfenner		}
93856893Sfenner		bp += advance;
93956893Sfenner		(void)printf(" forwarder=");
94056893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
94156893Sfenner			(void)printf("...");
94256893Sfenner			break;
94356893Sfenner		}
94456893Sfenner		bp += advance;
94556893Sfenner		TCHECK2(bp[0], 2);
94656893Sfenner		(void)printf(" TUNR ");
94756893Sfenner		relts_print(EXTRACT_16BITS(bp));
94856893Sfenner		break;
94956893Sfenner
95056893Sfenner
95156893Sfenner	 default:
95256893Sfenner		(void)printf(" [type %d]", PIM_TYPE(pim->pim_typever));
95356893Sfenner		break;
95456893Sfenner	}
95556893Sfenner
95656893Sfenner	return;
95756893Sfenner
95856893Sfennertrunc:
95956893Sfenner	(void)printf("[|pim]");
96056893Sfenner}
961