| plan 9 kernel history: overview | file list | diff list |
2002/0507/ip/il.c (diff list | history)
| ip/il.c on 1997/0327 | ||
| 1997/0327 | #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "ip.h" | |
| 1998/0929 | enum /* Connection state */ { Ilclosed, Ilsyncer, Ilsyncee, Ilestablished, Illistening, Ilclosing, | |
| 1998/0930 | Ilopening, /* only for file server */ | |
| 1998/0929 | }; | |
| 1997/0327 | char *ilstates[] = { "Closed", "Syncer", "Syncee", "Established", "Listening", | |
| 1998/0930 | "Closing", "Opening", /* only for file server */ | |
| 1997/0327 | }; enum /* Packet types */ { Ilsync, Ildata, Ildataquery, Ilack, | |
| 1997/0804 | Ilquery, | |
| 1997/0327 | Ilstate, Ilclose, }; | |
| 1998/0929 | char *iltype[] = { "sync", "data", "dataquery", "ack", "query", "state", "close" | |
| 1997/0327 | }; | |
| 1998/0930 | enum { Seconds = 1000, Iltickms = 50, /* time base */ AckDelay = 2*Iltickms, /* max time twixt message rcvd & ack sent */ | |
| 1999/0529 | MaxTimeout = 30*Seconds, /* max time between rexmit */ | |
| 1998/1013 | QueryTime = 10*Seconds, /* time between subsequent queries */ | |
| 2000/1121 | DeathTime = 30*QueryTime, | |
| 1998/0929 | ||
| 1998/0930 | MaxRexmit = 16, /* max retransmissions before hangup */ Defaultwin = 20, LogAGain = 3, AGain = 1<<LogAGain, LogDGain = 2, DGain = 1<<LogDGain, DefByteRate = 100, /* assume a megabit link */ DefRtt = 50, /* cross country on a great day */ }; | |
| 1997/0804 | enum { Nqt= 8, }; | |
| 1997/0327 | typedef struct Ilcb Ilcb; struct Ilcb /* Control block */ { int state; /* Connection state */ Conv *conv; QLock ackq; /* Unacknowledged queue */ Block *unacked; Block *unackedtail; | |
| 1998/0930 | ulong unackedbytes; | |
| 1997/0327 | QLock outo; /* Out of order packet queue */ Block *outoforder; ulong next; /* Id of next to send */ ulong recvd; /* Last packet received */ | |
| 1998/0929 | ulong acksent; /* Last packet acked */ | |
| 1997/0327 | ulong start; /* Local start id */ ulong rstart; /* Remote start id */ | |
| 1998/0929 | int window; /* Maximum receive window */ | |
| 1998/0930 | int rxquery; /* number of queries on this connection */ | |
| 1998/0929 | int rxtot; /* number of retransmits on this connection */ int rexmit; /* number of retransmits of *unacked */ ulong qt[Nqt+1]; /* state table for query messages */ int qtx; /* ... index into qt */ | |
| 2001/0227 | /* if set, fasttimeout causes a connection request to terminate after 4*Iltickms */ int fasttimeout; | |
| 1998/0929 | /* timers */ ulong lastxmit; /* time of last xmit */ ulong lastrecv; /* time of last recv */ ulong timeout; /* retransmission time for *unacked */ ulong acktime; /* time to send next ack */ ulong querytime; /* time to send next query */ /* adaptive measurements */ | |
| 1997/0730 | int delay; /* Average of the fixed rtt delay */ | |
| 1998/0306 | int rate; /* Average uchar rate */ | |
| 1997/0730 | int mdev; /* Mean deviation of rtt */ | |
| 1997/0802 | int maxrtt; /* largest rtt seen */ | |
| 1997/0327 | ulong rttack; /* The ack we are waiting for */ | |
| 1997/0730 | int rttlen; /* Length of rttack packet */ | |
| 1998/0929 | uvlong rttstart; /* Time we issued rttack packet */ | |
| 1997/0327 | }; enum { IL_IPSIZE = 20, IL_HDRSIZE = 18, IL_LISTEN = 0, IL_CONNECT = 1, IP_ILPROTO = 40, }; typedef struct Ilhdr Ilhdr; struct Ilhdr { | |
| 1998/0306 | uchar vihl; /* Version and header length */ uchar tos; /* Type of service */ uchar length[2]; /* packet length */ uchar id[2]; /* Identification */ uchar frag[2]; /* Fragment information */ uchar ttl; /* Time to live */ uchar proto; /* Protocol */ uchar cksum[2]; /* Header checksum */ uchar src[4]; /* Ip source */ uchar dst[4]; /* Ip destination */ uchar ilsum[2]; /* Checksum including header */ uchar illen[2]; /* Packet length */ uchar iltype; /* Packet type */ uchar ilspec; /* Special */ uchar ilsrc[2]; /* Src port */ uchar ildst[2]; /* Dst port */ uchar ilid[4]; /* Sequence id */ uchar ilack[4]; /* Acked sequence */ | |
| 1997/0327 | }; | |
| 2000/0706 | enum { InMsgs, OutMsgs, CsumErrs, /* checksum errors */ HlenErrs, /* header length error */ LenErrs, /* short packet */ OutOfOrder, /* out of order */ Retrans, /* retransmissions */ DupMsg, DupBytes, | |
| 1998/0313 | ||
| 2000/0706 | Nstats, }; static char *statnames[] = { [InMsgs] "InMsgs", [OutMsgs] "OutMsgs", [CsumErrs] "CsumErrs", [HlenErrs] "HlenErr", [LenErrs] "LenErrs", [OutOfOrder] "OutOfOrder", [Retrans] "Retrans", [DupMsg] "DupMsg", [DupBytes] "DupBytes", }; | |
| 1998/0313 | typedef struct Ilpriv Ilpriv; struct Ilpriv | |
| 1997/0916 | { | |
| 2001/0301 | Ipht ht; | |
| 2000/0706 | ulong stats[Nstats]; | |
| 1997/0916 | ||
| 2001/0301 | ulong csumerr; /* checksum errors */ ulong hlenerr; /* header length error */ ulong lenerr; /* short packet */ ulong order; /* out of order */ ulong rexmit; /* retransmissions */ ulong dup; ulong dupb; | |
| 1998/0313 | ||
| 2001/0301 | Rendez ilr; | |
| 1998/0924 | /* keeping track of the ack kproc */ int ackprocstarted; QLock apl; | |
| 1998/0313 | }; | |
| 1997/0804 | /* state for query/dataquery messages */ | |
| 1997/0327 | void ilrcvmsg(Conv*, Block*); | |
| 1997/0804 | void ilsendctl(Conv*, Ilhdr*, int, ulong, ulong, int); | |
| 1997/0327 | void ilackq(Ilcb*, Block*); void ilprocess(Conv*, Ilhdr*, Block*); void ilpullup(Conv*); void ilhangup(Conv*, char*); void ilfreeq(Ilcb*); void ilrexmit(Ilcb*); void ilbackoff(Ilcb*); | |
| 1998/0929 | void ilsettimeout(Ilcb*); | |
| 2001/0227 | char* ilstart(Conv*, int, int); | |
| 1998/0313 | void ilackproc(void*); | |
| 1997/0327 | void iloutoforder(Conv*, Ilhdr*, Block*); | |
| 2001/0623 | void iliput(Proto*, Ipifc*, Block*); | |
| 1998/0313 | void iladvise(Proto*, Block*, char*); | |
| 1997/0804 | int ilnextqt(Ilcb*); | |
| 1998/0929 | void ilcbinit(Ilcb*); | |
| 1999/0501 | int later(ulong, ulong, char*); | |
| 1999/0917 | void ilreject(Fs*, Ilhdr*); | |
| 2001/0301 | void illocalclose(Conv *c); | |
| 1997/0327 | int ilcksum = 1; static int initseq = 25001; | |
| 1999/0703 | static ulong scalediv, scalemul; | |
| 1998/0930 | static char *etime = "connection timed out"; | |
| 1997/0327 | static char* ilconnect(Conv *c, char **argv, int argc) { | |
| 2001/0303 | char *e, *p; | |
| 2001/0227 | int fast; | |
| 1997/0327 | ||
| 2001/0303 | /* huge hack to quickly try an il connection */ fast = 0; if(argc > 1){ p = strstr(argv[1], "!fasttimeout"); if(p != nil){ *p = 0; fast = 1; } } | |
| 1997/0521 | e = Fsstdconnect(c, argv, argc); | |
| 1997/0327 | if(e != nil) return e; | |
| 2001/0227 | return ilstart(c, IL_CONNECT, fast); | |
| 1997/0327 | } | |
| 1998/0306 | static int ilstate(Conv *c, char *state, int n) | |
| 1997/0327 | { Ilcb *ic; ic = (Ilcb*)(c->ptcl); | |
| 1998/0930 | return snprint(state, n, "%s del %5.5d Br %5.5d md %5.5d una %5.5lud rex %5.5d rxq %5.5d max %5.5d", | |
| 1998/0306 | ilstates[ic->state], ic->delay>>LogAGain, ic->rate>>LogAGain, ic->mdev>>LogDGain, | |
| 1998/0930 | ic->unackedbytes, ic->rxtot, ic->rxquery, ic->maxrtt); | |
| 1998/0306 | } | |
| 1997/0327 | ||
| 1998/0306 | static int ilinuse(Conv *c) { Ilcb *ic; | |
| 1997/0327 | ||
| 1998/0306 | ic = (Ilcb*)(c->ptcl); return ic->state != Ilclosed; | |
| 1997/0327 | } /* called with c locked */ | |
| 1997/0403 | static char* ilannounce(Conv *c, char **argv, int argc) | |
| 1997/0327 | { char *e; | |
| 1997/0403 | e = Fsstdannounce(c, argv, argc); | |
| 1997/0404 | if(e != nil) | |
| 1997/0403 | return e; | |
| 2001/0227 | e = ilstart(c, IL_LISTEN, 0); | |
| 1997/0403 | if(e != nil) return e; | |
| 1998/0313 | Fsconnected(c, nil); | |
| 1997/0403 | return nil; | |
| 1997/0327 | } | |
| 2001/0301 | void illocalclose(Conv *c) { Ilcb *ic; Ilpriv *ipriv; ipriv = c->p->priv; ic = (Ilcb*)c->ptcl; ic->state = Ilclosed; iphtrem(&ipriv->ht, c); ipmove(c->laddr, IPnoaddr); c->lport = 0; } | |
| 1997/0327 | static void ilclose(Conv *c) { Ilcb *ic; ic = (Ilcb*)c->ptcl; qclose(c->rq); qclose(c->wq); qclose(c->eq); switch(ic->state) { case Ilclosing: case Ilclosed: break; case Ilsyncer: case Ilsyncee: case Ilestablished: ic->state = Ilclosing; | |
| 1999/0429 | ilsettimeout(ic); | |
| 1997/0804 | ilsendctl(c, nil, Ilclose, ic->next, ic->recvd, 0); | |
| 1997/0327 | break; case Illistening: | |
| 2001/0301 | illocalclose(c); | |
| 1997/0327 | break; } | |
| 1997/0902 | ilfreeq(ic); | |
| 1997/0327 | } void | |
| 2001/0306 | ilkick(Conv *c) | |
| 1997/0327 | { Ilhdr *ih; Ilcb *ic; int dlen; | |
| 1998/0929 | ulong id, ack; | |
| 1997/0327 | Block *bp; | |
| 1998/0313 | Fs *f; | |
| 2000/0706 | Ilpriv *priv; | |
| 1997/0327 | ||
| 1998/0313 | f = c->p->f; | |
| 2000/0706 | priv = c->p->priv; | |
| 1997/0327 | ic = (Ilcb*)c->ptcl; bp = qget(c->wq); if(bp == nil) return; switch(ic->state) { case Ilclosed: case Illistening: case Ilclosing: freeblist(bp); qhangup(c->rq, nil); return; } dlen = blocklen(bp); /* Make space to fit il & ip */ bp = padblock(bp, IL_IPSIZE+IL_HDRSIZE); ih = (Ilhdr *)(bp->rp); | |
| 2002/0507 | ih->vihl = IP_VER4; | |
| 1997/0327 | /* Ip fields */ ih->frag[0] = 0; ih->frag[1] = 0; | |
| 1998/0306 | v6tov4(ih->dst, c->raddr); v6tov4(ih->src, c->laddr); | |
| 1997/0327 | ih->proto = IP_ILPROTO; /* Il fields */ hnputs(ih->illen, dlen+IL_HDRSIZE); hnputs(ih->ilsrc, c->lport); hnputs(ih->ildst, c->rport); qlock(&ic->ackq); id = ic->next++; hnputl(ih->ilid, id); | |
| 1998/0929 | ack = ic->recvd; hnputl(ih->ilack, ack); ic->acksent = ack; ic->acktime = msec + AckDelay; | |
| 1997/0327 | ih->iltype = Ildata; ih->ilspec = 0; ih->ilsum[0] = 0; ih->ilsum[1] = 0; /* Checksum of ilheader plus data (not ip & no pseudo header) */ if(ilcksum) hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, dlen+IL_HDRSIZE)); ilackq(ic, bp); qunlock(&ic->ackq); /* Start the round trip timer for this packet if the timer is free */ if(ic->rttack == 0) { ic->rttack = id; | |
| 1998/0929 | ic->rttstart = fastticks(nil); | |
| 1997/0730 | ic->rttlen = dlen + IL_IPSIZE + IL_HDRSIZE; | |
| 1997/0327 | } | |
| 1999/0430 | if(later(msec, ic->timeout, nil)) | |
| 1998/0929 | ilsettimeout(ic); | |
| 2002/0507 | ipoput4(f, bp, 0, c->ttl, c->tos); | |
| 2000/0706 | priv->stats[OutMsgs]++; | |
| 1997/0327 | } static void ilcreate(Conv *c) { c->rq = qopen(64*1024, 0, 0, c); c->wq = qopen(64*1024, 0, 0, 0); } | |
| 1997/0916 | int | |
| 1998/0313 | ilxstats(Proto *il, char *buf, int len) | |
| 1997/0916 | { | |
| 2000/0706 | Ilpriv *priv; char *p, *e; int i; | |
| 1998/0306 | ||
| 2000/0706 | priv = il->priv; p = buf; e = p+len; for(i = 0; i < Nstats; i++) p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]); return p - buf; | |
| 1997/0916 | } | |
| 1997/0327 | void ilackq(Ilcb *ic, Block *bp) { Block *np; | |
| 1997/0730 | int n; | |
| 1997/0327 | ||
| 1997/0730 | n = blocklen(bp); | |
| 1997/0327 | /* Enqueue a copy on the unacked queue in case this one gets lost */ | |
| 1997/0730 | np = copyblock(bp, n); | |
| 1997/0327 | if(ic->unacked) ic->unackedtail->list = np; | |
| 1998/0929 | else | |
| 1997/0327 | ic->unacked = np; ic->unackedtail = np; np->list = nil; | |
| 1998/0930 | ic->unackedbytes += n; | |
| 1997/0327 | } | |
| 1997/0805 | static | |
| 1997/0327 | void | |
| 1998/0929 | ilrttcalc(Ilcb *ic, Block *bp) | |
| 1997/0801 | { | |
| 1998/0930 | int rtt, tt, pt, delay, rate; | |
| 1997/0801 | ||
| 1999/0703 | rtt = fastticks(nil) - ic->rttstart; rtt = (rtt*scalemul)/scalediv; | |
| 1997/0802 | delay = ic->delay; rate = ic->rate; | |
| 1997/0801 | ||
| 1998/0929 | /* Guard against zero wrap */ | |
| 1999/0703 | if(rtt > 120000 || rtt < 0) | |
| 1997/0801 | return; | |
| 1998/0930 | /* this block had to be transmitted after the one acked so count its size */ ic->rttlen += blocklen(bp) + IL_IPSIZE + IL_HDRSIZE; if(ic->rttlen < 256){ /* guess fixed delay as rtt of small packets */ delay += rtt - (delay>>LogAGain); | |
| 1997/0802 | if(delay < AGain) delay = AGain; ic->delay = delay; | |
| 1998/0930 | } else { /* if packet took longer than avg rtt delay, recalc rate */ tt = rtt - (delay>>LogAGain); if(tt > 0){ rate += ic->rttlen/tt - (rate>>LogAGain); if(rate < AGain) rate = AGain; ic->rate = rate; } | |
| 1997/0801 | } /* mdev */ | |
| 1997/0802 | pt = ic->rttlen/(rate>>LogAGain) + (delay>>LogAGain); | |
| 1998/0930 | ic->mdev += abs(rtt-pt) - (ic->mdev>>LogDGain); | |
| 1997/0801 | ||
| 1998/0930 | if(rtt > ic->maxrtt) ic->maxrtt = rtt; | |
| 1997/0801 | } | |
| 1997/0730 | void | |
| 1998/0929 | ilackto(Ilcb *ic, ulong ackto, Block *bp) | |
| 1997/0327 | { Ilhdr *h; | |
| 1997/0730 | ulong id; | |
| 1997/0327 | ||
| 1997/0801 | if(ic->rttack == ackto) | |
| 1998/0929 | ilrttcalc(ic, bp); | |
| 1997/0730 | ||
| 1997/0802 | /* Cancel if we've passed the packet we were interested in */ | |
| 1997/0327 | if(ic->rttack <= ackto) ic->rttack = 0; qlock(&ic->ackq); while(ic->unacked) { h = (Ilhdr *)ic->unacked->rp; id = nhgetl(h->ilid); if(ackto < id) break; bp = ic->unacked; ic->unacked = bp->list; bp->list = nil; | |
| 1998/0930 | ic->unackedbytes -= blocklen(bp); | |
| 1997/0327 | freeblist(bp); | |
| 2001/0302 | ic->rexmit = 0; | |
| 1998/0929 | ilsettimeout(ic); | |
| 1997/0327 | } qunlock(&ic->ackq); } void | |
| 2001/0623 | iliput(Proto *il, Ipifc*, Block *bp) | |
| 1997/0327 | { char *st; Ilcb *ic; Ilhdr *ih; | |
| 1998/0306 | uchar raddr[IPaddrlen]; uchar laddr[IPaddrlen]; | |
| 1997/0327 | ushort sp, dp, csum; int plen, illen; | |
| 2001/0823 | Conv *new, *s; | |
| 1998/0313 | Ilpriv *ipriv; | |
| 1997/0327 | ||
| 1998/0313 | ipriv = il->priv; | |
| 1997/0327 | ih = (Ilhdr *)bp->rp; plen = blocklen(bp); if(plen < IL_IPSIZE+IL_HDRSIZE){ | |
| 1998/0313 | netlog(il->f, Logil, "il: hlenerr\n"); | |
| 2000/0706 | ipriv->stats[HlenErrs]++; | |
| 1997/0327 | goto raise; } illen = nhgets(ih->illen); if(illen+IL_IPSIZE > plen){ | |
| 1998/0313 | netlog(il->f, Logil, "il: lenerr\n"); | |
| 2000/0706 | ipriv->stats[LenErrs]++; | |
| 1997/0327 | goto raise; } sp = nhgets(ih->ildst); dp = nhgets(ih->ilsrc); | |
| 1998/0306 | v4tov6(raddr, ih->src); | |
| 2001/0301 | v4tov6(laddr, ih->dst); | |
| 1997/0327 | ||
| 1998/0313 | if((csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) { | |
| 1997/0327 | if(ih->iltype < 0 || ih->iltype > Ilclose) st = "?"; else st = iltype[ih->iltype]; | |
| 2000/0706 | ipriv->stats[CsumErrs]++; | |
| 1998/0313 | netlog(il->f, Logil, "il: cksum %ux %ux, pkt(%s id %lud ack %lud %I/%d->%d)\n", | |
| 1998/0306 | csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp); | |
| 1997/0327 | goto raise; } | |
| 1999/0302 | qlock(il); | |
| 2001/0301 | s = iphtlook(&ipriv->ht, raddr, dp, laddr, sp); if(s == nil){ | |
| 2001/0302 | if(ih->iltype == Ilsync) ilreject(il->f, ih); /* no listener */ | |
| 1999/0302 | qunlock(il); | |
| 1997/0327 | goto raise; } | |
| 2001/0301 | ic = (Ilcb*)s->ptcl; if(ic->state == Illistening){ if(ih->iltype != Ilsync){ qunlock(il); if(ih->iltype < 0 || ih->iltype > Ilclose) st = "?"; else st = iltype[ih->iltype]; ilreject(il->f, ih); /* no channel and not sync */ netlog(il->f, Logil, "il: no channel, pkt(%s id %lud ack %lud %I/%ud->%ud)\n", st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp); goto raise; } | |
| 1997/0327 | ||
| 2001/0823 | new = Fsnewcall(s, raddr, dp, laddr, sp); if(new == nil){ | |
| 2001/0301 | qunlock(il); netlog(il->f, Logil, "il: bad newcall %I/%ud->%ud\n", raddr, sp, dp); ilsendctl(s, ih, Ilclose, 0, nhgetl(ih->ilid), 0); goto raise; | |
| 1997/0327 | } | |
| 2001/0823 | s = new; | |
| 2001/0301 | ic = (Ilcb*)s->ptcl; ic->conv = s; ic->state = Ilsyncee; ilcbinit(ic); ic->rstart = nhgetl(ih->ilid); iphtadd(&ipriv->ht, s); | |
| 1997/0327 | } | |
| 2001/0301 | qlock(s); | |
| 1999/0302 | qunlock(il); if(waserror()){ | |
| 2001/0301 | qunlock(s); | |
| 1999/0302 | nexterror(); } | |
| 2001/0301 | ilprocess(s, ih, bp); qunlock(s); | |
| 1999/0302 | poperror(); | |
| 1997/0327 | return; raise: freeblist(bp); } void _ilprocess(Conv *s, Ilhdr *h, Block *bp) { Ilcb *ic; ulong id, ack; | |
| 2000/0706 | Ilpriv *priv; | |
| 1997/0327 | id = nhgetl(h->ilid); ack = nhgetl(h->ilack); ic = (Ilcb*)s->ptcl; | |
| 1998/0929 | ic->lastrecv = msec; | |
| 1998/1013 | ic->querytime = msec + QueryTime; | |
| 2000/0706 | priv = s->p->priv; priv->stats[InMsgs]++; | |
| 1997/0327 | switch(ic->state) { default: | |
| 1998/0313 | netlog(s->p->f, Logil, "il: unknown state %d\n", ic->state); | |
| 1997/0327 | case Ilclosed: freeblist(bp); break; case Ilsyncer: switch(h->iltype) { default: break; case Ilsync: if(ack != ic->start) ilhangup(s, "connection rejected"); else { ic->recvd = id; ic->rstart = id; | |
| 1997/0804 | ilsendctl(s, nil, Ilack, ic->next, ic->recvd, 0); | |
| 1997/0327 | ic->state = Ilestablished; | |
| 2001/0302 | ic->fasttimeout = 0; ic->rexmit = 0; | |
| 1998/0313 | Fsconnected(s, nil); | |
| 1997/0327 | ilpullup(s); } break; case Ilclose: if(ack == ic->start) | |
| 1999/0917 | ilhangup(s, "connection rejected"); | |
| 1997/0327 | break; } freeblist(bp); break; case Ilsyncee: switch(h->iltype) { default: break; case Ilsync: | |
| 2001/0301 | if(id != ic->rstart || ack != 0){ illocalclose(s); } else { | |
| 1997/0327 | ic->recvd = id; | |
| 1997/0804 | ilsendctl(s, nil, Ilsync, ic->start, ic->recvd, 0); | |
| 1997/0327 | } break; case Ilack: if(ack == ic->start) { ic->state = Ilestablished; | |
| 2001/0302 | ic->fasttimeout = 0; ic->rexmit = 0; | |
| 1997/0327 | ilpullup(s); } break; | |
| 1999/0916 | case Ildata: if(ack == ic->start) { ic->state = Ilestablished; | |
| 2001/0302 | ic->fasttimeout = 0; ic->rexmit = 0; | |
| 1999/0916 | goto established; } break; | |
| 1997/0327 | case Ilclose: if(ack == ic->start) ilhangup(s, "remote close"); break; } freeblist(bp); break; case Ilestablished: | |
| 1999/0916 | established: | |
| 1997/0327 | switch(h->iltype) { case Ilsync: if(id != ic->rstart) ilhangup(s, "remote close"); | |
| 1998/0929 | else | |
| 1997/0804 | ilsendctl(s, nil, Ilack, ic->next, ic->rstart, 0); | |
| 1997/0327 | freeblist(bp); break; case Ildata: | |
| 1998/0929 | ilackto(ic, ack, bp); | |
| 1997/0327 | iloutoforder(s, h, bp); ilpullup(s); break; case Ildataquery: | |
| 1998/0929 | ilackto(ic, ack, bp); | |
| 1997/0327 | iloutoforder(s, h, bp); ilpullup(s); | |
| 1997/0804 | ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec); | |
| 1997/0327 | break; case Ilack: | |
| 1998/0929 | ilackto(ic, ack, bp); | |
| 1997/0327 | freeblist(bp); break; | |
| 1997/0804 | case Ilquery: | |
| 1998/0929 | ilackto(ic, ack, bp); | |
| 1997/0804 | ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec); | |
| 1997/0327 | freeblist(bp); break; case Ilstate: | |
| 1998/0930 | if(ack >= ic->rttack) ic->rttack = 0; | |
| 1998/0929 | ilackto(ic, ack, bp); | |
| 1997/0804 | if(h->ilspec > Nqt) h->ilspec = 0; | |
| 1998/0929 | if(ic->qt[h->ilspec] > ack){ | |
| 1997/0804 | ilrexmit(ic); | |
| 1998/0929 | ilsettimeout(ic); } | |
| 1997/0327 | freeblist(bp); break; case Ilclose: freeblist(bp); if(ack < ic->start || ack > ic->next) break; | |
| 1999/0917 | ic->recvd = id; | |
| 1997/0804 | ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0); | |
| 1997/0327 | ic->state = Ilclosing; | |
| 1999/0429 | ilsettimeout(ic); | |
| 1997/0327 | ilfreeq(ic); break; } break; case Illistening: freeblist(bp); break; case Ilclosing: switch(h->iltype) { case Ilclose: ic->recvd = id; | |
| 1997/0804 | ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0); | |
| 1997/0327 | if(ack == ic->next) ilhangup(s, nil); break; default: break; } freeblist(bp); break; } } void ilrexmit(Ilcb *ic) { Ilhdr *h; Block *nb; | |
| 1997/0803 | Conv *c; ulong id; | |
| 1998/0930 | Ilpriv *priv; | |
| 1997/0327 | nb = nil; qlock(&ic->ackq); if(ic->unacked) nb = copyblock(ic->unacked, blocklen(ic->unacked)); qunlock(&ic->ackq); | |
| 1999/0821 | if(nb == nil) | |
| 1997/0327 | return; h = (Ilhdr*)nb->rp; | |
| 2002/0507 | h->vihl = IP_VER4; | |
| 1997/0327 | h->iltype = Ildataquery; hnputl(h->ilack, ic->recvd); | |
| 1997/0804 | h->ilspec = ilnextqt(ic); | |
| 1997/0327 | h->ilsum[0] = 0; h->ilsum[1] = 0; | |
| 1998/0313 | hnputs(h->ilsum, ptclcsum(nb, IL_IPSIZE, nhgets(h->illen))); | |
| 1997/0327 | ||
| 1997/0803 | c = ic->conv; id = nhgetl(h->ilid); | |
| 1998/0929 | netlog(c->p->f, Logil, "il: rexmit %d %ud: %d %d: %i %d/%d\n", id, ic->recvd, ic->rexmit, ic->timeout, | |
| 1997/0803 | c->raddr, c->lport, c->rport); | |
| 1998/0929 | ilbackoff(ic); | |
| 2002/0507 | ipoput4(c->p->f, nb, 0, ic->conv->ttl, ic->conv->tos); | |
| 1998/0930 | /* statistics */ ic->rxtot++; priv = c->p->priv; priv->rexmit++; | |
| 1997/0327 | } /* DEBUG */ void ilprocess(Conv *s, Ilhdr *h, Block *bp) { Ilcb *ic; ic = (Ilcb*)s->ptcl; USED(ic); | |
| 1998/0313 | netlog(s->p->f, Logilmsg, "%11s rcv %d/%d snt %d/%d pkt(%s id %d ack %d %d->%d) ", | |
| 1997/0327 | ilstates[ic->state], ic->rstart, ic->recvd, ic->start, ic->next, iltype[h->iltype], nhgetl(h->ilid), nhgetl(h->ilack), nhgets(h->ilsrc), nhgets(h->ildst)); _ilprocess(s, h, bp); | |
| 1998/0313 | netlog(s->p->f, Logilmsg, "%11s rcv %d snt %d\n", ilstates[ic->state], ic->recvd, ic->next); | |
| 1997/0327 | } void ilhangup(Conv *s, char *msg) { Ilcb *ic; int callout; | |
| 1998/0929 | netlog(s->p->f, Logil, "il: hangup! %I %d/%d: %s\n", s->raddr, s->lport, s->rport, msg?msg:"no reason"); | |
| 1997/0327 | ic = (Ilcb*)s->ptcl; callout = ic->state == Ilsyncer; | |
| 2001/0301 | illocalclose(s); | |
| 1997/0327 | qhangup(s->rq, msg); qhangup(s->wq, msg); if(callout) | |
| 1998/0313 | Fsconnected(s, msg); | |
| 1997/0327 | } void ilpullup(Conv *s) { Ilcb *ic; Ilhdr *oh; Block *bp; ulong oid, dlen; | |
| 1998/0313 | Ilpriv *ipriv; | |
| 1997/0327 | ic = (Ilcb*)s->ptcl; if(ic->state != Ilestablished) return; qlock(&ic->outo); while(ic->outoforder) { bp = ic->outoforder; oh = (Ilhdr*)bp->rp; oid = nhgetl(oh->ilid); if(oid <= ic->recvd) { ic->outoforder = bp->list; freeblist(bp); continue; } | |
| 1997/0916 | if(oid != ic->recvd+1){ | |
| 1998/0313 | ipriv = s->p->priv; | |
| 2000/0706 | ipriv->stats[OutOfOrder]++; | |
| 1997/0327 | break; | |
| 1997/0916 | } | |
| 1997/0327 | ic->recvd = oid; ic->outoforder = bp->list; bp->list = nil; dlen = nhgets(oh->illen)-IL_HDRSIZE; bp = trimblock(bp, IL_IPSIZE+IL_HDRSIZE, dlen); /* * Upper levels don't know about multiple-block * messages so copy all into one (yick). */ bp = concatblock(bp); if(bp == 0) panic("ilpullup"); | |
| 1998/0923 | bp = packblock(bp); if(bp == 0) panic("ilpullup2"); qpassnolim(s->rq, bp); | |
| 1997/0327 | } qunlock(&ic->outo); } void iloutoforder(Conv *s, Ilhdr *h, Block *bp) { Ilcb *ic; | |
| 1998/0306 | uchar *lid; | |
| 1997/0327 | Block *f, **l; ulong id, newid; | |
| 1998/0313 | Ilpriv *ipriv; | |
| 1997/0327 | ||
| 1998/0313 | ipriv = s->p->priv; | |
| 1997/0327 | ic = (Ilcb*)s->ptcl; bp->list = nil; id = nhgetl(h->ilid); /* Window checks */ if(id <= ic->recvd || id > ic->recvd+ic->window) { | |
| 1998/0313 | netlog(s->p->f, Logil, "il: message outside window %ud <%ud-%ud>: %i %d/%d\n", | |
| 1997/0327 | id, ic->recvd, ic->recvd+ic->window, s->raddr, s->lport, s->rport); freeblist(bp); return; } /* Packet is acceptable so sort onto receive queue for pullup */ qlock(&ic->outo); if(ic->outoforder == nil) ic->outoforder = bp; else { l = &ic->outoforder; for(f = *l; f; f = f->list) { lid = ((Ilhdr*)(f->rp))->ilid; newid = nhgetl(lid); if(id <= newid) { if(id == newid) { | |
| 2000/0706 | ipriv->stats[DupMsg]++; ipriv->stats[DupBytes] += blocklen(bp); | |
| 1997/0327 | qunlock(&ic->outo); freeblist(bp); return; } bp->list = f; *l = bp; qunlock(&ic->outo); return; } l = &f->list; } *l = bp; } qunlock(&ic->outo); } void | |
| 1997/0804 | ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec) | |
| 1997/0327 | { Ilhdr *ih; Ilcb *ic; Block *bp; | |
| 1999/0817 | int ttl, tos; | |
| 1997/0327 | bp = allocb(IL_IPSIZE+IL_HDRSIZE); bp->wp += IL_IPSIZE+IL_HDRSIZE; ih = (Ilhdr *)(bp->rp); | |
| 2002/0507 | ih->vihl = IP_VER4; | |
| 1997/0327 | /* Ip fields */ ih->proto = IP_ILPROTO; hnputs(ih->illen, IL_HDRSIZE); ih->frag[0] = 0; ih->frag[1] = 0; if(inih) { hnputl(ih->dst, nhgetl(inih->src)); hnputl(ih->src, nhgetl(inih->dst)); hnputs(ih->ilsrc, nhgets(inih->ildst)); hnputs(ih->ildst, nhgets(inih->ilsrc)); hnputl(ih->ilid, nhgetl(inih->ilack)); hnputl(ih->ilack, nhgetl(inih->ilid)); ttl = MAXTTL; | |
| 1999/0817 | tos = DFLTTOS; | |
| 1997/0327 | } else { | |
| 1998/0306 | v6tov4(ih->dst, ipc->raddr); v6tov4(ih->src, ipc->laddr); | |
| 1997/0327 | hnputs(ih->ilsrc, ipc->lport); hnputs(ih->ildst, ipc->rport); hnputl(ih->ilid, id); hnputl(ih->ilack, ack); ic = (Ilcb*)ipc->ptcl; | |
| 1998/0929 | ic->acksent = ack; ic->acktime = msec; | |
| 1997/0327 | ttl = ipc->ttl; | |
| 1999/0817 | tos = ipc->tos; | |
| 1997/0327 | } ih->iltype = type; | |
| 1997/0804 | ih->ilspec = ilspec; | |
| 1997/0327 | ih->ilsum[0] = 0; ih->ilsum[1] = 0; if(ilcksum) hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE)); | |
| 2002/0507 | ||
| 2001/0823 | if(ipc==nil) panic("ipc is nil caller is %.8lux", getcallerpc(&ipc)); if(ipc->p==nil) panic("ipc->p is nil"); | |
| 1997/0327 | ||
| 1999/0630 | netlog(ipc->p->f, Logilmsg, "ctl(%s id %d ack %d %d->%d)\n", | |
| 1997/0327 | iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack), nhgets(ih->ilsrc), nhgets(ih->ildst)); | |
| 2002/0507 | ipoput4(ipc->p->f, bp, 0, ttl, tos); | |
| 1999/0917 | } void ilreject(Fs *f, Ilhdr *inih) { Ilhdr *ih; Block *bp; bp = allocb(IL_IPSIZE+IL_HDRSIZE); bp->wp += IL_IPSIZE+IL_HDRSIZE; ih = (Ilhdr *)(bp->rp); | |
| 2002/0507 | ih->vihl = IP_VER4; | |
| 1999/0917 | /* Ip fields */ ih->proto = IP_ILPROTO; hnputs(ih->illen, IL_HDRSIZE); ih->frag[0] = 0; ih->frag[1] = 0; hnputl(ih->dst, nhgetl(inih->src)); hnputl(ih->src, nhgetl(inih->dst)); hnputs(ih->ilsrc, nhgets(inih->ildst)); hnputs(ih->ildst, nhgets(inih->ilsrc)); hnputl(ih->ilid, nhgetl(inih->ilack)); hnputl(ih->ilack, nhgetl(inih->ilid)); ih->iltype = Ilclose; ih->ilspec = 0; ih->ilsum[0] = 0; ih->ilsum[1] = 0; if(ilcksum) hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE)); | |
| 2002/0507 | ipoput4(f, bp, 0, MAXTTL, DFLTTOS); | |
| 1997/0327 | } void | |
| 1998/0929 | ilsettimeout(Ilcb *ic) { ulong pt; | |
| 1998/0930 | pt = (ic->delay>>LogAGain) + ic->unackedbytes/(ic->rate>>LogAGain) | |
| 1999/0703 | + (ic->mdev>>(LogDGain-1)) | |
| 1998/0930 | + AckDelay; | |
| 1998/0929 | if(pt > MaxTimeout) pt = MaxTimeout; ic->timeout = msec + pt; } void ilbackoff(Ilcb *ic) { ulong pt; int i; | |
| 1998/0930 | pt = (ic->delay>>LogAGain) + ic->unackedbytes/(ic->rate>>LogAGain) | |
| 1999/0703 | + (ic->mdev>>(LogDGain-1)) | |
| 1998/0930 | + AckDelay; | |
| 1998/0929 | for(i = 0; i < ic->rexmit; i++) pt = pt + (pt>>1); if(pt > MaxTimeout) pt = MaxTimeout; ic->timeout = msec + pt; | |
| 2001/0227 | if(ic->fasttimeout) ic->timeout = msec+Iltickms; | |
| 1998/0929 | ic->rexmit++; } | |
| 1999/0424 | // complain if two numbers not within an hour of each other #define Tfuture (1000*60*60) int later(ulong t1, ulong t2, char *x) { int dt; dt = t1 - t2; if(dt > 0) { | |
| 1999/0430 | if(x != nil && dt > Tfuture) | |
| 1999/0424 | print("%s: way future %d\n", x, dt); return 1; } if(dt < -Tfuture) { | |
| 1999/0430 | if(x != nil) print("%s: way past %d\n", x, -dt); | |
| 1999/0424 | return 1; } return 0; } | |
| 1998/0929 | void | |
| 1998/0313 | ilackproc(void *x) | |
| 1997/0327 | { Ilcb *ic; Conv **s, *p; | |
| 1998/0313 | Proto *il; Ilpriv *ipriv; | |
| 1997/0327 | ||
| 1998/0313 | il = x; ipriv = il->priv; | |
| 1997/0327 | loop: | |
| 1998/0313 | tsleep(&ipriv->ilr, return0, 0, Iltickms); for(s = il->conv; s && *s; s++) { | |
| 1997/0327 | p = *s; ic = (Ilcb*)p->ptcl; switch(ic->state) { case Ilclosed: case Illistening: break; case Ilclosing: | |
| 1999/0429 | if(later(msec, ic->timeout, "timeout0")) { | |
| 1998/0929 | if(ic->rexmit > MaxRexmit){ ilhangup(p, nil); break; } | |
| 1997/0804 | ilsendctl(p, nil, Ilclose, ic->next, ic->recvd, 0); | |
| 1997/0327 | ilbackoff(ic); } break; | |
| 1999/0331 | ||
| 1997/0327 | case Ilsyncee: case Ilsyncer: | |
| 1999/0429 | if(later(msec, ic->timeout, "timeout1")) { | |
| 1998/0929 | if(ic->rexmit > MaxRexmit){ ilhangup(p, etime); break; } | |
| 1997/0804 | ilsendctl(p, nil, Ilsync, ic->start, ic->recvd, 0); | |
| 1997/0327 | ilbackoff(ic); } break; | |
| 1999/0331 | ||
| 1997/0327 | case Ilestablished: | |
| 1999/0424 | if(ic->recvd != ic->acksent) if(later(msec, ic->acktime, "acktime")) | |
| 1997/0804 | ilsendctl(p, nil, Ilack, ic->next, ic->recvd, 0); | |
| 1997/0327 | ||
| 1999/0424 | if(later(msec, ic->querytime, "querytime")){ if(later(msec, ic->lastrecv+DeathTime, "deathtime")){ | |
| 1998/0929 | netlog(il->f, Logil, "il: hangup: deathtime\n"); | |
| 1997/0327 | ilhangup(p, etime); break; } | |
| 1997/0804 | ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic)); | |
| 1998/0929 | ic->querytime = msec + QueryTime; | |
| 1997/0327 | } | |
| 1998/0929 | ||
| 1999/0424 | if(ic->unacked != nil) | |
| 1999/0429 | if(later(msec, ic->timeout, "timeout2")) { | |
| 1998/0929 | if(ic->rexmit > MaxRexmit){ netlog(il->f, Logil, "il: hangup: too many rexmits\n"); ilhangup(p, etime); break; } | |
| 1998/0930 | ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic)); ic->rxquery++; ilbackoff(ic); | |
| 1997/0327 | } break; } } goto loop; } void | |
| 1998/0929 | ilcbinit(Ilcb *ic) | |
| 1997/0327 | { | |
| 1998/0929 | ic->start = nrand(0x1000000); ic->next = ic->start+1; ic->recvd = 0; ic->window = Defaultwin; | |
| 1998/0930 | ic->unackedbytes = 0; | |
| 1998/0929 | ic->unacked = nil; ic->outoforder = nil; ic->rexmit = 0; ic->rxtot = 0; | |
| 1998/1001 | ic->rxquery = 0; | |
| 1998/0929 | ic->qtx = 1; | |
| 2001/0227 | ic->fasttimeout = 0; | |
| 1998/0929 | /* timers */ ic->delay = DefRtt<<LogAGain; ic->mdev = DefRtt<<LogDGain; ic->rate = DefByteRate<<LogAGain; ic->querytime = msec + QueryTime; ic->lastrecv = msec; /* or we'll timeout right away */ ilsettimeout(ic); | |
| 1997/0327 | } char* | |
| 2001/0227 | ilstart(Conv *c, int type, int fasttimeout) | |
| 1997/0327 | { Ilcb *ic; | |
| 1998/0924 | Ilpriv *ipriv; | |
| 2001/0527 | char kpname[KNAMELEN]; | |
| 1998/0924 | ipriv = c->p->priv; if(ipriv->ackprocstarted == 0){ qlock(&ipriv->apl); if(ipriv->ackprocstarted == 0){ sprint(kpname, "#I%dilack", c->p->f->dev); kproc(kpname, ilackproc, c->p); ipriv->ackprocstarted = 1; } qunlock(&ipriv->apl); } | |
| 1997/0327 | ic = (Ilcb*)c->ptcl; ic->conv = c; if(ic->state != Ilclosed) | |
| 1998/0929 | return nil; | |
| 1997/0327 | ||
| 1998/0929 | ilcbinit(ic); | |
| 2001/0227 | if(fasttimeout){ /* timeout if we can't connect quickly */ ic->fasttimeout = 1; ic->timeout = msec+Iltickms; ic->rexmit = MaxRexmit - 4; }; | |
| 1997/0327 | switch(type) { default: | |
| 1998/0313 | netlog(c->p->f, Logil, "il: start: type %d\n", type); | |
| 1997/0327 | break; case IL_LISTEN: ic->state = Illistening; | |
| 2001/0301 | iphtadd(&ipriv->ht, c); | |
| 1997/0327 | break; case IL_CONNECT: ic->state = Ilsyncer; | |
| 2001/0301 | iphtadd(&ipriv->ht, c); | |
| 1997/0804 | ilsendctl(c, nil, Ilsync, ic->start, ic->recvd, 0); | |
| 1997/0327 | break; } | |
| 1998/0929 | return nil; | |
| 1997/0327 | } void ilfreeq(Ilcb *ic) { Block *bp, *next; qlock(&ic->ackq); for(bp = ic->unacked; bp; bp = next) { next = bp->list; freeblist(bp); } ic->unacked = nil; qunlock(&ic->ackq); qlock(&ic->outo); for(bp = ic->outoforder; bp; bp = next) { next = bp->list; freeblist(bp); } ic->outoforder = nil; qunlock(&ic->outo); } void | |
| 1998/0313 | iladvise(Proto *il, Block *bp, char *msg) | |
| 1997/0327 | { Ilhdr *h; Ilcb *ic; | |
| 1998/0306 | uchar source[IPaddrlen], dest[IPaddrlen]; | |
| 1997/0327 | ushort psource; Conv *s, **p; h = (Ilhdr*)(bp->rp); | |
| 1998/0306 | v4tov6(dest, h->dst); v4tov6(source, h->src); | |
| 1997/0327 | psource = nhgets(h->ilsrc); /* Look for a connection, unfortunately the destination port is missing */ | |
| 1999/0302 | qlock(il); | |
| 1998/0313 | for(p = il->conv; *p; p++) { | |
| 1997/0327 | s = *p; | |
| 1998/0306 | if(s->lport == psource) if(ipcmp(s->laddr, source) == 0) if(ipcmp(s->raddr, dest) == 0){ | |
| 1999/0302 | qunlock(il); | |
| 1997/0327 | ic = (Ilcb*)s->ptcl; switch(ic->state){ case Ilsyncer: ilhangup(s, msg); break; } | |
| 1999/0302 | freeblist(bp); return; | |
| 1997/0327 | } } | |
| 1999/0302 | qunlock(il); | |
| 1997/0327 | freeblist(bp); | |
| 1997/0804 | } int ilnextqt(Ilcb *ic) { int x; qlock(&ic->ackq); x = ic->qtx; if(++x > Nqt) x = 1; ic->qtx = x; | |
| 1998/1013 | ic->qt[x] = ic->next-1; /* highest xmitted packet */ ic->qt[0] = ic->qt[x]; /* compatibility with old implementations */ | |
| 1997/0804 | qunlock(&ic->ackq); return x; | |
| 1998/0929 | } | |
| 1999/0703 | /* calculate scale constants that converts fast ticks to ms (more or less) */ | |
| 1998/0929 | static void | |
| 1999/0703 | inittimescale(void) | |
| 1998/0929 | { | |
| 1999/0703 | uvlong hz; | |
| 1998/0929 | fastticks(&hz); | |
| 1999/0703 | if(hz > 1000){ scalediv = hz/1000; scalemul = 1; } else { scalediv = 1; scalemul = 1000/hz; | |
| 1998/0929 | } } void ilinit(Fs *f) { Proto *il; | |
| 1999/0703 | inittimescale(); | |
| 1998/0929 | il = smalloc(sizeof(Proto)); il->priv = smalloc(sizeof(Ilpriv)); il->name = "il"; il->kick = ilkick; il->connect = ilconnect; il->announce = ilannounce; il->state = ilstate; il->create = ilcreate; il->close = ilclose; il->rcv = iliput; il->ctl = nil; il->advise = iladvise; il->stats = ilxstats; il->inuse = ilinuse; | |
| 2000/0424 | il->gc = nil; | |
| 1998/0929 | il->ipproto = IP_ILPROTO; | |
| 2001/0922 | il->nc = scalednconv(); | |
| 1998/0929 | il->ptclsize = sizeof(Ilcb); Fsproto(f, il); | |
| 1997/0327 | } | |