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