1 /* $OpenBSD: print-icmp6.c,v 1.10 2011/09/17 19:56:19 bluhm Exp $ */ 2 3 /* 4 * Copyright (c) 1988, 1989, 1990, 1991, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that: (1) source code distributions 9 * retain the above copyright notice and this paragraph in its entirety, (2) 10 * distributions including binary code include the above copyright notice and 11 * this paragraph in its entirety in the documentation or other materials 12 * provided with the distribution, and (3) all advertising materials mentioning 13 * features or use of this software display the following acknowledgement: 14 * ``This product includes software developed by the University of California, 15 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 16 * the University nor the names of its contributors may be used to endorse 17 * or promote products derived from this software without specific prior 18 * written permission. 19 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 20 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 21 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 22 */ 23 24 #ifdef INET6 25 26 #include <ctype.h> 27 28 #include <sys/param.h> 29 #include <sys/time.h> 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 33 #include <net/if.h> 34 35 #include <netinet/in.h> 36 #include <netinet/if_ether.h> 37 #include <netinet/in_systm.h> 38 #include <netinet/ip.h> 39 #include <netinet/ip_icmp.h> 40 #include <netinet/ip_var.h> 41 #include <netinet/udp.h> 42 #include <netinet/udp_var.h> 43 #include <netinet/tcp.h> 44 45 #include <arpa/inet.h> 46 47 #include <stdio.h> 48 49 #include <netinet/ip6.h> 50 #include <netinet/icmp6.h> 51 #include <netinet6/mld6.h> 52 53 #include "interface.h" 54 #include "addrtoname.h" 55 56 void icmp6_opt_print(const u_char *, int); 57 void mld6_print(const u_char *); 58 void mldv2_query_print(const u_char *, u_int); 59 void mldv2_report_print(const u_char *, u_int); 60 61 /* mldv2 report types */ 62 static struct tok mldv2report2str[] = { 63 { 1, "is_in" }, 64 { 2, "is_ex" }, 65 { 3, "to_in" }, 66 { 4, "to_ex" }, 67 { 5, "allow" }, 68 { 6, "block" }, 69 { 0, NULL } 70 }; 71 72 #define MLDV2_QUERY_QRV 24 73 #define MLDV2_QUERY_QQIC 25 74 #define MLDV2_QUERY_NSRCS 26 75 #define MLDV2_QUERY_SRC0 28 76 77 #define MLDV2_QUERY_QRV_SFLAG (1 << 3) 78 79 #define MLD_V1_QUERY_MINLEN 24 80 81 #define MLDV2_REPORT_GROUP0 8 82 83 #define MLDV2_REPORT_MINLEN 8 84 #define MLDV2_REPORT_MINGRPLEN 20 85 86 #define MLDV2_RGROUP_NSRCS 2 87 #define MLDV2_RGROUP_MADDR 4 88 89 #define MLDV2_MRC_FLOAT (1 << 15) 90 #define MLDV2_MRD(mant, exp) ((mant | 0x1000) << (exp + 3)) 91 92 #define MLDV2_QQIC_FLOAT (1 << 7) 93 #define MLDV2_QQI(mant, exp) ((mant | 0x10) << (exp + 3)) 94 95 void 96 icmp6_print(const u_char *bp, u_int length, const u_char *bp2) 97 { 98 register const struct icmp6_hdr *dp; 99 register const struct ip6_hdr *ip; 100 register const char *str; 101 register const struct ip6_hdr *oip; 102 register const struct udphdr *ouh; 103 register int hlen, dport; 104 register const u_char *ep; 105 char buf[256]; 106 int icmp6len; 107 108 #if 0 109 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc 110 #endif 111 112 dp = (struct icmp6_hdr *)bp; 113 ip = (struct ip6_hdr *)bp2; 114 oip = (struct ip6_hdr *)(dp + 1); 115 str = buf; 116 /* 'ep' points to the end of avaible data. */ 117 ep = snapend; 118 if (ip->ip6_plen) 119 icmp6len = (ntohs(ip->ip6_plen) + sizeof(struct ip6_hdr) - 120 (bp - bp2)); 121 else /* XXX: jumbo payload case... */ 122 icmp6len = snapend - bp; 123 124 #if 0 125 (void)printf("%s > %s: ", 126 ip6addr_string(&ip->ip6_src), 127 ip6addr_string(&ip->ip6_dst)); 128 #endif 129 130 TCHECK(dp->icmp6_code); 131 switch (dp->icmp6_type) { 132 case ICMP6_DST_UNREACH: 133 TCHECK(oip->ip6_dst); 134 switch (dp->icmp6_code) { 135 case ICMP6_DST_UNREACH_NOROUTE: 136 printf("icmp6: %s unreachable route", 137 ip6addr_string(&oip->ip6_dst)); 138 break; 139 case ICMP6_DST_UNREACH_ADMIN: 140 printf("icmp6: %s unreachable prohibited", 141 ip6addr_string(&oip->ip6_dst)); 142 break; 143 #ifdef ICMP6_DST_UNREACH_BEYONDSCOPE 144 case ICMP6_DST_UNREACH_BEYONDSCOPE: 145 #else 146 case ICMP6_DST_UNREACH_NOTNEIGHBOR: 147 #endif 148 printf("icmp6: %s beyond scope of source address %s", 149 ip6addr_string(&oip->ip6_dst), 150 ip6addr_string(&oip->ip6_src)); 151 break; 152 case ICMP6_DST_UNREACH_ADDR: 153 printf("icmp6: %s unreachable address", 154 ip6addr_string(&oip->ip6_dst)); 155 break; 156 case ICMP6_DST_UNREACH_NOPORT: 157 TCHECK(oip->ip6_nxt); 158 hlen = sizeof(struct ip6_hdr); 159 ouh = (struct udphdr *)(((u_char *)oip) + hlen); 160 TCHECK(ouh->uh_dport); 161 dport = ntohs(ouh->uh_dport); 162 switch (oip->ip6_nxt) { 163 case IPPROTO_TCP: 164 printf("icmp6: %s tcp port %s unreachable", 165 ip6addr_string(&oip->ip6_dst), 166 tcpport_string(dport)); 167 break; 168 case IPPROTO_UDP: 169 printf("icmp6: %s udp port %s unreachable", 170 ip6addr_string(&oip->ip6_dst), 171 udpport_string(dport)); 172 break; 173 default: 174 printf("icmp6: %s protocol %d port %d unreachable", 175 ip6addr_string(&oip->ip6_dst), 176 oip->ip6_nxt, dport); 177 break; 178 } 179 break; 180 default: 181 printf("icmp6: %s unreachable code-#%d", 182 ip6addr_string(&oip->ip6_dst), 183 dp->icmp6_code); 184 break; 185 } 186 break; 187 case ICMP6_PACKET_TOO_BIG: 188 TCHECK(dp->icmp6_mtu); 189 printf("icmp6: too big %u", (u_int32_t)ntohl(dp->icmp6_mtu)); 190 break; 191 case ICMP6_TIME_EXCEEDED: 192 TCHECK(oip->ip6_dst); 193 switch (dp->icmp6_code) { 194 case ICMP6_TIME_EXCEED_TRANSIT: 195 printf("icmp6: time exceeded in-transit for %s", 196 ip6addr_string(&oip->ip6_dst)); 197 break; 198 case ICMP6_TIME_EXCEED_REASSEMBLY: 199 printf("icmp6: ip6 reassembly time exceeded"); 200 break; 201 default: 202 printf("icmp6: time exceeded code-#%d", 203 dp->icmp6_code); 204 break; 205 } 206 break; 207 case ICMP6_PARAM_PROB: 208 TCHECK(oip->ip6_dst); 209 switch (dp->icmp6_code) { 210 case ICMP6_PARAMPROB_HEADER: 211 printf("icmp6: parameter problem errorneous - octet %u", 212 (u_int32_t)ntohl(dp->icmp6_pptr)); 213 break; 214 case ICMP6_PARAMPROB_NEXTHEADER: 215 printf("icmp6: parameter problem next header - octet %u", 216 (u_int32_t)ntohl(dp->icmp6_pptr)); 217 break; 218 case ICMP6_PARAMPROB_OPTION: 219 printf("icmp6: parameter problem option - octet %u", 220 (u_int32_t)ntohl(dp->icmp6_pptr)); 221 break; 222 default: 223 printf("icmp6: parameter problem code-#%d", 224 dp->icmp6_code); 225 break; 226 } 227 break; 228 case ICMP6_ECHO_REQUEST: 229 case ICMP6_ECHO_REPLY: 230 printf("icmp6: echo %s", dp->icmp6_type == ICMP6_ECHO_REQUEST ? 231 "request" : "reply"); 232 if (vflag) { 233 TCHECK(dp->icmp6_seq); 234 printf(" (id:%04x seq:%u)", 235 ntohs(dp->icmp6_id), ntohs(dp->icmp6_seq)); 236 } 237 break; 238 case ICMP6_MEMBERSHIP_QUERY: 239 printf("icmp6: multicast listener query "); 240 if (length == MLD_V1_QUERY_MINLEN) { 241 mld6_print((const u_char *)dp); 242 } else if (length >= MLD_V2_QUERY_MINLEN) { 243 printf("v2 "); 244 mldv2_query_print((const u_char *)dp, length); 245 } else { 246 printf("unknown-version (len %u) ", length); 247 } 248 break; 249 case ICMP6_MEMBERSHIP_REPORT: 250 printf("icmp6: multicast listener report "); 251 mld6_print((const u_char *)dp); 252 break; 253 case ICMP6_MEMBERSHIP_REDUCTION: 254 printf("icmp6: multicast listener done "); 255 mld6_print((const u_char *)dp); 256 break; 257 case ND_ROUTER_SOLICIT: 258 printf("icmp6: router solicitation "); 259 if (vflag) { 260 #define RTSOLLEN 8 261 icmp6_opt_print((const u_char *)dp + RTSOLLEN, 262 icmp6len - RTSOLLEN); 263 } 264 break; 265 case ND_ROUTER_ADVERT: 266 printf("icmp6: router advertisement"); 267 if (vflag) { 268 struct nd_router_advert *p; 269 270 p = (struct nd_router_advert *)dp; 271 TCHECK(p->nd_ra_retransmit); 272 printf("(chlim=%d, ", (int)p->nd_ra_curhoplimit); 273 if (p->nd_ra_flags_reserved & ND_RA_FLAG_MANAGED) 274 printf("M"); 275 if (p->nd_ra_flags_reserved & ND_RA_FLAG_OTHER) 276 printf("O"); 277 if (p->nd_ra_flags_reserved != 0) 278 printf(" "); 279 printf("router_ltime=%d, ", ntohs(p->nd_ra_router_lifetime)); 280 printf("reachable_time=%u, ", 281 (u_int32_t)ntohl(p->nd_ra_reachable)); 282 printf("retrans_time=%u)", 283 (u_int32_t)ntohl(p->nd_ra_retransmit)); 284 #define RTADVLEN 16 285 icmp6_opt_print((const u_char *)dp + RTADVLEN, 286 icmp6len - RTADVLEN); 287 } 288 break; 289 case ND_NEIGHBOR_SOLICIT: 290 { 291 struct nd_neighbor_solicit *p; 292 p = (struct nd_neighbor_solicit *)dp; 293 TCHECK(p->nd_ns_target); 294 printf("icmp6: neighbor sol: who has %s", 295 ip6addr_string(&p->nd_ns_target)); 296 if (vflag) { 297 #define NDSOLLEN 24 298 icmp6_opt_print((const u_char *)dp + NDSOLLEN, 299 icmp6len - NDSOLLEN); 300 } 301 } 302 break; 303 case ND_NEIGHBOR_ADVERT: 304 { 305 struct nd_neighbor_advert *p; 306 307 p = (struct nd_neighbor_advert *)dp; 308 TCHECK(p->nd_na_target); 309 printf("icmp6: neighbor adv: tgt is %s", 310 ip6addr_string(&p->nd_na_target)); 311 if (vflag) { 312 #define ND_NA_FLAG_ALL \ 313 (ND_NA_FLAG_ROUTER|ND_NA_FLAG_SOLICITED|ND_NA_FLAG_OVERRIDE) 314 /* we don't need ntohl() here. see advanced-api-04. */ 315 if (p->nd_na_flags_reserved & ND_NA_FLAG_ALL) { 316 #undef ND_NA_FLAG_ALL 317 u_int32_t flags; 318 319 flags = p->nd_na_flags_reserved; 320 printf("("); 321 if (flags & ND_NA_FLAG_ROUTER) 322 printf("R"); 323 if (flags & ND_NA_FLAG_SOLICITED) 324 printf("S"); 325 if (flags & ND_NA_FLAG_OVERRIDE) 326 printf("O"); 327 printf(")"); 328 } 329 #define NDADVLEN 24 330 icmp6_opt_print((const u_char *)dp + NDADVLEN, 331 icmp6len - NDADVLEN); 332 } 333 } 334 break; 335 case ND_REDIRECT: 336 { 337 #define RDR(i) ((struct nd_redirect *)(i)) 338 char tgtbuf[INET6_ADDRSTRLEN], dstbuf[INET6_ADDRSTRLEN]; 339 340 TCHECK(RDR(dp)->nd_rd_dst); 341 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_target, 342 tgtbuf, INET6_ADDRSTRLEN); 343 inet_ntop(AF_INET6, &RDR(dp)->nd_rd_dst, 344 dstbuf, INET6_ADDRSTRLEN); 345 printf("icmp6: redirect %s to %s", dstbuf, tgtbuf); 346 #define REDIRECTLEN 40 347 if (vflag) { 348 icmp6_opt_print((const u_char *)dp + REDIRECTLEN, 349 icmp6len - REDIRECTLEN); 350 } 351 break; 352 } 353 case ICMP6_ROUTER_RENUMBERING: 354 switch (dp->icmp6_code) { 355 case ICMP6_ROUTER_RENUMBERING_COMMAND: 356 printf("icmp6: router renum command"); 357 break; 358 case ICMP6_ROUTER_RENUMBERING_RESULT: 359 printf("icmp6: router renum result"); 360 break; 361 default: 362 printf("icmp6: router renum code-#%d", dp->icmp6_code); 363 break; 364 } 365 break; 366 #ifdef ICMP6_WRUREQUEST 367 case ICMP6_WRUREQUEST: /*ICMP6_FQDN_QUERY*/ 368 { 369 int siz; 370 siz = ep - (u_char *)(dp + 1); 371 if (siz == 4) 372 printf("icmp6: who-are-you request"); 373 else { 374 printf("icmp6: FQDN request"); 375 if (vflag) { 376 if (siz < 8) 377 printf("?(icmp6_data %d bytes)", siz); 378 else if (8 < siz) 379 printf("?(extra %d bytes)", siz - 8); 380 } 381 } 382 break; 383 } 384 #endif /*ICMP6_WRUREQUEST*/ 385 #ifdef ICMP6_WRUREPLY 386 case ICMP6_WRUREPLY: /*ICMP6_FQDN_REPLY*/ 387 { 388 enum { UNKNOWN, WRU, FQDN } mode = UNKNOWN; 389 u_char const *buf; 390 u_char const *cp = NULL; 391 392 buf = (u_char *)(dp + 1); 393 394 /* fair guess */ 395 if (buf[12] == ep - buf - 13) 396 mode = FQDN; 397 else if (dp->icmp6_code == 1) 398 mode = FQDN; 399 400 /* wild guess */ 401 if (mode == UNKNOWN) { 402 cp = buf + 4; 403 while (cp < ep) { 404 if (!isprint(*cp++)) 405 mode = FQDN; 406 } 407 } 408 #ifndef abs 409 #define abs(a) ((0 < (a)) ? (a) : -(a)) 410 #endif 411 if (mode == UNKNOWN && 2 < abs(buf[12] - (ep - buf - 13))) 412 mode = WRU; 413 if (mode == UNKNOWN) 414 mode = FQDN; 415 416 if (mode == WRU) { 417 cp = buf + 4; 418 printf("icmp6: who-are-you reply(\""); 419 } else if (mode == FQDN) { 420 cp = buf + 13; 421 printf("icmp6: FQDN reply(\""); 422 } 423 for (; cp < ep; cp++) 424 printf((isprint(*cp) ? "%c" : "\\%03o"), *cp); 425 printf("\""); 426 if (vflag) { 427 printf(",%s", mode == FQDN ? "FQDN" : "WRU"); 428 if (mode == FQDN) { 429 int ttl; 430 ttl = (int)ntohl(*(u_int32_t *)&buf[8]); 431 if (dp->icmp6_code == 1) 432 printf(",TTL=unknown"); 433 else if (ttl < 0) 434 printf(",TTL=%d:invalid", ttl); 435 else 436 printf(",TTL=%d", ttl); 437 if (buf[12] != ep - buf - 13) { 438 (void)printf(",invalid namelen:%d/%u", 439 buf[12], 440 (unsigned int)(ep - buf - 13)); 441 } 442 } 443 } 444 printf(")"); 445 break; 446 } 447 #endif /*ICMP6_WRUREPLY*/ 448 case MLDV2_LISTENER_REPORT: 449 printf("multicast listener report v2"); 450 mldv2_report_print((const u_char *) dp, length); 451 break; 452 default: 453 printf("icmp6: type-#%d", dp->icmp6_type); 454 break; 455 } 456 return; 457 trunc: 458 fputs("[|icmp6]", stdout); 459 #if 0 460 #undef TCHECK 461 #endif 462 } 463 464 void 465 icmp6_opt_print(register const u_char *bp, int resid) 466 { 467 register const struct nd_opt_hdr *op; 468 register const struct nd_opt_hdr *opl; /* why there's no struct? */ 469 register const struct nd_opt_prefix_info *opp; 470 register const struct icmp6_opts_redirect *opr; 471 register const struct nd_opt_mtu *opm; 472 register const u_char *ep; 473 int opts_len; 474 #if 0 475 register const struct ip6_hdr *ip; 476 register const char *str; 477 register const struct ip6_hdr *oip; 478 register const struct udphdr *ouh; 479 register int hlen, dport; 480 char buf[256]; 481 #endif 482 483 #if 0 484 #define TCHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) goto trunc 485 #endif 486 #define ECHECK(var) if ((u_char *)&(var) > ep - sizeof(var)) return 487 488 op = (struct nd_opt_hdr *)bp; 489 #if 0 490 ip = (struct ip6_hdr *)bp2; 491 oip = &dp->icmp6_ip6; 492 str = buf; 493 #endif 494 /* 'ep' points to the end of avaible data. */ 495 ep = snapend; 496 497 ECHECK(op->nd_opt_len); 498 if (resid <= 0) 499 return; 500 if (op->nd_opt_len == 0) 501 goto trunc; 502 if (bp + (op->nd_opt_len << 3) > ep) 503 goto trunc; 504 switch (op->nd_opt_type) { 505 case ND_OPT_SOURCE_LINKADDR: 506 opl = (struct nd_opt_hdr *)op; 507 #if 1 508 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) 509 goto trunc; 510 #else 511 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); 512 #endif 513 printf("(src lladdr: %s", 514 etheraddr_string((u_char *)(opl + 1))); 515 if (opl->nd_opt_len != 1) 516 printf("!"); 517 printf(")"); 518 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 519 resid - (op->nd_opt_len << 3)); 520 break; 521 case ND_OPT_TARGET_LINKADDR: 522 opl = (struct nd_opt_hdr *)op; 523 #if 1 524 if ((u_char *)opl + (opl->nd_opt_len << 3) > ep) 525 goto trunc; 526 #else 527 TCHECK((u_char *)opl + (opl->nd_opt_len << 3) - 1); 528 #endif 529 printf("(tgt lladdr: %s", 530 etheraddr_string((u_char *)(opl + 1))); 531 if (opl->nd_opt_len != 1) 532 printf("!"); 533 printf(")"); 534 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 535 resid - (op->nd_opt_len << 3)); 536 break; 537 case ND_OPT_PREFIX_INFORMATION: 538 opp = (struct nd_opt_prefix_info *)op; 539 TCHECK(opp->nd_opt_pi_prefix); 540 printf("(prefix info: "); 541 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) 542 printf("L"); 543 if (opp->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_AUTO) 544 printf("A"); 545 if (opp->nd_opt_pi_flags_reserved) 546 printf(" "); 547 printf("valid_ltime="); 548 if ((u_int32_t)ntohl(opp->nd_opt_pi_valid_time) == ~0U) 549 printf("infinity"); 550 else { 551 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_valid_time)); 552 } 553 printf(", "); 554 printf("preferred_ltime="); 555 if ((u_int32_t)ntohl(opp->nd_opt_pi_preferred_time) == ~0U) 556 printf("infinity"); 557 else { 558 printf("%u", (u_int32_t)ntohl(opp->nd_opt_pi_preferred_time)); 559 } 560 printf(", "); 561 printf("prefix=%s/%d", ip6addr_string(&opp->nd_opt_pi_prefix), 562 opp->nd_opt_pi_prefix_len); 563 if (opp->nd_opt_pi_len != 4) 564 printf("!"); 565 printf(")"); 566 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 567 resid - (op->nd_opt_len << 3)); 568 break; 569 case ND_OPT_REDIRECTED_HEADER: 570 opr = (struct icmp6_opts_redirect *)op; 571 printf("(redirect)"); 572 /* xxx */ 573 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 574 resid - (op->nd_opt_len << 3)); 575 break; 576 case ND_OPT_MTU: 577 opm = (struct nd_opt_mtu *)op; 578 TCHECK(opm->nd_opt_mtu_mtu); 579 printf("(mtu: "); 580 printf("mtu=%u", (u_int32_t)ntohl(opm->nd_opt_mtu_mtu)); 581 if (opm->nd_opt_mtu_len != 1) 582 printf("!"); 583 printf(")"); 584 icmp6_opt_print((const u_char *)op + (op->nd_opt_len << 3), 585 resid - (op->nd_opt_len << 3)); 586 break; 587 default: 588 opts_len = op->nd_opt_len; 589 printf("(unknown opt_type=%d, opt_len=%d)", 590 op->nd_opt_type, opts_len); 591 if (opts_len == 0) 592 opts_len = 1; /* XXX */ 593 icmp6_opt_print((const u_char *)op + (opts_len << 3), 594 resid - (opts_len << 3)); 595 break; 596 } 597 return; 598 trunc: 599 fputs("[ndp opt]", stdout); 600 return; 601 #if 0 602 #undef TCHECK 603 #endif 604 #undef ECHECK 605 } 606 607 void 608 mld6_print(register const u_char *bp) 609 { 610 register struct mld6_hdr *mp = (struct mld6_hdr *)bp; 611 register const u_char *ep; 612 613 /* 'ep' points to the end of avaible data. */ 614 ep = snapend; 615 616 if ((u_char *)mp + sizeof(*mp) > ep) 617 return; 618 619 printf("max resp delay: %d ", ntohs(mp->mld6_maxdelay)); 620 printf("addr: %s", ip6addr_string(&mp->mld6_addr)); 621 622 return; 623 } 624 625 void 626 mldv2_report_print(const u_char *bp, u_int len) 627 { 628 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 629 u_int group, nsrcs, ngroups; 630 u_int i, j; 631 632 if (len < MLDV2_REPORT_MINLEN) { 633 printf(" [invalid len %d]", len); 634 return; 635 } 636 637 TCHECK(icp->icmp6_data16[1]); 638 ngroups = ntohs(icp->icmp6_data16[1]); 639 printf(", %d group record(s)", ngroups); 640 if (vflag > 0) { 641 /* Print the group records */ 642 group = MLDV2_REPORT_GROUP0; 643 for (i = 0; i < ngroups; i++) { 644 /* type(1) + auxlen(1) + numsrc(2) + grp(16) */ 645 if (len < group + MLDV2_REPORT_MINGRPLEN) { 646 printf(" [invalid number of groups]"); 647 return; 648 } 649 TCHECK2(bp[group + MLDV2_RGROUP_MADDR], 650 sizeof(struct in6_addr)); 651 printf(" [gaddr %s", 652 ip6addr_string(&bp[group + MLDV2_RGROUP_MADDR])); 653 printf(" %s", tok2str(mldv2report2str, 654 " [v2-report-#%d]", bp[group])); 655 nsrcs = (bp[group + MLDV2_RGROUP_NSRCS] << 8) + 656 bp[group + MLDV2_RGROUP_NSRCS + 1]; 657 /* Check the number of sources and print them */ 658 if (len < group + MLDV2_REPORT_MINGRPLEN + 659 (nsrcs * sizeof(struct in6_addr))) { 660 printf(" [invalid number of sources %d]", nsrcs); 661 return; 662 } 663 if (vflag == 1) 664 printf(", %d source(s)", nsrcs); 665 else { 666 /* Print the sources */ 667 (void)printf(" {"); 668 for (j = 0; j < nsrcs; j++) { 669 TCHECK2(bp[group + 670 MLDV2_REPORT_MINGRPLEN + 671 j * sizeof(struct in6_addr)], 672 sizeof(struct in6_addr)); 673 printf(" %s", ip6addr_string(&bp[group + 674 MLDV2_REPORT_MINGRPLEN + j * 675 sizeof(struct in6_addr)])); 676 } 677 (void)printf(" }"); 678 } 679 /* Next group record */ 680 group += MLDV2_REPORT_MINGRPLEN + nsrcs * 681 sizeof(struct in6_addr); 682 printf("]"); 683 } 684 } 685 return; 686 trunc: 687 (void)printf("[|icmp6]"); 688 return; 689 } 690 691 void 692 mldv2_query_print(const u_char *bp, u_int len) 693 { 694 struct icmp6_hdr *icp = (struct icmp6_hdr *) bp; 695 u_int mrc, qqic; 696 int mrd, qqi; 697 int mant, exp; 698 u_int nsrcs; 699 u_int i; 700 701 if (len < MLD_V2_QUERY_MINLEN) { 702 printf(" [invalid len %d]", len); 703 return; 704 } 705 TCHECK(icp->icmp6_data16[0]); 706 mrc = ntohs(icp->icmp6_data16[0]); 707 if (mrc & MLDV2_MRC_FLOAT) { 708 mant = MLD_MRC_MANT(mrc); 709 exp = MLD_MRC_EXP(mrc); 710 mrd = MLDV2_MRD(mant, exp); 711 } else { 712 mrd = mrc; 713 } 714 if (vflag) { 715 (void)printf(" [max resp delay=%d]", mrd); 716 } 717 TCHECK2(bp[8], sizeof(struct in6_addr)); 718 printf(" [gaddr %s", ip6addr_string(&bp[8])); 719 720 if (vflag) { 721 TCHECK(bp[MLDV2_QUERY_QQIC]); 722 if (bp[MLDV2_QUERY_QRV] & MLDV2_QUERY_QRV_SFLAG) { 723 printf(" sflag"); 724 } 725 if (MLD_QRV(bp[MLDV2_QUERY_QRV])) { 726 printf(" robustness=%d", MLD_QRV(bp[MLDV2_QUERY_QRV])); 727 } 728 qqic = bp[MLDV2_QUERY_QQIC]; 729 if (qqic & MLDV2_QQIC_FLOAT) { 730 mant = MLD_QQIC_MANT(qqic); 731 exp = MLD_QQIC_EXP(qqic); 732 qqi = MLDV2_QQI(mant, exp); 733 } else { 734 qqi = bp[MLDV2_QUERY_QQIC]; 735 } 736 printf(" qqi=%d", qqi); 737 } 738 739 TCHECK2(bp[MLDV2_QUERY_NSRCS], 2); 740 nsrcs = ntohs(*(u_short *)&bp[MLDV2_QUERY_NSRCS]); 741 if (nsrcs > 0) { 742 if (len < MLD_V2_QUERY_MINLEN + nsrcs * sizeof(struct in6_addr)) 743 printf(" [invalid number of sources]"); 744 else if (vflag > 1) { 745 printf(" {"); 746 for (i = 0; i < nsrcs; i++) { 747 TCHECK2(bp[MLDV2_QUERY_SRC0 + i * 748 sizeof(struct in6_addr)], 749 sizeof(struct in6_addr)); 750 printf(" %s", 751 ip6addr_string(&bp[MLDV2_QUERY_SRC0 + i * 752 sizeof(struct in6_addr)])); 753 } 754 printf(" }"); 755 } else 756 printf(", %d source(s)", nsrcs); 757 } 758 printf("]"); 759 return; 760 trunc: 761 (void)printf("[|icmp6]"); 762 return; 763 } 764 765 766 #endif /* INET6 */ 767