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