print-pim.c revision 56893
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.
2017680Spst */
2117680Spst
2217680Spst#ifndef lint
2326180Sfennerstatic const char rcsid[] =
2456893Sfenner    "@(#) $Header: /tcpdump/master/tcpdump/print-pim.c,v 1.15.2.1 2000/01/25 18:29:05 itojun Exp $ (LBL)";
2517680Spst#endif
2617680Spst
2756893Sfenner#ifdef HAVE_CONFIG_H
2856893Sfenner#include "config.h"
2956893Sfenner#endif
3056893Sfenner
3117680Spst#include <sys/param.h>
3217680Spst#include <sys/time.h>
3317680Spst#include <sys/socket.h>
3417680Spst
3517680Spst#include <netinet/in.h>
3617680Spst#include <netinet/in_systm.h>
3717680Spst#include <netinet/ip.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;
4656893Sfenner			/* upper 4bit: the PIM message type, currently they are:
4756893Sfenner			 * Hello, Register, Register-Stop, Join/Prune,
4856893Sfenner			 * Bootstrap, Assert, Graft (PIM-DM only),
4956893Sfenner			 * Graft-Ack (PIM-DM only), C-RP-Adv
5056893Sfenner			 */
5156893Sfenner			/* lower 4bit: PIM version number; 2 for PIMv2 */
5256893Sfenner#define PIM_TYPE(x)	(((x) & 0xf0) >> 4)
5356893Sfenner#define PIM_VER(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
6756893Sfennerstatic void pimv2_print(register const u_char *bp, register u_int len);
6856893Sfenner
6956893Sfennerstatic void
7056893Sfennerpimv1_join_prune_print(register const u_char *bp, register u_int len)
7156893Sfenner{
7256893Sfenner    int maddrlen, addrlen, ngroups, njoin, nprune;
7356893Sfenner    int njp;
7456893Sfenner
7556893Sfenner    /* If it's a single group and a single source, use 1-line output. */
7656893Sfenner    if (TTEST2(bp[0], 30) && bp[11] == 1 &&
7756893Sfenner	((njoin = EXTRACT_16BITS(&bp[20])) + EXTRACT_16BITS(&bp[22])) == 1) {
7856893Sfenner	    int hold;
7956893Sfenner
8056893Sfenner	    (void)printf(" RPF %s ", ipaddr_string(bp));
8156893Sfenner	    hold = EXTRACT_16BITS(&bp[6]);
8256893Sfenner	    if (hold != 180) {
8356893Sfenner		(void)printf("Hold ");
8456893Sfenner		relts_print(hold);
8556893Sfenner	    }
8656893Sfenner	    (void)printf("%s (%s/%d, %s", njoin ? "Join" : "Prune",
8756893Sfenner		    ipaddr_string(&bp[26]), bp[25] & 0x3f,
8856893Sfenner		    ipaddr_string(&bp[12]));
8956893Sfenner	    if (EXTRACT_32BITS(&bp[16]) != 0xffffffff)
9056893Sfenner		    (void)printf("/%s", ipaddr_string(&bp[16]));
9156893Sfenner	    (void)printf(") %s%s %s",
9256893Sfenner		    (bp[24] & 0x01) ? "Sparse" : "Dense",
9356893Sfenner		    (bp[25] & 0x80) ? " WC" : "",
9456893Sfenner		    (bp[25] & 0x40) ? "RP" : "SPT");
9556893Sfenner	    return;
9656893Sfenner    }
9756893Sfenner
9856893Sfenner    TCHECK2(bp[0], 4);
9956893Sfenner    (void)printf("\n Upstream Nbr: %s", ipaddr_string(bp));
10056893Sfenner    TCHECK2(bp[6], 2);
10156893Sfenner    (void)printf("\n Hold time: ");
10256893Sfenner    relts_print(EXTRACT_16BITS(&bp[6]));
10356893Sfenner    bp += 8; len -= 8;
10456893Sfenner
10556893Sfenner    TCHECK2(bp[0], 4);
10656893Sfenner    maddrlen = bp[1];
10756893Sfenner    addrlen = bp[2];
10856893Sfenner    ngroups = bp[3];
10956893Sfenner    bp += 4; len -= 4;
11056893Sfenner    while (ngroups--) {
11156893Sfenner	TCHECK2(bp[0], 4);
11256893Sfenner	(void)printf("\n\tGroup: %s", ipaddr_string(bp));
11356893Sfenner	if (EXTRACT_32BITS(&bp[4]) != 0xffffffff)
11456893Sfenner		(void)printf("/%s", ipaddr_string(&bp[4]));
11556893Sfenner	TCHECK2(bp[8], 4);
11656893Sfenner	njoin = EXTRACT_16BITS(&bp[8]);
11756893Sfenner	nprune = EXTRACT_16BITS(&bp[10]);
11856893Sfenner	(void)printf(" joined: %d pruned: %d", njoin, nprune);
11956893Sfenner	bp += 12; len -= 12;
12056893Sfenner	for (njp = 0; njp < (njoin + nprune); njp++) {
12156893Sfenner	    char *type;
12256893Sfenner
12356893Sfenner	    if (njp < njoin) {
12456893Sfenner		type = "Join ";
12556893Sfenner	    } else {
12656893Sfenner		type = "Prune";
12756893Sfenner	    }
12856893Sfenner	    TCHECK2(bp[0], 6);
12956893Sfenner	    (void)printf("\n\t%s %s%s%s%s/%d", type,
13056893Sfenner			    (bp[0] & 0x01) ? "Sparse " : "Dense ",
13156893Sfenner			    (bp[1] & 0x80) ? "WC " : "",
13256893Sfenner			    (bp[1] & 0x40) ? "RP " : "SPT ",
13356893Sfenner			    ipaddr_string(&bp[2]), bp[1] & 0x3f);
13456893Sfenner	    bp += 6; len -= 6;
13556893Sfenner	}
13656893Sfenner    }
13756893Sfenner    return;
13856893Sfennertrunc:
13956893Sfenner    (void)printf("[|pim]");
14056893Sfenner    return;
14156893Sfenner}
14256893Sfenner
14317680Spstvoid
14456893Sfennerpimv1_print(register const u_char *bp, register u_int len)
14517680Spst{
14617680Spst    register const u_char *ep;
14717680Spst    register u_char type;
14817680Spst
14917680Spst    ep = (const u_char *)snapend;
15017680Spst    if (bp >= ep)
15117680Spst	return;
15217680Spst
15317680Spst    type = bp[1];
15417680Spst
15517680Spst    switch (type) {
15617680Spst    case 0:
15717680Spst	(void)printf(" Query");
15856893Sfenner	if (TTEST(bp[8])) {
15956893Sfenner		switch (bp[8] >> 4) {
16056893Sfenner		    case 0:	(void)printf(" Dense-mode");
16156893Sfenner				break;
16256893Sfenner		    case 1:	(void)printf(" Sparse-mode");
16356893Sfenner				break;
16456893Sfenner		    case 2:	(void)printf(" Sparse-Dense-mode");
16556893Sfenner				break;
16656893Sfenner		    default:	(void)printf(" mode-%d", bp[8] >> 4);
16756893Sfenner				break;
16856893Sfenner		}
16956893Sfenner	}
17056893Sfenner	if (vflag) {
17156893Sfenner	    TCHECK2(bp[10],2);
17256893Sfenner	    (void)printf(" (Hold-time ");
17356893Sfenner	    relts_print(EXTRACT_16BITS(&bp[10]));
17456893Sfenner	    (void)printf(")");
17556893Sfenner	}
17617680Spst	break;
17717680Spst
17817680Spst    case 1:
17917680Spst	(void)printf(" Register");
18056893Sfenner	TCHECK2(bp[8], 20);			/* ip header */
18156893Sfenner	(void)printf(" for %s > %s", ipaddr_string(&bp[20]),
18256893Sfenner				     ipaddr_string(&bp[24]));
18317680Spst	break;
18417680Spst
18517680Spst    case 2:
18617680Spst	(void)printf(" Register-Stop");
18756893Sfenner	TCHECK2(bp[12], 4);
18856893Sfenner	(void)printf(" for %s > %s", ipaddr_string(&bp[8]),
18956893Sfenner				     ipaddr_string(&bp[12]));
19017680Spst	break;
19117680Spst
19217680Spst    case 3:
19317680Spst	(void)printf(" Join/Prune");
19456893Sfenner	if (vflag) {
19556893Sfenner	    pimv1_join_prune_print(&bp[8], len - 8);
19656893Sfenner	}
19717680Spst	break;
19817680Spst
19917680Spst    case 4:
20017680Spst	(void)printf(" RP-reachable");
20156893Sfenner	if (vflag) {
20256893Sfenner		TCHECK2(bp[22], 2);
20356893Sfenner		(void)printf(" group %s",
20456893Sfenner			ipaddr_string(&bp[8]));
20556893Sfenner		if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
20656893Sfenner			(void)printf("/%s", ipaddr_string(&bp[12]));
20756893Sfenner		(void)printf(" RP %s hold ",
20856893Sfenner			ipaddr_string(&bp[16]));
20956893Sfenner		relts_print(EXTRACT_16BITS(&bp[22]));
21056893Sfenner	}
21117680Spst	break;
21217680Spst
21317680Spst    case 5:
21417680Spst	(void)printf(" Assert");
21556893Sfenner	TCHECK2(bp[16], 4);
21656893Sfenner	(void)printf(" for %s > %s", ipaddr_string(&bp[16]),
21756893Sfenner					    ipaddr_string(&bp[8]));
21856893Sfenner	if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
21956893Sfenner		(void)printf("/%s", ipaddr_string(&bp[12]));
22056893Sfenner	TCHECK2(bp[24], 4);
22156893Sfenner	(void)printf(" %s pref %d metric %d",
22256893Sfenner		(bp[20] & 0x80) ? "RP-tree" : "SPT",
22356893Sfenner		EXTRACT_32BITS(&bp[20]) & 0x7fffffff,
22456893Sfenner		EXTRACT_32BITS(&bp[24]));
22517680Spst	break;
22617680Spst
22717680Spst    case 6:
22817680Spst	(void)printf(" Graft");
22956893Sfenner	if (vflag) {
23056893Sfenner	    pimv1_join_prune_print(&bp[8], len - 8);
23156893Sfenner	}
23217680Spst	break;
23317680Spst
23417680Spst    case 7:
23517680Spst	(void)printf(" Graft-ACK");
23656893Sfenner	if (vflag) {
23756893Sfenner	    pimv1_join_prune_print(&bp[8], len - 8);
23856893Sfenner	}
23917680Spst	break;
24017680Spst
24117680Spst    case 8:
24217680Spst	(void)printf(" Mode");
24317680Spst	break;
24417680Spst
24517680Spst    default:
24617680Spst	(void)printf(" [type %d]", type);
24717680Spst	break;
24817680Spst    }
24956893Sfenner    if ((bp[4] >> 4) != 1)
25056893Sfenner	(void)printf(" [v%d]", bp[4] >> 4);
25156893Sfenner    return;
25256893Sfenner
25356893Sfennertrunc:
25456893Sfenner    (void)printf("[|pim]");
25556893Sfenner    return;
25617680Spst}
25756893Sfenner
25856893Sfenner/*
25956893Sfenner * auto-RP is a cisco protocol, documented at
26056893Sfenner * ftp://ftpeng.cisco.com/ipmulticast/pim-autorp-spec01.txt
26156893Sfenner */
26256893Sfennervoid
26356893Sfennercisco_autorp_print(register const u_char *bp, register u_int len)
26456893Sfenner{
26556893Sfenner    int type;
26656893Sfenner    int numrps;
26756893Sfenner    int hold;
26856893Sfenner
26956893Sfenner    TCHECK(bp[0]);
27056893Sfenner    (void)printf(" auto-rp ");
27156893Sfenner    type = bp[0];
27256893Sfenner    switch (type) {
27356893Sfenner    case 0x11:
27456893Sfenner	(void)printf("candidate-advert");
27556893Sfenner	break;
27656893Sfenner    case 0x12:
27756893Sfenner	(void)printf("mapping");
27856893Sfenner	break;
27956893Sfenner    default:
28056893Sfenner	(void)printf("type-0x%02x", type);
28156893Sfenner	break;
28256893Sfenner    }
28356893Sfenner
28456893Sfenner    TCHECK(bp[1]);
28556893Sfenner    numrps = bp[1];
28656893Sfenner
28756893Sfenner    TCHECK2(bp[2], 2);
28856893Sfenner    (void)printf(" Hold ");
28956893Sfenner    hold = EXTRACT_16BITS(&bp[2]);
29056893Sfenner    if (hold)
29156893Sfenner	relts_print(EXTRACT_16BITS(&bp[2]));
29256893Sfenner    else
29356893Sfenner	printf("FOREVER");
29456893Sfenner
29556893Sfenner    /* Next 4 bytes are reserved. */
29656893Sfenner
29756893Sfenner    bp += 8; len -= 8;
29856893Sfenner
29956893Sfenner    /*XXX skip unless -v? */
30056893Sfenner
30156893Sfenner    /*
30256893Sfenner     * Rest of packet:
30356893Sfenner     * numrps entries of the form:
30456893Sfenner     * 32 bits: RP
30556893Sfenner     * 6 bits: reserved
30656893Sfenner     * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
30756893Sfenner     * 8 bits: # of entries for this RP
30856893Sfenner     * each entry: 7 bits: reserved, 1 bit: negative,
30956893Sfenner     *			8 bits: mask 32 bits: source
31056893Sfenner     * lather, rinse, repeat.
31156893Sfenner     */
31256893Sfenner    while (numrps--) {
31356893Sfenner	int nentries;
31456893Sfenner	char s;
31556893Sfenner
31656893Sfenner	TCHECK2(bp[0], 4);
31756893Sfenner	(void)printf(" RP %s", ipaddr_string(bp));
31856893Sfenner	TCHECK(bp[4]);
31956893Sfenner	switch(bp[4] & 0x3) {
32056893Sfenner	case 0:	printf(" PIMv?");
32156893Sfenner		break;
32256893Sfenner	case 1:	printf(" PIMv1");
32356893Sfenner		break;
32456893Sfenner	case 2:	printf(" PIMv2");
32556893Sfenner		break;
32656893Sfenner	case 3:	printf(" PIMv1+2");
32756893Sfenner		break;
32856893Sfenner	}
32956893Sfenner	TCHECK(bp[5]);
33056893Sfenner	nentries = bp[5];
33156893Sfenner	bp += 6; len -= 6;
33256893Sfenner	s = ' ';
33356893Sfenner	for (; nentries; nentries--) {
33456893Sfenner	    TCHECK2(bp[0], 6);
33556893Sfenner	    (void)printf("%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
33656893Sfenner					ipaddr_string(&bp[2]), bp[1]);
33756893Sfenner	    s = ',';
33856893Sfenner	    bp += 6; len -= 6;
33956893Sfenner	}
34056893Sfenner    }
34156893Sfenner    return;
34256893Sfenner
34356893Sfennertrunc:
34456893Sfenner    (void)printf("[|autorp]");
34556893Sfenner    return;
34656893Sfenner}
34756893Sfenner
34856893Sfennervoid
34956893Sfennerpim_print(register const u_char *bp, register u_int len)
35056893Sfenner{
35156893Sfenner	register const u_char *ep;
35256893Sfenner	register struct pim *pim = (struct pim *)bp;
35356893Sfenner
35456893Sfenner	ep = (const u_char *)snapend;
35556893Sfenner	if (bp >= ep)
35656893Sfenner		return;
35756893Sfenner#ifdef notyet			/* currently we see only version and type */
35856893Sfenner	TCHECK(pim->pim_rsv);
35956893Sfenner#endif
36056893Sfenner
36156893Sfenner	switch(PIM_VER(pim->pim_typever)) {
36256893Sfenner	 case 2:		/* avoid hardcoding? */
36356893Sfenner		(void)printf("v2");
36456893Sfenner		pimv2_print(bp, len);
36556893Sfenner		break;
36656893Sfenner	 default:
36756893Sfenner		(void)printf("v%d", PIM_VER(pim->pim_typever));
36856893Sfenner		break;
36956893Sfenner	}
37056893Sfenner	return;
37156893Sfenner}
37256893Sfenner
37356893Sfenner/*
37456893Sfenner * PIMv2 uses encoded address representations.
37556893Sfenner *
37656893Sfenner * The last PIM-SM I-D before RFC2117 was published specified the
37756893Sfenner * following representation for unicast addresses.  However, RFC2117
37856893Sfenner * specified no encoding for unicast addresses with the unicast
37956893Sfenner * address length specified in the header.  Therefore, we have to
38056893Sfenner * guess which encoding is being used (Cisco's PIMv2 implementation
38156893Sfenner * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
38256893Sfenner * field into a 'unicast-address-length-in-bytes' field.  We guess
38356893Sfenner * that it's the draft encoding if this reserved field is zero.
38456893Sfenner *
38556893Sfenner * RFC2362 goes back to the encoded format, and calls the addr length
38656893Sfenner * field "reserved" again.
38756893Sfenner *
38856893Sfenner * The first byte is the address family, from:
38956893Sfenner *
39056893Sfenner *    0    Reserved
39156893Sfenner *    1    IP (IP version 4)
39256893Sfenner *    2    IP6 (IP version 6)
39356893Sfenner *    3    NSAP
39456893Sfenner *    4    HDLC (8-bit multidrop)
39556893Sfenner *    5    BBN 1822
39656893Sfenner *    6    802 (includes all 802 media plus Ethernet "canonical format")
39756893Sfenner *    7    E.163
39856893Sfenner *    8    E.164 (SMDS, Frame Relay, ATM)
39956893Sfenner *    9    F.69 (Telex)
40056893Sfenner *   10    X.121 (X.25, Frame Relay)
40156893Sfenner *   11    IPX
40256893Sfenner *   12    Appletalk
40356893Sfenner *   13    Decnet IV
40456893Sfenner *   14    Banyan Vines
40556893Sfenner *   15    E.164 with NSAP format subaddress
40656893Sfenner *
40756893Sfenner * In addition, the second byte is an "Encoding".  0 is the default
40856893Sfenner * encoding for the address family, and no other encodings are currently
40956893Sfenner * specified.
41056893Sfenner *
41156893Sfenner */
41256893Sfenner
41356893Sfennerstatic int pimv2_addr_len;
41456893Sfenner
41556893Sfennerenum pimv2_addrtype {
41656893Sfenner	pimv2_unicast, pimv2_group, pimv2_source
41756893Sfenner};
41856893Sfenner#if 0
41956893Sfennerstatic char *addrtypestr[] = {
42056893Sfenner	"unicast", "group", "source"
42156893Sfenner};
42256893Sfenner#endif
42356893Sfenner
42456893Sfenner/*  0                   1                   2                   3
42556893Sfenner *  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
42656893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
42756893Sfenner * | Addr Family   | Encoding Type |     Unicast Address           |
42856893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
42956893Sfenner *  0                   1                   2                   3
43056893Sfenner *  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
43156893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43256893Sfenner * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
43356893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43456893Sfenner * |                Group multicast Address                        |
43556893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43656893Sfenner *  0                   1                   2                   3
43756893Sfenner *  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
43856893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
43956893Sfenner * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
44056893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44156893Sfenner * |                        Source Address                         |
44256893Sfenner * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44356893Sfenner */
44456893Sfennerstatic int
44556893Sfennerpimv2_addr_print(const u_char *bp, enum pimv2_addrtype at, int silent)
44656893Sfenner{
44756893Sfenner	int af;
44856893Sfenner	char *afstr;
44956893Sfenner	int len, hdrlen;
45056893Sfenner
45156893Sfenner	TCHECK(bp[0]);
45256893Sfenner
45356893Sfenner	if (pimv2_addr_len == 0) {
45456893Sfenner		TCHECK(bp[1]);
45556893Sfenner		switch (bp[0]) {
45656893Sfenner		 case 1:
45756893Sfenner			af = AF_INET;
45856893Sfenner			afstr = "IPv4";
45956893Sfenner			len = 4;
46056893Sfenner			break;
46156893Sfenner#ifdef INET6
46256893Sfenner		 case 2:
46356893Sfenner			af = AF_INET6;
46456893Sfenner			afstr = "IPv6";
46556893Sfenner			len = 16;
46656893Sfenner			break;
46756893Sfenner#endif
46856893Sfenner		 default:
46956893Sfenner			return -1;
47056893Sfenner		}
47156893Sfenner		if (bp[1] != 0)
47256893Sfenner			return -1;
47356893Sfenner		hdrlen = 2;
47456893Sfenner	} else {
47556893Sfenner		switch (pimv2_addr_len) {
47656893Sfenner		 case 4:
47756893Sfenner			af = AF_INET;
47856893Sfenner			afstr = "IPv4";
47956893Sfenner			break;
48056893Sfenner#ifdef INET6
48156893Sfenner		 case 16:
48256893Sfenner			af = AF_INET6;
48356893Sfenner			afstr = "IPv6";
48456893Sfenner			break;
48556893Sfenner#endif
48656893Sfenner		 default:
48756893Sfenner			return -1;
48856893Sfenner			break;
48956893Sfenner		}
49056893Sfenner		len = pimv2_addr_len;
49156893Sfenner		hdrlen = 0;
49256893Sfenner	}
49356893Sfenner
49456893Sfenner	bp += hdrlen;
49556893Sfenner	switch (at) {
49656893Sfenner	 case pimv2_unicast:
49756893Sfenner		TCHECK2(bp[0], len);
49856893Sfenner		if (af == AF_INET) {
49956893Sfenner			if (!silent)
50056893Sfenner				(void)printf("%s", ipaddr_string(bp));
50156893Sfenner		}
50256893Sfenner#ifdef INET6
50356893Sfenner		else if (af == AF_INET6) {
50456893Sfenner			if (!silent)
50556893Sfenner				(void)printf("%s", ip6addr_string(bp));
50656893Sfenner		}
50756893Sfenner#endif
50856893Sfenner		return hdrlen + len;
50956893Sfenner	 case pimv2_group:
51056893Sfenner	 case pimv2_source:
51156893Sfenner		TCHECK2(bp[0], len + 2);
51256893Sfenner		if (af == AF_INET) {
51356893Sfenner			if (!silent) {
51456893Sfenner				(void)printf("%s", ipaddr_string(bp + 2));
51556893Sfenner				if (bp[1] != 32)
51656893Sfenner					(void)printf("/%u", bp[1]);
51756893Sfenner			}
51856893Sfenner		}
51956893Sfenner#ifdef INET6
52056893Sfenner		else if (af == AF_INET6) {
52156893Sfenner			if (!silent) {
52256893Sfenner				(void)printf("%s", ip6addr_string(bp + 2));
52356893Sfenner				if (bp[1] != 128)
52456893Sfenner					(void)printf("/%u", bp[1]);
52556893Sfenner			}
52656893Sfenner		}
52756893Sfenner#endif
52856893Sfenner		if (bp[0] && !silent) {
52956893Sfenner			if (at == pimv2_group) {
53056893Sfenner				(void)printf("(0x%02x)", bp[0]);
53156893Sfenner			} else {
53256893Sfenner				(void)printf("(%s%s%s",
53356893Sfenner					bp[0] & 0x04 ? "S" : "",
53456893Sfenner					bp[0] & 0x02 ? "W" : "",
53556893Sfenner					bp[0] & 0x01 ? "R" : "");
53656893Sfenner				if (bp[0] & 0xf8) {
53756893Sfenner					(void) printf("+0x%02x", bp[0] & 0xf8);
53856893Sfenner				}
53956893Sfenner				(void)printf(")");
54056893Sfenner			}
54156893Sfenner		}
54256893Sfenner		return hdrlen + 2 + len;
54356893Sfenner	default:
54456893Sfenner		return -1;
54556893Sfenner	}
54656893Sfennertrunc:
54756893Sfenner	return -1;
54856893Sfenner}
54956893Sfenner
55056893Sfennerstatic void
55156893Sfennerpimv2_print(register const u_char *bp, register u_int len)
55256893Sfenner{
55356893Sfenner	register const u_char *ep;
55456893Sfenner	register struct pim *pim = (struct pim *)bp;
55556893Sfenner	int advance;
55656893Sfenner
55756893Sfenner	ep = (const u_char *)snapend;
55856893Sfenner	if (bp >= ep)
55956893Sfenner		return;
56056893Sfenner	TCHECK(pim->pim_rsv);
56156893Sfenner	pimv2_addr_len = pim->pim_rsv;
56256893Sfenner	if (pimv2_addr_len != 0)
56356893Sfenner		(void)printf("[RFC2117-encoding] ");
56456893Sfenner
56556893Sfenner	switch (PIM_TYPE(pim->pim_typever)) {
56656893Sfenner	 case 0:
56756893Sfenner	    {
56856893Sfenner		u_int16_t otype, olen;
56956893Sfenner		(void)printf(" Hello");
57056893Sfenner		bp += 4;
57156893Sfenner		while (bp < ep) {
57256893Sfenner			TCHECK2(bp[0], 4);
57356893Sfenner			otype = EXTRACT_16BITS(&bp[0]);
57456893Sfenner			olen = EXTRACT_16BITS(&bp[2]);
57556893Sfenner			TCHECK2(bp[0], 4 + olen);
57656893Sfenner			switch (otype) {
57756893Sfenner			case 1:		/* Hold time */
57856893Sfenner				(void)printf(" (Hold-time ");
57956893Sfenner				relts_print(EXTRACT_16BITS(&bp[4]));
58056893Sfenner				(void)printf(")");
58156893Sfenner				break;
58256893Sfenner
58356893Sfenner			/* XXX
58456893Sfenner			 * draft-ietf-idmr-pimv2-dr-priority-00.txt
58556893Sfenner			 * says that DR-Priority is option 19.
58656893Sfenner			 * draft-ietf-pim-v2-sm-00.txt says it's 18.
58756893Sfenner			 */
58856893Sfenner			case 18:	/* DR-Priority */
58956893Sfenner				(void)printf(" (DR-Priority: %d)", EXTRACT_32BITS(&bp[4]));
59056893Sfenner				break;
59156893Sfenner
59256893Sfenner			case 19:	/* Bidir-Capable */
59356893Sfenner				if (olen == 4)
59456893Sfenner					(void)printf(" (OLD-DR-Priority: %d)", EXTRACT_32BITS(&bp[4]));
59556893Sfenner				else
59656893Sfenner					(void)printf(" (bidir-capable)");
59756893Sfenner				break;
59856893Sfenner
59956893Sfenner			case 20:
60056893Sfenner				(void)printf(" (Genid: 0x%08x)", EXTRACT_32BITS(&bp[4]));
60156893Sfenner				break;
60256893Sfenner
60356893Sfenner			case 21:
60456893Sfenner				(void)printf(" (State Refresh Capable");
60556893Sfenner				if (EXTRACT_32BITS(&bp[4]) != 1) {
60656893Sfenner					(void)printf(" ?0x%x?", EXTRACT_32BITS(&bp[4]));
60756893Sfenner				}
60856893Sfenner				(void)printf(")");
60956893Sfenner				break;
61056893Sfenner
61156893Sfenner			default:
61256893Sfenner				if (vflag)
61356893Sfenner					(void)printf(" [Hello option %d]", otype);
61456893Sfenner			}
61556893Sfenner			bp += 4 + olen;
61656893Sfenner		}
61756893Sfenner		break;
61856893Sfenner	    }
61956893Sfenner
62056893Sfenner	 case 1:
62156893Sfenner	 {
62256893Sfenner		struct ip *ip;
62356893Sfenner
62456893Sfenner		(void)printf(" Register");
62556893Sfenner		if (vflag && bp + 8 <= ep) {
62656893Sfenner			(void)printf(" %s%s", bp[4] & 0x80 ? "B" : "",
62756893Sfenner				bp[4] & 0x40 ? "N" : "");
62856893Sfenner		}
62956893Sfenner		bp += 8; len -= 8;
63056893Sfenner
63156893Sfenner		/* encapsulated multicast packet */
63256893Sfenner		if (bp >= ep)
63356893Sfenner			break;
63456893Sfenner		ip = (struct ip *)bp;
63556893Sfenner		switch(ip->ip_v) {
63656893Sfenner		 case 4:	/* IPv4 */
63756893Sfenner			printf(" ");
63856893Sfenner			ip_print(bp, len);
63956893Sfenner			break;
64056893Sfenner#ifdef INET6
64156893Sfenner		 case 6:	/* IPv6 */
64256893Sfenner			printf(" ");
64356893Sfenner			ip6_print(bp, len);
64456893Sfenner			break;
64556893Sfenner#endif
64656893Sfenner		 default:
64756893Sfenner			(void)printf(" IP ver %d", ip->ip_v);
64856893Sfenner			break;
64956893Sfenner		}
65056893Sfenner		break;
65156893Sfenner	 }
65256893Sfenner
65356893Sfenner	 case 2:
65456893Sfenner		(void)printf(" Register-Stop");
65556893Sfenner		bp += 4; len -= 4;
65656893Sfenner		if (bp >= ep)
65756893Sfenner			break;
65856893Sfenner		(void)printf(" group=");
65956893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
66056893Sfenner			(void)printf("...");
66156893Sfenner			break;
66256893Sfenner		}
66356893Sfenner		bp += advance; len -= advance;
66456893Sfenner		if (bp >= ep)
66556893Sfenner			break;
66656893Sfenner		(void)printf(" source=");
66756893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
66856893Sfenner			(void)printf("...");
66956893Sfenner			break;
67056893Sfenner		}
67156893Sfenner		bp += advance; len -= advance;
67256893Sfenner		break;
67356893Sfenner
67456893Sfenner	 case 3:
67556893Sfenner	 case 6:
67656893Sfenner	 case 7:
67756893Sfenner	    {
67856893Sfenner		u_int8_t ngroup;
67956893Sfenner		u_int16_t holdtime;
68056893Sfenner		u_int16_t njoin;
68156893Sfenner		u_int16_t nprune;
68256893Sfenner		int i, j;
68356893Sfenner
68456893Sfenner		switch (PIM_TYPE(pim->pim_typever)) {
68556893Sfenner		 case 3:
68656893Sfenner			(void)printf(" Join/Prune");
68756893Sfenner			break;
68856893Sfenner		 case 6:
68956893Sfenner			(void)printf(" Graft");
69056893Sfenner			break;
69156893Sfenner		 case 7:
69256893Sfenner			(void)printf(" Graft-ACK");
69356893Sfenner			break;
69456893Sfenner		}
69556893Sfenner		bp += 4; len -= 4;
69656893Sfenner		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
69756893Sfenner			if (bp >= ep)
69856893Sfenner				break;
69956893Sfenner			(void)printf(" upstream-neighbor=");
70056893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
70156893Sfenner				(void)printf("...");
70256893Sfenner				break;
70356893Sfenner			}
70456893Sfenner			bp += advance; len -= advance;
70556893Sfenner		}
70656893Sfenner		if (bp + 4 > ep)
70756893Sfenner			break;
70856893Sfenner		ngroup = bp[1];
70956893Sfenner		holdtime = EXTRACT_16BITS(&bp[2]);
71056893Sfenner		(void)printf(" groups=%u", ngroup);
71156893Sfenner		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
71256893Sfenner			(void)printf(" holdtime=");
71356893Sfenner			if (holdtime == 0xffff)
71456893Sfenner				(void)printf("infty");
71556893Sfenner			else
71656893Sfenner				relts_print(holdtime);
71756893Sfenner		}
71856893Sfenner		bp += 4; len -= 4;
71956893Sfenner		for (i = 0; i < ngroup; i++) {
72056893Sfenner			if (bp >= ep)
72156893Sfenner				goto jp_done;
72256893Sfenner			(void)printf(" (group%d: ", i);
72356893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
72456893Sfenner				(void)printf("...)");
72556893Sfenner				goto jp_done;
72656893Sfenner			}
72756893Sfenner			bp += advance; len -= advance;
72856893Sfenner			if (bp + 4 > ep) {
72956893Sfenner				(void)printf("...)");
73056893Sfenner				goto jp_done;
73156893Sfenner			}
73256893Sfenner			njoin = EXTRACT_16BITS(&bp[0]);
73356893Sfenner			nprune = EXTRACT_16BITS(&bp[2]);
73456893Sfenner			(void)printf(" join=%u", njoin);
73556893Sfenner			bp += 4; len -= 4;
73656893Sfenner			for (j = 0; j < njoin; j++) {
73756893Sfenner				(void)printf(" ");
73856893Sfenner				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
73956893Sfenner					(void)printf("...)");
74056893Sfenner					goto jp_done;
74156893Sfenner				}
74256893Sfenner				bp += advance; len -= advance;
74356893Sfenner			}
74456893Sfenner			(void)printf(" prune=%u", nprune);
74556893Sfenner			for (j = 0; j < nprune; j++) {
74656893Sfenner				(void)printf(" ");
74756893Sfenner				if ((advance = pimv2_addr_print(bp, pimv2_source, 0)) < 0) {
74856893Sfenner					(void)printf("...)");
74956893Sfenner					goto jp_done;
75056893Sfenner				}
75156893Sfenner				bp += advance; len -= advance;
75256893Sfenner			}
75356893Sfenner			(void)printf(")");
75456893Sfenner		}
75556893Sfenner	jp_done:
75656893Sfenner		break;
75756893Sfenner	    }
75856893Sfenner
75956893Sfenner	 case 4:
76056893Sfenner	 {
76156893Sfenner		int i, j, frpcnt;
76256893Sfenner
76356893Sfenner		(void)printf(" Bootstrap");
76456893Sfenner		bp += 4;
76556893Sfenner
76656893Sfenner		/* Fragment Tag, Hash Mask len, and BSR-priority */
76756893Sfenner		if (bp + sizeof(u_int16_t) >= ep) break;
76856893Sfenner		(void)printf(" tag=%x", EXTRACT_16BITS(bp));
76956893Sfenner		bp += sizeof(u_int16_t);
77056893Sfenner		if (bp >= ep) break;
77156893Sfenner		(void)printf(" hashmlen=%d", bp[0]);
77256893Sfenner		if (bp + 1 >= ep) break;
77356893Sfenner		(void)printf(" BSRprio=%d", bp[1]);
77456893Sfenner		bp += 2;
77556893Sfenner
77656893Sfenner		/* Encoded-Unicast-BSR-Address */
77756893Sfenner		if (bp >= ep) break;
77856893Sfenner		(void)printf(" BSR=");
77956893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
78056893Sfenner			(void)printf("...");
78156893Sfenner			break;
78256893Sfenner		}
78356893Sfenner		bp += advance;
78456893Sfenner
78556893Sfenner		for (i = 0; bp < ep; i++) {
78656893Sfenner			/* Encoded-Group Address */
78756893Sfenner			(void)printf(" (group%d: ", i);
78856893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
78956893Sfenner			    < 0) {
79056893Sfenner				(void)printf("...)");
79156893Sfenner				goto bs_done;
79256893Sfenner			}
79356893Sfenner			bp += advance;
79456893Sfenner
79556893Sfenner			/* RP-Count, Frag RP-Cnt, and rsvd */
79656893Sfenner			if (bp >= ep) {
79756893Sfenner				(void)printf("...)");
79856893Sfenner				goto bs_done;
79956893Sfenner			}
80056893Sfenner			(void)printf(" RPcnt=%d", frpcnt = bp[0]);
80156893Sfenner			if (bp + 1 >= ep) {
80256893Sfenner				(void)printf("...)");
80356893Sfenner				goto bs_done;
80456893Sfenner			}
80556893Sfenner			(void)printf(" FRPcnt=%d", bp[1]);
80656893Sfenner			bp += 4;
80756893Sfenner
80856893Sfenner			for (j = 0; j < frpcnt && bp < ep; j++) {
80956893Sfenner				/* each RP info */
81056893Sfenner				(void)printf(" RP%d=", j);
81156893Sfenner				if ((advance = pimv2_addr_print(bp,
81256893Sfenner								pimv2_unicast,
81356893Sfenner								0)) < 0) {
81456893Sfenner					(void)printf("...)");
81556893Sfenner					goto bs_done;
81656893Sfenner				}
81756893Sfenner				bp += advance;
81856893Sfenner
81956893Sfenner				if (bp + 1 >= ep) {
82056893Sfenner					(void)printf("...)");
82156893Sfenner					goto bs_done;
82256893Sfenner				}
82356893Sfenner				(void)printf(",holdtime=");
82456893Sfenner				relts_print(EXTRACT_16BITS(bp));
82556893Sfenner				if (bp + 2 >= ep) {
82656893Sfenner					(void)printf("...)");
82756893Sfenner					goto bs_done;
82856893Sfenner				}
82956893Sfenner				(void)printf(",prio=%d", bp[2]);
83056893Sfenner				bp += 4;
83156893Sfenner			}
83256893Sfenner			(void)printf(")");
83356893Sfenner		}
83456893Sfenner	   bs_done:
83556893Sfenner		break;
83656893Sfenner	 }
83756893Sfenner	 case 5:
83856893Sfenner		(void)printf(" Assert");
83956893Sfenner		bp += 4; len -= 4;
84056893Sfenner		if (bp >= ep)
84156893Sfenner			break;
84256893Sfenner		(void)printf(" group=");
84356893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
84456893Sfenner			(void)printf("...");
84556893Sfenner			break;
84656893Sfenner		}
84756893Sfenner		bp += advance; len -= advance;
84856893Sfenner		if (bp >= ep)
84956893Sfenner			break;
85056893Sfenner		(void)printf(" src=");
85156893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
85256893Sfenner			(void)printf("...");
85356893Sfenner			break;
85456893Sfenner		}
85556893Sfenner		bp += advance; len -= advance;
85656893Sfenner		if (bp + 8 > ep)
85756893Sfenner			break;
85856893Sfenner		if (bp[0] & 0x80)
85956893Sfenner			(void)printf(" RPT");
86056893Sfenner		(void)printf(" pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff);
86156893Sfenner		(void)printf(" metric=%u", EXTRACT_32BITS(&bp[4]));
86256893Sfenner		break;
86356893Sfenner
86456893Sfenner	 case 8:
86556893Sfenner	 {
86656893Sfenner		int i, pfxcnt;
86756893Sfenner
86856893Sfenner		(void)printf(" Candidate-RP-Advertisement");
86956893Sfenner		bp += 4;
87056893Sfenner
87156893Sfenner		/* Prefix-Cnt, Priority, and Holdtime */
87256893Sfenner		if (bp >= ep) break;
87356893Sfenner		(void)printf(" prefix-cnt=%d", bp[0]);
87456893Sfenner		pfxcnt = bp[0];
87556893Sfenner		if (bp + 1 >= ep) break;
87656893Sfenner		(void)printf(" prio=%d", bp[1]);
87756893Sfenner		if (bp + 3 >= ep) break;
87856893Sfenner		(void)printf(" holdtime=");
87956893Sfenner		relts_print(EXTRACT_16BITS(&bp[2]));
88056893Sfenner		bp += 4;
88156893Sfenner
88256893Sfenner		/* Encoded-Unicast-RP-Address */
88356893Sfenner		if (bp >= ep) break;
88456893Sfenner		(void)printf(" RP=");
88556893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
88656893Sfenner			(void)printf("...");
88756893Sfenner			break;
88856893Sfenner		}
88956893Sfenner		bp += advance;
89056893Sfenner
89156893Sfenner		/* Encoded-Group Addresses */
89256893Sfenner		for (i = 0; i < pfxcnt && bp < ep; i++) {
89356893Sfenner			(void)printf(" Group%d=", i);
89456893Sfenner			if ((advance = pimv2_addr_print(bp, pimv2_group, 0))
89556893Sfenner			    < 0) {
89656893Sfenner				(void)printf("...");
89756893Sfenner				break;
89856893Sfenner			}
89956893Sfenner			bp += advance;
90056893Sfenner		}
90156893Sfenner		break;
90256893Sfenner	 }
90356893Sfenner
90456893Sfenner	 case 9:
90556893Sfenner		(void)printf(" Prune-Refresh");
90656893Sfenner		(void)printf(" src=");
90756893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
90856893Sfenner			(void)printf("...");
90956893Sfenner			break;
91056893Sfenner		}
91156893Sfenner		bp += advance;
91256893Sfenner		(void)printf(" grp=");
91356893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_group, 0)) < 0) {
91456893Sfenner			(void)printf("...");
91556893Sfenner			break;
91656893Sfenner		}
91756893Sfenner		bp += advance;
91856893Sfenner		(void)printf(" forwarder=");
91956893Sfenner		if ((advance = pimv2_addr_print(bp, pimv2_unicast, 0)) < 0) {
92056893Sfenner			(void)printf("...");
92156893Sfenner			break;
92256893Sfenner		}
92356893Sfenner		bp += advance;
92456893Sfenner		TCHECK2(bp[0], 2);
92556893Sfenner		(void)printf(" TUNR ");
92656893Sfenner		relts_print(EXTRACT_16BITS(bp));
92756893Sfenner		break;
92856893Sfenner
92956893Sfenner
93056893Sfenner	 default:
93156893Sfenner		(void)printf(" [type %d]", PIM_TYPE(pim->pim_typever));
93256893Sfenner		break;
93356893Sfenner	}
93456893Sfenner
93556893Sfenner	return;
93656893Sfenner
93756893Sfennertrunc:
93856893Sfenner	(void)printf("[|pim]");
93956893Sfenner}
940