il.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       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 }