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