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