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