--- /n/sources/plan9/sys/src/9/boot/boot.h Fri Jul 22 03:38:12 2011 +++ /sys/src/9/boot/boot.h Wed Mar 21 00:00:00 2012 @@ -61,6 +61,9 @@ extern void configtcp(Method*); extern int connecttcp(void); +extern void configil(Method*); +extern int connectil(void); + extern void configlocal(Method*); extern int connectlocal(void); --- /n/sources/plan9/sys/src/9/boot/bootip.c Fri Jul 22 03:38:12 2011 +++ /sys/src/9/boot/bootip.c Wed Mar 21 00:00:00 2012 @@ -143,6 +143,22 @@ return fd; } +void +configil(Method*) +{ + configip(bargc, bargv, 1); + setauthaddr("tcp", 567); +} + +int +connectil(void) +{ + char buf[64]; + + snprint(buf, sizeof buf, "il!%I!17008", fsip); + return dial(buf, 0, 0, 0); +} + static int isvalidip(uchar *ip) { --- /sys/src/9/ip/il.c Wed Mar 21 21:04:59 2012 +++ /sys/src/9/ip/il.c Wed Mar 21 00:00:00 2012 @@ -0,0 +1,1408 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "ip.h" + +enum /* Connection state */ +{ + Ilclosed, + Ilsyncer, + Ilsyncee, + Ilestablished, + Illistening, + Ilclosing, + Ilopening, /* only for file server */ +}; + +char *ilstates[] = +{ + "Closed", + "Syncer", + "Syncee", + "Established", + "Listen", + "Closing", + "Opening", /* only for file server */ +}; + +enum /* Packet types */ +{ + Ilsync, + Ildata, + Ildataquery, + Ilack, + Ilquery, + Ilstate, + Ilclose, +}; + +char *iltype[] = +{ + "sync", + "data", + "dataquery", + "ack", + "query", + "state", + "close" +}; + +enum +{ + Seconds = 1000, + Iltickms = 50, /* time base */ + AckDelay = 2*Iltickms, /* max time twixt message rcvd & ack sent */ + MaxTimeout = 30*Seconds, /* max time between rexmit */ + QueryTime = 10*Seconds, /* time between subsequent queries */ + DeathTime = 30*QueryTime, + + MaxRexmit = 16, /* max retransmissions before hangup */ + Defaultwin = 20, + + LogAGain = 3, + AGain = 1< 1){ + p = strstr(argv[1], "!fasttimeout"); + if(p != nil){ + *p = 0; + fast = 1; + } + } + + e = Fsstdconnect(c, argv, argc); + if(e != nil) + return e; + return ilstart(c, IL_CONNECT, fast); +} + +static int +ilstate(Conv *c, char *state, int n) +{ + Ilcb *ic; + + ic = (Ilcb*)(c->ptcl); + 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", + ilstates[ic->state], + c->rq ? qlen(c->rq) : 0, + c->wq ? qlen(c->wq) : 0, + ic->delay>>LogAGain, ic->rate>>LogAGain, ic->mdev>>LogDGain, + ic->unackedbytes, ic->rxtot, ic->rxquery, ic->maxrtt); +} + +static int +ilinuse(Conv *c) +{ + Ilcb *ic; + + ic = (Ilcb*)(c->ptcl); + return ic->state != Ilclosed; + +} + +/* called with c locked */ +static char* +ilannounce(Conv *c, char **argv, int argc) +{ + char *e; + + e = Fsstdannounce(c, argv, argc); + if(e != nil) + return e; + e = ilstart(c, IL_LISTEN, 0); + if(e != nil) + return e; + Fsconnected(c, nil); + + return nil; +} + +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; +} + +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; + ilsettimeout(ic); + ilsendctl(c, nil, Ilclose, ic->next, ic->recvd, 0); + break; + case Illistening: + illocalclose(c); + break; + } + ilfreeq(ic); +} + +void +ilkick(void *x, Block *bp) +{ + Conv *c = x; + Ilhdr *ih; + Ilcb *ic; + int dlen; + ulong id, ack; + Fs *f; + Ilpriv *priv; + + f = c->p->f; + priv = c->p->priv; + ic = (Ilcb*)c->ptcl; + + 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); + ih->vihl = IP_VER4; + + /* Ip fields */ + ih->frag[0] = 0; + ih->frag[1] = 0; + v6tov4(ih->dst, c->raddr); + v6tov4(ih->src, c->laddr); + 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); + ack = ic->recvd; + hnputl(ih->ilack, ack); + ic->acksent = ack; + ic->acktime = NOW + AckDelay; + 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; + ic->rttstart = fastticks(nil); + ic->rttlen = dlen + IL_IPSIZE + IL_HDRSIZE; + } + + if(later(NOW, ic->timeout, nil)) + ilsettimeout(ic); + ipoput4(f, bp, 0, c->ttl, c->tos, c); + priv->stats[OutMsgs]++; +} + +static void +ilcreate(Conv *c) +{ + c->rq = qopen(Maxrq, 0, 0, c); + c->wq = qbypass(ilkick, c); +} + +int +ilxstats(Proto *il, char *buf, int len) +{ + Ilpriv *priv; + char *p, *e; + int i; + + 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; +} + +void +ilackq(Ilcb *ic, Block *bp) +{ + Block *np; + int n; + + n = blocklen(bp); + + /* Enqueue a copy on the unacked queue in case this one gets lost */ + np = copyblock(bp, n); + if(ic->unacked) + ic->unackedtail->list = np; + else + ic->unacked = np; + ic->unackedtail = np; + np->list = nil; + ic->unackedbytes += n; +} + +static +void +ilrttcalc(Ilcb *ic, Block *bp) +{ + int rtt, tt, pt, delay, rate; + + rtt = fastticks(nil) - ic->rttstart; + rtt = (rtt*scalemul)/scalediv; + delay = ic->delay; + rate = ic->rate; + + /* Guard against zero wrap */ + if(rtt > 120000 || rtt < 0) + return; + + /* 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); + if(delay < AGain) + delay = AGain; + ic->delay = delay; + } 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; + } + } + + /* mdev */ + pt = ic->rttlen/(rate>>LogAGain) + (delay>>LogAGain); + ic->mdev += abs(rtt-pt) - (ic->mdev>>LogDGain); + + if(rtt > ic->maxrtt) + ic->maxrtt = rtt; +} + +void +ilackto(Ilcb *ic, ulong ackto, Block *bp) +{ + Ilhdr *h; + ulong id; + + if(ic->rttack == ackto) + ilrttcalc(ic, bp); + + /* Cancel if we've passed the packet we were interested in */ + 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; + ic->unackedbytes -= blocklen(bp); + freeblist(bp); + ic->rexmit = 0; + ilsettimeout(ic); + } + qunlock(&ic->ackq); +} + +void +iliput(Proto *il, Ipifc*, Block *bp) +{ + char *st; + Ilcb *ic; + Ilhdr *ih; + uchar raddr[IPaddrlen]; + uchar laddr[IPaddrlen]; + ushort sp, dp, csum; + int plen, illen; + Conv *new, *s; + Ilpriv *ipriv; + + ipriv = il->priv; + + ih = (Ilhdr *)bp->rp; + plen = blocklen(bp); + if(plen < IL_IPSIZE+IL_HDRSIZE){ + netlog(il->f, Logil, "il: hlenerr\n"); + ipriv->stats[HlenErrs]++; + goto raise; + } + + illen = nhgets(ih->illen); + if(illen+IL_IPSIZE > plen){ + netlog(il->f, Logil, "il: lenerr\n"); + ipriv->stats[LenErrs]++; + goto raise; + } + + sp = nhgets(ih->ildst); + dp = nhgets(ih->ilsrc); + v4tov6(raddr, ih->src); + v4tov6(laddr, ih->dst); + + if((csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) { + if(ih->iltype > Ilclose) + st = "?"; + else + st = iltype[ih->iltype]; + ipriv->stats[CsumErrs]++; + netlog(il->f, Logil, "il: cksum %ux %ux, pkt(%s id %lud ack %lud %I/%d->%d)\n", + csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp); + goto raise; + } + + qlock(il); + s = iphtlook(&ipriv->ht, raddr, dp, laddr, sp); + if(s == nil){ + if(ih->iltype == Ilsync) + ilreject(il->f, ih); /* no listener */ + qunlock(il); + goto raise; + } + + ic = (Ilcb*)s->ptcl; + if(ic->state == Illistening){ + if(ih->iltype != Ilsync){ + qunlock(il); + if(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; + } + + new = Fsnewcall(s, raddr, dp, laddr, sp, V4); + if(new == nil){ + 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; + } + s = new; + + ic = (Ilcb*)s->ptcl; + + ic->conv = s; + ic->state = Ilsyncee; + ilcbinit(ic); + ic->rstart = nhgetl(ih->ilid); + iphtadd(&ipriv->ht, s); + } + + qlock(s); + qunlock(il); + if(waserror()){ + qunlock(s); + nexterror(); + } + ilprocess(s, ih, bp); + qunlock(s); + poperror(); + return; +raise: + freeblist(bp); +} + +void +_ilprocess(Conv *s, Ilhdr *h, Block *bp) +{ + Ilcb *ic; + ulong id, ack; + Ilpriv *priv; + + id = nhgetl(h->ilid); + ack = nhgetl(h->ilack); + + ic = (Ilcb*)s->ptcl; + + ic->lastrecv = NOW; + ic->querytime = NOW + QueryTime; + priv = s->p->priv; + priv->stats[InMsgs]++; + + switch(ic->state) { + default: + netlog(s->p->f, Logil, "il: unknown state %d\n", ic->state); + 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; + ilsendctl(s, nil, Ilack, ic->next, ic->recvd, 0); + ic->state = Ilestablished; + ic->fasttimeout = 0; + ic->rexmit = 0; + Fsconnected(s, nil); + ilpullup(s); + } + break; + case Ilclose: + if(ack == ic->start) + ilhangup(s, "connection rejected"); + break; + } + freeblist(bp); + break; + case Ilsyncee: + switch(h->iltype) { + default: + break; + case Ilsync: + if(id != ic->rstart || ack != 0){ + illocalclose(s); + } else { + ic->recvd = id; + ilsendctl(s, nil, Ilsync, ic->start, ic->recvd, 0); + } + break; + case Ilack: + if(ack == ic->start) { + ic->state = Ilestablished; + ic->fasttimeout = 0; + ic->rexmit = 0; + ilpullup(s); + } + break; + case Ildata: + if(ack == ic->start) { + ic->state = Ilestablished; + ic->fasttimeout = 0; + ic->rexmit = 0; + goto established; + } + break; + case Ilclose: + if(ack == ic->start) + ilhangup(s, "remote close"); + break; + } + freeblist(bp); + break; + case Ilestablished: + established: + switch(h->iltype) { + case Ilsync: + if(id != ic->rstart) + ilhangup(s, "remote close"); + else + ilsendctl(s, nil, Ilack, ic->next, ic->rstart, 0); + freeblist(bp); + break; + case Ildata: + /* + * avoid consuming all the mount rpc buffers in the + * system. if the input queue is too long, drop this + * packet. + */ + if (s->rq && qlen(s->rq) >= Maxrq) { + priv->stats[DroppedMsgs]++; + freeblist(bp); + break; + } + + ilackto(ic, ack, bp); + iloutoforder(s, h, bp); + ilpullup(s); + break; + case Ildataquery: + ilackto(ic, ack, bp); + iloutoforder(s, h, bp); + ilpullup(s); + ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec); + break; + case Ilack: + ilackto(ic, ack, bp); + freeblist(bp); + break; + case Ilquery: + ilackto(ic, ack, bp); + ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec); + freeblist(bp); + break; + case Ilstate: + if(ack >= ic->rttack) + ic->rttack = 0; + ilackto(ic, ack, bp); + if(h->ilspec > Nqt) + h->ilspec = 0; + if(ic->qt[h->ilspec] > ack){ + ilrexmit(ic); + ilsettimeout(ic); + } + freeblist(bp); + break; + case Ilclose: + freeblist(bp); + if(ack < ic->start || ack > ic->next) + break; + ic->recvd = id; + ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0); + ic->state = Ilclosing; + ilsettimeout(ic); + ilfreeq(ic); + break; + } + break; + case Illistening: + freeblist(bp); + break; + case Ilclosing: + switch(h->iltype) { + case Ilclose: + ic->recvd = id; + ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0); + if(ack == ic->next) + ilhangup(s, nil); + break; + default: + break; + } + freeblist(bp); + break; + } +} + +void +ilrexmit(Ilcb *ic) +{ + Ilhdr *h; + Block *nb; + Conv *c; + ulong id; + Ilpriv *priv; + + nb = nil; + qlock(&ic->ackq); + if(ic->unacked) + nb = copyblock(ic->unacked, blocklen(ic->unacked)); + qunlock(&ic->ackq); + + if(nb == nil) + return; + + h = (Ilhdr*)nb->rp; + h->vihl = IP_VER4; + + h->iltype = Ildataquery; + hnputl(h->ilack, ic->recvd); + h->ilspec = ilnextqt(ic); + h->ilsum[0] = 0; + h->ilsum[1] = 0; + hnputs(h->ilsum, ptclcsum(nb, IL_IPSIZE, nhgets(h->illen))); + + c = ic->conv; + id = nhgetl(h->ilid); + netlog(c->p->f, Logil, "il: rexmit %d %ud: %d %d: %i %d/%d\n", id, ic->recvd, + ic->rexmit, ic->timeout, + c->raddr, c->lport, c->rport); + + ilbackoff(ic); + + ipoput4(c->p->f, nb, 0, c->ttl, c->tos, c); + + /* statistics */ + ic->rxtot++; + priv = c->p->priv; + priv->rexmit++; +} + +/* DEBUG */ +void +ilprocess(Conv *s, Ilhdr *h, Block *bp) +{ + Ilcb *ic; + + ic = (Ilcb*)s->ptcl; + + USED(ic); + netlog(s->p->f, Logilmsg, "%11s rcv %d/%d snt %d/%d pkt(%s id %d ack %d %d->%d) ", + 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); + + netlog(s->p->f, Logilmsg, "%11s rcv %d snt %d\n", ilstates[ic->state], ic->recvd, ic->next); +} + +void +ilhangup(Conv *s, char *msg) +{ + Ilcb *ic; + int callout; + + netlog(s->p->f, Logil, "il: hangup! %I %d/%d: %s\n", s->raddr, + s->lport, s->rport, msg?msg:"no reason"); + + ic = (Ilcb*)s->ptcl; + callout = ic->state == Ilsyncer; + illocalclose(s); + + qhangup(s->rq, msg); + qhangup(s->wq, msg); + + if(callout) + Fsconnected(s, msg); +} + +void +ilpullup(Conv *s) +{ + Ilcb *ic; + Ilhdr *oh; + Block *bp; + ulong oid, dlen; + Ilpriv *ipriv; + + 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; + } + if(oid != ic->recvd+1){ + ipriv = s->p->priv; + ipriv->stats[OutOfOrder]++; + break; + } + + 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"); + bp = packblock(bp); + if(bp == 0) + panic("ilpullup2"); + qpass(s->rq, bp); + } + qunlock(&ic->outo); +} + +void +iloutoforder(Conv *s, Ilhdr *h, Block *bp) +{ + Ilcb *ic; + uchar *lid; + Block *f, **l; + ulong id, newid; + Ilpriv *ipriv; + + ipriv = s->p->priv; + ic = (Ilcb*)s->ptcl; + bp->list = nil; + + id = nhgetl(h->ilid); + /* Window checks */ + if(id <= ic->recvd || id > ic->recvd+ic->window) { + netlog(s->p->f, Logil, "il: message outside window %ud <%ud-%ud>: %i %d/%d\n", + 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) { + ipriv->stats[DupMsg]++; + ipriv->stats[DupBytes] += blocklen(bp); + qunlock(&ic->outo); + freeblist(bp); + return; + } + bp->list = f; + *l = bp; + qunlock(&ic->outo); + return; + } + l = &f->list; + } + *l = bp; + } + qunlock(&ic->outo); +} + +void +ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec) +{ + Ilhdr *ih; + Ilcb *ic; + Block *bp; + int ttl, tos; + + bp = allocb(IL_IPSIZE+IL_HDRSIZE); + bp->wp += IL_IPSIZE+IL_HDRSIZE; + + ih = (Ilhdr *)(bp->rp); + ih->vihl = IP_VER4; + + /* 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; + tos = DFLTTOS; + } + else { + v6tov4(ih->dst, ipc->raddr); + v6tov4(ih->src, ipc->laddr); + hnputs(ih->ilsrc, ipc->lport); + hnputs(ih->ildst, ipc->rport); + hnputl(ih->ilid, id); + hnputl(ih->ilack, ack); + ic = (Ilcb*)ipc->ptcl; + ic->acksent = ack; + ic->acktime = NOW; + ttl = ipc->ttl; + tos = ipc->tos; + } + ih->iltype = type; + ih->ilspec = ilspec; + ih->ilsum[0] = 0; + ih->ilsum[1] = 0; + + if(ilcksum) + hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE)); + +if(ipc==nil) + panic("ipc is nil caller is %#p", getcallerpc(&ipc)); +if(ipc->p==nil) + panic("ipc->p is nil"); + + netlog(ipc->p->f, Logilmsg, "ctl(%s id %d ack %d %d->%d)\n", + iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack), + nhgets(ih->ilsrc), nhgets(ih->ildst)); + + ipoput4(ipc->p->f, bp, 0, ttl, tos, ipc); +} + +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); + ih->vihl = IP_VER4; + + /* 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)); + + ipoput4(f, bp, 0, MAXTTL, DFLTTOS, nil); +} + +void +ilsettimeout(Ilcb *ic) +{ + ulong pt; + + pt = (ic->delay>>LogAGain) + + ic->unackedbytes/(ic->rate>>LogAGain) + + (ic->mdev>>(LogDGain-1)) + + AckDelay; + if(pt > MaxTimeout) + pt = MaxTimeout; + ic->timeout = NOW + pt; +} + +void +ilbackoff(Ilcb *ic) +{ + ulong pt; + int i; + + pt = (ic->delay>>LogAGain) + + ic->unackedbytes/(ic->rate>>LogAGain) + + (ic->mdev>>(LogDGain-1)) + + AckDelay; + for(i = 0; i < ic->rexmit; i++) + pt = pt + (pt>>1); + if(pt > MaxTimeout) + pt = MaxTimeout; + ic->timeout = NOW + pt; + + if(ic->fasttimeout) + ic->timeout = NOW+Iltickms; + + ic->rexmit++; +} + +// 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) { + if(x != nil && dt > Tfuture) + print("%s: way future %d\n", x, dt); + return 1; + } + if(dt < -Tfuture) { + if(x != nil) + print("%s: way past %d\n", x, -dt); + return 1; + } + return 0; +} + +void +ilackproc(void *x) +{ + Ilcb *ic; + Conv **s, *p; + Proto *il; + + il = x; + +loop: + tsleep(&up->sleep, return0, 0, Iltickms); + for(s = il->conv; s && *s; s++) { + p = *s; + ic = (Ilcb*)p->ptcl; + + switch(ic->state) { + case Ilclosed: + case Illistening: + break; + case Ilclosing: + if(later(NOW, ic->timeout, "timeout0")) { + if(ic->rexmit > MaxRexmit){ + ilhangup(p, nil); + break; + } + ilsendctl(p, nil, Ilclose, ic->next, ic->recvd, 0); + ilbackoff(ic); + } + break; + + case Ilsyncee: + case Ilsyncer: + if(later(NOW, ic->timeout, "timeout1")) { + if(ic->rexmit > MaxRexmit){ + ilhangup(p, etime); + break; + } + ilsendctl(p, nil, Ilsync, ic->start, ic->recvd, 0); + ilbackoff(ic); + } + break; + + case Ilestablished: + if(ic->recvd != ic->acksent) + if(later(NOW, ic->acktime, "acktime")) + ilsendctl(p, nil, Ilack, ic->next, ic->recvd, 0); + + if(later(NOW, ic->querytime, "querytime")){ + if(later(NOW, ic->lastrecv+DeathTime, "deathtime")){ + netlog(il->f, Logil, "il: hangup: deathtime\n"); + ilhangup(p, etime); + break; + } + ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic)); + ic->querytime = NOW + QueryTime; + } + + if(ic->unacked != nil) + if(later(NOW, ic->timeout, "timeout2")) { + if(ic->rexmit > MaxRexmit){ + netlog(il->f, Logil, "il: hangup: too many rexmits\n"); + ilhangup(p, etime); + break; + } + ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic)); + ic->rxquery++; + ilbackoff(ic); + } + break; + } + } + goto loop; +} + +void +ilcbinit(Ilcb *ic) +{ + ic->start = nrand(0x1000000); + ic->next = ic->start+1; + ic->recvd = 0; + ic->window = Defaultwin; + ic->unackedbytes = 0; + ic->unacked = nil; + ic->outoforder = nil; + ic->rexmit = 0; + ic->rxtot = 0; + ic->rxquery = 0; + ic->qtx = 1; + ic->fasttimeout = 0; + + /* timers */ + ic->delay = DefRtt<mdev = DefRtt<rate = DefByteRate<querytime = NOW + QueryTime; + ic->lastrecv = NOW; /* or we'll timeout right away */ + ilsettimeout(ic); +} + +char* +ilstart(Conv *c, int type, int fasttimeout) +{ + Ilcb *ic; + Ilpriv *ipriv; + char kpname[KNAMELEN]; + + 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); + } + + ic = (Ilcb*)c->ptcl; + ic->conv = c; + + if(ic->state != Ilclosed) + return nil; + + ilcbinit(ic); + + if(fasttimeout){ + /* timeout if we can't connect quickly */ + ic->fasttimeout = 1; + ic->timeout = NOW+Iltickms; + ic->rexmit = MaxRexmit - 4; + }; + + switch(type) { + default: + netlog(c->p->f, Logil, "il: start: type %d\n", type); + break; + case IL_LISTEN: + ic->state = Illistening; + iphtadd(&ipriv->ht, c); + break; + case IL_CONNECT: + ic->state = Ilsyncer; + iphtadd(&ipriv->ht, c); + ilsendctl(c, nil, Ilsync, ic->start, ic->recvd, 0); + break; + } + + return nil; +} + +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 +iladvise(Proto *il, Block *bp, char *msg) +{ + Ilhdr *h; + Ilcb *ic; + uchar source[IPaddrlen], dest[IPaddrlen]; + ushort psource; + Conv *s, **p; + + h = (Ilhdr*)(bp->rp); + + v4tov6(dest, h->dst); + v4tov6(source, h->src); + psource = nhgets(h->ilsrc); + + + /* Look for a connection, unfortunately the destination port is missing */ + qlock(il); + for(p = il->conv; *p; p++) { + s = *p; + if(s->lport == psource) + if(ipcmp(s->laddr, source) == 0) + if(ipcmp(s->raddr, dest) == 0){ + qunlock(il); + ic = (Ilcb*)s->ptcl; + switch(ic->state){ + case Ilsyncer: + ilhangup(s, msg); + break; + } + freeblist(bp); + return; + } + } + qunlock(il); + freeblist(bp); +} + +int +ilnextqt(Ilcb *ic) +{ + int x; + + qlock(&ic->ackq); + x = ic->qtx; + if(++x > Nqt) + x = 1; + ic->qtx = x; + ic->qt[x] = ic->next-1; /* highest xmitted packet */ + ic->qt[0] = ic->qt[x]; /* compatibility with old implementations */ + qunlock(&ic->ackq); + + return x; +} + +/* calculate scale constants that converts fast ticks to ms (more or less) */ +static void +inittimescale(void) +{ + uvlong hz; + + fastticks(&hz); + if(hz > 1000){ + scalediv = hz/1000; + scalemul = 1; + } else { + scalediv = 1; + scalemul = 1000/hz; + } +} + +void +ilinit(Fs *f) +{ + Proto *il; + + inittimescale(); + + il = smalloc(sizeof(Proto)); + il->priv = smalloc(sizeof(Ilpriv)); + il->name = "il"; + 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; + il->gc = nil; + il->ipproto = IP_ILPROTO; + il->nc = scalednconv(); + il->ptclsize = sizeof(Ilcb); + Fsproto(f, il); +} --- /n/sources/plan9/sys/src/9/ip/ip.h Wed Nov 25 04:19:33 2009 +++ /sys/src/9/ip/ip.h Wed Mar 21 00:00:00 2012 @@ -486,9 +486,11 @@ Logip= 1<<1, Logtcp= 1<<2, Logfs= 1<<3, + Logil= 1<<4, Logicmp= 1<<5, Logudp= 1<<6, Logcompress= 1<<7, + Logilmsg= 1<<8, Loggre= 1<<9, Logppp= 1<<10, Logtcprxmt= 1<<11, --- /n/sources/plan9/sys/src/9/ip/netlog.c Mon Dec 12 01:06:28 2011 +++ /sys/src/9/ip/netlog.c Wed Mar 21 00:00:00 2012 @@ -40,9 +40,11 @@ { "ip", Logip, }, { "fs", Logfs, }, { "tcp", Logtcp, }, + { "il", Logil, }, { "icmp", Logicmp, }, { "udp", Logudp, }, { "compress", Logcompress, }, + { "ilmsg", Logil|Logilmsg, }, { "gre", Loggre, }, { "tcpwin", Logtcp|Logtcpwin, }, { "tcprxmt", Logtcp|Logtcprxmt, },