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