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