Home | History | Annotate | Download | only in tcpdump
      1 /*
      2  * Copyright (c) 1995, 1996
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that: (1) source code distributions
      7  * retain the above copyright notice and this paragraph in its entirety, (2)
      8  * distributions including binary code include the above copyright notice and
      9  * this paragraph in its entirety in the documentation or other materials
     10  * provided with the distribution, and (3) all advertising materials mentioning
     11  * features or use of this software display the following acknowledgement:
     12  * ``This product includes software developed by the University of California,
     13  * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
     14  * the University nor the names of its contributors may be used to endorse
     15  * or promote products derived from this software without specific prior
     16  * written permission.
     17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
     18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
     19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     20  */
     21 
     22 /* \summary: Protocol Independent Multicast (PIM) printer */
     23 
     24 #ifdef HAVE_CONFIG_H
     25 #include "config.h"
     26 #endif
     27 
     28 #include <netdissect-stdinc.h>
     29 
     30 #include "netdissect.h"
     31 #include "addrtoname.h"
     32 #include "extract.h"
     33 
     34 #include "ip.h"
     35 #include "ip6.h"
     36 #include "ipproto.h"
     37 
     38 #define PIMV1_TYPE_QUERY           0
     39 #define PIMV1_TYPE_REGISTER        1
     40 #define PIMV1_TYPE_REGISTER_STOP   2
     41 #define PIMV1_TYPE_JOIN_PRUNE      3
     42 #define PIMV1_TYPE_RP_REACHABILITY 4
     43 #define PIMV1_TYPE_ASSERT          5
     44 #define PIMV1_TYPE_GRAFT           6
     45 #define PIMV1_TYPE_GRAFT_ACK       7
     46 
     47 static const struct tok pimv1_type_str[] = {
     48 	{ PIMV1_TYPE_QUERY,           "Query"         },
     49 	{ PIMV1_TYPE_REGISTER,        "Register"      },
     50 	{ PIMV1_TYPE_REGISTER_STOP,   "Register-Stop" },
     51 	{ PIMV1_TYPE_JOIN_PRUNE,      "Join/Prune"    },
     52 	{ PIMV1_TYPE_RP_REACHABILITY, "RP-reachable"  },
     53 	{ PIMV1_TYPE_ASSERT,          "Assert"        },
     54 	{ PIMV1_TYPE_GRAFT,           "Graft"         },
     55 	{ PIMV1_TYPE_GRAFT_ACK,       "Graft-ACK"     },
     56 	{ 0, NULL }
     57 };
     58 
     59 #define PIMV2_TYPE_HELLO         0
     60 #define PIMV2_TYPE_REGISTER      1
     61 #define PIMV2_TYPE_REGISTER_STOP 2
     62 #define PIMV2_TYPE_JOIN_PRUNE    3
     63 #define PIMV2_TYPE_BOOTSTRAP     4
     64 #define PIMV2_TYPE_ASSERT        5
     65 #define PIMV2_TYPE_GRAFT         6
     66 #define PIMV2_TYPE_GRAFT_ACK     7
     67 #define PIMV2_TYPE_CANDIDATE_RP  8
     68 #define PIMV2_TYPE_PRUNE_REFRESH 9
     69 #define PIMV2_TYPE_DF_ELECTION   10
     70 #define PIMV2_TYPE_ECMP_REDIRECT 11
     71 
     72 static const struct tok pimv2_type_values[] = {
     73     { PIMV2_TYPE_HELLO,         "Hello" },
     74     { PIMV2_TYPE_REGISTER,      "Register" },
     75     { PIMV2_TYPE_REGISTER_STOP, "Register Stop" },
     76     { PIMV2_TYPE_JOIN_PRUNE,    "Join / Prune" },
     77     { PIMV2_TYPE_BOOTSTRAP,     "Bootstrap" },
     78     { PIMV2_TYPE_ASSERT,        "Assert" },
     79     { PIMV2_TYPE_GRAFT,         "Graft" },
     80     { PIMV2_TYPE_GRAFT_ACK,     "Graft Acknowledgement" },
     81     { PIMV2_TYPE_CANDIDATE_RP,  "Candidate RP Advertisement" },
     82     { PIMV2_TYPE_PRUNE_REFRESH, "Prune Refresh" },
     83     { PIMV2_TYPE_DF_ELECTION,   "DF Election" },
     84     { PIMV2_TYPE_ECMP_REDIRECT, "ECMP Redirect" },
     85     { 0, NULL}
     86 };
     87 
     88 #define PIMV2_HELLO_OPTION_HOLDTIME             1
     89 #define PIMV2_HELLO_OPTION_LANPRUNEDELAY        2
     90 #define PIMV2_HELLO_OPTION_DR_PRIORITY_OLD     18
     91 #define PIMV2_HELLO_OPTION_DR_PRIORITY         19
     92 #define PIMV2_HELLO_OPTION_GENID               20
     93 #define PIMV2_HELLO_OPTION_REFRESH_CAP         21
     94 #define PIMV2_HELLO_OPTION_BIDIR_CAP           22
     95 #define PIMV2_HELLO_OPTION_ADDRESS_LIST        24
     96 #define PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD 65001
     97 
     98 static const struct tok pimv2_hello_option_values[] = {
     99     { PIMV2_HELLO_OPTION_HOLDTIME,         "Hold Time" },
    100     { PIMV2_HELLO_OPTION_LANPRUNEDELAY,    "LAN Prune Delay" },
    101     { PIMV2_HELLO_OPTION_DR_PRIORITY_OLD,  "DR Priority (Old)" },
    102     { PIMV2_HELLO_OPTION_DR_PRIORITY,      "DR Priority" },
    103     { PIMV2_HELLO_OPTION_GENID,            "Generation ID" },
    104     { PIMV2_HELLO_OPTION_REFRESH_CAP,      "State Refresh Capability" },
    105     { PIMV2_HELLO_OPTION_BIDIR_CAP,        "Bi-Directional Capability" },
    106     { PIMV2_HELLO_OPTION_ADDRESS_LIST,     "Address List" },
    107     { PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD, "Address List (Old)" },
    108     { 0, NULL}
    109 };
    110 
    111 #define PIMV2_REGISTER_FLAG_LEN      4
    112 #define PIMV2_REGISTER_FLAG_BORDER 0x80000000
    113 #define PIMV2_REGISTER_FLAG_NULL   0x40000000
    114 
    115 static const struct tok pimv2_register_flag_values[] = {
    116     { PIMV2_REGISTER_FLAG_BORDER, "Border" },
    117     { PIMV2_REGISTER_FLAG_NULL, "Null" },
    118     { 0, NULL}
    119 };
    120 
    121 /*
    122  * XXX: We consider a case where IPv6 is not ready yet for portability,
    123  * but PIM dependent defintions should be independent of IPv6...
    124  */
    125 
    126 struct pim {
    127 	uint8_t pim_typever;
    128 			/* upper 4bit: PIM version number; 2 for PIMv2 */
    129 			/* lower 4bit: the PIM message type, currently they are:
    130 			 * Hello, Register, Register-Stop, Join/Prune,
    131 			 * Bootstrap, Assert, Graft (PIM-DM only),
    132 			 * Graft-Ack (PIM-DM only), C-RP-Adv
    133 			 */
    134 #define PIM_VER(x)	(((x) & 0xf0) >> 4)
    135 #define PIM_TYPE(x)	((x) & 0x0f)
    136 	u_char  pim_rsv;	/* Reserved */
    137 	u_short	pim_cksum;	/* IP style check sum */
    138 };
    139 
    140 static void pimv2_print(netdissect_options *, register const u_char *bp, register u_int len, const u_char *);
    141 
    142 static void
    143 pimv1_join_prune_print(netdissect_options *ndo,
    144                        register const u_char *bp, register u_int len)
    145 {
    146 	int ngroups, njoin, nprune;
    147 	int njp;
    148 
    149 	/* If it's a single group and a single source, use 1-line output. */
    150 	if (ND_TTEST2(bp[0], 30) && bp[11] == 1 &&
    151 	    ((njoin = EXTRACT_16BITS(&bp[20])) + EXTRACT_16BITS(&bp[22])) == 1) {
    152 		int hold;
    153 
    154 		ND_PRINT((ndo, " RPF %s ", ipaddr_string(ndo, bp)));
    155 		hold = EXTRACT_16BITS(&bp[6]);
    156 		if (hold != 180) {
    157 			ND_PRINT((ndo, "Hold "));
    158 			unsigned_relts_print(ndo, hold);
    159 		}
    160 		ND_PRINT((ndo, "%s (%s/%d, %s", njoin ? "Join" : "Prune",
    161 		ipaddr_string(ndo, &bp[26]), bp[25] & 0x3f,
    162 		ipaddr_string(ndo, &bp[12])));
    163 		if (EXTRACT_32BITS(&bp[16]) != 0xffffffff)
    164 			ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[16])));
    165 		ND_PRINT((ndo, ") %s%s %s",
    166 		    (bp[24] & 0x01) ? "Sparse" : "Dense",
    167 		    (bp[25] & 0x80) ? " WC" : "",
    168 		    (bp[25] & 0x40) ? "RP" : "SPT"));
    169 		return;
    170 	}
    171 
    172 	if (len < sizeof(struct in_addr))
    173 		goto trunc;
    174 	ND_TCHECK2(bp[0], sizeof(struct in_addr));
    175 	if (ndo->ndo_vflag > 1)
    176 		ND_PRINT((ndo, "\n"));
    177 	ND_PRINT((ndo, " Upstream Nbr: %s", ipaddr_string(ndo, bp)));
    178 	bp += 4;
    179 	len -= 4;
    180 	if (len < 4)
    181 		goto trunc;
    182 	ND_TCHECK2(bp[2], 2);
    183 	if (ndo->ndo_vflag > 1)
    184 		ND_PRINT((ndo, "\n"));
    185 	ND_PRINT((ndo, " Hold time: "));
    186 	unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[2]));
    187 	if (ndo->ndo_vflag < 2)
    188 		return;
    189 	bp += 4;
    190 	len -= 4;
    191 
    192 	if (len < 4)
    193 		goto trunc;
    194 	ND_TCHECK2(bp[0], 4);
    195 	ngroups = bp[3];
    196 	bp += 4;
    197 	len -= 4;
    198 	while (ngroups--) {
    199 		/*
    200 		 * XXX - does the address have length "addrlen" and the
    201 		 * mask length "maddrlen"?
    202 		 */
    203 		if (len < 4)
    204 			goto trunc;
    205 		ND_TCHECK2(bp[0], sizeof(struct in_addr));
    206 		ND_PRINT((ndo, "\n\tGroup: %s", ipaddr_string(ndo, bp)));
    207 		bp += 4;
    208 		len -= 4;
    209 		if (len < 4)
    210 			goto trunc;
    211 		ND_TCHECK2(bp[0], sizeof(struct in_addr));
    212 		if (EXTRACT_32BITS(&bp[0]) != 0xffffffff)
    213 			ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[0])));
    214 		bp += 4;
    215 		len -= 4;
    216 		if (len < 4)
    217 			goto trunc;
    218 		ND_TCHECK2(bp[0], 4);
    219 		njoin = EXTRACT_16BITS(&bp[0]);
    220 		nprune = EXTRACT_16BITS(&bp[2]);
    221 		ND_PRINT((ndo, " joined: %d pruned: %d", njoin, nprune));
    222 		bp += 4;
    223 		len -= 4;
    224 		for (njp = 0; njp < (njoin + nprune); njp++) {
    225 			const char *type;
    226 
    227 			if (njp < njoin)
    228 				type = "Join ";
    229 			else
    230 				type = "Prune";
    231 			if (len < 6)
    232 				goto trunc;
    233 			ND_TCHECK2(bp[0], 6);
    234 			ND_PRINT((ndo, "\n\t%s %s%s%s%s/%d", type,
    235 			    (bp[0] & 0x01) ? "Sparse " : "Dense ",
    236 			    (bp[1] & 0x80) ? "WC " : "",
    237 			    (bp[1] & 0x40) ? "RP " : "SPT ",
    238 			    ipaddr_string(ndo, &bp[2]),
    239 			    bp[1] & 0x3f));
    240 			bp += 6;
    241 			len -= 6;
    242 		}
    243 	}
    244 	return;
    245 trunc:
    246 	ND_PRINT((ndo, "[|pim]"));
    247 	return;
    248 }
    249 
    250 void
    251 pimv1_print(netdissect_options *ndo,
    252             register const u_char *bp, register u_int len)
    253 {
    254 	register u_char type;
    255 
    256 	ND_TCHECK(bp[1]);
    257 	type = bp[1];
    258 
    259 	ND_PRINT((ndo, " %s", tok2str(pimv1_type_str, "[type %u]", type)));
    260 	switch (type) {
    261 	case PIMV1_TYPE_QUERY:
    262 		if (ND_TTEST(bp[8])) {
    263 			switch (bp[8] >> 4) {
    264 			case 0:
    265 				ND_PRINT((ndo, " Dense-mode"));
    266 				break;
    267 			case 1:
    268 				ND_PRINT((ndo, " Sparse-mode"));
    269 				break;
    270 			case 2:
    271 				ND_PRINT((ndo, " Sparse-Dense-mode"));
    272 				break;
    273 			default:
    274 				ND_PRINT((ndo, " mode-%d", bp[8] >> 4));
    275 				break;
    276 			}
    277 		}
    278 		if (ndo->ndo_vflag) {
    279 			ND_TCHECK2(bp[10],2);
    280 			ND_PRINT((ndo, " (Hold-time "));
    281 			unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[10]));
    282 			ND_PRINT((ndo, ")"));
    283 		}
    284 		break;
    285 
    286 	case PIMV1_TYPE_REGISTER:
    287 		ND_TCHECK2(bp[8], 20);			/* ip header */
    288 		ND_PRINT((ndo, " for %s > %s", ipaddr_string(ndo, &bp[20]),
    289 		    ipaddr_string(ndo, &bp[24])));
    290 		break;
    291 	case PIMV1_TYPE_REGISTER_STOP:
    292 		ND_TCHECK2(bp[12], sizeof(struct in_addr));
    293 		ND_PRINT((ndo, " for %s > %s", ipaddr_string(ndo, &bp[8]),
    294 		    ipaddr_string(ndo, &bp[12])));
    295 		break;
    296 	case PIMV1_TYPE_RP_REACHABILITY:
    297 		if (ndo->ndo_vflag) {
    298 			ND_TCHECK2(bp[22], 2);
    299 			ND_PRINT((ndo, " group %s", ipaddr_string(ndo, &bp[8])));
    300 			if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
    301 				ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[12])));
    302 			ND_PRINT((ndo, " RP %s hold ", ipaddr_string(ndo, &bp[16])));
    303 			unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[22]));
    304 		}
    305 		break;
    306 	case PIMV1_TYPE_ASSERT:
    307 		ND_TCHECK2(bp[16], sizeof(struct in_addr));
    308 		ND_PRINT((ndo, " for %s > %s", ipaddr_string(ndo, &bp[16]),
    309 		    ipaddr_string(ndo, &bp[8])));
    310 		if (EXTRACT_32BITS(&bp[12]) != 0xffffffff)
    311 			ND_PRINT((ndo, "/%s", ipaddr_string(ndo, &bp[12])));
    312 		ND_TCHECK2(bp[24], 4);
    313 		ND_PRINT((ndo, " %s pref %d metric %d",
    314 		    (bp[20] & 0x80) ? "RP-tree" : "SPT",
    315 		EXTRACT_32BITS(&bp[20]) & 0x7fffffff,
    316 		EXTRACT_32BITS(&bp[24])));
    317 		break;
    318 	case PIMV1_TYPE_JOIN_PRUNE:
    319 	case PIMV1_TYPE_GRAFT:
    320 	case PIMV1_TYPE_GRAFT_ACK:
    321 		if (ndo->ndo_vflag) {
    322 			if (len < 8)
    323 				goto trunc;
    324 			pimv1_join_prune_print(ndo, &bp[8], len - 8);
    325 		}
    326 		break;
    327 	}
    328 	ND_TCHECK(bp[4]);
    329 	if ((bp[4] >> 4) != 1)
    330 		ND_PRINT((ndo, " [v%d]", bp[4] >> 4));
    331 	return;
    332 
    333 trunc:
    334 	ND_PRINT((ndo, "[|pim]"));
    335 	return;
    336 }
    337 
    338 /*
    339  * auto-RP is a cisco protocol, documented at
    340  * ftp://ftpeng.cisco.com/ipmulticast/specs/pim-autorp-spec01.txt
    341  *
    342  * This implements version 1+, dated Sept 9, 1998.
    343  */
    344 void
    345 cisco_autorp_print(netdissect_options *ndo,
    346                    register const u_char *bp, register u_int len)
    347 {
    348 	int type;
    349 	int numrps;
    350 	int hold;
    351 
    352 	if (len < 8)
    353 		goto trunc;
    354 	ND_TCHECK(bp[0]);
    355 	ND_PRINT((ndo, " auto-rp "));
    356 	type = bp[0];
    357 	switch (type) {
    358 	case 0x11:
    359 		ND_PRINT((ndo, "candidate-advert"));
    360 		break;
    361 	case 0x12:
    362 		ND_PRINT((ndo, "mapping"));
    363 		break;
    364 	default:
    365 		ND_PRINT((ndo, "type-0x%02x", type));
    366 		break;
    367 	}
    368 
    369 	ND_TCHECK(bp[1]);
    370 	numrps = bp[1];
    371 
    372 	ND_TCHECK2(bp[2], 2);
    373 	ND_PRINT((ndo, " Hold "));
    374 	hold = EXTRACT_16BITS(&bp[2]);
    375 	if (hold)
    376 		unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[2]));
    377 	else
    378 		ND_PRINT((ndo, "FOREVER"));
    379 
    380 	/* Next 4 bytes are reserved. */
    381 
    382 	bp += 8; len -= 8;
    383 
    384 	/*XXX skip unless -v? */
    385 
    386 	/*
    387 	 * Rest of packet:
    388 	 * numrps entries of the form:
    389 	 * 32 bits: RP
    390 	 * 6 bits: reserved
    391 	 * 2 bits: PIM version supported, bit 0 is "supports v1", 1 is "v2".
    392 	 * 8 bits: # of entries for this RP
    393 	 * each entry: 7 bits: reserved, 1 bit: negative,
    394 	 *	       8 bits: mask 32 bits: source
    395 	 * lather, rinse, repeat.
    396 	 */
    397 	while (numrps--) {
    398 		int nentries;
    399 		char s;
    400 
    401 		if (len < 4)
    402 			goto trunc;
    403 		ND_TCHECK2(bp[0], 4);
    404 		ND_PRINT((ndo, " RP %s", ipaddr_string(ndo, bp)));
    405 		bp += 4;
    406 		len -= 4;
    407 		if (len < 1)
    408 			goto trunc;
    409 		ND_TCHECK(bp[0]);
    410 		switch (bp[0] & 0x3) {
    411 		case 0: ND_PRINT((ndo, " PIMv?"));
    412 			break;
    413 		case 1:	ND_PRINT((ndo, " PIMv1"));
    414 			break;
    415 		case 2:	ND_PRINT((ndo, " PIMv2"));
    416 			break;
    417 		case 3:	ND_PRINT((ndo, " PIMv1+2"));
    418 			break;
    419 		}
    420 		if (bp[0] & 0xfc)
    421 			ND_PRINT((ndo, " [rsvd=0x%02x]", bp[0] & 0xfc));
    422 		bp += 1;
    423 		len -= 1;
    424 		if (len < 1)
    425 			goto trunc;
    426 		ND_TCHECK(bp[0]);
    427 		nentries = bp[0];
    428 		bp += 1;
    429 		len -= 1;
    430 		s = ' ';
    431 		for (; nentries; nentries--) {
    432 			if (len < 6)
    433 				goto trunc;
    434 			ND_TCHECK2(bp[0], 6);
    435 			ND_PRINT((ndo, "%c%s%s/%d", s, bp[0] & 1 ? "!" : "",
    436 			          ipaddr_string(ndo, &bp[2]), bp[1]));
    437 			if (bp[0] & 0x02) {
    438 				ND_PRINT((ndo, " bidir"));
    439 			}
    440 			if (bp[0] & 0xfc) {
    441 				ND_PRINT((ndo, "[rsvd=0x%02x]", bp[0] & 0xfc));
    442 			}
    443 			s = ',';
    444 			bp += 6; len -= 6;
    445 		}
    446 	}
    447 	return;
    448 
    449 trunc:
    450 	ND_PRINT((ndo, "[|autorp]"));
    451 	return;
    452 }
    453 
    454 void
    455 pim_print(netdissect_options *ndo,
    456           register const u_char *bp, register u_int len, const u_char *bp2)
    457 {
    458 	register const struct pim *pim = (const struct pim *)bp;
    459 
    460 #ifdef notyet			/* currently we see only version and type */
    461 	ND_TCHECK(pim->pim_rsv);
    462 #endif
    463 
    464 	ND_TCHECK(pim->pim_typever);
    465 	switch (PIM_VER(pim->pim_typever)) {
    466 	case 2:
    467 		if (!ndo->ndo_vflag) {
    468 			ND_PRINT((ndo, "PIMv%u, %s, length %u",
    469 			          PIM_VER(pim->pim_typever),
    470 			          tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever)),
    471 			          len));
    472 			return;
    473 		} else {
    474 			ND_PRINT((ndo, "PIMv%u, length %u\n\t%s",
    475 			          PIM_VER(pim->pim_typever),
    476 			          len,
    477 			          tok2str(pimv2_type_values,"Unknown Type",PIM_TYPE(pim->pim_typever))));
    478 			pimv2_print(ndo, bp, len, bp2);
    479 		}
    480 		break;
    481 	default:
    482 		ND_PRINT((ndo, "PIMv%u, length %u",
    483 		          PIM_VER(pim->pim_typever),
    484 		          len));
    485 		break;
    486 	}
    487 	return;
    488 
    489 trunc:
    490 	ND_PRINT((ndo, "[|pim]"));
    491 	return;
    492 }
    493 
    494 /*
    495  * PIMv2 uses encoded address representations.
    496  *
    497  * The last PIM-SM I-D before RFC2117 was published specified the
    498  * following representation for unicast addresses.  However, RFC2117
    499  * specified no encoding for unicast addresses with the unicast
    500  * address length specified in the header.  Therefore, we have to
    501  * guess which encoding is being used (Cisco's PIMv2 implementation
    502  * uses the non-RFC encoding).  RFC2117 turns a previously "Reserved"
    503  * field into a 'unicast-address-length-in-bytes' field.  We guess
    504  * that it's the draft encoding if this reserved field is zero.
    505  *
    506  * RFC2362 goes back to the encoded format, and calls the addr length
    507  * field "reserved" again.
    508  *
    509  * The first byte is the address family, from:
    510  *
    511  *    0    Reserved
    512  *    1    IP (IP version 4)
    513  *    2    IP6 (IP version 6)
    514  *    3    NSAP
    515  *    4    HDLC (8-bit multidrop)
    516  *    5    BBN 1822
    517  *    6    802 (includes all 802 media plus Ethernet "canonical format")
    518  *    7    E.163
    519  *    8    E.164 (SMDS, Frame Relay, ATM)
    520  *    9    F.69 (Telex)
    521  *   10    X.121 (X.25, Frame Relay)
    522  *   11    IPX
    523  *   12    Appletalk
    524  *   13    Decnet IV
    525  *   14    Banyan Vines
    526  *   15    E.164 with NSAP format subaddress
    527  *
    528  * In addition, the second byte is an "Encoding".  0 is the default
    529  * encoding for the address family, and no other encodings are currently
    530  * specified.
    531  *
    532  */
    533 
    534 enum pimv2_addrtype {
    535 	pimv2_unicast, pimv2_group, pimv2_source
    536 };
    537 
    538 /*  0                   1                   2                   3
    539  *  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
    540  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    541  * | Addr Family   | Encoding Type |     Unicast Address           |
    542  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+++++++
    543  *  0                   1                   2                   3
    544  *  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
    545  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    546  * | Addr Family   | Encoding Type |   Reserved    |  Mask Len     |
    547  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    548  * |                Group multicast Address                        |
    549  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    550  *  0                   1                   2                   3
    551  *  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
    552  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    553  * | Addr Family   | Encoding Type | Rsrvd   |S|W|R|  Mask Len     |
    554  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    555  * |                        Source Address                         |
    556  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    557  */
    558 static int
    559 pimv2_addr_print(netdissect_options *ndo,
    560                  const u_char *bp, u_int len, enum pimv2_addrtype at,
    561                  u_int addr_len, int silent)
    562 {
    563 	int af;
    564 	int hdrlen;
    565 
    566 	if (addr_len == 0) {
    567 		if (len < 2)
    568 			goto trunc;
    569 		ND_TCHECK(bp[1]);
    570 		switch (bp[0]) {
    571 		case 1:
    572 			af = AF_INET;
    573 			addr_len = (u_int)sizeof(struct in_addr);
    574 			break;
    575 		case 2:
    576 			af = AF_INET6;
    577 			addr_len = (u_int)sizeof(struct in6_addr);
    578 			break;
    579 		default:
    580 			return -1;
    581 		}
    582 		if (bp[1] != 0)
    583 			return -1;
    584 		hdrlen = 2;
    585 	} else {
    586 		switch (addr_len) {
    587 		case sizeof(struct in_addr):
    588 			af = AF_INET;
    589 			break;
    590 		case sizeof(struct in6_addr):
    591 			af = AF_INET6;
    592 			break;
    593 		default:
    594 			return -1;
    595 			break;
    596 		}
    597 		hdrlen = 0;
    598 	}
    599 
    600 	bp += hdrlen;
    601 	len -= hdrlen;
    602 	switch (at) {
    603 	case pimv2_unicast:
    604 		if (len < addr_len)
    605 			goto trunc;
    606 		ND_TCHECK2(bp[0], addr_len);
    607 		if (af == AF_INET) {
    608 			if (!silent)
    609 				ND_PRINT((ndo, "%s", ipaddr_string(ndo, bp)));
    610 		}
    611 		else if (af == AF_INET6) {
    612 			if (!silent)
    613 				ND_PRINT((ndo, "%s", ip6addr_string(ndo, bp)));
    614 		}
    615 		return hdrlen + addr_len;
    616 	case pimv2_group:
    617 	case pimv2_source:
    618 		if (len < addr_len + 2)
    619 			goto trunc;
    620 		ND_TCHECK2(bp[0], addr_len + 2);
    621 		if (af == AF_INET) {
    622 			if (!silent) {
    623 				ND_PRINT((ndo, "%s", ipaddr_string(ndo, bp + 2)));
    624 				if (bp[1] != 32)
    625 					ND_PRINT((ndo, "/%u", bp[1]));
    626 			}
    627 		}
    628 		else if (af == AF_INET6) {
    629 			if (!silent) {
    630 				ND_PRINT((ndo, "%s", ip6addr_string(ndo, bp + 2)));
    631 				if (bp[1] != 128)
    632 					ND_PRINT((ndo, "/%u", bp[1]));
    633 			}
    634 		}
    635 		if (bp[0] && !silent) {
    636 			if (at == pimv2_group) {
    637 				ND_PRINT((ndo, "(0x%02x)", bp[0]));
    638 			} else {
    639 				ND_PRINT((ndo, "(%s%s%s",
    640 					bp[0] & 0x04 ? "S" : "",
    641 					bp[0] & 0x02 ? "W" : "",
    642 					bp[0] & 0x01 ? "R" : ""));
    643 				if (bp[0] & 0xf8) {
    644 					ND_PRINT((ndo, "+0x%02x", bp[0] & 0xf8));
    645 				}
    646 				ND_PRINT((ndo, ")"));
    647 			}
    648 		}
    649 		return hdrlen + 2 + addr_len;
    650 	default:
    651 		return -1;
    652 	}
    653 trunc:
    654 	return -1;
    655 }
    656 
    657 enum checksum_status {
    658 	CORRECT,
    659 	INCORRECT,
    660 	UNVERIFIED
    661 };
    662 
    663 static enum checksum_status
    664 pimv2_check_checksum(netdissect_options *ndo, const u_char *bp,
    665 		     const u_char *bp2, u_int len)
    666 {
    667 	const struct ip *ip;
    668 	u_int cksum;
    669 
    670 	if (!ND_TTEST2(bp[0], len)) {
    671 		/* We don't have all the data. */
    672 		return (UNVERIFIED);
    673 	}
    674 	ip = (const struct ip *)bp2;
    675 	if (IP_V(ip) == 4) {
    676 		struct cksum_vec vec[1];
    677 
    678 		vec[0].ptr = bp;
    679 		vec[0].len = len;
    680 		cksum = in_cksum(vec, 1);
    681 		return (cksum ? INCORRECT : CORRECT);
    682 	} else if (IP_V(ip) == 6) {
    683 		const struct ip6_hdr *ip6;
    684 
    685 		ip6 = (const struct ip6_hdr *)bp2;
    686 		cksum = nextproto6_cksum(ndo, ip6, bp, len, len, IPPROTO_PIM);
    687 		return (cksum ? INCORRECT : CORRECT);
    688 	} else {
    689 		return (UNVERIFIED);
    690 	}
    691 }
    692 
    693 static void
    694 pimv2_print(netdissect_options *ndo,
    695             register const u_char *bp, register u_int len, const u_char *bp2)
    696 {
    697 	register const struct pim *pim = (const struct pim *)bp;
    698 	int advance;
    699 	enum checksum_status cksum_status;
    700 	int pimv2_addr_len;
    701 
    702 	if (len < 2)
    703 		goto trunc;
    704 	ND_TCHECK(pim->pim_rsv);
    705 	pimv2_addr_len = pim->pim_rsv;
    706 	if (pimv2_addr_len != 0)
    707 		ND_PRINT((ndo, ", RFC2117-encoding"));
    708 
    709 	if (len < 4)
    710 		goto trunc;
    711 	ND_TCHECK(pim->pim_cksum);
    712 	ND_PRINT((ndo, ", cksum 0x%04x ", EXTRACT_16BITS(&pim->pim_cksum)));
    713 	if (EXTRACT_16BITS(&pim->pim_cksum) == 0) {
    714 		ND_PRINT((ndo, "(unverified)"));
    715 	} else {
    716 		if (PIM_TYPE(pim->pim_typever) == PIMV2_TYPE_REGISTER) {
    717 			/*
    718 			 * The checksum only covers the packet header,
    719 			 * not the encapsulated packet.
    720 			 */
    721 			cksum_status = pimv2_check_checksum(ndo, bp, bp2, 8);
    722 			if (cksum_status == INCORRECT) {
    723 				/*
    724 				 * To quote RFC 4601, "For interoperability
    725 				 * reasons, a message carrying a checksum
    726 				 * calculated over the entire PIM Register
    727 				 * message should also be accepted."
    728 				 */
    729 				cksum_status = pimv2_check_checksum(ndo, bp, bp2, len);
    730 			}
    731 		} else {
    732 			/*
    733 			 * The checksum covers the entire packet.
    734 			 */
    735 			cksum_status = pimv2_check_checksum(ndo, bp, bp2, len);
    736 		}
    737 		switch (cksum_status) {
    738 
    739 		case CORRECT:
    740 			ND_PRINT((ndo, "(correct)"));
    741 			break;
    742 
    743 		case INCORRECT:
    744 			ND_PRINT((ndo, "(incorrect)"));
    745 			break;
    746 
    747 		case UNVERIFIED:
    748 			ND_PRINT((ndo, "(unverified)"));
    749 			break;
    750 		}
    751 	}
    752 	bp += 4;
    753 	len -= 4;
    754 
    755 	switch (PIM_TYPE(pim->pim_typever)) {
    756 	case PIMV2_TYPE_HELLO:
    757 	    {
    758 		uint16_t otype, olen;
    759 		while (len > 0) {
    760 			if (len < 4)
    761 				goto trunc;
    762 			ND_TCHECK2(bp[0], 4);
    763 			otype = EXTRACT_16BITS(&bp[0]);
    764 			olen = EXTRACT_16BITS(&bp[2]);
    765 			ND_PRINT((ndo, "\n\t  %s Option (%u), length %u, Value: ",
    766 			          tok2str(pimv2_hello_option_values, "Unknown", otype),
    767 			          otype,
    768 			          olen));
    769 			bp += 4;
    770 			len -= 4;
    771 
    772 			if (len < olen)
    773 				goto trunc;
    774 			ND_TCHECK2(bp[0], olen);
    775 			switch (otype) {
    776 			case PIMV2_HELLO_OPTION_HOLDTIME:
    777 				if (olen != 2) {
    778 					ND_PRINT((ndo, "ERROR: Option Length != 2 Bytes (%u)", olen));
    779 				} else {
    780 					unsigned_relts_print(ndo, EXTRACT_16BITS(bp));
    781 				}
    782 				break;
    783 
    784 			case PIMV2_HELLO_OPTION_LANPRUNEDELAY:
    785 				if (olen != 4) {
    786 					ND_PRINT((ndo, "ERROR: Option Length != 4 Bytes (%u)", olen));
    787 				} else {
    788 					char t_bit;
    789 					uint16_t lan_delay, override_interval;
    790 					lan_delay = EXTRACT_16BITS(bp);
    791 					override_interval = EXTRACT_16BITS(bp+2);
    792 					t_bit = (lan_delay & 0x8000)? 1 : 0;
    793 					lan_delay &= ~0x8000;
    794 					ND_PRINT((ndo, "\n\t    T-bit=%d, LAN delay %dms, Override interval %dms",
    795 					t_bit, lan_delay, override_interval));
    796 				}
    797 				break;
    798 
    799 			case PIMV2_HELLO_OPTION_DR_PRIORITY_OLD:
    800 			case PIMV2_HELLO_OPTION_DR_PRIORITY:
    801 				switch (olen) {
    802 				case 0:
    803 					ND_PRINT((ndo, "Bi-Directional Capability (Old)"));
    804 					break;
    805 				case 4:
    806 					ND_PRINT((ndo, "%u", EXTRACT_32BITS(bp)));
    807 					break;
    808 				default:
    809 					ND_PRINT((ndo, "ERROR: Option Length != 4 Bytes (%u)", olen));
    810 					break;
    811 				}
    812 				break;
    813 
    814 			case PIMV2_HELLO_OPTION_GENID:
    815 				if (olen != 4) {
    816 					ND_PRINT((ndo, "ERROR: Option Length != 4 Bytes (%u)", olen));
    817 				} else {
    818 					ND_PRINT((ndo, "0x%08x", EXTRACT_32BITS(bp)));
    819 				}
    820 				break;
    821 
    822 			case PIMV2_HELLO_OPTION_REFRESH_CAP:
    823 				if (olen != 4) {
    824 					ND_PRINT((ndo, "ERROR: Option Length != 4 Bytes (%u)", olen));
    825 				} else {
    826 					ND_PRINT((ndo, "v%d", *bp));
    827 					if (*(bp+1) != 0) {
    828 						ND_PRINT((ndo, ", interval "));
    829 						unsigned_relts_print(ndo, *(bp+1));
    830 					}
    831 					if (EXTRACT_16BITS(bp+2) != 0) {
    832 						ND_PRINT((ndo, " ?0x%04x?", EXTRACT_16BITS(bp+2)));
    833 					}
    834 				}
    835 				break;
    836 
    837 			case  PIMV2_HELLO_OPTION_BIDIR_CAP:
    838 				break;
    839 
    840 			case PIMV2_HELLO_OPTION_ADDRESS_LIST_OLD:
    841 			case PIMV2_HELLO_OPTION_ADDRESS_LIST:
    842 				if (ndo->ndo_vflag > 1) {
    843 					const u_char *ptr = bp;
    844 					u_int plen = len;
    845 					while (ptr < (bp+olen)) {
    846 						ND_PRINT((ndo, "\n\t    "));
    847 						advance = pimv2_addr_print(ndo, ptr, plen, pimv2_unicast, pimv2_addr_len, 0);
    848 						if (advance < 0)
    849 							goto trunc;
    850 						ptr += advance;
    851 						plen -= advance;
    852 					}
    853 				}
    854 				break;
    855 			default:
    856 				if (ndo->ndo_vflag <= 1)
    857 					print_unknown_data(ndo, bp, "\n\t    ", olen);
    858 				break;
    859 			}
    860 			/* do we want to see an additionally hexdump ? */
    861 			if (ndo->ndo_vflag> 1)
    862 				print_unknown_data(ndo, bp, "\n\t    ", olen);
    863 			bp += olen;
    864 			len -= olen;
    865 		}
    866 		break;
    867 	    }
    868 
    869 	case PIMV2_TYPE_REGISTER:
    870 	{
    871 		const struct ip *ip;
    872 
    873 		if (len < 4)
    874 			goto trunc;
    875 		ND_TCHECK2(*bp, PIMV2_REGISTER_FLAG_LEN);
    876 
    877 		ND_PRINT((ndo, ", Flags [ %s ]\n\t",
    878 		          tok2str(pimv2_register_flag_values,
    879 		          "none",
    880 		          EXTRACT_32BITS(bp))));
    881 
    882 		bp += 4; len -= 4;
    883 		/* encapsulated multicast packet */
    884 		if (len == 0)
    885 			goto trunc;
    886 		ip = (const struct ip *)bp;
    887 		ND_TCHECK(ip->ip_vhl);
    888 		switch (IP_V(ip)) {
    889                 case 0: /* Null header */
    890 			ND_TCHECK(ip->ip_dst);
    891 			ND_PRINT((ndo, "IP-Null-header %s > %s",
    892 			          ipaddr_string(ndo, &ip->ip_src),
    893 			          ipaddr_string(ndo, &ip->ip_dst)));
    894 			break;
    895 
    896 		case 4:	/* IPv4 */
    897 			ip_print(ndo, bp, len);
    898 			break;
    899 
    900 		case 6:	/* IPv6 */
    901 			ip6_print(ndo, bp, len);
    902 			break;
    903 
    904 		default:
    905 			ND_PRINT((ndo, "IP ver %d", IP_V(ip)));
    906 			break;
    907 		}
    908 		break;
    909 	}
    910 
    911 	case PIMV2_TYPE_REGISTER_STOP:
    912 		ND_PRINT((ndo, " group="));
    913 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
    914 			goto trunc;
    915 		bp += advance; len -= advance;
    916 		ND_PRINT((ndo, " source="));
    917 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
    918 			goto trunc;
    919 		bp += advance; len -= advance;
    920 		break;
    921 
    922 	case PIMV2_TYPE_JOIN_PRUNE:
    923 	case PIMV2_TYPE_GRAFT:
    924 	case PIMV2_TYPE_GRAFT_ACK:
    925 
    926 
    927         /*
    928          * 0                   1                   2                   3
    929          *   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
    930          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    931          *  |PIM Ver| Type  | Addr length   |           Checksum            |
    932          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    933          *  |             Unicast-Upstream Neighbor Address                 |
    934          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    935          *  |  Reserved     | Num groups    |          Holdtime             |
    936          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    937          *  |            Encoded-Multicast Group Address-1                  |
    938          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    939          *  |   Number of Joined  Sources   |   Number of Pruned Sources    |
    940          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    941          *  |               Encoded-Joined Source Address-1                 |
    942          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    943          *  |                             .                                 |
    944          *  |                             .                                 |
    945          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    946          *  |               Encoded-Joined Source Address-n                 |
    947          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    948          *  |               Encoded-Pruned Source Address-1                 |
    949          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    950          *  |                             .                                 |
    951          *  |                             .                                 |
    952          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    953          *  |               Encoded-Pruned Source Address-n                 |
    954          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    955          *  |                           .                                   |
    956          *  |                           .                                   |
    957          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    958          *  |                Encoded-Multicast Group Address-n              |
    959          *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    960          */
    961 
    962 	    {
    963 		uint8_t ngroup;
    964 		uint16_t holdtime;
    965 		uint16_t njoin;
    966 		uint16_t nprune;
    967 		int i, j;
    968 
    969 		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
    970 			ND_PRINT((ndo, ", upstream-neighbor: "));
    971 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
    972 				goto trunc;
    973 			bp += advance; len -= advance;
    974 		}
    975 		if (len < 4)
    976 			goto trunc;
    977 		ND_TCHECK2(*bp, 4);
    978 		ngroup = bp[1];
    979 		holdtime = EXTRACT_16BITS(&bp[2]);
    980 		ND_PRINT((ndo, "\n\t  %u group(s)", ngroup));
    981 		if (PIM_TYPE(pim->pim_typever) != 7) {	/*not for Graft-ACK*/
    982 			ND_PRINT((ndo, ", holdtime: "));
    983 			if (holdtime == 0xffff)
    984 				ND_PRINT((ndo, "infinite"));
    985 			else
    986 				unsigned_relts_print(ndo, holdtime);
    987 		}
    988 		bp += 4; len -= 4;
    989 		for (i = 0; i < ngroup; i++) {
    990 			ND_PRINT((ndo, "\n\t    group #%u: ", i+1));
    991 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
    992 				goto trunc;
    993 			bp += advance; len -= advance;
    994 			if (len < 4)
    995 				goto trunc;
    996 			ND_TCHECK2(*bp, 4);
    997 			njoin = EXTRACT_16BITS(&bp[0]);
    998 			nprune = EXTRACT_16BITS(&bp[2]);
    999 			ND_PRINT((ndo, ", joined sources: %u, pruned sources: %u", njoin, nprune));
   1000 			bp += 4; len -= 4;
   1001 			for (j = 0; j < njoin; j++) {
   1002 				ND_PRINT((ndo, "\n\t      joined source #%u: ", j+1));
   1003 				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
   1004 					goto trunc;
   1005 				bp += advance; len -= advance;
   1006 			}
   1007 			for (j = 0; j < nprune; j++) {
   1008 				ND_PRINT((ndo, "\n\t      pruned source #%u: ", j+1));
   1009 				if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_source, pimv2_addr_len, 0)) < 0)
   1010 					goto trunc;
   1011 				bp += advance; len -= advance;
   1012 			}
   1013 		}
   1014 		break;
   1015 	    }
   1016 
   1017 	case PIMV2_TYPE_BOOTSTRAP:
   1018 	{
   1019 		int i, j, frpcnt;
   1020 
   1021 		/* Fragment Tag, Hash Mask len, and BSR-priority */
   1022 		if (len < 2)
   1023 			goto trunc;
   1024 		ND_TCHECK_16BITS(bp);
   1025 		ND_PRINT((ndo, " tag=%x", EXTRACT_16BITS(bp)));
   1026 		bp += 2;
   1027 		len -= 2;
   1028 		if (len < 1)
   1029 			goto trunc;
   1030 		ND_TCHECK(bp[0]);
   1031 		ND_PRINT((ndo, " hashmlen=%d", bp[0]));
   1032 		if (len < 2)
   1033 			goto trunc;
   1034 		ND_TCHECK(bp[2]);
   1035 		ND_PRINT((ndo, " BSRprio=%d", bp[1]));
   1036 		bp += 2;
   1037 		len -= 2;
   1038 
   1039 		/* Encoded-Unicast-BSR-Address */
   1040 		ND_PRINT((ndo, " BSR="));
   1041 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
   1042 			goto trunc;
   1043 		bp += advance;
   1044 		len -= advance;
   1045 
   1046 		for (i = 0; len > 0; i++) {
   1047 			/* Encoded-Group Address */
   1048 			ND_PRINT((ndo, " (group%d: ", i));
   1049 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
   1050 				goto trunc;
   1051 			bp += advance;
   1052 			len -= advance;
   1053 
   1054 			/* RP-Count, Frag RP-Cnt, and rsvd */
   1055 			if (len < 1)
   1056 				goto trunc;
   1057 			ND_TCHECK(bp[0]);
   1058 			ND_PRINT((ndo, " RPcnt=%d", bp[0]));
   1059 			if (len < 2)
   1060 				goto trunc;
   1061 			ND_TCHECK(bp[1]);
   1062 			ND_PRINT((ndo, " FRPcnt=%d", frpcnt = bp[1]));
   1063 			if (len < 4)
   1064 				goto trunc;
   1065 			bp += 4;
   1066 			len -= 4;
   1067 
   1068 			for (j = 0; j < frpcnt && len > 0; j++) {
   1069 				/* each RP info */
   1070 				ND_PRINT((ndo, " RP%d=", j));
   1071 				if ((advance = pimv2_addr_print(ndo, bp, len,
   1072 								pimv2_unicast,
   1073 								pimv2_addr_len,
   1074 								0)) < 0)
   1075 					goto trunc;
   1076 				bp += advance;
   1077 				len -= advance;
   1078 
   1079 				if (len < 2)
   1080 					goto trunc;
   1081 				ND_TCHECK_16BITS(bp);
   1082 				ND_PRINT((ndo, ",holdtime="));
   1083 				unsigned_relts_print(ndo, EXTRACT_16BITS(bp));
   1084 				if (len < 3)
   1085 					goto trunc;
   1086 				ND_TCHECK(bp[2]);
   1087 				ND_PRINT((ndo, ",prio=%d", bp[2]));
   1088 				if (len < 4)
   1089 					goto trunc;
   1090 				bp += 4;
   1091 				len -= 4;
   1092 			}
   1093 			ND_PRINT((ndo, ")"));
   1094 		}
   1095 		break;
   1096 	}
   1097 	case PIMV2_TYPE_ASSERT:
   1098 		ND_PRINT((ndo, " group="));
   1099 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
   1100 			goto trunc;
   1101 		bp += advance; len -= advance;
   1102 		ND_PRINT((ndo, " src="));
   1103 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
   1104 			goto trunc;
   1105 		bp += advance; len -= advance;
   1106 		if (len < 8)
   1107 			goto trunc;
   1108 		ND_TCHECK2(*bp, 8);
   1109 		if (bp[0] & 0x80)
   1110 			ND_PRINT((ndo, " RPT"));
   1111 		ND_PRINT((ndo, " pref=%u", EXTRACT_32BITS(&bp[0]) & 0x7fffffff));
   1112 		ND_PRINT((ndo, " metric=%u", EXTRACT_32BITS(&bp[4])));
   1113 		break;
   1114 
   1115 	case PIMV2_TYPE_CANDIDATE_RP:
   1116 	{
   1117 		int i, pfxcnt;
   1118 
   1119 		/* Prefix-Cnt, Priority, and Holdtime */
   1120 		if (len < 1)
   1121 			goto trunc;
   1122 		ND_TCHECK(bp[0]);
   1123 		ND_PRINT((ndo, " prefix-cnt=%d", bp[0]));
   1124 		pfxcnt = bp[0];
   1125 		if (len < 2)
   1126 			goto trunc;
   1127 		ND_TCHECK(bp[1]);
   1128 		ND_PRINT((ndo, " prio=%d", bp[1]));
   1129 		if (len < 4)
   1130 			goto trunc;
   1131 		ND_TCHECK_16BITS(&bp[2]);
   1132 		ND_PRINT((ndo, " holdtime="));
   1133 		unsigned_relts_print(ndo, EXTRACT_16BITS(&bp[2]));
   1134 		bp += 4;
   1135 		len -= 4;
   1136 
   1137 		/* Encoded-Unicast-RP-Address */
   1138 		ND_PRINT((ndo, " RP="));
   1139 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
   1140 			goto trunc;
   1141 		bp += advance;
   1142 		len -= advance;
   1143 
   1144 		/* Encoded-Group Addresses */
   1145 		for (i = 0; i < pfxcnt && len > 0; i++) {
   1146 			ND_PRINT((ndo, " Group%d=", i));
   1147 			if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
   1148 				goto trunc;
   1149 			bp += advance;
   1150 			len -= advance;
   1151 		}
   1152 		break;
   1153 	}
   1154 
   1155 	case PIMV2_TYPE_PRUNE_REFRESH:
   1156 		ND_PRINT((ndo, " src="));
   1157 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
   1158 			goto trunc;
   1159 		bp += advance;
   1160 		len -= advance;
   1161 		ND_PRINT((ndo, " grp="));
   1162 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_group, pimv2_addr_len, 0)) < 0)
   1163 			goto trunc;
   1164 		bp += advance;
   1165 		len -= advance;
   1166 		ND_PRINT((ndo, " forwarder="));
   1167 		if ((advance = pimv2_addr_print(ndo, bp, len, pimv2_unicast, pimv2_addr_len, 0)) < 0)
   1168 			goto trunc;
   1169 		bp += advance;
   1170 		len -= advance;
   1171 		if (len < 2)
   1172 			goto trunc;
   1173 		ND_TCHECK_16BITS(bp);
   1174 		ND_PRINT((ndo, " TUNR "));
   1175 		unsigned_relts_print(ndo, EXTRACT_16BITS(bp));
   1176 		break;
   1177 
   1178 
   1179 	 default:
   1180 		ND_PRINT((ndo, " [type %d]", PIM_TYPE(pim->pim_typever)));
   1181 		break;
   1182 	}
   1183 
   1184 	return;
   1185 
   1186 trunc:
   1187 	ND_PRINT((ndo, "[|pim]"));
   1188 }
   1189 
   1190 /*
   1191  * Local Variables:
   1192  * c-style: whitesmith
   1193  * c-basic-offset: 8
   1194  * End:
   1195  */
   1196