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