1 /* 2 * Internet Control Message Protocol for IPv6 3 */ 4 #include "u.h" 5 #include "../port/lib.h" 6 #include "mem.h" 7 #include "dat.h" 8 #include "fns.h" 9 #include "../port/error.h" 10 #include "ip.h" 11 #include "ipv6.h" 12 13 enum 14 { 15 InMsgs6, 16 InErrors6, 17 OutMsgs6, 18 CsumErrs6, 19 LenErrs6, 20 HlenErrs6, 21 HoplimErrs6, 22 IcmpCodeErrs6, 23 TargetErrs6, 24 OptlenErrs6, 25 AddrmxpErrs6, 26 RouterAddrErrs6, 27 28 Nstats6, 29 }; 30 31 enum { 32 ICMP_USEAD6 = 40, 33 }; 34 35 enum { 36 Oflag = 1<<5, 37 Sflag = 1<<6, 38 Rflag = 1<<7, 39 }; 40 41 enum { 42 /* ICMPv6 types */ 43 EchoReply = 0, 44 UnreachableV6 = 1, 45 PacketTooBigV6 = 2, 46 TimeExceedV6 = 3, 47 SrcQuench = 4, 48 ParamProblemV6 = 4, 49 Redirect = 5, 50 EchoRequest = 8, 51 TimeExceed = 11, 52 InParmProblem = 12, 53 Timestamp = 13, 54 TimestampReply = 14, 55 InfoRequest = 15, 56 InfoReply = 16, 57 AddrMaskRequest = 17, 58 AddrMaskReply = 18, 59 EchoRequestV6 = 128, 60 EchoReplyV6 = 129, 61 RouterSolicit = 133, 62 RouterAdvert = 134, 63 NbrSolicit = 135, 64 NbrAdvert = 136, 65 RedirectV6 = 137, 66 67 Maxtype6 = 137, 68 }; 69 70 typedef struct ICMPpkt ICMPpkt; 71 typedef struct IPICMP IPICMP; 72 typedef struct Ndpkt Ndpkt; 73 typedef struct NdiscC NdiscC; 74 75 struct ICMPpkt { 76 uchar type; 77 uchar code; 78 uchar cksum[2]; 79 uchar icmpid[2]; 80 uchar seq[2]; 81 }; 82 83 struct IPICMP { 84 Ip6hdr; 85 ICMPpkt; 86 }; 87 88 struct NdiscC 89 { 90 IPICMP; 91 uchar target[IPaddrlen]; 92 }; 93 94 struct Ndpkt 95 { 96 NdiscC; 97 uchar otype; 98 uchar olen; /* length in units of 8 octets(incl type, code), 99 * 1 for IEEE 802 addresses */ 100 uchar lnaddr[6]; /* link-layer address */ 101 }; 102 103 typedef struct Icmppriv6 104 { 105 ulong stats[Nstats6]; 106 107 /* message counts */ 108 ulong in[Maxtype6+1]; 109 ulong out[Maxtype6+1]; 110 } Icmppriv6; 111 112 typedef struct Icmpcb6 113 { 114 QLock; 115 uchar headers; 116 } Icmpcb6; 117 118 char *icmpnames6[Maxtype6+1] = 119 { 120 [EchoReply] "EchoReply", 121 [UnreachableV6] "UnreachableV6", 122 [PacketTooBigV6] "PacketTooBigV6", 123 [TimeExceedV6] "TimeExceedV6", 124 [SrcQuench] "SrcQuench", 125 [Redirect] "Redirect", 126 [EchoRequest] "EchoRequest", 127 [TimeExceed] "TimeExceed", 128 [InParmProblem] "InParmProblem", 129 [Timestamp] "Timestamp", 130 [TimestampReply] "TimestampReply", 131 [InfoRequest] "InfoRequest", 132 [InfoReply] "InfoReply", 133 [AddrMaskRequest] "AddrMaskRequest", 134 [AddrMaskReply] "AddrMaskReply", 135 [EchoRequestV6] "EchoRequestV6", 136 [EchoReplyV6] "EchoReplyV6", 137 [RouterSolicit] "RouterSolicit", 138 [RouterAdvert] "RouterAdvert", 139 [NbrSolicit] "NbrSolicit", 140 [NbrAdvert] "NbrAdvert", 141 [RedirectV6] "RedirectV6", 142 }; 143 144 static char *statnames6[Nstats6] = 145 { 146 [InMsgs6] "InMsgs", 147 [InErrors6] "InErrors", 148 [OutMsgs6] "OutMsgs", 149 [CsumErrs6] "CsumErrs", 150 [LenErrs6] "LenErrs", 151 [HlenErrs6] "HlenErrs", 152 [HoplimErrs6] "HoplimErrs", 153 [IcmpCodeErrs6] "IcmpCodeErrs", 154 [TargetErrs6] "TargetErrs", 155 [OptlenErrs6] "OptlenErrs", 156 [AddrmxpErrs6] "AddrmxpErrs", 157 [RouterAddrErrs6] "RouterAddrErrs", 158 }; 159 160 static char *unreachcode[] = 161 { 162 [icmp6_no_route] "no route to destination", 163 [icmp6_ad_prohib] "comm with destination administratively prohibited", 164 [icmp6_unassigned] "icmp unreachable: unassigned error code (2)", 165 [icmp6_adr_unreach] "address unreachable", 166 [icmp6_port_unreach] "port unreachable", 167 [icmp6_unkn_code] "icmp unreachable: unknown code", 168 }; 169 170 static void icmpkick6(void *x, Block *bp); 171 172 static void 173 icmpcreate6(Conv *c) 174 { 175 c->rq = qopen(64*1024, Qmsg, 0, c); 176 c->wq = qbypass(icmpkick6, c); 177 } 178 179 static void 180 set_cksum(Block *bp) 181 { 182 IPICMP *p = (IPICMP *)(bp->rp); 183 184 hnputl(p->vcf, 0); /* borrow IP header as pseudoheader */ 185 hnputs(p->ploadlen, blocklen(bp)-IPV6HDR_LEN); 186 p->proto = 0; 187 p->ttl = ICMPv6; /* ttl gets set later */ 188 hnputs(p->cksum, 0); 189 hnputs(p->cksum, ptclcsum(bp, 0, blocklen(bp))); 190 p->proto = ICMPv6; 191 } 192 193 static Block * 194 newIPICMP(int packetlen) 195 { 196 Block *nbp; 197 198 nbp = allocb(packetlen); 199 nbp->wp += packetlen; 200 memset(nbp->rp, 0, packetlen); 201 return nbp; 202 } 203 204 void 205 icmpadvise6(Proto *icmp, Block *bp, char *msg) 206 { 207 ushort recid; 208 Conv **c, *s; 209 IPICMP *p; 210 211 p = (IPICMP *)bp->rp; 212 recid = nhgets(p->icmpid); 213 214 for(c = icmp->conv; *c; c++) { 215 s = *c; 216 if(s->lport == recid && ipcmp(s->raddr, p->dst) == 0){ 217 qhangup(s->rq, msg); 218 qhangup(s->wq, msg); 219 break; 220 } 221 } 222 freeblist(bp); 223 } 224 225 static void 226 icmpkick6(void *x, Block *bp) 227 { 228 uchar laddr[IPaddrlen], raddr[IPaddrlen]; 229 Conv *c = x; 230 IPICMP *p; 231 Icmppriv6 *ipriv = c->p->priv; 232 Icmpcb6 *icb = (Icmpcb6*)c->ptcl; 233 234 if(bp == nil) 235 return; 236 237 if(icb->headers==6) { 238 /* get user specified addresses */ 239 bp = pullupblock(bp, ICMP_USEAD6); 240 if(bp == nil) 241 return; 242 bp->rp += 8; 243 ipmove(laddr, bp->rp); 244 bp->rp += IPaddrlen; 245 ipmove(raddr, bp->rp); 246 bp->rp += IPaddrlen; 247 bp = padblock(bp, sizeof(Ip6hdr)); 248 } 249 250 if(blocklen(bp) < sizeof(IPICMP)){ 251 freeblist(bp); 252 return; 253 } 254 p = (IPICMP *)(bp->rp); 255 if(icb->headers == 6) { 256 ipmove(p->dst, raddr); 257 ipmove(p->src, laddr); 258 } else { 259 ipmove(p->dst, c->raddr); 260 ipmove(p->src, c->laddr); 261 hnputs(p->icmpid, c->lport); 262 } 263 264 set_cksum(bp); 265 p->vcf[0] = 0x06 << 4; 266 if(p->type <= Maxtype6) 267 ipriv->out[p->type]++; 268 ipoput6(c->p->f, bp, 0, c->ttl, c->tos, nil); 269 } 270 271 char* 272 icmpctl6(Conv *c, char **argv, int argc) 273 { 274 Icmpcb6 *icb; 275 276 icb = (Icmpcb6*) c->ptcl; 277 if(argc==1 && strcmp(argv[0], "headers")==0) { 278 icb->headers = 6; 279 return nil; 280 } 281 return "unknown control request"; 282 } 283 284 static void 285 goticmpkt6(Proto *icmp, Block *bp, int muxkey) 286 { 287 ushort recid; 288 uchar *addr; 289 Conv **c, *s; 290 IPICMP *p = (IPICMP *)bp->rp; 291 292 if(muxkey == 0) { 293 recid = nhgets(p->icmpid); 294 addr = p->src; 295 } else { 296 recid = muxkey; 297 addr = p->dst; 298 } 299 300 for(c = icmp->conv; *c; c++){ 301 s = *c; 302 if(s->lport == recid && ipcmp(s->raddr, addr) == 0){ 303 bp = concatblock(bp); 304 if(bp != nil) 305 qpass(s->rq, bp); 306 return; 307 } 308 } 309 310 freeblist(bp); 311 } 312 313 static Block * 314 mkechoreply6(Block *bp, Ipifc *ifc) 315 { 316 uchar addr[IPaddrlen]; 317 IPICMP *p = (IPICMP *)(bp->rp); 318 319 ipmove(addr, p->src); 320 if(!isv6mcast(p->dst)) 321 ipmove(p->src, p->dst); 322 else if (!ipv6anylocal(ifc, p->src)) 323 return nil; 324 ipmove(p->dst, addr); 325 p->type = EchoReplyV6; 326 set_cksum(bp); 327 return bp; 328 } 329 330 /* 331 * sends out an ICMPv6 neighbor solicitation 332 * suni == SRC_UNSPEC or SRC_UNI, 333 * tuni == TARG_MULTI => multicast for address resolution, 334 * and tuni == TARG_UNI => neighbor reachability. 335 */ 336 extern void 337 icmpns(Fs *f, uchar* src, int suni, uchar* targ, int tuni, uchar* mac) 338 { 339 Block *nbp; 340 Ndpkt *np; 341 Proto *icmp = f->t2p[ICMPv6]; 342 Icmppriv6 *ipriv = icmp->priv; 343 344 nbp = newIPICMP(sizeof(Ndpkt)); 345 np = (Ndpkt*) nbp->rp; 346 347 if(suni == SRC_UNSPEC) 348 memmove(np->src, v6Unspecified, IPaddrlen); 349 else 350 memmove(np->src, src, IPaddrlen); 351 352 if(tuni == TARG_UNI) 353 memmove(np->dst, targ, IPaddrlen); 354 else 355 ipv62smcast(np->dst, targ); 356 357 np->type = NbrSolicit; 358 np->code = 0; 359 memmove(np->target, targ, IPaddrlen); 360 if(suni != SRC_UNSPEC) { 361 np->otype = SRC_LLADDR; 362 np->olen = 1; /* 1+1+6 = 8 = 1 8-octet */ 363 memmove(np->lnaddr, mac, sizeof(np->lnaddr)); 364 } else 365 nbp->wp -= sizeof(Ndpkt) - sizeof(NdiscC); 366 367 set_cksum(nbp); 368 np = (Ndpkt*)nbp->rp; 369 np->ttl = HOP_LIMIT; 370 np->vcf[0] = 0x06 << 4; 371 ipriv->out[NbrSolicit]++; 372 netlog(f, Logicmp, "sending neighbor solicitation %I\n", targ); 373 ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil); 374 } 375 376 /* 377 * sends out an ICMPv6 neighbor advertisement. pktflags == RSO flags. 378 */ 379 extern void 380 icmpna(Fs *f, uchar* src, uchar* dst, uchar* targ, uchar* mac, uchar flags) 381 { 382 Block *nbp; 383 Ndpkt *np; 384 Proto *icmp = f->t2p[ICMPv6]; 385 Icmppriv6 *ipriv = icmp->priv; 386 387 nbp = newIPICMP(sizeof(Ndpkt)); 388 np = (Ndpkt*)nbp->rp; 389 390 memmove(np->src, src, IPaddrlen); 391 memmove(np->dst, dst, IPaddrlen); 392 393 np->type = NbrAdvert; 394 np->code = 0; 395 np->icmpid[0] = flags; 396 memmove(np->target, targ, IPaddrlen); 397 398 np->otype = TARGET_LLADDR; 399 np->olen = 1; 400 memmove(np->lnaddr, mac, sizeof(np->lnaddr)); 401 402 set_cksum(nbp); 403 np = (Ndpkt*) nbp->rp; 404 np->ttl = HOP_LIMIT; 405 np->vcf[0] = 0x06 << 4; 406 ipriv->out[NbrAdvert]++; 407 netlog(f, Logicmp, "sending neighbor advertisement %I\n", src); 408 ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil); 409 } 410 411 extern void 412 icmphostunr(Fs *f, Ipifc *ifc, Block *bp, int code, int free) 413 { 414 int osz = BLEN(bp); 415 int sz = MIN(sizeof(IPICMP) + osz, v6MINTU); 416 Block *nbp; 417 IPICMP *np; 418 Ip6hdr *p; 419 Proto *icmp = f->t2p[ICMPv6]; 420 Icmppriv6 *ipriv = icmp->priv; 421 422 p = (Ip6hdr *)bp->rp; 423 424 if(isv6mcast(p->src)) 425 goto clean; 426 427 nbp = newIPICMP(sz); 428 np = (IPICMP *)nbp->rp; 429 430 rlock(ifc); 431 if(ipv6anylocal(ifc, np->src)) 432 netlog(f, Logicmp, "send icmphostunr -> s%I d%I\n", 433 p->src, p->dst); 434 else { 435 netlog(f, Logicmp, "icmphostunr fail -> s%I d%I\n", 436 p->src, p->dst); 437 freeblist(nbp); 438 if(free) 439 goto clean; 440 else 441 return; 442 } 443 444 memmove(np->dst, p->src, IPaddrlen); 445 np->type = UnreachableV6; 446 np->code = code; 447 memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP)); 448 set_cksum(nbp); 449 np->ttl = HOP_LIMIT; 450 np->vcf[0] = 0x06 << 4; 451 ipriv->out[UnreachableV6]++; 452 453 if(free) 454 ipiput6(f, ifc, nbp); 455 else { 456 ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil); 457 return; 458 } 459 460 clean: 461 runlock(ifc); 462 freeblist(bp); 463 } 464 465 extern void 466 icmpttlexceeded6(Fs *f, Ipifc *ifc, Block *bp) 467 { 468 int osz = BLEN(bp); 469 int sz = MIN(sizeof(IPICMP) + osz, v6MINTU); 470 Block *nbp; 471 IPICMP *np; 472 Ip6hdr *p; 473 Proto *icmp = f->t2p[ICMPv6]; 474 Icmppriv6 *ipriv = icmp->priv; 475 476 p = (Ip6hdr *)bp->rp; 477 478 if(isv6mcast(p->src)) 479 return; 480 481 nbp = newIPICMP(sz); 482 np = (IPICMP *) nbp->rp; 483 484 if(ipv6anylocal(ifc, np->src)) 485 netlog(f, Logicmp, "send icmpttlexceeded6 -> s%I d%I\n", 486 p->src, p->dst); 487 else { 488 netlog(f, Logicmp, "icmpttlexceeded6 fail -> s%I d%I\n", 489 p->src, p->dst); 490 return; 491 } 492 493 memmove(np->dst, p->src, IPaddrlen); 494 np->type = TimeExceedV6; 495 np->code = 0; 496 memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP)); 497 set_cksum(nbp); 498 np->ttl = HOP_LIMIT; 499 np->vcf[0] = 0x06 << 4; 500 ipriv->out[TimeExceedV6]++; 501 ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil); 502 } 503 504 extern void 505 icmppkttoobig6(Fs *f, Ipifc *ifc, Block *bp) 506 { 507 int osz = BLEN(bp); 508 int sz = MIN(sizeof(IPICMP) + osz, v6MINTU); 509 Block *nbp; 510 IPICMP *np; 511 Ip6hdr *p; 512 Proto *icmp = f->t2p[ICMPv6]; 513 Icmppriv6 *ipriv = icmp->priv; 514 515 p = (Ip6hdr *)bp->rp; 516 517 if(isv6mcast(p->src)) 518 return; 519 520 nbp = newIPICMP(sz); 521 np = (IPICMP *)nbp->rp; 522 523 if(ipv6anylocal(ifc, np->src)) 524 netlog(f, Logicmp, "send icmppkttoobig6 -> s%I d%I\n", 525 p->src, p->dst); 526 else { 527 netlog(f, Logicmp, "icmppkttoobig6 fail -> s%I d%I\n", 528 p->src, p->dst); 529 return; 530 } 531 532 memmove(np->dst, p->src, IPaddrlen); 533 np->type = PacketTooBigV6; 534 np->code = 0; 535 hnputl(np->icmpid, ifc->maxtu - ifc->m->hsize); 536 memmove(nbp->rp + sizeof(IPICMP), bp->rp, sz - sizeof(IPICMP)); 537 set_cksum(nbp); 538 np->ttl = HOP_LIMIT; 539 np->vcf[0] = 0x06 << 4; 540 ipriv->out[PacketTooBigV6]++; 541 ipoput6(f, nbp, 0, MAXTTL, DFLTTOS, nil); 542 } 543 544 /* 545 * RFC 2461, pages 39-40, pages 57-58. 546 */ 547 static int 548 valid(Proto *icmp, Ipifc *ifc, Block *bp, Icmppriv6 *ipriv) 549 { 550 int sz, osz, unsp, n, ttl, iplen; 551 int pktsz = BLEN(bp); 552 uchar *packet = bp->rp; 553 IPICMP *p = (IPICMP *) packet; 554 Ndpkt *np; 555 556 USED(ifc); 557 n = blocklen(bp); 558 if(n < sizeof(IPICMP)) { 559 ipriv->stats[HlenErrs6]++; 560 netlog(icmp->f, Logicmp, "icmp hlen %d\n", n); 561 goto err; 562 } 563 564 iplen = nhgets(p->ploadlen); 565 if(iplen > n-IPV6HDR_LEN || (iplen % 1)) { 566 ipriv->stats[LenErrs6]++; 567 netlog(icmp->f, Logicmp, "icmp length %d\n", iplen); 568 goto err; 569 } 570 571 /* Rather than construct explicit pseudoheader, overwrite IPv6 header */ 572 if(p->proto != ICMPv6) { 573 /* This code assumes no extension headers!!! */ 574 netlog(icmp->f, Logicmp, "icmp error: extension header\n"); 575 goto err; 576 } 577 memset(packet, 0, 4); 578 ttl = p->ttl; 579 p->ttl = p->proto; 580 p->proto = 0; 581 if(ptclcsum(bp, 0, iplen + IPV6HDR_LEN)) { 582 ipriv->stats[CsumErrs6]++; 583 netlog(icmp->f, Logicmp, "icmp checksum error\n"); 584 goto err; 585 } 586 p->proto = p->ttl; 587 p->ttl = ttl; 588 589 /* additional tests for some pkt types */ 590 if (p->type == NbrSolicit || p->type == NbrAdvert || 591 p->type == RouterAdvert || p->type == RouterSolicit || 592 p->type == RedirectV6) { 593 if(p->ttl != HOP_LIMIT) { 594 ipriv->stats[HoplimErrs6]++; 595 goto err; 596 } 597 if(p->code != 0) { 598 ipriv->stats[IcmpCodeErrs6]++; 599 goto err; 600 } 601 602 switch (p->type) { 603 case NbrSolicit: 604 case NbrAdvert: 605 np = (Ndpkt*) p; 606 if(isv6mcast(np->target)) { 607 ipriv->stats[TargetErrs6]++; 608 goto err; 609 } 610 if(optexsts(np) && np->olen == 0) { 611 ipriv->stats[OptlenErrs6]++; 612 goto err; 613 } 614 615 if (p->type == NbrSolicit && 616 ipcmp(np->src, v6Unspecified) == 0) 617 if(!issmcast(np->dst) || optexsts(np)) { 618 ipriv->stats[AddrmxpErrs6]++; 619 goto err; 620 } 621 622 if(p->type == NbrAdvert) 623 if(isv6mcast(np->dst) && 624 (nhgets(np->icmpid) & Sflag)){ 625 ipriv->stats[AddrmxpErrs6]++; 626 goto err; 627 } 628 break; 629 630 case RouterAdvert: 631 if(pktsz - sizeof(Ip6hdr) < 16) { 632 ipriv->stats[HlenErrs6]++; 633 goto err; 634 } 635 if(!islinklocal(p->src)) { 636 ipriv->stats[RouterAddrErrs6]++; 637 goto err; 638 } 639 sz = sizeof(IPICMP) + 8; 640 while (sz+1 < pktsz) { 641 osz = packet[sz+1]; 642 if(osz <= 0) { 643 ipriv->stats[OptlenErrs6]++; 644 goto err; 645 } 646 sz += 8*osz; 647 } 648 break; 649 650 case RouterSolicit: 651 if(pktsz - sizeof(Ip6hdr) < 8) { 652 ipriv->stats[HlenErrs6]++; 653 goto err; 654 } 655 unsp = (ipcmp(p->src, v6Unspecified) == 0); 656 sz = sizeof(IPICMP) + 8; 657 while (sz+1 < pktsz) { 658 osz = packet[sz+1]; 659 if(osz <= 0 || 660 (unsp && packet[sz] == SRC_LLADDR)) { 661 ipriv->stats[OptlenErrs6]++; 662 goto err; 663 } 664 sz += 8*osz; 665 } 666 break; 667 668 case RedirectV6: 669 /* to be filled in */ 670 break; 671 672 default: 673 goto err; 674 } 675 } 676 return 1; 677 err: 678 ipriv->stats[InErrors6]++; 679 return 0; 680 } 681 682 static int 683 targettype(Fs *f, Ipifc *ifc, uchar *target) 684 { 685 Iplifc *lifc; 686 int t; 687 688 rlock(ifc); 689 if(ipproxyifc(f, ifc, target)) { 690 runlock(ifc); 691 return t_uniproxy; 692 } 693 694 for(lifc = ifc->lifc; lifc; lifc = lifc->next) 695 if(ipcmp(lifc->local, target) == 0) { 696 t = (lifc->tentative)? t_unitent: t_unirany; 697 runlock(ifc); 698 return t; 699 } 700 701 runlock(ifc); 702 return 0; 703 } 704 705 static void 706 icmpiput6(Proto *icmp, Ipifc *ipifc, Block *bp) 707 { 708 int refresh = 1; 709 char *msg, m2[128]; 710 uchar pktflags; 711 uchar *packet = bp->rp; 712 uchar lsrc[IPaddrlen]; 713 Block *r; 714 IPICMP *p = (IPICMP *)packet; 715 Icmppriv6 *ipriv = icmp->priv; 716 Iplifc *lifc; 717 Ndpkt* np; 718 Proto *pr; 719 720 if(!valid(icmp, ipifc, bp, ipriv) || p->type > Maxtype6) 721 goto raise; 722 723 ipriv->in[p->type]++; 724 725 switch(p->type) { 726 case EchoRequestV6: 727 r = mkechoreply6(bp, ipifc); 728 if(r == nil) 729 goto raise; 730 ipriv->out[EchoReply]++; 731 ipoput6(icmp->f, r, 0, MAXTTL, DFLTTOS, nil); 732 break; 733 734 case UnreachableV6: 735 if(p->code > 4) 736 msg = unreachcode[icmp6_unkn_code]; 737 else 738 msg = unreachcode[p->code]; 739 740 bp->rp += sizeof(IPICMP); 741 if(blocklen(bp) < 8){ 742 ipriv->stats[LenErrs6]++; 743 goto raise; 744 } 745 p = (IPICMP *)bp->rp; 746 pr = Fsrcvpcolx(icmp->f, p->proto); 747 if(pr != nil && pr->advise != nil) { 748 (*pr->advise)(pr, bp, msg); 749 return; 750 } 751 752 bp->rp -= sizeof(IPICMP); 753 goticmpkt6(icmp, bp, 0); 754 break; 755 756 case TimeExceedV6: 757 if(p->code == 0){ 758 sprint(m2, "ttl exceeded at %I", p->src); 759 760 bp->rp += sizeof(IPICMP); 761 if(blocklen(bp) < 8){ 762 ipriv->stats[LenErrs6]++; 763 goto raise; 764 } 765 p = (IPICMP *)bp->rp; 766 pr = Fsrcvpcolx(icmp->f, p->proto); 767 if(pr && pr->advise) { 768 (*pr->advise)(pr, bp, m2); 769 return; 770 } 771 bp->rp -= sizeof(IPICMP); 772 } 773 774 goticmpkt6(icmp, bp, 0); 775 break; 776 777 case RouterAdvert: 778 case RouterSolicit: 779 /* using lsrc as a temp, munge hdr for goticmp6 */ 780 if (0) { 781 memmove(lsrc, p->src, IPaddrlen); 782 memmove(p->src, p->dst, IPaddrlen); 783 memmove(p->dst, lsrc, IPaddrlen); 784 } 785 goticmpkt6(icmp, bp, p->type); 786 break; 787 788 case NbrSolicit: 789 np = (Ndpkt*) p; 790 pktflags = 0; 791 switch (targettype(icmp->f, ipifc, np->target)) { 792 case t_unirany: 793 pktflags |= Oflag; 794 /* fall through */ 795 796 case t_uniproxy: 797 if(ipcmp(np->src, v6Unspecified) != 0) { 798 arpenter(icmp->f, V6, np->src, np->lnaddr, 799 8*np->olen-2, 0); 800 pktflags |= Sflag; 801 } 802 if(ipv6local(ipifc, lsrc)) 803 icmpna(icmp->f, lsrc, 804 (ipcmp(np->src, v6Unspecified) == 0? 805 v6allnodesL: np->src), 806 np->target, ipifc->mac, pktflags); 807 else 808 freeblist(bp); 809 break; 810 811 case t_unitent: 812 /* not clear what needs to be done. send up 813 * an icmp mesg saying don't use this address? */ 814 default: 815 freeblist(bp); 816 } 817 break; 818 819 case NbrAdvert: 820 np = (Ndpkt*) p; 821 822 /* 823 * if the target address matches one of the local interface 824 * addresses and the local interface address has tentative bit 825 * set, insert into ARP table. this is so the duplicate address 826 * detection part of ipconfig can discover duplication through 827 * the arp table. 828 */ 829 lifc = iplocalonifc(ipifc, np->target); 830 if(lifc && lifc->tentative) 831 refresh = 0; 832 arpenter(icmp->f, V6, np->target, np->lnaddr, 8*np->olen-2, 833 refresh); 834 freeblist(bp); 835 break; 836 837 case PacketTooBigV6: 838 default: 839 goticmpkt6(icmp, bp, 0); 840 break; 841 } 842 return; 843 raise: 844 freeblist(bp); 845 } 846 847 int 848 icmpstats6(Proto *icmp6, char *buf, int len) 849 { 850 Icmppriv6 *priv; 851 char *p, *e; 852 int i; 853 854 priv = icmp6->priv; 855 p = buf; 856 e = p+len; 857 for(i = 0; i < Nstats6; i++) 858 p = seprint(p, e, "%s: %lud\n", statnames6[i], priv->stats[i]); 859 for(i = 0; i <= Maxtype6; i++) 860 if(icmpnames6[i]) 861 p = seprint(p, e, "%s: %lud %lud\n", icmpnames6[i], 862 priv->in[i], priv->out[i]); 863 /* else 864 p = seprint(p, e, "%d: %lud %lud\n", i, priv->in[i], 865 priv->out[i]); 866 */ 867 return p - buf; 868 } 869 870 871 /* import from icmp.c */ 872 extern int icmpstate(Conv *c, char *state, int n); 873 extern char* icmpannounce(Conv *c, char **argv, int argc); 874 extern char* icmpconnect(Conv *c, char **argv, int argc); 875 extern void icmpclose(Conv *c); 876 877 void 878 icmp6init(Fs *fs) 879 { 880 Proto *icmp6 = smalloc(sizeof(Proto)); 881 882 icmp6->priv = smalloc(sizeof(Icmppriv6)); 883 icmp6->name = "icmpv6"; 884 icmp6->connect = icmpconnect; 885 icmp6->announce = icmpannounce; 886 icmp6->state = icmpstate; 887 icmp6->create = icmpcreate6; 888 icmp6->close = icmpclose; 889 icmp6->rcv = icmpiput6; 890 icmp6->stats = icmpstats6; 891 icmp6->ctl = icmpctl6; 892 icmp6->advise = icmpadvise6; 893 icmp6->gc = nil; 894 icmp6->ipproto = ICMPv6; 895 icmp6->nc = 16; 896 icmp6->ptclsize = sizeof(Icmpcb6); 897 898 Fsproto(fs, icmp6); 899 } 900