]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ip/il.c
kernel: dont use atomic increment for Proc.nlocks, maintain Lock.m for lock(), use...
[plan9front.git] / sys / src / 9 / ip / il.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "../port/error.h"
7
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         uvlong  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: %llud\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*, 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 %s, pkt(%ux id %ud ack %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 %ud ack %ud %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 %lud %lud: %d %lud: %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 %lud/%lud snt %lud/%lud pkt(%s id %d ack %ud %ud->%ud) ",
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 %lud snt %lud\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 %lud <%lud-%lud>: %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         while(waserror())
1149                 ;
1150 loop:
1151         tsleep(&up->sleep, return0, 0, Iltickms);
1152         for(s = il->conv; s && *s; s++) {
1153                 p = *s;
1154                 ic = (Ilcb*)p->ptcl;
1155
1156                 switch(ic->state) {
1157                 case Ilclosed:
1158                 case Illistening:
1159                         break;
1160                 case Ilclosing:
1161                         if(later(NOW, ic->timeout, "timeout0")) {
1162                                 if(ic->rexmit > MaxRexmit){
1163                                         ilhangup(p, nil);
1164                                         break;
1165                                 }
1166                                 ilsendctl(p, nil, Ilclose, ic->next, ic->recvd, 0);
1167                                 ilbackoff(ic);
1168                         }
1169                         break;
1170
1171                 case Ilsyncee:
1172                 case Ilsyncer:
1173                         if(later(NOW, ic->timeout, "timeout1")) {
1174                                 if(ic->rexmit > MaxRexmit){
1175                                         ilhangup(p, etime);
1176                                         break;
1177                                 }
1178                                 ilsendctl(p, nil, Ilsync, ic->start, ic->recvd, 0);
1179                                 ilbackoff(ic);
1180                         }
1181                         break;
1182
1183                 case Ilestablished:
1184                         if(ic->recvd != ic->acksent)
1185                         if(later(NOW, ic->acktime, "acktime"))
1186                                 ilsendctl(p, nil, Ilack, ic->next, ic->recvd, 0);
1187
1188                         if(later(NOW, ic->querytime, "querytime")){
1189                                 if(later(NOW, ic->lastrecv+DeathTime, "deathtime")){
1190                                         netlog(il->f, Logil, "il: hangup: deathtime\n");
1191                                         ilhangup(p, etime);
1192                                         break;
1193                                 }
1194                                 ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic));
1195                                 ic->querytime = NOW + QueryTime;
1196                         }
1197
1198                         if(ic->unacked != nil)
1199                         if(later(NOW, ic->timeout, "timeout2")) {
1200                                 if(ic->rexmit > MaxRexmit){
1201                                         netlog(il->f, Logil, "il: hangup: too many rexmits\n");
1202                                         ilhangup(p, etime);
1203                                         break;
1204                                 }
1205                                 ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic));
1206                                 ic->rxquery++;
1207                                 ilbackoff(ic);
1208                         }
1209                         break;
1210                 }
1211         }
1212         goto loop;
1213 }
1214
1215 void
1216 ilcbinit(Ilcb *ic)
1217 {
1218         ic->start = nrand(0x1000000);
1219         ic->next = ic->start+1;
1220         ic->recvd = 0;
1221         ic->window = Defaultwin;
1222         ic->unackedbytes = 0;
1223         ic->unacked = nil;
1224         ic->outoforder = nil;
1225         ic->rexmit = 0;
1226         ic->rxtot = 0;
1227         ic->rxquery = 0;
1228         ic->qtx = 1;
1229         ic->fasttimeout = 0;
1230
1231         /* timers */
1232         ic->delay = DefRtt<<LogAGain;
1233         ic->mdev = DefRtt<<LogDGain;
1234         ic->rate = DefByteRate<<LogAGain;
1235         ic->querytime = NOW + QueryTime;
1236         ic->lastrecv = NOW;     /* or we'll timeout right away */
1237         ilsettimeout(ic);
1238 }
1239
1240 char*
1241 ilstart(Conv *c, int type, int fasttimeout)
1242 {
1243         Ilcb *ic;
1244         Ilpriv *ipriv;
1245         char kpname[KNAMELEN];
1246
1247         ipriv = c->p->priv;
1248
1249         if(ipriv->ackprocstarted == 0){
1250                 qlock(&ipriv->apl);
1251                 if(ipriv->ackprocstarted == 0){
1252                         sprint(kpname, "#I%dilack", c->p->f->dev);
1253                         kproc(kpname, ilackproc, c->p);
1254                         ipriv->ackprocstarted = 1;
1255                 }
1256                 qunlock(&ipriv->apl);
1257         }
1258
1259         ic = (Ilcb*)c->ptcl;
1260         ic->conv = c;
1261
1262         if(ic->state != Ilclosed)
1263                 return nil;
1264
1265         ilcbinit(ic);
1266
1267         if(fasttimeout){
1268                 /* timeout if we can't connect quickly */
1269                 ic->fasttimeout = 1;
1270                 ic->timeout = NOW+Iltickms;
1271                 ic->rexmit = MaxRexmit - 4;
1272         };
1273
1274         switch(type) {
1275         default:
1276                 netlog(c->p->f, Logil, "il: start: type %d\n", type);
1277                 break;
1278         case IL_LISTEN:
1279                 ic->state = Illistening;
1280                 iphtadd(&ipriv->ht, c);
1281                 break;
1282         case IL_CONNECT:
1283                 ic->state = Ilsyncer;
1284                 iphtadd(&ipriv->ht, c);
1285                 ilsendctl(c, nil, Ilsync, ic->start, ic->recvd, 0);
1286                 break;
1287         }
1288
1289         return nil;
1290 }
1291
1292 void
1293 ilfreeq(Ilcb *ic)
1294 {
1295         Block *bp, *next;
1296
1297         qlock(&ic->ackq);
1298         for(bp = ic->unacked; bp; bp = next) {
1299                 next = bp->list;
1300                 freeblist(bp);
1301         }
1302         ic->unacked = nil;
1303         qunlock(&ic->ackq);
1304
1305         qlock(&ic->outo);
1306         for(bp = ic->outoforder; bp; bp = next) {
1307                 next = bp->list;
1308                 freeblist(bp);
1309         }
1310         ic->outoforder = nil;
1311         qunlock(&ic->outo);
1312 }
1313
1314 void
1315 iladvise(Proto *il, Block *bp, char *msg)
1316 {
1317         Ilhdr *h;
1318         Ilcb *ic;               
1319         uchar source[IPaddrlen], dest[IPaddrlen];
1320         ushort psource;
1321         Conv *s, **p;
1322
1323         h = (Ilhdr*)(bp->rp);
1324
1325         v4tov6(dest, h->dst);
1326         v4tov6(source, h->src);
1327         psource = nhgets(h->ilsrc);
1328
1329
1330         /* Look for a connection, unfortunately the destination port is missing */
1331         qlock(il);
1332         for(p = il->conv; *p; p++) {
1333                 s = *p;
1334                 if(s->lport == psource)
1335                 if(ipcmp(s->laddr, source) == 0)
1336                 if(ipcmp(s->raddr, dest) == 0){
1337                         qunlock(il);
1338                         ic = (Ilcb*)s->ptcl;
1339                         switch(ic->state){
1340                         case Ilsyncer:
1341                                 ilhangup(s, msg);
1342                                 break;
1343                         }
1344                         freeblist(bp);
1345                         return;
1346                 }
1347         }
1348         qunlock(il);
1349         freeblist(bp);
1350 }
1351
1352 int
1353 ilnextqt(Ilcb *ic)
1354 {
1355         int x;
1356
1357         qlock(&ic->ackq);
1358         x = ic->qtx;
1359         if(++x > Nqt)
1360                 x = 1;
1361         ic->qtx = x;
1362         ic->qt[x] = ic->next-1; /* highest xmitted packet */
1363         ic->qt[0] = ic->qt[x];  /* compatibility with old implementations */
1364         qunlock(&ic->ackq);
1365
1366         return x;
1367 }
1368
1369 /* calculate scale constants that converts fast ticks to ms (more or less) */
1370 static void
1371 inittimescale(void)
1372 {
1373         uvlong hz;
1374
1375         fastticks(&hz);
1376         if(hz > 1000){
1377                 scalediv = hz/1000;
1378                 scalemul = 1;
1379         } else {
1380                 scalediv = 1;
1381                 scalemul = 1000/hz;
1382         }
1383 }
1384
1385 void
1386 ilinit(Fs *f)
1387 {
1388         Proto *il;
1389
1390         inittimescale();
1391
1392         il = smalloc(sizeof(Proto));
1393         il->priv = smalloc(sizeof(Ilpriv));
1394         il->name = "il";
1395         il->connect = ilconnect;
1396         il->announce = ilannounce;
1397         il->state = ilstate;
1398         il->create = ilcreate;
1399         il->close = ilclose;
1400         il->rcv = iliput;
1401         il->ctl = nil;
1402         il->advise = iladvise;
1403         il->stats = ilxstats;
1404         il->inuse = ilinuse;
1405         il->gc = nil;
1406         il->ipproto = IP_ILPROTO;
1407         il->nc = scalednconv();
1408         il->ptclsize = sizeof(Ilcb);
1409         Fsproto(f, il);
1410 }