il.c (27215B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 8 #include "ip.h" 9 10 enum /* Connection state */ 11 { 12 Ilclosed, 13 Ilsyncer, 14 Ilsyncee, 15 Ilestablished, 16 Illistening, 17 Ilclosing, 18 Ilopening, /* only for file server */ 19 }; 20 21 char *ilstates[] = 22 { 23 "Closed", 24 "Syncer", 25 "Syncee", 26 "Established", 27 "Listen", 28 "Closing", 29 "Opening", /* only for file server */ 30 }; 31 32 enum /* Packet types */ 33 { 34 Ilsync, 35 Ildata, 36 Ildataquery, 37 Ilack, 38 Ilquery, 39 Ilstate, 40 Ilclose, 41 }; 42 43 char *iltype[] = 44 { 45 "sync", 46 "data", 47 "dataquery", 48 "ack", 49 "query", 50 "state", 51 "close" 52 }; 53 54 enum 55 { 56 Seconds = 1000, 57 Iltickms = 50, /* time base */ 58 AckDelay = 2*Iltickms, /* max time twixt message rcvd & ack sent */ 59 MaxTimeout = 30*Seconds, /* max time between rexmit */ 60 QueryTime = 10*Seconds, /* time between subsequent queries */ 61 DeathTime = 30*QueryTime, 62 63 MaxRexmit = 16, /* max retransmissions before hangup */ 64 Defaultwin = 20, 65 66 LogAGain = 3, 67 AGain = 1<<LogAGain, 68 LogDGain = 2, 69 DGain = 1<<LogDGain, 70 71 DefByteRate = 100, /* assume a megabit link */ 72 DefRtt = 50, /* cross country on a great day */ 73 74 Maxrq = 64*1024, 75 }; 76 77 enum 78 { 79 Nqt= 8, 80 }; 81 82 typedef struct Ilcb Ilcb; 83 struct Ilcb /* Control block */ 84 { 85 int state; /* Connection state */ 86 Conv *conv; 87 QLock ackq; /* Unacknowledged queue */ 88 Block *unacked; 89 Block *unackedtail; 90 ulong unackedbytes; 91 QLock outo; /* Out of order packet queue */ 92 Block *outoforder; 93 ulong next; /* Id of next to send */ 94 ulong recvd; /* Last packet received */ 95 ulong acksent; /* Last packet acked */ 96 ulong start; /* Local start id */ 97 ulong rstart; /* Remote start id */ 98 int window; /* Maximum receive window */ 99 int rxquery; /* number of queries on this connection */ 100 int rxtot; /* number of retransmits on this connection */ 101 int rexmit; /* number of retransmits of *unacked */ 102 ulong qt[Nqt+1]; /* state table for query messages */ 103 int qtx; /* ... index into qt */ 104 105 /* if set, fasttimeout causes a connection request to terminate after 4*Iltickms */ 106 int fasttimeout; 107 108 /* timers */ 109 ulong lastxmit; /* time of last xmit */ 110 ulong lastrecv; /* time of last recv */ 111 ulong timeout; /* retransmission time for *unacked */ 112 ulong acktime; /* time to send next ack */ 113 ulong querytime; /* time to send next query */ 114 115 /* adaptive measurements */ 116 int delay; /* Average of the fixed rtt delay */ 117 int rate; /* Average uchar rate */ 118 int mdev; /* Mean deviation of rtt */ 119 int maxrtt; /* largest rtt seen */ 120 ulong rttack; /* The ack we are waiting for */ 121 int rttlen; /* Length of rttack packet */ 122 uvlong rttstart; /* Time we issued rttack packet */ 123 }; 124 125 enum 126 { 127 IL_IPSIZE = 20, 128 IL_HDRSIZE = 18, 129 IL_LISTEN = 0, 130 IL_CONNECT = 1, 131 IP_ILPROTO = 40, 132 }; 133 134 typedef struct Ilhdr Ilhdr; 135 struct Ilhdr 136 { 137 uchar vihl; /* Version and header length */ 138 uchar tos; /* Type of service */ 139 uchar length[2]; /* packet length */ 140 uchar id[2]; /* Identification */ 141 uchar frag[2]; /* Fragment information */ 142 uchar ttl; /* Time to live */ 143 uchar proto; /* Protocol */ 144 uchar cksum[2]; /* Header checksum */ 145 uchar src[4]; /* Ip source */ 146 uchar dst[4]; /* Ip destination */ 147 uchar ilsum[2]; /* Checksum including header */ 148 uchar illen[2]; /* Packet length */ 149 uchar iltype; /* Packet type */ 150 uchar ilspec; /* Special */ 151 uchar ilsrc[2]; /* Src port */ 152 uchar ildst[2]; /* Dst port */ 153 uchar ilid[4]; /* Sequence id */ 154 uchar ilack[4]; /* Acked sequence */ 155 }; 156 157 enum 158 { 159 InMsgs, 160 OutMsgs, 161 CsumErrs, /* checksum errors */ 162 HlenErrs, /* header length error */ 163 LenErrs, /* short packet */ 164 OutOfOrder, /* out of order */ 165 Retrans, /* retransmissions */ 166 DupMsg, 167 DupBytes, 168 DroppedMsgs, 169 170 Nstats, 171 }; 172 173 static char *statnames[] = 174 { 175 [InMsgs] "InMsgs", 176 [OutMsgs] "OutMsgs", 177 [CsumErrs] "CsumErrs", 178 [HlenErrs] "HlenErr", 179 [LenErrs] "LenErrs", 180 [OutOfOrder] "OutOfOrder", 181 [Retrans] "Retrans", 182 [DupMsg] "DupMsg", 183 [DupBytes] "DupBytes", 184 [DroppedMsgs] "DroppedMsgs", 185 }; 186 187 typedef struct Ilpriv Ilpriv; 188 struct Ilpriv 189 { 190 Ipht ht; 191 192 ulong stats[Nstats]; 193 194 ulong csumerr; /* checksum errors */ 195 ulong hlenerr; /* header length error */ 196 ulong lenerr; /* short packet */ 197 ulong order; /* out of order */ 198 ulong rexmit; /* retransmissions */ 199 ulong dup; 200 ulong dupb; 201 202 /* keeping track of the ack kproc */ 203 int ackprocstarted; 204 QLock apl; 205 }; 206 207 /* state for query/dataquery messages */ 208 209 210 void ilrcvmsg(Conv*, Block*); 211 void ilsendctl(Conv*, Ilhdr*, int, ulong, ulong, int); 212 void ilackq(Ilcb*, Block*); 213 void ilprocess(Conv*, Ilhdr*, Block*); 214 void ilpullup(Conv*); 215 void ilhangup(Conv*, char*); 216 void ilfreeq(Ilcb*); 217 void ilrexmit(Ilcb*); 218 void ilbackoff(Ilcb*); 219 void ilsettimeout(Ilcb*); 220 char* ilstart(Conv*, int, int); 221 void ilackproc(void*); 222 void iloutoforder(Conv*, Ilhdr*, Block*); 223 void iliput(Proto*, Ipifc*, Block*); 224 void iladvise(Proto*, Block*, char*); 225 int ilnextqt(Ilcb*); 226 void ilcbinit(Ilcb*); 227 int later(ulong, ulong, char*); 228 void ilreject(Fs*, Ilhdr*); 229 void illocalclose(Conv *c); 230 int ilcksum = 1; 231 static int initseq = 25001; 232 static ulong scalediv, scalemul; 233 static char *etime = "connection timed out"; 234 235 static char* 236 ilconnect(Conv *c, char **argv, int argc) 237 { 238 char *e, *p; 239 int fast; 240 241 /* huge hack to quickly try an il connection */ 242 fast = 0; 243 if(argc > 1){ 244 p = strstr(argv[1], "!fasttimeout"); 245 if(p != nil){ 246 *p = 0; 247 fast = 1; 248 } 249 } 250 251 e = Fsstdconnect(c, argv, argc); 252 if(e != nil) 253 return e; 254 return ilstart(c, IL_CONNECT, fast); 255 } 256 257 static int 258 ilstate(Conv *c, char *state, int n) 259 { 260 Ilcb *ic; 261 262 ic = (Ilcb*)(c->ptcl); 263 return snprint(state, n, "%s qin %d qout %d del %5.5d Br %5.5d md %5.5d una %5.5lud rex %5.5d rxq %5.5d max %5.5d\n", 264 ilstates[ic->state], 265 c->rq ? qlen(c->rq) : 0, 266 c->wq ? qlen(c->wq) : 0, 267 ic->delay>>LogAGain, ic->rate>>LogAGain, ic->mdev>>LogDGain, 268 ic->unackedbytes, ic->rxtot, ic->rxquery, ic->maxrtt); 269 } 270 271 static int 272 ilinuse(Conv *c) 273 { 274 Ilcb *ic; 275 276 ic = (Ilcb*)(c->ptcl); 277 return ic->state != Ilclosed; 278 279 } 280 281 /* called with c locked */ 282 static char* 283 ilannounce(Conv *c, char **argv, int argc) 284 { 285 char *e; 286 287 e = Fsstdannounce(c, argv, argc); 288 if(e != nil) 289 return e; 290 e = ilstart(c, IL_LISTEN, 0); 291 if(e != nil) 292 return e; 293 Fsconnected(c, nil); 294 295 return nil; 296 } 297 298 void 299 illocalclose(Conv *c) 300 { 301 Ilcb *ic; 302 Ilpriv *ipriv; 303 304 ipriv = c->p->priv; 305 ic = (Ilcb*)c->ptcl; 306 ic->state = Ilclosed; 307 iphtrem(&ipriv->ht, c); 308 ipmove(c->laddr, IPnoaddr); 309 c->lport = 0; 310 } 311 312 static void 313 ilclose(Conv *c) 314 { 315 Ilcb *ic; 316 317 ic = (Ilcb*)c->ptcl; 318 319 qclose(c->rq); 320 qclose(c->wq); 321 qclose(c->eq); 322 323 switch(ic->state) { 324 case Ilclosing: 325 case Ilclosed: 326 break; 327 case Ilsyncer: 328 case Ilsyncee: 329 case Ilestablished: 330 ic->state = Ilclosing; 331 ilsettimeout(ic); 332 ilsendctl(c, nil, Ilclose, ic->next, ic->recvd, 0); 333 break; 334 case Illistening: 335 illocalclose(c); 336 break; 337 } 338 ilfreeq(ic); 339 } 340 341 void 342 ilkick(void *x, Block *bp) 343 { 344 Conv *c = x; 345 Ilhdr *ih; 346 Ilcb *ic; 347 int dlen; 348 ulong id, ack; 349 Fs *f; 350 Ilpriv *priv; 351 352 f = c->p->f; 353 priv = c->p->priv; 354 ic = (Ilcb*)c->ptcl; 355 356 if(bp == nil) 357 return; 358 359 switch(ic->state) { 360 case Ilclosed: 361 case Illistening: 362 case Ilclosing: 363 freeblist(bp); 364 qhangup(c->rq, nil); 365 return; 366 } 367 368 dlen = blocklen(bp); 369 370 /* Make space to fit il & ip */ 371 bp = padblock(bp, IL_IPSIZE+IL_HDRSIZE); 372 ih = (Ilhdr *)(bp->rp); 373 ih->vihl = IP_VER4; 374 375 /* Ip fields */ 376 ih->frag[0] = 0; 377 ih->frag[1] = 0; 378 v6tov4(ih->dst, c->raddr); 379 v6tov4(ih->src, c->laddr); 380 ih->proto = IP_ILPROTO; 381 382 /* Il fields */ 383 hnputs(ih->illen, dlen+IL_HDRSIZE); 384 hnputs(ih->ilsrc, c->lport); 385 hnputs(ih->ildst, c->rport); 386 387 qlock(&ic->ackq); 388 id = ic->next++; 389 hnputl(ih->ilid, id); 390 ack = ic->recvd; 391 hnputl(ih->ilack, ack); 392 ic->acksent = ack; 393 ic->acktime = NOW + AckDelay; 394 ih->iltype = Ildata; 395 ih->ilspec = 0; 396 ih->ilsum[0] = 0; 397 ih->ilsum[1] = 0; 398 399 /* Checksum of ilheader plus data (not ip & no pseudo header) */ 400 if(ilcksum) 401 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, dlen+IL_HDRSIZE)); 402 403 ilackq(ic, bp); 404 qunlock(&ic->ackq); 405 406 /* Start the round trip timer for this packet if the timer is free */ 407 if(ic->rttack == 0) { 408 ic->rttack = id; 409 ic->rttstart = fastticks(nil); 410 ic->rttlen = dlen + IL_IPSIZE + IL_HDRSIZE; 411 } 412 413 if(later(NOW, ic->timeout, nil)) 414 ilsettimeout(ic); 415 ipoput4(f, bp, 0, c->ttl, c->tos, c); 416 priv->stats[OutMsgs]++; 417 } 418 419 static void 420 ilcreate(Conv *c) 421 { 422 c->rq = qopen(Maxrq, 0, 0, c); 423 c->wq = qbypass(ilkick, c); 424 } 425 426 int 427 ilxstats(Proto *il, char *buf, int len) 428 { 429 Ilpriv *priv; 430 char *p, *e; 431 int i; 432 433 priv = il->priv; 434 p = buf; 435 e = p+len; 436 for(i = 0; i < Nstats; i++) 437 p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]); 438 return p - buf; 439 } 440 441 void 442 ilackq(Ilcb *ic, Block *bp) 443 { 444 Block *np; 445 int n; 446 447 n = blocklen(bp); 448 449 /* Enqueue a copy on the unacked queue in case this one gets lost */ 450 np = copyblock(bp, n); 451 if(ic->unacked) 452 ic->unackedtail->list = np; 453 else 454 ic->unacked = np; 455 ic->unackedtail = np; 456 np->list = nil; 457 ic->unackedbytes += n; 458 } 459 460 static 461 void 462 ilrttcalc(Ilcb *ic, Block *bp) 463 { 464 int rtt, tt, pt, delay, rate; 465 466 rtt = fastticks(nil) - ic->rttstart; 467 rtt = (rtt*scalemul)/scalediv; 468 delay = ic->delay; 469 rate = ic->rate; 470 471 /* Guard against zero wrap */ 472 if(rtt > 120000 || rtt < 0) 473 return; 474 475 /* this block had to be transmitted after the one acked so count its size */ 476 ic->rttlen += blocklen(bp) + IL_IPSIZE + IL_HDRSIZE; 477 478 if(ic->rttlen < 256){ 479 /* guess fixed delay as rtt of small packets */ 480 delay += rtt - (delay>>LogAGain); 481 if(delay < AGain) 482 delay = AGain; 483 ic->delay = delay; 484 } else { 485 /* if packet took longer than avg rtt delay, recalc rate */ 486 tt = rtt - (delay>>LogAGain); 487 if(tt > 0){ 488 rate += ic->rttlen/tt - (rate>>LogAGain); 489 if(rate < AGain) 490 rate = AGain; 491 ic->rate = rate; 492 } 493 } 494 495 /* mdev */ 496 pt = ic->rttlen/(rate>>LogAGain) + (delay>>LogAGain); 497 ic->mdev += abs(rtt-pt) - (ic->mdev>>LogDGain); 498 499 if(rtt > ic->maxrtt) 500 ic->maxrtt = rtt; 501 } 502 503 void 504 ilackto(Ilcb *ic, ulong ackto, Block *bp) 505 { 506 Ilhdr *h; 507 ulong id; 508 509 if(ic->rttack == ackto) 510 ilrttcalc(ic, bp); 511 512 /* Cancel if we've passed the packet we were interested in */ 513 if(ic->rttack <= ackto) 514 ic->rttack = 0; 515 516 qlock(&ic->ackq); 517 while(ic->unacked) { 518 h = (Ilhdr *)ic->unacked->rp; 519 id = nhgetl(h->ilid); 520 if(ackto < id) 521 break; 522 523 bp = ic->unacked; 524 ic->unacked = bp->list; 525 bp->list = nil; 526 ic->unackedbytes -= blocklen(bp); 527 freeblist(bp); 528 ic->rexmit = 0; 529 ilsettimeout(ic); 530 } 531 qunlock(&ic->ackq); 532 } 533 534 void 535 iliput(Proto *il, Ipifc *dummy, Block *bp) 536 { 537 char *st; 538 Ilcb *ic; 539 Ilhdr *ih; 540 uchar raddr[IPaddrlen]; 541 uchar laddr[IPaddrlen]; 542 ushort sp, dp, csum; 543 int plen, illen; 544 Conv *new, *s; 545 Ilpriv *ipriv; 546 547 ipriv = il->priv; 548 549 ih = (Ilhdr *)bp->rp; 550 plen = blocklen(bp); 551 if(plen < IL_IPSIZE+IL_HDRSIZE){ 552 netlog(il->f, Logil, "il: hlenerr\n"); 553 ipriv->stats[HlenErrs]++; 554 goto raise; 555 } 556 557 illen = nhgets(ih->illen); 558 if(illen+IL_IPSIZE > plen){ 559 netlog(il->f, Logil, "il: lenerr\n"); 560 ipriv->stats[LenErrs]++; 561 goto raise; 562 } 563 564 sp = nhgets(ih->ildst); 565 dp = nhgets(ih->ilsrc); 566 v4tov6(raddr, ih->src); 567 v4tov6(laddr, ih->dst); 568 569 if((csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) { 570 if(ih->iltype > Ilclose) 571 st = "?"; 572 else 573 st = iltype[ih->iltype]; 574 ipriv->stats[CsumErrs]++; 575 netlog(il->f, Logil, "il: cksum %ux %ux, pkt(%s id %lud ack %lud %I/%d->%d)\n", 576 csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp); 577 goto raise; 578 } 579 580 QLOCK(il); 581 s = iphtlook(&ipriv->ht, raddr, dp, laddr, sp); 582 if(s == nil){ 583 if(ih->iltype == Ilsync) 584 ilreject(il->f, ih); /* no listener */ 585 QUNLOCK(il); 586 goto raise; 587 } 588 589 ic = (Ilcb*)s->ptcl; 590 if(ic->state == Illistening){ 591 if(ih->iltype != Ilsync){ 592 QUNLOCK(il); 593 if(ih->iltype > Ilclose) 594 st = "?"; 595 else 596 st = iltype[ih->iltype]; 597 ilreject(il->f, ih); /* no channel and not sync */ 598 netlog(il->f, Logil, "il: no channel, pkt(%s id %lud ack %lud %I/%ud->%ud)\n", 599 st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp); 600 goto raise; 601 } 602 603 new = Fsnewcall(s, raddr, dp, laddr, sp, V4); 604 if(new == nil){ 605 QUNLOCK(il); 606 netlog(il->f, Logil, "il: bad newcall %I/%ud->%ud\n", raddr, sp, dp); 607 ilsendctl(s, ih, Ilclose, 0, nhgetl(ih->ilid), 0); 608 goto raise; 609 } 610 s = new; 611 612 ic = (Ilcb*)s->ptcl; 613 614 ic->conv = s; 615 ic->state = Ilsyncee; 616 ilcbinit(ic); 617 ic->rstart = nhgetl(ih->ilid); 618 iphtadd(&ipriv->ht, s); 619 } 620 621 QLOCK(s); 622 QUNLOCK(il); 623 if(waserror()){ 624 QUNLOCK(s); 625 nexterror(); 626 } 627 ilprocess(s, ih, bp); 628 QUNLOCK(s); 629 poperror(); 630 return; 631 raise: 632 freeblist(bp); 633 } 634 635 void 636 _ilprocess(Conv *s, Ilhdr *h, Block *bp) 637 { 638 Ilcb *ic; 639 ulong id, ack; 640 Ilpriv *priv; 641 642 id = nhgetl(h->ilid); 643 ack = nhgetl(h->ilack); 644 645 ic = (Ilcb*)s->ptcl; 646 647 ic->lastrecv = NOW; 648 ic->querytime = NOW + QueryTime; 649 priv = s->p->priv; 650 priv->stats[InMsgs]++; 651 652 switch(ic->state) { 653 default: 654 netlog(s->p->f, Logil, "il: unknown state %d\n", ic->state); 655 case Ilclosed: 656 freeblist(bp); 657 break; 658 case Ilsyncer: 659 switch(h->iltype) { 660 default: 661 break; 662 case Ilsync: 663 if(ack != ic->start) 664 ilhangup(s, "connection rejected"); 665 else { 666 ic->recvd = id; 667 ic->rstart = id; 668 ilsendctl(s, nil, Ilack, ic->next, ic->recvd, 0); 669 ic->state = Ilestablished; 670 ic->fasttimeout = 0; 671 ic->rexmit = 0; 672 Fsconnected(s, nil); 673 ilpullup(s); 674 } 675 break; 676 case Ilclose: 677 if(ack == ic->start) 678 ilhangup(s, "connection rejected"); 679 break; 680 } 681 freeblist(bp); 682 break; 683 case Ilsyncee: 684 switch(h->iltype) { 685 default: 686 break; 687 case Ilsync: 688 if(id != ic->rstart || ack != 0){ 689 illocalclose(s); 690 } else { 691 ic->recvd = id; 692 ilsendctl(s, nil, Ilsync, ic->start, ic->recvd, 0); 693 } 694 break; 695 case Ilack: 696 if(ack == ic->start) { 697 ic->state = Ilestablished; 698 ic->fasttimeout = 0; 699 ic->rexmit = 0; 700 ilpullup(s); 701 } 702 break; 703 case Ildata: 704 if(ack == ic->start) { 705 ic->state = Ilestablished; 706 ic->fasttimeout = 0; 707 ic->rexmit = 0; 708 goto established; 709 } 710 break; 711 case Ilclose: 712 if(ack == ic->start) 713 ilhangup(s, "remote close"); 714 break; 715 } 716 freeblist(bp); 717 break; 718 case Ilestablished: 719 established: 720 switch(h->iltype) { 721 case Ilsync: 722 if(id != ic->rstart) 723 ilhangup(s, "remote close"); 724 else 725 ilsendctl(s, nil, Ilack, ic->next, ic->rstart, 0); 726 freeblist(bp); 727 break; 728 case Ildata: 729 /* 730 * avoid consuming all the mount rpc buffers in the 731 * system. if the input queue is too long, drop this 732 * packet. 733 */ 734 if (s->rq && qlen(s->rq) >= Maxrq) { 735 priv->stats[DroppedMsgs]++; 736 freeblist(bp); 737 break; 738 } 739 740 ilackto(ic, ack, bp); 741 iloutoforder(s, h, bp); 742 ilpullup(s); 743 break; 744 case Ildataquery: 745 ilackto(ic, ack, bp); 746 iloutoforder(s, h, bp); 747 ilpullup(s); 748 ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec); 749 break; 750 case Ilack: 751 ilackto(ic, ack, bp); 752 freeblist(bp); 753 break; 754 case Ilquery: 755 ilackto(ic, ack, bp); 756 ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec); 757 freeblist(bp); 758 break; 759 case Ilstate: 760 if(ack >= ic->rttack) 761 ic->rttack = 0; 762 ilackto(ic, ack, bp); 763 if(h->ilspec > Nqt) 764 h->ilspec = 0; 765 if(ic->qt[h->ilspec] > ack){ 766 ilrexmit(ic); 767 ilsettimeout(ic); 768 } 769 freeblist(bp); 770 break; 771 case Ilclose: 772 freeblist(bp); 773 if(ack < ic->start || ack > ic->next) 774 break; 775 ic->recvd = id; 776 ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0); 777 ic->state = Ilclosing; 778 ilsettimeout(ic); 779 ilfreeq(ic); 780 break; 781 } 782 break; 783 case Illistening: 784 freeblist(bp); 785 break; 786 case Ilclosing: 787 switch(h->iltype) { 788 case Ilclose: 789 ic->recvd = id; 790 ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0); 791 if(ack == ic->next) 792 ilhangup(s, nil); 793 break; 794 default: 795 break; 796 } 797 freeblist(bp); 798 break; 799 } 800 } 801 802 void 803 ilrexmit(Ilcb *ic) 804 { 805 Ilhdr *h; 806 Block *nb; 807 Conv *c; 808 ulong id; 809 Ilpriv *priv; 810 811 nb = nil; 812 qlock(&ic->ackq); 813 if(ic->unacked) 814 nb = copyblock(ic->unacked, blocklen(ic->unacked)); 815 qunlock(&ic->ackq); 816 817 if(nb == nil) 818 return; 819 820 h = (Ilhdr*)nb->rp; 821 h->vihl = IP_VER4; 822 823 h->iltype = Ildataquery; 824 hnputl(h->ilack, ic->recvd); 825 h->ilspec = ilnextqt(ic); 826 h->ilsum[0] = 0; 827 h->ilsum[1] = 0; 828 hnputs(h->ilsum, ptclcsum(nb, IL_IPSIZE, nhgets(h->illen))); 829 830 c = ic->conv; 831 id = nhgetl(h->ilid); 832 netlog(c->p->f, Logil, "il: rexmit %d %ud: %d %d: %i %d/%d\n", id, ic->recvd, 833 ic->rexmit, ic->timeout, 834 c->raddr, c->lport, c->rport); 835 836 ilbackoff(ic); 837 838 ipoput4(c->p->f, nb, 0, c->ttl, c->tos, c); 839 840 /* statistics */ 841 ic->rxtot++; 842 priv = c->p->priv; 843 priv->rexmit++; 844 } 845 846 /* DEBUG */ 847 void 848 ilprocess(Conv *s, Ilhdr *h, Block *bp) 849 { 850 Ilcb *ic; 851 852 ic = (Ilcb*)s->ptcl; 853 854 USED(ic); 855 netlog(s->p->f, Logilmsg, "%11s rcv %d/%d snt %d/%d pkt(%s id %d ack %d %d->%d) ", 856 ilstates[ic->state], ic->rstart, ic->recvd, ic->start, 857 ic->next, iltype[h->iltype], nhgetl(h->ilid), 858 nhgetl(h->ilack), nhgets(h->ilsrc), nhgets(h->ildst)); 859 860 _ilprocess(s, h, bp); 861 862 netlog(s->p->f, Logilmsg, "%11s rcv %d snt %d\n", ilstates[ic->state], ic->recvd, ic->next); 863 } 864 865 void 866 ilhangup(Conv *s, char *msg) 867 { 868 Ilcb *ic; 869 int callout; 870 871 netlog(s->p->f, Logil, "il: hangup! %I %d/%d: %s\n", s->raddr, 872 s->lport, s->rport, msg?msg:"no reason"); 873 874 ic = (Ilcb*)s->ptcl; 875 callout = ic->state == Ilsyncer; 876 illocalclose(s); 877 878 qhangup(s->rq, msg); 879 qhangup(s->wq, msg); 880 881 if(callout) 882 Fsconnected(s, msg); 883 } 884 885 void 886 ilpullup(Conv *s) 887 { 888 Ilcb *ic; 889 Ilhdr *oh; 890 Block *bp; 891 ulong oid, dlen; 892 Ilpriv *ipriv; 893 894 ic = (Ilcb*)s->ptcl; 895 if(ic->state != Ilestablished) 896 return; 897 898 qlock(&ic->outo); 899 while(ic->outoforder) { 900 bp = ic->outoforder; 901 oh = (Ilhdr*)bp->rp; 902 oid = nhgetl(oh->ilid); 903 if(oid <= ic->recvd) { 904 ic->outoforder = bp->list; 905 freeblist(bp); 906 continue; 907 } 908 if(oid != ic->recvd+1){ 909 ipriv = s->p->priv; 910 ipriv->stats[OutOfOrder]++; 911 break; 912 } 913 914 ic->recvd = oid; 915 ic->outoforder = bp->list; 916 917 bp->list = nil; 918 dlen = nhgets(oh->illen)-IL_HDRSIZE; 919 bp = trimblock(bp, IL_IPSIZE+IL_HDRSIZE, dlen); 920 /* 921 * Upper levels don't know about multiple-block 922 * messages so copy all into one (yick). 923 */ 924 bp = concatblock(bp); 925 if(bp == 0) 926 panic("ilpullup"); 927 bp = packblock(bp); 928 if(bp == 0) 929 panic("ilpullup2"); 930 qpass(s->rq, bp); 931 } 932 qunlock(&ic->outo); 933 } 934 935 void 936 iloutoforder(Conv *s, Ilhdr *h, Block *bp) 937 { 938 Ilcb *ic; 939 uchar *lid; 940 Block *f, **l; 941 ulong id, newid; 942 Ilpriv *ipriv; 943 944 ipriv = s->p->priv; 945 ic = (Ilcb*)s->ptcl; 946 bp->list = nil; 947 948 id = nhgetl(h->ilid); 949 /* Window checks */ 950 if(id <= ic->recvd || id > ic->recvd+ic->window) { 951 netlog(s->p->f, Logil, "il: message outside window %ud <%ud-%ud>: %i %d/%d\n", 952 id, ic->recvd, ic->recvd+ic->window, s->raddr, s->lport, s->rport); 953 freeblist(bp); 954 return; 955 } 956 957 /* Packet is acceptable so sort onto receive queue for pullup */ 958 qlock(&ic->outo); 959 if(ic->outoforder == nil) 960 ic->outoforder = bp; 961 else { 962 l = &ic->outoforder; 963 for(f = *l; f; f = f->list) { 964 lid = ((Ilhdr*)(f->rp))->ilid; 965 newid = nhgetl(lid); 966 if(id <= newid) { 967 if(id == newid) { 968 ipriv->stats[DupMsg]++; 969 ipriv->stats[DupBytes] += blocklen(bp); 970 qunlock(&ic->outo); 971 freeblist(bp); 972 return; 973 } 974 bp->list = f; 975 *l = bp; 976 qunlock(&ic->outo); 977 return; 978 } 979 l = &f->list; 980 } 981 *l = bp; 982 } 983 qunlock(&ic->outo); 984 } 985 986 void 987 ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec) 988 { 989 Ilhdr *ih; 990 Ilcb *ic; 991 Block *bp; 992 int ttl, tos; 993 994 bp = allocb(IL_IPSIZE+IL_HDRSIZE); 995 bp->wp += IL_IPSIZE+IL_HDRSIZE; 996 997 ih = (Ilhdr *)(bp->rp); 998 ih->vihl = IP_VER4; 999 1000 /* Ip fields */ 1001 ih->proto = IP_ILPROTO; 1002 hnputs(ih->illen, IL_HDRSIZE); 1003 ih->frag[0] = 0; 1004 ih->frag[1] = 0; 1005 if(inih) { 1006 hnputl(ih->dst, nhgetl(inih->src)); 1007 hnputl(ih->src, nhgetl(inih->dst)); 1008 hnputs(ih->ilsrc, nhgets(inih->ildst)); 1009 hnputs(ih->ildst, nhgets(inih->ilsrc)); 1010 hnputl(ih->ilid, nhgetl(inih->ilack)); 1011 hnputl(ih->ilack, nhgetl(inih->ilid)); 1012 ttl = MAXTTL; 1013 tos = DFLTTOS; 1014 } 1015 else { 1016 v6tov4(ih->dst, ipc->raddr); 1017 v6tov4(ih->src, ipc->laddr); 1018 hnputs(ih->ilsrc, ipc->lport); 1019 hnputs(ih->ildst, ipc->rport); 1020 hnputl(ih->ilid, id); 1021 hnputl(ih->ilack, ack); 1022 ic = (Ilcb*)ipc->ptcl; 1023 ic->acksent = ack; 1024 ic->acktime = NOW; 1025 ttl = ipc->ttl; 1026 tos = ipc->tos; 1027 } 1028 ih->iltype = type; 1029 ih->ilspec = ilspec; 1030 ih->ilsum[0] = 0; 1031 ih->ilsum[1] = 0; 1032 1033 if(ilcksum) 1034 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE)); 1035 1036 if(ipc==nil) 1037 panic("ipc is nil caller is %#p", getcallerpc(&ipc)); 1038 if(ipc->p==nil) 1039 panic("ipc->p is nil"); 1040 1041 netlog(ipc->p->f, Logilmsg, "ctl(%s id %d ack %d %d->%d)\n", 1042 iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack), 1043 nhgets(ih->ilsrc), nhgets(ih->ildst)); 1044 1045 ipoput4(ipc->p->f, bp, 0, ttl, tos, ipc); 1046 } 1047 1048 void 1049 ilreject(Fs *f, Ilhdr *inih) 1050 { 1051 Ilhdr *ih; 1052 Block *bp; 1053 1054 bp = allocb(IL_IPSIZE+IL_HDRSIZE); 1055 bp->wp += IL_IPSIZE+IL_HDRSIZE; 1056 1057 ih = (Ilhdr *)(bp->rp); 1058 ih->vihl = IP_VER4; 1059 1060 /* Ip fields */ 1061 ih->proto = IP_ILPROTO; 1062 hnputs(ih->illen, IL_HDRSIZE); 1063 ih->frag[0] = 0; 1064 ih->frag[1] = 0; 1065 hnputl(ih->dst, nhgetl(inih->src)); 1066 hnputl(ih->src, nhgetl(inih->dst)); 1067 hnputs(ih->ilsrc, nhgets(inih->ildst)); 1068 hnputs(ih->ildst, nhgets(inih->ilsrc)); 1069 hnputl(ih->ilid, nhgetl(inih->ilack)); 1070 hnputl(ih->ilack, nhgetl(inih->ilid)); 1071 ih->iltype = Ilclose; 1072 ih->ilspec = 0; 1073 ih->ilsum[0] = 0; 1074 ih->ilsum[1] = 0; 1075 1076 if(ilcksum) 1077 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE)); 1078 1079 ipoput4(f, bp, 0, MAXTTL, DFLTTOS, nil); 1080 } 1081 1082 void 1083 ilsettimeout(Ilcb *ic) 1084 { 1085 ulong pt; 1086 1087 pt = (ic->delay>>LogAGain) 1088 + ic->unackedbytes/(ic->rate>>LogAGain) 1089 + (ic->mdev>>(LogDGain-1)) 1090 + AckDelay; 1091 if(pt > MaxTimeout) 1092 pt = MaxTimeout; 1093 ic->timeout = NOW + pt; 1094 } 1095 1096 void 1097 ilbackoff(Ilcb *ic) 1098 { 1099 ulong pt; 1100 int i; 1101 1102 pt = (ic->delay>>LogAGain) 1103 + ic->unackedbytes/(ic->rate>>LogAGain) 1104 + (ic->mdev>>(LogDGain-1)) 1105 + AckDelay; 1106 for(i = 0; i < ic->rexmit; i++) 1107 pt = pt + (pt>>1); 1108 if(pt > MaxTimeout) 1109 pt = MaxTimeout; 1110 ic->timeout = NOW + pt; 1111 1112 if(ic->fasttimeout) 1113 ic->timeout = NOW+Iltickms; 1114 1115 ic->rexmit++; 1116 } 1117 1118 // complain if two numbers not within an hour of each other 1119 #define Tfuture (1000*60*60) 1120 int 1121 later(ulong t1, ulong t2, char *x) 1122 { 1123 int dt; 1124 1125 dt = t1 - t2; 1126 if(dt > 0) { 1127 if(x != nil && dt > Tfuture) 1128 print("%s: way future %d\n", x, dt); 1129 return 1; 1130 } 1131 if(dt < -Tfuture) { 1132 if(x != nil) 1133 print("%s: way past %d\n", x, -dt); 1134 return 1; 1135 } 1136 return 0; 1137 } 1138 1139 void 1140 ilackproc(void *x) 1141 { 1142 Ilcb *ic; 1143 Conv **s, *p; 1144 Proto *il; 1145 1146 il = x; 1147 1148 loop: 1149 tsleep(&up->sleep, return0, 0, Iltickms); 1150 for(s = il->conv; s && *s; s++) { 1151 p = *s; 1152 ic = (Ilcb*)p->ptcl; 1153 1154 switch(ic->state) { 1155 case Ilclosed: 1156 case Illistening: 1157 break; 1158 case Ilclosing: 1159 if(later(NOW, ic->timeout, "timeout0")) { 1160 if(ic->rexmit > MaxRexmit){ 1161 ilhangup(p, nil); 1162 break; 1163 } 1164 ilsendctl(p, nil, Ilclose, ic->next, ic->recvd, 0); 1165 ilbackoff(ic); 1166 } 1167 break; 1168 1169 case Ilsyncee: 1170 case Ilsyncer: 1171 if(later(NOW, ic->timeout, "timeout1")) { 1172 if(ic->rexmit > MaxRexmit){ 1173 ilhangup(p, etime); 1174 break; 1175 } 1176 ilsendctl(p, nil, Ilsync, ic->start, ic->recvd, 0); 1177 ilbackoff(ic); 1178 } 1179 break; 1180 1181 case Ilestablished: 1182 if(ic->recvd != ic->acksent) 1183 if(later(NOW, ic->acktime, "acktime")) 1184 ilsendctl(p, nil, Ilack, ic->next, ic->recvd, 0); 1185 1186 if(later(NOW, ic->querytime, "querytime")){ 1187 if(later(NOW, ic->lastrecv+DeathTime, "deathtime")){ 1188 netlog(il->f, Logil, "il: hangup: deathtime\n"); 1189 ilhangup(p, etime); 1190 break; 1191 } 1192 ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic)); 1193 ic->querytime = NOW + QueryTime; 1194 } 1195 1196 if(ic->unacked != nil) 1197 if(later(NOW, ic->timeout, "timeout2")) { 1198 if(ic->rexmit > MaxRexmit){ 1199 netlog(il->f, Logil, "il: hangup: too many rexmits\n"); 1200 ilhangup(p, etime); 1201 break; 1202 } 1203 ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic)); 1204 ic->rxquery++; 1205 ilbackoff(ic); 1206 } 1207 break; 1208 } 1209 } 1210 goto loop; 1211 } 1212 1213 void 1214 ilcbinit(Ilcb *ic) 1215 { 1216 ic->start = nrand(0x1000000); 1217 ic->next = ic->start+1; 1218 ic->recvd = 0; 1219 ic->window = Defaultwin; 1220 ic->unackedbytes = 0; 1221 ic->unacked = nil; 1222 ic->outoforder = nil; 1223 ic->rexmit = 0; 1224 ic->rxtot = 0; 1225 ic->rxquery = 0; 1226 ic->qtx = 1; 1227 ic->fasttimeout = 0; 1228 1229 /* timers */ 1230 ic->delay = DefRtt<<LogAGain; 1231 ic->mdev = DefRtt<<LogDGain; 1232 ic->rate = DefByteRate<<LogAGain; 1233 ic->querytime = NOW + QueryTime; 1234 ic->lastrecv = NOW; /* or we'll timeout right away */ 1235 ilsettimeout(ic); 1236 } 1237 1238 char* 1239 ilstart(Conv *c, int type, int fasttimeout) 1240 { 1241 Ilcb *ic; 1242 Ilpriv *ipriv; 1243 char kpname[KNAMELEN]; 1244 1245 ipriv = c->p->priv; 1246 1247 if(ipriv->ackprocstarted == 0){ 1248 qlock(&ipriv->apl); 1249 if(ipriv->ackprocstarted == 0){ 1250 sprint(kpname, "#I%dilack", c->p->f->dev); 1251 kproc(kpname, ilackproc, c->p); 1252 ipriv->ackprocstarted = 1; 1253 } 1254 qunlock(&ipriv->apl); 1255 } 1256 1257 ic = (Ilcb*)c->ptcl; 1258 ic->conv = c; 1259 1260 if(ic->state != Ilclosed) 1261 return nil; 1262 1263 ilcbinit(ic); 1264 1265 if(fasttimeout){ 1266 /* timeout if we can't connect quickly */ 1267 ic->fasttimeout = 1; 1268 ic->timeout = NOW+Iltickms; 1269 ic->rexmit = MaxRexmit - 4; 1270 }; 1271 1272 switch(type) { 1273 default: 1274 netlog(c->p->f, Logil, "il: start: type %d\n", type); 1275 break; 1276 case IL_LISTEN: 1277 ic->state = Illistening; 1278 iphtadd(&ipriv->ht, c); 1279 break; 1280 case IL_CONNECT: 1281 ic->state = Ilsyncer; 1282 iphtadd(&ipriv->ht, c); 1283 ilsendctl(c, nil, Ilsync, ic->start, ic->recvd, 0); 1284 break; 1285 } 1286 1287 return nil; 1288 } 1289 1290 void 1291 ilfreeq(Ilcb *ic) 1292 { 1293 Block *bp, *next; 1294 1295 qlock(&ic->ackq); 1296 for(bp = ic->unacked; bp; bp = next) { 1297 next = bp->list; 1298 freeblist(bp); 1299 } 1300 ic->unacked = nil; 1301 qunlock(&ic->ackq); 1302 1303 qlock(&ic->outo); 1304 for(bp = ic->outoforder; bp; bp = next) { 1305 next = bp->list; 1306 freeblist(bp); 1307 } 1308 ic->outoforder = nil; 1309 qunlock(&ic->outo); 1310 } 1311 1312 void 1313 iladvise(Proto *il, Block *bp, char *msg) 1314 { 1315 Ilhdr *h; 1316 Ilcb *ic; 1317 uchar source[IPaddrlen], dest[IPaddrlen]; 1318 ushort psource; 1319 Conv *s, **p; 1320 1321 h = (Ilhdr*)(bp->rp); 1322 1323 v4tov6(dest, h->dst); 1324 v4tov6(source, h->src); 1325 psource = nhgets(h->ilsrc); 1326 1327 1328 /* Look for a connection, unfortunately the destination port is missing */ 1329 QLOCK(il); 1330 for(p = il->conv; *p; p++) { 1331 s = *p; 1332 if(s->lport == psource) 1333 if(ipcmp(s->laddr, source) == 0) 1334 if(ipcmp(s->raddr, dest) == 0){ 1335 QUNLOCK(il); 1336 ic = (Ilcb*)s->ptcl; 1337 switch(ic->state){ 1338 case Ilsyncer: 1339 ilhangup(s, msg); 1340 break; 1341 } 1342 freeblist(bp); 1343 return; 1344 } 1345 } 1346 QUNLOCK(il); 1347 freeblist(bp); 1348 } 1349 1350 int 1351 ilnextqt(Ilcb *ic) 1352 { 1353 int x; 1354 1355 qlock(&ic->ackq); 1356 x = ic->qtx; 1357 if(++x > Nqt) 1358 x = 1; 1359 ic->qtx = x; 1360 ic->qt[x] = ic->next-1; /* highest xmitted packet */ 1361 ic->qt[0] = ic->qt[x]; /* compatibility with old implementations */ 1362 qunlock(&ic->ackq); 1363 1364 return x; 1365 } 1366 1367 /* calculate scale constants that converts fast ticks to ms (more or less) */ 1368 static void 1369 inittimescale(void) 1370 { 1371 uvlong hz; 1372 1373 fastticks(&hz); 1374 if(hz > 1000){ 1375 scalediv = hz/1000; 1376 scalemul = 1; 1377 } else { 1378 scalediv = 1; 1379 scalemul = 1000/hz; 1380 } 1381 } 1382 1383 void 1384 ilinit(Fs *f) 1385 { 1386 Proto *il; 1387 1388 inittimescale(); 1389 1390 il = smalloc(sizeof(Proto)); 1391 il->priv = smalloc(sizeof(Ilpriv)); 1392 il->name = "il"; 1393 il->connect = ilconnect; 1394 il->announce = ilannounce; 1395 il->state = ilstate; 1396 il->create = ilcreate; 1397 il->close = ilclose; 1398 il->rcv = iliput; 1399 il->ctl = nil; 1400 il->advise = iladvise; 1401 il->stats = ilxstats; 1402 il->inuse = ilinuse; 1403 il->gc = nil; 1404 il->ipproto = IP_ILPROTO; 1405 il->nc = scalednconv(); 1406 il->ptclsize = sizeof(Ilcb); 1407 Fsproto(f, il); 1408 }