]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/ip/il.c
devip: fix router adv/sol options validation (options padded to 8 bytes)
[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 int     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         if(c->ipversion != V4)
255                 return "only IP version 4 supported";
256                 
257         return ilstart(c, IL_CONNECT, fast);
258 }
259
260 static int
261 ilstate(Conv *c, char *state, int n)
262 {
263         Ilcb *ic;
264
265         ic = (Ilcb*)(c->ptcl);
266         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",
267                 ilstates[ic->state],
268                 c->rq ? qlen(c->rq) : 0,
269                 c->wq ? qlen(c->wq) : 0,
270                 ic->delay>>LogAGain, ic->rate>>LogAGain, ic->mdev>>LogDGain,
271                 ic->unackedbytes, ic->rxtot, ic->rxquery, ic->maxrtt);
272 }
273
274 static int
275 ilinuse(Conv *c)
276 {
277         Ilcb *ic;
278
279         ic = (Ilcb*)(c->ptcl);
280         return ic->state != Ilclosed;
281
282 }
283
284 /* called with c locked */
285 static char*
286 ilannounce(Conv *c, char **argv, int argc)
287 {
288         char *e;
289
290         e = Fsstdannounce(c, argv, argc);
291         if(e != nil)
292                 return e;
293         e = ilstart(c, IL_LISTEN, 0);
294         if(e != nil)
295                 return e;
296         Fsconnected(c, nil);
297
298         return nil;
299 }
300
301 void
302 illocalclose(Conv *c)
303 {
304         Ilcb *ic;
305         Ilpriv *ipriv;
306
307         ipriv = c->p->priv;
308         ic = (Ilcb*)c->ptcl;
309         ic->state = Ilclosed;
310         iphtrem(&ipriv->ht, c);
311         ipmove(c->laddr, IPnoaddr);
312         c->lport = 0;
313 }
314
315 static void
316 ilclose(Conv *c)
317 {
318         Ilcb *ic;
319
320         ic = (Ilcb*)c->ptcl;
321
322         qclose(c->rq);
323         qclose(c->wq);
324         qclose(c->eq);
325
326         switch(ic->state) {
327         case Ilclosing:
328         case Ilclosed:
329                 break;
330         case Ilsyncer:
331         case Ilsyncee:
332         case Ilestablished:
333                 ic->state = Ilclosing;
334                 ilsettimeout(ic);
335                 ilsendctl(c, nil, Ilclose, ic->next, ic->recvd, 0);
336                 break;
337         case Illistening:
338                 illocalclose(c);
339                 break;
340         }
341         ilfreeq(ic);
342 }
343
344 void
345 ilkick(void *x, Block *bp)
346 {
347         Conv *c = x;
348         Ilhdr *ih;
349         Ilcb *ic;
350         int dlen;
351         ulong id, ack;
352         Fs *f;
353         Ilpriv *priv;
354
355         f = c->p->f;
356         priv = c->p->priv;
357         ic = (Ilcb*)c->ptcl;
358
359         if(bp == nil)
360                 return;
361
362         switch(ic->state) {
363         case Ilclosed:
364         case Illistening:
365         case Ilclosing:
366                 freeblist(bp);
367                 qhangup(c->rq, nil);
368                 return;
369         }
370
371         dlen = blocklen(bp);
372
373         /* Make space to fit il & ip */
374         bp = padblock(bp, IL_IPSIZE+IL_HDRSIZE);
375         ih = (Ilhdr *)(bp->rp);
376         ih->vihl = IP_VER4;
377
378         /* Ip fields */
379         ih->frag[0] = 0;
380         ih->frag[1] = 0;
381         v6tov4(ih->dst, c->raddr);
382         v6tov4(ih->src, c->laddr);
383         ih->proto = IP_ILPROTO;
384
385         /* Il fields */
386         hnputs(ih->illen, dlen+IL_HDRSIZE);
387         hnputs(ih->ilsrc, c->lport);
388         hnputs(ih->ildst, c->rport);
389
390         qlock(&ic->ackq);
391         id = ic->next++;
392         hnputl(ih->ilid, id);
393         ack = ic->recvd;
394         hnputl(ih->ilack, ack);
395         ic->acksent = ack;
396         ic->acktime = NOW + AckDelay;
397         ih->iltype = Ildata;
398         ih->ilspec = 0;
399         ih->ilsum[0] = 0;
400         ih->ilsum[1] = 0;
401
402         /* Checksum of ilheader plus data (not ip & no pseudo header) */
403         if(ilcksum)
404                 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, dlen+IL_HDRSIZE));
405
406         ilackq(ic, bp);
407         qunlock(&ic->ackq);
408
409         /* Start the round trip timer for this packet if the timer is free */
410         if(ic->rttack == 0) {
411                 ic->rttack = id;
412                 ic->rttstart = fastticks(nil);
413                 ic->rttlen = dlen + IL_IPSIZE + IL_HDRSIZE;
414         }
415
416         if(later(NOW, ic->timeout, nil))
417                 ilsettimeout(ic);
418         ipoput4(f, bp, 0, c->ttl, c->tos, c);
419         priv->stats[OutMsgs]++;
420 }
421
422 static void
423 ilcreate(Conv *c)
424 {
425         c->rq = qopen(Maxrq, 0, 0, c);
426         c->wq = qbypass(ilkick, c);
427 }
428
429 int
430 ilxstats(Proto *il, char *buf, int len)
431 {
432         Ilpriv *priv;
433         char *p, *e;
434         int i;
435
436         priv = il->priv;
437         p = buf;
438         e = p+len;
439         for(i = 0; i < Nstats; i++)
440                 p = seprint(p, e, "%s: %llud\n", statnames[i], priv->stats[i]);
441         return p - buf;
442 }
443
444 void
445 ilackq(Ilcb *ic, Block *bp)
446 {
447         Block *np;
448         int n;
449
450         n = blocklen(bp);
451
452         /* Enqueue a copy on the unacked queue in case this one gets lost */
453         np = copyblock(bp, n);
454         if(ic->unacked)
455                 ic->unackedtail->list = np;
456         else
457                 ic->unacked = np;
458         ic->unackedtail = np;
459         np->list = nil;
460         ic->unackedbytes += n;
461 }
462
463 static
464 void
465 ilrttcalc(Ilcb *ic, Block *bp)
466 {
467         int rtt, tt, pt, delay, rate;
468
469         rtt = fastticks(nil) - ic->rttstart;
470         rtt = (rtt*scalemul)/scalediv;
471         delay = ic->delay;
472         rate = ic->rate;
473
474         /* Guard against zero wrap */
475         if(rtt > 120000 || rtt < 0)
476                 return;
477
478         /* this block had to be transmitted after the one acked so count its size */
479         ic->rttlen += blocklen(bp)  + IL_IPSIZE + IL_HDRSIZE;
480
481         if(ic->rttlen < 256){
482                 /* guess fixed delay as rtt of small packets */
483                 delay += rtt - (delay>>LogAGain);
484                 if(delay < AGain)
485                         delay = AGain;
486                 ic->delay = delay;
487         } else {
488                 /* if packet took longer than avg rtt delay, recalc rate */
489                 tt = rtt - (delay>>LogAGain);
490                 if(tt > 0){
491                         rate += ic->rttlen/tt - (rate>>LogAGain);
492                         if(rate < AGain)
493                                 rate = AGain;
494                         ic->rate = rate;
495                 }
496         }
497
498         /* mdev */
499         pt = ic->rttlen/(rate>>LogAGain) + (delay>>LogAGain);
500         ic->mdev += abs(rtt-pt) - (ic->mdev>>LogDGain);
501
502         if(rtt > ic->maxrtt)
503                 ic->maxrtt = rtt;
504 }
505
506 void
507 ilackto(Ilcb *ic, ulong ackto, Block *bp)
508 {
509         Ilhdr *h;
510         ulong id;
511
512         if(ic->rttack == ackto)
513                 ilrttcalc(ic, bp);
514
515         /* Cancel if we've passed the packet we were interested in */
516         if(ic->rttack <= ackto)
517                 ic->rttack = 0;
518
519         qlock(&ic->ackq);
520         while(ic->unacked) {
521                 h = (Ilhdr *)ic->unacked->rp;
522                 id = nhgetl(h->ilid);
523                 if(ackto < id)
524                         break;
525
526                 bp = ic->unacked;
527                 ic->unacked = bp->list;
528                 bp->list = nil;
529                 ic->unackedbytes -= blocklen(bp);
530                 freeblist(bp);
531                 ic->rexmit = 0;
532                 ilsettimeout(ic);
533         }
534         qunlock(&ic->ackq);
535 }
536
537 void
538 iliput(Proto *il, Ipifc*, Block *bp)
539 {
540         char *st;
541         Ilcb *ic;
542         Ilhdr *ih;
543         uchar raddr[IPaddrlen];
544         uchar laddr[IPaddrlen];
545         ushort sp, dp, csum;
546         int plen, illen;
547         Conv *new, *s;
548         Ilpriv *ipriv;
549
550         ipriv = il->priv;
551
552         ih = (Ilhdr *)bp->rp;
553         plen = blocklen(bp);
554         if(plen > 0 && (ih->vihl&0xF0)!=IP_VER4)
555                 goto raise;     /* ignore non V4 packets */
556
557         if(plen < IL_IPSIZE+IL_HDRSIZE){
558                 netlog(il->f, Logil, "il: hlenerr\n");
559                 ipriv->stats[HlenErrs]++;
560                 goto raise;
561         }
562
563         illen = nhgets(ih->illen);
564         if(illen+IL_IPSIZE > plen){
565                 netlog(il->f, Logil, "il: lenerr\n");
566                 ipriv->stats[LenErrs]++;
567                 goto raise;
568         }
569
570         sp = nhgets(ih->ildst);
571         dp = nhgets(ih->ilsrc);
572         v4tov6(raddr, ih->src);
573         v4tov6(laddr, ih->dst);
574
575         if((csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) {
576                 if(ih->iltype > Ilclose)
577                         st = "?";
578                 else
579                         st = iltype[ih->iltype];
580                 ipriv->stats[CsumErrs]++;
581                 netlog(il->f, Logil, "il: cksum %ux %s, pkt(%ux id %ud ack %I/%d->%d)\n",
582                         csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp);
583                 goto raise;
584         }
585
586         qlock(il);
587         s = iphtlook(&ipriv->ht, raddr, dp, laddr, sp);
588         if(s == nil){
589                 if(ih->iltype == Ilsync)
590                         ilreject(il->f, ih);            /* no listener */
591                 qunlock(il);
592                 goto raise;
593         }
594
595         ic = (Ilcb*)s->ptcl;
596         if(ic->state == Illistening){
597                 if(ih->iltype != Ilsync){
598                         qunlock(il);
599                         if(ih->iltype > Ilclose)
600                                 st = "?";
601                         else
602                                 st = iltype[ih->iltype];
603                         ilreject(il->f, ih);            /* no channel and not sync */
604                         netlog(il->f, Logil, "il: no channel, pkt(%s id %ud ack %ud %I/%ud->%ud)\n",
605                                 st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp); 
606                         goto raise;
607                 }
608
609                 new = Fsnewcall(s, raddr, dp, laddr, sp, V4);
610                 if(new == nil){
611                         qunlock(il);
612                         netlog(il->f, Logil, "il: bad newcall %I/%ud->%ud\n", raddr, sp, dp);
613                         ilsendctl(s, ih, Ilclose, 0, nhgetl(ih->ilid), 0);
614                         goto raise;
615                 }
616                 s = new;
617
618                 ic = (Ilcb*)s->ptcl;
619         
620                 ic->conv = s;
621                 ic->state = Ilsyncee;
622                 ilcbinit(ic);
623                 ic->rstart = nhgetl(ih->ilid);
624                 iphtadd(&ipriv->ht, s);
625         }
626
627         qlock(s);
628         qunlock(il);
629         if(waserror()){
630                 qunlock(s);
631                 nexterror();
632         }
633         ilprocess(s, ih, bp);
634         qunlock(s);
635         poperror();
636         return;
637 raise:
638         freeblist(bp);
639 }
640
641 void
642 _ilprocess(Conv *s, Ilhdr *h, Block *bp)
643 {
644         Ilcb *ic;
645         ulong id, ack;
646         Ilpriv *priv;
647
648         id = nhgetl(h->ilid);
649         ack = nhgetl(h->ilack);
650
651         ic = (Ilcb*)s->ptcl;
652
653         ic->lastrecv = NOW;
654         ic->querytime = NOW + QueryTime;
655         priv = s->p->priv;
656         priv->stats[InMsgs]++;
657
658         switch(ic->state) {
659         default:
660                 netlog(s->p->f, Logil, "il: unknown state %d\n", ic->state);
661         case Ilclosed:
662                 freeblist(bp);
663                 break;
664         case Ilsyncer:
665                 switch(h->iltype) {
666                 default:
667                         break;
668                 case Ilsync:
669                         if(ack != ic->start)
670                                 ilhangup(s, "connection rejected");
671                         else {
672                                 ic->recvd = id;
673                                 ic->rstart = id;
674                                 ilsendctl(s, nil, Ilack, ic->next, ic->recvd, 0);
675                                 ic->state = Ilestablished;
676                                 ic->fasttimeout = 0;
677                                 ic->rexmit = 0;
678                                 Fsconnected(s, nil);
679                                 ilpullup(s);
680                         }
681                         break;
682                 case Ilclose:
683                         if(ack == ic->start)
684                                 ilhangup(s, "connection rejected");
685                         break;
686                 }
687                 freeblist(bp);
688                 break;
689         case Ilsyncee:
690                 switch(h->iltype) {
691                 default:
692                         break;
693                 case Ilsync:
694                         if(id != ic->rstart || ack != 0){
695                                 illocalclose(s);
696                         } else {
697                                 ic->recvd = id;
698                                 ilsendctl(s, nil, Ilsync, ic->start, ic->recvd, 0);
699                         }
700                         break;
701                 case Ilack:
702                         if(ack == ic->start) {
703                                 ic->state = Ilestablished;
704                                 ic->fasttimeout = 0;
705                                 ic->rexmit = 0;
706                                 ilpullup(s);
707                         }
708                         break;
709                 case Ildata:
710                         if(ack == ic->start) {
711                                 ic->state = Ilestablished;
712                                 ic->fasttimeout = 0;
713                                 ic->rexmit = 0;
714                                 goto established;
715                         }
716                         break;
717                 case Ilclose:
718                         if(ack == ic->start)
719                                 ilhangup(s, "remote close");
720                         break;
721                 }
722                 freeblist(bp);
723                 break;
724         case Ilestablished:
725         established:
726                 switch(h->iltype) {
727                 case Ilsync:
728                         if(id != ic->rstart)
729                                 ilhangup(s, "remote close");
730                         else
731                                 ilsendctl(s, nil, Ilack, ic->next, ic->rstart, 0);
732                         freeblist(bp);  
733                         break;
734                 case Ildata:
735                         /*
736                          * avoid consuming all the mount rpc buffers in the
737                          * system.  if the input queue is too long, drop this
738                          * packet.
739                          */
740                         if (s->rq && qlen(s->rq) >= Maxrq) {
741                                 priv->stats[DroppedMsgs]++;
742                                 freeblist(bp);
743                                 break;
744                         }
745
746                         ilackto(ic, ack, bp);
747                         iloutoforder(s, h, bp);
748                         ilpullup(s);
749                         break;
750                 case Ildataquery:
751                         ilackto(ic, ack, bp);
752                         iloutoforder(s, h, bp);
753                         ilpullup(s);
754                         ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec);
755                         break;
756                 case Ilack:
757                         ilackto(ic, ack, bp);
758                         freeblist(bp);
759                         break;
760                 case Ilquery:
761                         ilackto(ic, ack, bp);
762                         ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec);
763                         freeblist(bp);
764                         break;
765                 case Ilstate:
766                         if(ack >= ic->rttack)
767                                 ic->rttack = 0;
768                         ilackto(ic, ack, bp);
769                         if(h->ilspec > Nqt)
770                                 h->ilspec = 0;
771                         if(ic->qt[h->ilspec] > ack){
772                                 ilrexmit(ic);
773                                 ilsettimeout(ic);
774                         }
775                         freeblist(bp);
776                         break;
777                 case Ilclose:
778                         freeblist(bp);
779                         if(ack < ic->start || ack > ic->next) 
780                                 break;
781                         ic->recvd = id;
782                         ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0);
783                         ic->state = Ilclosing;
784                         ilsettimeout(ic);
785                         ilfreeq(ic);
786                         break;
787                 }
788                 break;
789         case Illistening:
790                 freeblist(bp);
791                 break;
792         case Ilclosing:
793                 switch(h->iltype) {
794                 case Ilclose:
795                         ic->recvd = id;
796                         ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0);
797                         if(ack == ic->next)
798                                 ilhangup(s, nil);
799                         break;
800                 default:
801                         break;
802                 }
803                 freeblist(bp);
804                 break;
805         }
806 }
807
808 void
809 ilrexmit(Ilcb *ic)
810 {
811         Ilhdr *h;
812         Block *nb;
813         Conv *c;
814         ulong id;
815         Ilpriv *priv;
816
817         nb = nil;
818         qlock(&ic->ackq);
819         if(ic->unacked)
820                 nb = copyblock(ic->unacked, blocklen(ic->unacked));
821         qunlock(&ic->ackq);
822
823         if(nb == nil)
824                 return;
825
826         h = (Ilhdr*)nb->rp;
827         h->vihl = IP_VER4;
828
829         h->iltype = Ildataquery;
830         hnputl(h->ilack, ic->recvd);
831         h->ilspec = ilnextqt(ic);
832         h->ilsum[0] = 0;
833         h->ilsum[1] = 0;
834         hnputs(h->ilsum, ptclcsum(nb, IL_IPSIZE, nhgets(h->illen)));
835
836         c = ic->conv;
837         id = nhgetl(h->ilid);
838         netlog(c->p->f, Logil, "il: rexmit %lud %lud: %d %lud: %I %d/%d\n", id, ic->recvd,
839                 ic->rexmit, ic->timeout,
840                 c->raddr, c->lport, c->rport);
841
842         ilbackoff(ic);
843
844         ipoput4(c->p->f, nb, 0, c->ttl, c->tos, c);
845
846         /* statistics */
847         ic->rxtot++;
848         priv = c->p->priv;
849         priv->rexmit++;
850 }
851
852 /* DEBUG */
853 void
854 ilprocess(Conv *s, Ilhdr *h, Block *bp)
855 {
856         Ilcb *ic;
857
858         ic = (Ilcb*)s->ptcl;
859
860         USED(ic);
861         netlog(s->p->f, Logilmsg, "%11s rcv %lud/%lud snt %lud/%lud pkt(%s id %d ack %ud %ud->%ud) ",
862                 ilstates[ic->state],  ic->rstart, ic->recvd, ic->start, 
863                 ic->next, iltype[h->iltype], nhgetl(h->ilid), 
864                 nhgetl(h->ilack), nhgets(h->ilsrc), nhgets(h->ildst));
865
866         _ilprocess(s, h, bp);
867
868         netlog(s->p->f, Logilmsg, "%11s rcv %lud snt %lud\n", ilstates[ic->state], ic->recvd, ic->next);
869 }
870
871 void
872 ilhangup(Conv *s, char *msg)
873 {
874         Ilcb *ic;
875         int callout;
876
877         netlog(s->p->f, Logil, "il: hangup! %I %d/%d: %s\n", s->raddr,
878                 s->lport, s->rport, msg?msg:"no reason");
879
880         ic = (Ilcb*)s->ptcl;
881         callout = ic->state == Ilsyncer;
882         illocalclose(s);
883
884         qhangup(s->rq, msg);
885         qhangup(s->wq, msg);
886
887         if(callout)
888                 Fsconnected(s, msg);
889 }
890
891 void
892 ilpullup(Conv *s)
893 {
894         Ilcb *ic;
895         Ilhdr *oh;
896         Block *bp;
897         ulong oid, dlen;
898         Ilpriv *ipriv;
899
900         ic = (Ilcb*)s->ptcl;
901         if(ic->state != Ilestablished)
902                 return;
903
904         qlock(&ic->outo);
905         while(ic->outoforder) {
906                 bp = ic->outoforder;
907                 oh = (Ilhdr*)bp->rp;
908                 oid = nhgetl(oh->ilid);
909                 if(oid <= ic->recvd) {
910                         ic->outoforder = bp->list;
911                         freeblist(bp);
912                         continue;
913                 }
914                 if(oid != ic->recvd+1){
915                         ipriv = s->p->priv;
916                         ipriv->stats[OutOfOrder]++;
917                         break;
918                 }
919
920                 ic->recvd = oid;
921                 ic->outoforder = bp->list;
922
923                 bp->list = nil;
924                 dlen = nhgets(oh->illen)-IL_HDRSIZE;
925                 bp = trimblock(bp, IL_IPSIZE+IL_HDRSIZE, dlen);
926                         
927                 /*
928                  * Upper levels don't know about multiple-block
929                  * messages so copy all into one (yick).
930                  */
931                 qpass(s->rq, packblock(concatblock(bp)));
932         }
933         qunlock(&ic->outo);
934 }
935
936 void
937 iloutoforder(Conv *s, Ilhdr *h, Block *bp)
938 {
939         Ilcb *ic;
940         uchar *lid;
941         Block *f, **l;
942         ulong id, newid;
943         Ilpriv *ipriv;
944
945         ipriv = s->p->priv;
946         ic = (Ilcb*)s->ptcl;
947         bp->list = nil;
948
949         id = nhgetl(h->ilid);
950         /* Window checks */
951         if(id <= ic->recvd || id > ic->recvd+ic->window) {
952                 netlog(s->p->f, Logil, "il: message outside window %lud <%lud-%lud>: %I %d/%d\n",
953                         id, ic->recvd, ic->recvd+ic->window, s->raddr, s->lport, s->rport);
954                 freeblist(bp);
955                 return;
956         }
957
958         /* Packet is acceptable so sort onto receive queue for pullup */
959         qlock(&ic->outo);
960         if(ic->outoforder == nil)
961                 ic->outoforder = bp;
962         else {
963                 l = &ic->outoforder;
964                 for(f = *l; f; f = f->list) {
965                         lid = ((Ilhdr*)(f->rp))->ilid;
966                         newid = nhgetl(lid);
967                         if(id <= newid) {
968                                 if(id == newid) {
969                                         ipriv->stats[DupMsg]++;
970                                         ipriv->stats[DupBytes] += blocklen(bp);
971                                         qunlock(&ic->outo);
972                                         freeblist(bp);
973                                         return;
974                                 }
975                                 bp->list = f;
976                                 *l = bp;
977                                 qunlock(&ic->outo);
978                                 return;
979                         }
980                         l = &f->list;
981                 }
982                 *l = bp;
983         }
984         qunlock(&ic->outo);
985 }
986
987 int
988 ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec)
989 {
990         Ilhdr *ih;
991         Ilcb *ic;
992         Block *bp;
993         int ttl, tos;
994
995         bp = allocb(IL_IPSIZE+IL_HDRSIZE);
996         bp->wp += IL_IPSIZE+IL_HDRSIZE;
997
998         ih = (Ilhdr *)(bp->rp);
999         ih->vihl = IP_VER4;
1000
1001         /* Ip fields */
1002         ih->proto = IP_ILPROTO;
1003         hnputs(ih->illen, IL_HDRSIZE);
1004         ih->frag[0] = 0;
1005         ih->frag[1] = 0;
1006         if(inih) {
1007                 hnputl(ih->dst, nhgetl(inih->src));
1008                 hnputl(ih->src, nhgetl(inih->dst));
1009                 hnputs(ih->ilsrc, nhgets(inih->ildst));
1010                 hnputs(ih->ildst, nhgets(inih->ilsrc));
1011                 hnputl(ih->ilid, nhgetl(inih->ilack));
1012                 hnputl(ih->ilack, nhgetl(inih->ilid));
1013                 ttl = MAXTTL;
1014                 tos = DFLTTOS;
1015         }
1016         else {
1017                 v6tov4(ih->dst, ipc->raddr);
1018                 v6tov4(ih->src, ipc->laddr);
1019                 hnputs(ih->ilsrc, ipc->lport);
1020                 hnputs(ih->ildst, ipc->rport);
1021                 hnputl(ih->ilid, id);
1022                 hnputl(ih->ilack, ack);
1023                 ic = (Ilcb*)ipc->ptcl;
1024                 ic->acksent = ack;
1025                 ic->acktime = NOW;
1026                 ttl = ipc->ttl;
1027                 tos = ipc->tos;
1028         }
1029         ih->iltype = type;
1030         ih->ilspec = ilspec;
1031         ih->ilsum[0] = 0;
1032         ih->ilsum[1] = 0;
1033
1034         if(ilcksum)
1035                 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE));
1036
1037 if(ipc==nil)
1038         panic("ipc is nil caller is %#p", getcallerpc(&ipc));
1039 if(ipc->p==nil)
1040         panic("ipc->p is nil");
1041
1042         netlog(ipc->p->f, Logilmsg, "ctl(%s id %d ack %d %d->%d)\n",
1043                 iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack), 
1044                 nhgets(ih->ilsrc), nhgets(ih->ildst));
1045
1046         return ipoput4(ipc->p->f, bp, 0, ttl, tos, ipc);
1047 }
1048
1049 void
1050 ilreject(Fs *f, Ilhdr *inih)
1051 {
1052         Ilhdr *ih;
1053         Block *bp;
1054
1055         bp = allocb(IL_IPSIZE+IL_HDRSIZE);
1056         bp->wp += IL_IPSIZE+IL_HDRSIZE;
1057
1058         ih = (Ilhdr *)(bp->rp);
1059         ih->vihl = IP_VER4;
1060
1061         /* Ip fields */
1062         ih->proto = IP_ILPROTO;
1063         hnputs(ih->illen, IL_HDRSIZE);
1064         ih->frag[0] = 0;
1065         ih->frag[1] = 0;
1066         hnputl(ih->dst, nhgetl(inih->src));
1067         hnputl(ih->src, nhgetl(inih->dst));
1068         hnputs(ih->ilsrc, nhgets(inih->ildst));
1069         hnputs(ih->ildst, nhgets(inih->ilsrc));
1070         hnputl(ih->ilid, nhgetl(inih->ilack));
1071         hnputl(ih->ilack, nhgetl(inih->ilid));
1072         ih->iltype = Ilclose;
1073         ih->ilspec = 0;
1074         ih->ilsum[0] = 0;
1075         ih->ilsum[1] = 0;
1076
1077         if(ilcksum)
1078                 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE));
1079
1080         ipoput4(f, bp, 0, MAXTTL, DFLTTOS, nil);
1081 }
1082
1083 void
1084 ilsettimeout(Ilcb *ic)
1085 {
1086         ulong pt;
1087
1088         pt = (ic->delay>>LogAGain)
1089                 + ic->unackedbytes/(ic->rate>>LogAGain)
1090                 + (ic->mdev>>(LogDGain-1))
1091                 + AckDelay;
1092         if(pt > MaxTimeout)
1093                 pt = MaxTimeout;
1094         ic->timeout = NOW + pt;
1095 }
1096
1097 void
1098 ilbackoff(Ilcb *ic)
1099 {
1100         ulong pt;
1101         int i;
1102
1103         pt = (ic->delay>>LogAGain)
1104                 + ic->unackedbytes/(ic->rate>>LogAGain)
1105                 + (ic->mdev>>(LogDGain-1))
1106                 + AckDelay;
1107         for(i = 0; i < ic->rexmit; i++)
1108                 pt = pt + (pt>>1);
1109         if(pt > MaxTimeout)
1110                 pt = MaxTimeout;
1111         ic->timeout = NOW + pt;
1112
1113         if(ic->fasttimeout)
1114                 ic->timeout = NOW+Iltickms;
1115
1116         ic->rexmit++;
1117 }
1118
1119 // complain if two numbers not within an hour of each other
1120 #define Tfuture (1000*60*60)
1121 int
1122 later(ulong t1, ulong t2, char *x)
1123 {
1124         int dt;
1125
1126         dt = t1 - t2;
1127         if(dt > 0) {
1128                 if(x != nil && dt > Tfuture)
1129                         print("%s: way future %d\n", x, dt);
1130                 return 1;
1131         }
1132         if(dt < -Tfuture) {
1133                 if(x != nil)
1134                         print("%s: way past %d\n", x, -dt);
1135                 return 1;
1136         }
1137         return 0;
1138 }
1139
1140 void
1141 ilackproc(void *x)
1142 {
1143         Ilcb *ic;
1144         Conv **s, *p;
1145         Proto *il;
1146
1147         il = x;
1148
1149         while(waserror())
1150                 ;
1151 loop:
1152         tsleep(&up->sleep, return0, 0, Iltickms);
1153         for(s = il->conv; s && *s; s++) {
1154                 p = *s;
1155                 ic = (Ilcb*)p->ptcl;
1156
1157                 switch(ic->state) {
1158                 case Ilclosed:
1159                 case Illistening:
1160                         break;
1161                 case Ilclosing:
1162                         if(later(NOW, ic->timeout, "timeout0")) {
1163                                 if(ic->rexmit > MaxRexmit){
1164                                         ilhangup(p, nil);
1165                                         break;
1166                                 }
1167                                 ilsendctl(p, nil, Ilclose, ic->next, ic->recvd, 0);
1168                                 ilbackoff(ic);
1169                         }
1170                         break;
1171
1172                 case Ilsyncee:
1173                 case Ilsyncer:
1174                         if(later(NOW, ic->timeout, "timeout1")) {
1175                                 if(ic->rexmit > MaxRexmit){
1176                                         ilhangup(p, etime);
1177                                         break;
1178                                 }
1179                                 ilsendctl(p, nil, Ilsync, ic->start, ic->recvd, 0);
1180                                 ilbackoff(ic);
1181                         }
1182                         break;
1183
1184                 case Ilestablished:
1185                         if(ic->recvd != ic->acksent)
1186                         if(later(NOW, ic->acktime, "acktime"))
1187                                 ilsendctl(p, nil, Ilack, ic->next, ic->recvd, 0);
1188
1189                         if(later(NOW, ic->querytime, "querytime")){
1190                                 if(later(NOW, ic->lastrecv+DeathTime, "deathtime")){
1191                                         netlog(il->f, Logil, "il: hangup: deathtime\n");
1192                                         ilhangup(p, etime);
1193                                         break;
1194                                 }
1195                                 ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic));
1196                                 ic->querytime = NOW + QueryTime;
1197                         }
1198
1199                         if(ic->unacked != nil)
1200                         if(later(NOW, ic->timeout, "timeout2")) {
1201                                 if(ic->rexmit > MaxRexmit){
1202                                         netlog(il->f, Logil, "il: hangup: too many rexmits\n");
1203                                         ilhangup(p, etime);
1204                                         break;
1205                                 }
1206                                 ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic));
1207                                 ic->rxquery++;
1208                                 ilbackoff(ic);
1209                         }
1210                         break;
1211                 }
1212         }
1213         goto loop;
1214 }
1215
1216 void
1217 ilcbinit(Ilcb *ic)
1218 {
1219         ic->start = nrand(0x1000000);
1220         ic->next = ic->start+1;
1221         ic->recvd = 0;
1222         ic->window = Defaultwin;
1223         ic->unackedbytes = 0;
1224         ic->unacked = nil;
1225         ic->outoforder = nil;
1226         ic->rexmit = 0;
1227         ic->rxtot = 0;
1228         ic->rxquery = 0;
1229         ic->qtx = 1;
1230         ic->fasttimeout = 0;
1231
1232         /* timers */
1233         ic->delay = DefRtt<<LogAGain;
1234         ic->mdev = DefRtt<<LogDGain;
1235         ic->rate = DefByteRate<<LogAGain;
1236         ic->querytime = NOW + QueryTime;
1237         ic->lastrecv = NOW;     /* or we'll timeout right away */
1238         ilsettimeout(ic);
1239 }
1240
1241 char*
1242 ilstart(Conv *c, int type, int fasttimeout)
1243 {
1244         Ilcb *ic;
1245         Ilpriv *ipriv;
1246         char kpname[KNAMELEN];
1247
1248         ipriv = c->p->priv;
1249
1250         if(ipriv->ackprocstarted == 0){
1251                 qlock(&ipriv->apl);
1252                 if(ipriv->ackprocstarted == 0){
1253                         sprint(kpname, "#I%dilack", c->p->f->dev);
1254                         kproc(kpname, ilackproc, c->p);
1255                         ipriv->ackprocstarted = 1;
1256                 }
1257                 qunlock(&ipriv->apl);
1258         }
1259
1260         ic = (Ilcb*)c->ptcl;
1261         ic->conv = c;
1262
1263         if(ic->state != Ilclosed)
1264                 return nil;
1265
1266         ilcbinit(ic);
1267
1268         if(fasttimeout){
1269                 /* timeout if we can't connect quickly */
1270                 ic->fasttimeout = 1;
1271                 ic->timeout = NOW+Iltickms;
1272                 ic->rexmit = MaxRexmit - 4;
1273         };
1274
1275         switch(type) {
1276         default:
1277                 netlog(c->p->f, Logil, "il: start: type %d\n", type);
1278                 break;
1279         case IL_LISTEN:
1280                 ic->state = Illistening;
1281                 iphtadd(&ipriv->ht, c);
1282                 break;
1283         case IL_CONNECT:
1284                 ic->state = Ilsyncer;
1285                 iphtadd(&ipriv->ht, c);
1286                 if(ilsendctl(c, nil, Ilsync, ic->start, ic->recvd, 0) < 0)
1287                         ilhangup(c, "no route");
1288                 break;
1289         }
1290
1291         return nil;
1292 }
1293
1294 void
1295 ilfreeq(Ilcb *ic)
1296 {
1297         Block *bp, *next;
1298
1299         qlock(&ic->ackq);
1300         for(bp = ic->unacked; bp; bp = next) {
1301                 next = bp->list;
1302                 freeblist(bp);
1303         }
1304         ic->unacked = nil;
1305         qunlock(&ic->ackq);
1306
1307         qlock(&ic->outo);
1308         for(bp = ic->outoforder; bp; bp = next) {
1309                 next = bp->list;
1310                 freeblist(bp);
1311         }
1312         ic->outoforder = nil;
1313         qunlock(&ic->outo);
1314 }
1315
1316 void
1317 iladvise(Proto *il, Block *bp, char *msg)
1318 {
1319         Ilhdr *h;
1320         Ilcb *ic;               
1321         uchar source[IPaddrlen], dest[IPaddrlen];
1322         ushort psource;
1323         Conv *s, **p;
1324
1325         h = (Ilhdr*)(bp->rp);
1326
1327         v4tov6(dest, h->dst);
1328         v4tov6(source, h->src);
1329         psource = nhgets(h->ilsrc);
1330
1331
1332         /* Look for a connection, unfortunately the destination port is missing */
1333         qlock(il);
1334         for(p = il->conv; *p; p++) {
1335                 s = *p;
1336                 if(s->lport == psource)
1337                 if(ipcmp(s->laddr, source) == 0)
1338                 if(ipcmp(s->raddr, dest) == 0){
1339                         if(s->ignoreadvice)
1340                                 break;
1341                         qunlock(il);
1342                         ic = (Ilcb*)s->ptcl;
1343                         switch(ic->state){
1344                         case Ilsyncer:
1345                                 ilhangup(s, msg);
1346                                 break;
1347                         }
1348                         freeblist(bp);
1349                         return;
1350                 }
1351         }
1352         qunlock(il);
1353         freeblist(bp);
1354 }
1355
1356 int
1357 ilnextqt(Ilcb *ic)
1358 {
1359         int x;
1360
1361         qlock(&ic->ackq);
1362         x = ic->qtx;
1363         if(++x > Nqt)
1364                 x = 1;
1365         ic->qtx = x;
1366         ic->qt[x] = ic->next-1; /* highest xmitted packet */
1367         ic->qt[0] = ic->qt[x];  /* compatibility with old implementations */
1368         qunlock(&ic->ackq);
1369
1370         return x;
1371 }
1372
1373 /* calculate scale constants that converts fast ticks to ms (more or less) */
1374 static void
1375 inittimescale(void)
1376 {
1377         uvlong hz;
1378
1379         fastticks(&hz);
1380         if(hz > 1000){
1381                 scalediv = hz/1000;
1382                 scalemul = 1;
1383         } else {
1384                 scalediv = 1;
1385                 scalemul = 1000/hz;
1386         }
1387 }
1388
1389 void
1390 ilinit(Fs *f)
1391 {
1392         Proto *il;
1393
1394         inittimescale();
1395
1396         il = smalloc(sizeof(Proto));
1397         il->priv = smalloc(sizeof(Ilpriv));
1398         il->name = "il";
1399         il->connect = ilconnect;
1400         il->announce = ilannounce;
1401         il->state = ilstate;
1402         il->create = ilcreate;
1403         il->close = ilclose;
1404         il->rcv = iliput;
1405         il->ctl = nil;
1406         il->advise = iladvise;
1407         il->stats = ilxstats;
1408         il->inuse = ilinuse;
1409         il->gc = nil;
1410         il->ipproto = IP_ILPROTO;
1411         il->nc = scalednconv();
1412         il->ptclsize = sizeof(Ilcb);
1413         Fsproto(f, il);
1414 }