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