1 /* 2 * Redistribution and use in source and binary forms, with or without 3 * modification, are permitted provided that: (1) source code 4 * distributions retain the above copyright notice and this paragraph 5 * in its entirety, and (2) distributions including binary code include 6 * the above copyright notice and this paragraph in its entirety in 7 * the documentation or other materials provided with the distribution. 8 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND 9 * WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT 10 * LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 11 * FOR A PARTICULAR PURPOSE. 12 * 13 * Original code by Andy Heffernan (ahh@juniper.net) 14 */ 15 16 #include <sys/cdefs.h> 17 #ifndef lint 18 #if 0 19 static const char rcsid[] _U_ = 20 "@(#) Header: /tcpdump/master/tcpdump/print-pgm.c,v 1.5 2005-06-07 22:05:58 guy Exp "; 21 #else 22 __RCSID("$NetBSD: print-pgm.c,v 1.4 2013/10/20 02:58:34 christos Exp $"); 23 #endif 24 #endif 25 26 #ifdef HAVE_CONFIG_H 27 #include "config.h" 28 #endif 29 30 #include <tcpdump-stdinc.h> 31 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include "interface.h" 37 #include "extract.h" 38 #include "addrtoname.h" 39 40 #include "ip.h" 41 #ifdef INET6 42 #include "ip6.h" 43 #endif 44 #include "ipproto.h" 45 46 /* 47 * PGM header (RFC 3208) 48 */ 49 struct pgm_header { 50 u_int16_t pgm_sport; 51 u_int16_t pgm_dport; 52 u_int8_t pgm_type; 53 u_int8_t pgm_options; 54 u_int16_t pgm_sum; 55 u_int8_t pgm_gsid[6]; 56 u_int16_t pgm_length; 57 }; 58 59 struct pgm_spm { 60 u_int32_t pgms_seq; 61 u_int32_t pgms_trailseq; 62 u_int32_t pgms_leadseq; 63 u_int16_t pgms_nla_afi; 64 u_int16_t pgms_reserved; 65 /* ... u_int8_t pgms_nla[0]; */ 66 /* ... options */ 67 }; 68 69 struct pgm_nak { 70 u_int32_t pgmn_seq; 71 u_int16_t pgmn_source_afi; 72 u_int16_t pgmn_reserved; 73 /* ... u_int8_t pgmn_source[0]; */ 74 /* ... u_int16_t pgmn_group_afi */ 75 /* ... u_int16_t pgmn_reserved2; */ 76 /* ... u_int8_t pgmn_group[0]; */ 77 /* ... options */ 78 }; 79 80 struct pgm_ack { 81 u_int32_t pgma_rx_max_seq; 82 u_int32_t pgma_bitmap; 83 /* ... options */ 84 }; 85 86 struct pgm_poll { 87 u_int32_t pgmp_seq; 88 u_int16_t pgmp_round; 89 u_int16_t pgmp_reserved; 90 /* ... options */ 91 }; 92 93 struct pgm_polr { 94 u_int32_t pgmp_seq; 95 u_int16_t pgmp_round; 96 u_int16_t pgmp_subtype; 97 u_int16_t pgmp_nla_afi; 98 u_int16_t pgmp_reserved; 99 /* ... u_int8_t pgmp_nla[0]; */ 100 /* ... options */ 101 }; 102 103 struct pgm_data { 104 u_int32_t pgmd_seq; 105 u_int32_t pgmd_trailseq; 106 /* ... options */ 107 }; 108 109 typedef enum _pgm_type { 110 PGM_SPM = 0, /* source path message */ 111 PGM_POLL = 1, /* POLL Request */ 112 PGM_POLR = 2, /* POLL Response */ 113 PGM_ODATA = 4, /* original data */ 114 PGM_RDATA = 5, /* repair data */ 115 PGM_NAK = 8, /* NAK */ 116 PGM_NULLNAK = 9, /* Null NAK */ 117 PGM_NCF = 10, /* NAK Confirmation */ 118 PGM_ACK = 11, /* ACK for congestion control */ 119 PGM_SPMR = 12, /* SPM request */ 120 PGM_MAX = 255 121 } pgm_type; 122 123 #define PGM_OPT_BIT_PRESENT 0x01 124 #define PGM_OPT_BIT_NETWORK 0x02 125 #define PGM_OPT_BIT_VAR_PKTLEN 0x40 126 #define PGM_OPT_BIT_PARITY 0x80 127 128 #define PGM_OPT_LENGTH 0x00 129 #define PGM_OPT_FRAGMENT 0x01 130 #define PGM_OPT_NAK_LIST 0x02 131 #define PGM_OPT_JOIN 0x03 132 #define PGM_OPT_NAK_BO_IVL 0x04 133 #define PGM_OPT_NAK_BO_RNG 0x05 134 135 #define PGM_OPT_REDIRECT 0x07 136 #define PGM_OPT_PARITY_PRM 0x08 137 #define PGM_OPT_PARITY_GRP 0x09 138 #define PGM_OPT_CURR_TGSIZE 0x0A 139 #define PGM_OPT_NBR_UNREACH 0x0B 140 #define PGM_OPT_PATH_NLA 0x0C 141 142 #define PGM_OPT_SYN 0x0D 143 #define PGM_OPT_FIN 0x0E 144 #define PGM_OPT_RST 0x0F 145 #define PGM_OPT_CR 0x10 146 #define PGM_OPT_CRQST 0x11 147 148 #define PGM_OPT_PGMCC_DATA 0x12 149 #define PGM_OPT_PGMCC_FEEDBACK 0x13 150 151 #define PGM_OPT_MASK 0x7f 152 153 #define PGM_OPT_END 0x80 /* end of options marker */ 154 155 #define PGM_MIN_OPT_LEN 4 156 157 #ifndef AFI_IP 158 #define AFI_IP 1 159 #define AFI_IP6 2 160 #endif 161 162 void 163 pgm_print(register const u_char *bp, register u_int length, 164 register const u_char *bp2) 165 { 166 register const struct pgm_header *pgm; 167 register const struct ip *ip; 168 register char ch; 169 u_int16_t sport, dport; 170 int addr_size; 171 const void *nla; 172 int nla_af; 173 #ifdef INET6 174 char nla_buf[INET6_ADDRSTRLEN]; 175 register const struct ip6_hdr *ip6; 176 #else 177 char nla_buf[INET_ADDRSTRLEN]; 178 #endif 179 u_int8_t opt_type, opt_len; 180 u_int32_t seq, opts_len, len, offset; 181 182 pgm = (struct pgm_header *)bp; 183 ip = (struct ip *)bp2; 184 #ifdef INET6 185 if (IP_V(ip) == 6) 186 ip6 = (struct ip6_hdr *)bp2; 187 else 188 ip6 = NULL; 189 #else /* INET6 */ 190 if (IP_V(ip) == 6) { 191 (void)printf("Can't handle IPv6"); 192 return; 193 } 194 #endif /* INET6 */ 195 ch = '\0'; 196 if (!TTEST(pgm->pgm_dport)) { 197 #ifdef INET6 198 if (ip6) { 199 (void)printf("%s > %s: [|pgm]", 200 ip6addr_string(&ip6->ip6_src), 201 ip6addr_string(&ip6->ip6_dst)); 202 return; 203 } else 204 #endif /* INET6 */ 205 { 206 (void)printf("%s > %s: [|pgm]", 207 ipaddr_string(&ip->ip_src), 208 ipaddr_string(&ip->ip_dst)); 209 return; 210 } 211 } 212 213 sport = EXTRACT_16BITS(&pgm->pgm_sport); 214 dport = EXTRACT_16BITS(&pgm->pgm_dport); 215 216 #ifdef INET6 217 if (ip6) { 218 if (ip6->ip6_nxt == IPPROTO_PGM) { 219 (void)printf("%s.%s > %s.%s: ", 220 ip6addr_string(&ip6->ip6_src), 221 tcpport_string(sport), 222 ip6addr_string(&ip6->ip6_dst), 223 tcpport_string(dport)); 224 } else { 225 (void)printf("%s > %s: ", 226 tcpport_string(sport), tcpport_string(dport)); 227 } 228 } else 229 #endif /*INET6*/ 230 { 231 if (ip->ip_p == IPPROTO_PGM) { 232 (void)printf("%s.%s > %s.%s: ", 233 ipaddr_string(&ip->ip_src), 234 tcpport_string(sport), 235 ipaddr_string(&ip->ip_dst), 236 tcpport_string(dport)); 237 } else { 238 (void)printf("%s > %s: ", 239 tcpport_string(sport), tcpport_string(dport)); 240 } 241 } 242 243 TCHECK(*pgm); 244 245 (void)printf("PGM, length %u", pgm->pgm_length); 246 247 if (!vflag) 248 return; 249 250 if (length > pgm->pgm_length) 251 length = pgm->pgm_length; 252 253 (void)printf(" 0x%02x%02x%02x%02x%02x%02x ", 254 pgm->pgm_gsid[0], 255 pgm->pgm_gsid[1], 256 pgm->pgm_gsid[2], 257 pgm->pgm_gsid[3], 258 pgm->pgm_gsid[4], 259 pgm->pgm_gsid[5]); 260 switch (pgm->pgm_type) { 261 case PGM_SPM: { 262 struct pgm_spm *spm; 263 264 spm = (struct pgm_spm *)(pgm + 1); 265 TCHECK(*spm); 266 267 switch (EXTRACT_16BITS(&spm->pgms_nla_afi)) { 268 case AFI_IP: 269 addr_size = sizeof(struct in_addr); 270 nla_af = AF_INET; 271 break; 272 #ifdef INET6 273 case AFI_IP6: 274 addr_size = sizeof(struct in6_addr); 275 nla_af = AF_INET6; 276 break; 277 #endif 278 default: 279 goto trunc; 280 break; 281 } 282 bp = (u_char *) (spm + 1); 283 TCHECK2(*bp, addr_size); 284 nla = bp; 285 bp += addr_size; 286 287 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 288 (void)printf("SPM seq %u trail %u lead %u nla %s", 289 EXTRACT_32BITS(&spm->pgms_seq), 290 EXTRACT_32BITS(&spm->pgms_trailseq), 291 EXTRACT_32BITS(&spm->pgms_leadseq), 292 nla_buf); 293 break; 294 } 295 296 case PGM_POLL: { 297 struct pgm_poll *poll; 298 299 poll = (struct pgm_poll *)(pgm + 1); 300 TCHECK(*poll); 301 (void)printf("POLL seq %u round %u", 302 EXTRACT_32BITS(&poll->pgmp_seq), 303 EXTRACT_16BITS(&poll->pgmp_round)); 304 bp = (u_char *) (poll + 1); 305 break; 306 } 307 case PGM_POLR: { 308 struct pgm_polr *polr; 309 u_int32_t ivl, rnd, mask; 310 311 polr = (struct pgm_polr *)(pgm + 1); 312 TCHECK(*polr); 313 314 switch (EXTRACT_16BITS(&polr->pgmp_nla_afi)) { 315 case AFI_IP: 316 addr_size = sizeof(struct in_addr); 317 nla_af = AF_INET; 318 break; 319 #ifdef INET6 320 case AFI_IP6: 321 addr_size = sizeof(struct in6_addr); 322 nla_af = AF_INET6; 323 break; 324 #endif 325 default: 326 goto trunc; 327 break; 328 } 329 bp = (u_char *) (polr + 1); 330 TCHECK2(*bp, addr_size); 331 nla = bp; 332 bp += addr_size; 333 334 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 335 336 TCHECK2(*bp, sizeof(u_int32_t)); 337 ivl = EXTRACT_32BITS(bp); 338 bp += sizeof(u_int32_t); 339 340 TCHECK2(*bp, sizeof(u_int32_t)); 341 rnd = EXTRACT_32BITS(bp); 342 bp += sizeof(u_int32_t); 343 344 TCHECK2(*bp, sizeof(u_int32_t)); 345 mask = EXTRACT_32BITS(bp); 346 bp += sizeof(u_int32_t); 347 348 (void)printf("POLR seq %u round %u nla %s ivl %u rnd 0x%08x " 349 "mask 0x%08x", EXTRACT_32BITS(&polr->pgmp_seq), 350 EXTRACT_16BITS(&polr->pgmp_round), nla_buf, ivl, rnd, mask); 351 break; 352 } 353 case PGM_ODATA: { 354 struct pgm_data *odata; 355 356 odata = (struct pgm_data *)(pgm + 1); 357 TCHECK(*odata); 358 (void)printf("ODATA trail %u seq %u", 359 EXTRACT_32BITS(&odata->pgmd_trailseq), 360 EXTRACT_32BITS(&odata->pgmd_seq)); 361 bp = (u_char *) (odata + 1); 362 break; 363 } 364 365 case PGM_RDATA: { 366 struct pgm_data *rdata; 367 368 rdata = (struct pgm_data *)(pgm + 1); 369 TCHECK(*rdata); 370 (void)printf("RDATA trail %u seq %u", 371 EXTRACT_32BITS(&rdata->pgmd_trailseq), 372 EXTRACT_32BITS(&rdata->pgmd_seq)); 373 bp = (u_char *) (rdata + 1); 374 break; 375 } 376 377 case PGM_NAK: 378 case PGM_NULLNAK: 379 case PGM_NCF: { 380 struct pgm_nak *nak; 381 const void *source, *group; 382 int source_af, group_af; 383 #ifdef INET6 384 char source_buf[INET6_ADDRSTRLEN], group_buf[INET6_ADDRSTRLEN]; 385 #else 386 char source_buf[INET_ADDRSTRLEN], group_buf[INET_ADDRSTRLEN]; 387 #endif 388 389 nak = (struct pgm_nak *)(pgm + 1); 390 TCHECK(*nak); 391 392 /* 393 * Skip past the source, saving info along the way 394 * and stopping if we don't have enough. 395 */ 396 switch (EXTRACT_16BITS(&nak->pgmn_source_afi)) { 397 case AFI_IP: 398 addr_size = sizeof(struct in_addr); 399 source_af = AF_INET; 400 break; 401 #ifdef INET6 402 case AFI_IP6: 403 addr_size = sizeof(struct in6_addr); 404 source_af = AF_INET6; 405 break; 406 #endif 407 default: 408 goto trunc; 409 break; 410 } 411 bp = (u_char *) (nak + 1); 412 TCHECK2(*bp, addr_size); 413 source = bp; 414 bp += addr_size; 415 416 /* 417 * Skip past the group, saving info along the way 418 * and stopping if we don't have enough. 419 */ 420 switch (EXTRACT_16BITS(bp)) { 421 case AFI_IP: 422 addr_size = sizeof(struct in_addr); 423 group_af = AF_INET; 424 break; 425 #ifdef INET6 426 case AFI_IP6: 427 addr_size = sizeof(struct in6_addr); 428 group_af = AF_INET6; 429 break; 430 #endif 431 default: 432 goto trunc; 433 break; 434 } 435 bp += (2 * sizeof(u_int16_t)); 436 TCHECK2(*bp, addr_size); 437 group = bp; 438 bp += addr_size; 439 440 /* 441 * Options decoding can go here. 442 */ 443 inet_ntop(source_af, source, source_buf, sizeof(source_buf)); 444 inet_ntop(group_af, group, group_buf, sizeof(group_buf)); 445 switch (pgm->pgm_type) { 446 case PGM_NAK: 447 (void)printf("NAK "); 448 break; 449 case PGM_NULLNAK: 450 (void)printf("NNAK "); 451 break; 452 case PGM_NCF: 453 (void)printf("NCF "); 454 break; 455 default: 456 break; 457 } 458 (void)printf("(%s -> %s), seq %u", 459 source_buf, group_buf, EXTRACT_32BITS(&nak->pgmn_seq)); 460 break; 461 } 462 463 case PGM_ACK: { 464 struct pgm_ack *ack; 465 466 ack = (struct pgm_ack *)(pgm + 1); 467 TCHECK(*ack); 468 (void)printf("ACK seq %u", 469 EXTRACT_32BITS(&ack->pgma_rx_max_seq)); 470 bp = (u_char *) (ack + 1); 471 break; 472 } 473 474 case PGM_SPMR: 475 (void)printf("SPMR"); 476 break; 477 478 default: 479 (void)printf("UNKNOWN type %0x02x", pgm->pgm_type); 480 break; 481 482 } 483 if (pgm->pgm_options & PGM_OPT_BIT_PRESENT) { 484 485 /* 486 * make sure there's enough for the first option header 487 */ 488 if (!TTEST2(*bp, PGM_MIN_OPT_LEN)) { 489 (void)printf("[|OPT]"); 490 return; 491 } 492 493 /* 494 * That option header MUST be an OPT_LENGTH option 495 * (see the first paragraph of section 9.1 in RFC 3208). 496 */ 497 opt_type = *bp++; 498 if ((opt_type & PGM_OPT_MASK) != PGM_OPT_LENGTH) { 499 (void)printf("[First option bad, should be PGM_OPT_LENGTH, is %u]", opt_type & PGM_OPT_MASK); 500 return; 501 } 502 opt_len = *bp++; 503 if (opt_len != 4) { 504 (void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len); 505 return; 506 } 507 opts_len = EXTRACT_16BITS(bp); 508 if (opts_len < 4) { 509 (void)printf("[Bad total option length %u < 4]", opts_len); 510 return; 511 } 512 bp += sizeof(u_int16_t); 513 (void)printf(" OPTS LEN %d", opts_len); 514 opts_len -= 4; 515 516 while (opts_len) { 517 if (opts_len < PGM_MIN_OPT_LEN) { 518 (void)printf("[Total option length leaves no room for final option]"); 519 return; 520 } 521 opt_type = *bp++; 522 opt_len = *bp++; 523 if (opt_len < PGM_MIN_OPT_LEN) { 524 (void)printf("[Bad option, length %u < %u]", opt_len, 525 PGM_MIN_OPT_LEN); 526 break; 527 } 528 if (opts_len < opt_len) { 529 (void)printf("[Total option length leaves no room for final option]"); 530 return; 531 } 532 if (!TTEST2(*bp, opt_len - 2)) { 533 (void)printf(" [|OPT]"); 534 return; 535 } 536 537 switch (opt_type & PGM_OPT_MASK) { 538 case PGM_OPT_LENGTH: 539 if (opt_len != 4) { 540 (void)printf("[Bad OPT_LENGTH option, length %u != 4]", opt_len); 541 return; 542 } 543 (void)printf(" OPTS LEN (extra?) %d", EXTRACT_16BITS(bp)); 544 bp += sizeof(u_int16_t); 545 opts_len -= 4; 546 break; 547 548 case PGM_OPT_FRAGMENT: 549 if (opt_len != 16) { 550 (void)printf("[Bad OPT_FRAGMENT option, length %u != 16]", opt_len); 551 return; 552 } 553 bp += 2; /* skip flags */ 554 seq = EXTRACT_32BITS(bp); 555 bp += sizeof(u_int32_t); 556 offset = EXTRACT_32BITS(bp); 557 bp += sizeof(u_int32_t); 558 len = EXTRACT_32BITS(bp); 559 bp += sizeof(u_int32_t); 560 (void)printf(" FRAG seq %u off %u len %u", seq, offset, len); 561 opts_len -= 16; 562 break; 563 564 case PGM_OPT_NAK_LIST: 565 bp += 2; /* skip flags */ 566 opt_len -= sizeof(u_int32_t); /* option header */ 567 (void)printf(" NAK LIST"); 568 while (opt_len) { 569 if (opt_len < sizeof(u_int32_t)) { 570 (void)printf("[Option length not a multiple of 4]"); 571 return; 572 } 573 TCHECK2(*bp, sizeof(u_int32_t)); 574 (void)printf(" %u", EXTRACT_32BITS(bp)); 575 bp += sizeof(u_int32_t); 576 opt_len -= sizeof(u_int32_t); 577 opts_len -= sizeof(u_int32_t); 578 } 579 break; 580 581 case PGM_OPT_JOIN: 582 if (opt_len != 8) { 583 (void)printf("[Bad OPT_JOIN option, length %u != 8]", opt_len); 584 return; 585 } 586 bp += 2; /* skip flags */ 587 seq = EXTRACT_32BITS(bp); 588 bp += sizeof(u_int32_t); 589 (void)printf(" JOIN %u", seq); 590 opts_len -= 8; 591 break; 592 593 case PGM_OPT_NAK_BO_IVL: 594 if (opt_len != 12) { 595 (void)printf("[Bad OPT_NAK_BO_IVL option, length %u != 12]", opt_len); 596 return; 597 } 598 bp += 2; /* skip flags */ 599 offset = EXTRACT_32BITS(bp); 600 bp += sizeof(u_int32_t); 601 seq = EXTRACT_32BITS(bp); 602 bp += sizeof(u_int32_t); 603 (void)printf(" BACKOFF ivl %u ivlseq %u", offset, seq); 604 opts_len -= 12; 605 break; 606 607 case PGM_OPT_NAK_BO_RNG: 608 if (opt_len != 12) { 609 (void)printf("[Bad OPT_NAK_BO_RNG option, length %u != 12]", opt_len); 610 return; 611 } 612 bp += 2; /* skip flags */ 613 offset = EXTRACT_32BITS(bp); 614 bp += sizeof(u_int32_t); 615 seq = EXTRACT_32BITS(bp); 616 bp += sizeof(u_int32_t); 617 (void)printf(" BACKOFF max %u min %u", offset, seq); 618 opts_len -= 12; 619 break; 620 621 case PGM_OPT_REDIRECT: 622 bp += 2; /* skip flags */ 623 switch (EXTRACT_16BITS(bp)) { 624 case AFI_IP: 625 addr_size = sizeof(struct in_addr); 626 nla_af = AF_INET; 627 break; 628 #ifdef INET6 629 case AFI_IP6: 630 addr_size = sizeof(struct in6_addr); 631 nla_af = AF_INET6; 632 break; 633 #endif 634 default: 635 goto trunc; 636 break; 637 } 638 bp += (2 * sizeof(u_int16_t)); 639 if (opt_len != 4 + addr_size) { 640 (void)printf("[Bad OPT_REDIRECT option, length %u != 4 + address size]", opt_len); 641 return; 642 } 643 TCHECK2(*bp, addr_size); 644 nla = bp; 645 bp += addr_size; 646 647 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 648 (void)printf(" REDIRECT %s", (char *)nla); 649 opts_len -= 4 + addr_size; 650 break; 651 652 case PGM_OPT_PARITY_PRM: 653 if (opt_len != 8) { 654 (void)printf("[Bad OPT_PARITY_PRM option, length %u != 8]", opt_len); 655 return; 656 } 657 bp += 2; /* skip flags */ 658 len = EXTRACT_32BITS(bp); 659 bp += sizeof(u_int32_t); 660 (void)printf(" PARITY MAXTGS %u", len); 661 opts_len -= 8; 662 break; 663 664 case PGM_OPT_PARITY_GRP: 665 if (opt_len != 8) { 666 (void)printf("[Bad OPT_PARITY_GRP option, length %u != 8]", opt_len); 667 return; 668 } 669 bp += 2; /* skip flags */ 670 seq = EXTRACT_32BITS(bp); 671 bp += sizeof(u_int32_t); 672 (void)printf(" PARITY GROUP %u", seq); 673 opts_len -= 8; 674 break; 675 676 case PGM_OPT_CURR_TGSIZE: 677 if (opt_len != 8) { 678 (void)printf("[Bad OPT_CURR_TGSIZE option, length %u != 8]", opt_len); 679 return; 680 } 681 bp += 2; /* skip flags */ 682 len = EXTRACT_32BITS(bp); 683 bp += sizeof(u_int32_t); 684 (void)printf(" PARITY ATGS %u", len); 685 opts_len -= 8; 686 break; 687 688 case PGM_OPT_NBR_UNREACH: 689 if (opt_len != 4) { 690 (void)printf("[Bad OPT_NBR_UNREACH option, length %u != 4]", opt_len); 691 return; 692 } 693 bp += 2; /* skip flags */ 694 (void)printf(" NBR_UNREACH"); 695 opts_len -= 4; 696 break; 697 698 case PGM_OPT_PATH_NLA: 699 (void)printf(" PATH_NLA [%d]", opt_len); 700 bp += opt_len; 701 opts_len -= opt_len; 702 break; 703 704 case PGM_OPT_SYN: 705 if (opt_len != 4) { 706 (void)printf("[Bad OPT_SYN option, length %u != 4]", opt_len); 707 return; 708 } 709 bp += 2; /* skip flags */ 710 (void)printf(" SYN"); 711 opts_len -= 4; 712 break; 713 714 case PGM_OPT_FIN: 715 if (opt_len != 4) { 716 (void)printf("[Bad OPT_FIN option, length %u != 4]", opt_len); 717 return; 718 } 719 bp += 2; /* skip flags */ 720 (void)printf(" FIN"); 721 opts_len -= 4; 722 break; 723 724 case PGM_OPT_RST: 725 if (opt_len != 4) { 726 (void)printf("[Bad OPT_RST option, length %u != 4]", opt_len); 727 return; 728 } 729 bp += 2; /* skip flags */ 730 (void)printf(" RST"); 731 opts_len -= 4; 732 break; 733 734 case PGM_OPT_CR: 735 (void)printf(" CR"); 736 bp += opt_len; 737 opts_len -= opt_len; 738 break; 739 740 case PGM_OPT_CRQST: 741 if (opt_len != 4) { 742 (void)printf("[Bad OPT_CRQST option, length %u != 4]", opt_len); 743 return; 744 } 745 bp += 2; /* skip flags */ 746 (void)printf(" CRQST"); 747 opts_len -= 4; 748 break; 749 750 case PGM_OPT_PGMCC_DATA: 751 bp += 2; /* skip flags */ 752 offset = EXTRACT_32BITS(bp); 753 bp += sizeof(u_int32_t); 754 switch (EXTRACT_16BITS(bp)) { 755 case AFI_IP: 756 addr_size = sizeof(struct in_addr); 757 nla_af = AF_INET; 758 break; 759 #ifdef INET6 760 case AFI_IP6: 761 addr_size = sizeof(struct in6_addr); 762 nla_af = AF_INET6; 763 break; 764 #endif 765 default: 766 goto trunc; 767 break; 768 } 769 bp += (2 * sizeof(u_int16_t)); 770 if (opt_len != 12 + addr_size) { 771 (void)printf("[Bad OPT_PGMCC_DATA option, length %u != 12 + address size]", opt_len); 772 return; 773 } 774 TCHECK2(*bp, addr_size); 775 nla = bp; 776 bp += addr_size; 777 778 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 779 (void)printf(" PGMCC DATA %u %s", offset, (char*)nla); 780 opts_len -= 16; 781 break; 782 783 case PGM_OPT_PGMCC_FEEDBACK: 784 bp += 2; /* skip flags */ 785 offset = EXTRACT_32BITS(bp); 786 bp += sizeof(u_int32_t); 787 switch (EXTRACT_16BITS(bp)) { 788 case AFI_IP: 789 addr_size = sizeof(struct in_addr); 790 nla_af = AF_INET; 791 break; 792 #ifdef INET6 793 case AFI_IP6: 794 addr_size = sizeof(struct in6_addr); 795 nla_af = AF_INET6; 796 break; 797 #endif 798 default: 799 goto trunc; 800 break; 801 } 802 bp += (2 * sizeof(u_int16_t)); 803 if (opt_len != 12 + addr_size) { 804 (void)printf("[Bad OPT_PGMCC_FEEDBACK option, length %u != 12 + address size]", opt_len); 805 return; 806 } 807 TCHECK2(*bp, addr_size); 808 nla = bp; 809 bp += addr_size; 810 811 inet_ntop(nla_af, nla, nla_buf, sizeof(nla_buf)); 812 (void)printf(" PGMCC FEEDBACK %u %s", offset, (char*)nla); 813 opts_len -= 16; 814 break; 815 816 default: 817 (void)printf(" OPT_%02X [%d] ", opt_type, opt_len); 818 bp += opt_len; 819 opts_len -= opt_len; 820 break; 821 } 822 823 if (opt_type & PGM_OPT_END) 824 break; 825 } 826 } 827 828 (void)printf(" [%u]", EXTRACT_16BITS(&pgm->pgm_length)); 829 830 return; 831 832 trunc: 833 fputs("[|pgm]", stdout); 834 if (ch != '\0') 835 putchar('>'); 836 } 837