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