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