il.c - vx32 - Local 9vx git repository for patches.
(HTM) git clone git://r-36.net/vx32
(DIR) Log
(DIR) Files
(DIR) Refs
---
il.c (27215B)
---
1 #include "u.h"
2 #include "lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "error.h"
7
8 #include "ip.h"
9
10 enum /* Connection state */
11 {
12 Ilclosed,
13 Ilsyncer,
14 Ilsyncee,
15 Ilestablished,
16 Illistening,
17 Ilclosing,
18 Ilopening, /* only for file server */
19 };
20
21 char *ilstates[] =
22 {
23 "Closed",
24 "Syncer",
25 "Syncee",
26 "Established",
27 "Listen",
28 "Closing",
29 "Opening", /* only for file server */
30 };
31
32 enum /* Packet types */
33 {
34 Ilsync,
35 Ildata,
36 Ildataquery,
37 Ilack,
38 Ilquery,
39 Ilstate,
40 Ilclose,
41 };
42
43 char *iltype[] =
44 {
45 "sync",
46 "data",
47 "dataquery",
48 "ack",
49 "query",
50 "state",
51 "close"
52 };
53
54 enum
55 {
56 Seconds = 1000,
57 Iltickms = 50, /* time base */
58 AckDelay = 2*Iltickms, /* max time twixt message rcvd & ack sent */
59 MaxTimeout = 30*Seconds, /* max time between rexmit */
60 QueryTime = 10*Seconds, /* time between subsequent queries */
61 DeathTime = 30*QueryTime,
62
63 MaxRexmit = 16, /* max retransmissions before hangup */
64 Defaultwin = 20,
65
66 LogAGain = 3,
67 AGain = 1<<LogAGain,
68 LogDGain = 2,
69 DGain = 1<<LogDGain,
70
71 DefByteRate = 100, /* assume a megabit link */
72 DefRtt = 50, /* cross country on a great day */
73
74 Maxrq = 64*1024,
75 };
76
77 enum
78 {
79 Nqt= 8,
80 };
81
82 typedef struct Ilcb Ilcb;
83 struct Ilcb /* Control block */
84 {
85 int state; /* Connection state */
86 Conv *conv;
87 QLock ackq; /* Unacknowledged queue */
88 Block *unacked;
89 Block *unackedtail;
90 ulong unackedbytes;
91 QLock outo; /* Out of order packet queue */
92 Block *outoforder;
93 ulong next; /* Id of next to send */
94 ulong recvd; /* Last packet received */
95 ulong acksent; /* Last packet acked */
96 ulong start; /* Local start id */
97 ulong rstart; /* Remote start id */
98 int window; /* Maximum receive window */
99 int rxquery; /* number of queries on this connection */
100 int rxtot; /* number of retransmits on this connection */
101 int rexmit; /* number of retransmits of *unacked */
102 ulong qt[Nqt+1]; /* state table for query messages */
103 int qtx; /* ... index into qt */
104
105 /* if set, fasttimeout causes a connection request to terminate after 4*Iltickms */
106 int fasttimeout;
107
108 /* timers */
109 ulong lastxmit; /* time of last xmit */
110 ulong lastrecv; /* time of last recv */
111 ulong timeout; /* retransmission time for *unacked */
112 ulong acktime; /* time to send next ack */
113 ulong querytime; /* time to send next query */
114
115 /* adaptive measurements */
116 int delay; /* Average of the fixed rtt delay */
117 int rate; /* Average uchar rate */
118 int mdev; /* Mean deviation of rtt */
119 int maxrtt; /* largest rtt seen */
120 ulong rttack; /* The ack we are waiting for */
121 int rttlen; /* Length of rttack packet */
122 uvlong rttstart; /* Time we issued rttack packet */
123 };
124
125 enum
126 {
127 IL_IPSIZE = 20,
128 IL_HDRSIZE = 18,
129 IL_LISTEN = 0,
130 IL_CONNECT = 1,
131 IP_ILPROTO = 40,
132 };
133
134 typedef struct Ilhdr Ilhdr;
135 struct Ilhdr
136 {
137 uchar vihl; /* Version and header length */
138 uchar tos; /* Type of service */
139 uchar length[2]; /* packet length */
140 uchar id[2]; /* Identification */
141 uchar frag[2]; /* Fragment information */
142 uchar ttl; /* Time to live */
143 uchar proto; /* Protocol */
144 uchar cksum[2]; /* Header checksum */
145 uchar src[4]; /* Ip source */
146 uchar dst[4]; /* Ip destination */
147 uchar ilsum[2]; /* Checksum including header */
148 uchar illen[2]; /* Packet length */
149 uchar iltype; /* Packet type */
150 uchar ilspec; /* Special */
151 uchar ilsrc[2]; /* Src port */
152 uchar ildst[2]; /* Dst port */
153 uchar ilid[4]; /* Sequence id */
154 uchar ilack[4]; /* Acked sequence */
155 };
156
157 enum
158 {
159 InMsgs,
160 OutMsgs,
161 CsumErrs, /* checksum errors */
162 HlenErrs, /* header length error */
163 LenErrs, /* short packet */
164 OutOfOrder, /* out of order */
165 Retrans, /* retransmissions */
166 DupMsg,
167 DupBytes,
168 DroppedMsgs,
169
170 Nstats,
171 };
172
173 static char *statnames[] =
174 {
175 [InMsgs] "InMsgs",
176 [OutMsgs] "OutMsgs",
177 [CsumErrs] "CsumErrs",
178 [HlenErrs] "HlenErr",
179 [LenErrs] "LenErrs",
180 [OutOfOrder] "OutOfOrder",
181 [Retrans] "Retrans",
182 [DupMsg] "DupMsg",
183 [DupBytes] "DupBytes",
184 [DroppedMsgs] "DroppedMsgs",
185 };
186
187 typedef struct Ilpriv Ilpriv;
188 struct Ilpriv
189 {
190 Ipht ht;
191
192 ulong stats[Nstats];
193
194 ulong csumerr; /* checksum errors */
195 ulong hlenerr; /* header length error */
196 ulong lenerr; /* short packet */
197 ulong order; /* out of order */
198 ulong rexmit; /* retransmissions */
199 ulong dup;
200 ulong dupb;
201
202 /* keeping track of the ack kproc */
203 int ackprocstarted;
204 QLock apl;
205 };
206
207 /* state for query/dataquery messages */
208
209
210 void ilrcvmsg(Conv*, Block*);
211 void ilsendctl(Conv*, Ilhdr*, int, ulong, ulong, int);
212 void ilackq(Ilcb*, Block*);
213 void ilprocess(Conv*, Ilhdr*, Block*);
214 void ilpullup(Conv*);
215 void ilhangup(Conv*, char*);
216 void ilfreeq(Ilcb*);
217 void ilrexmit(Ilcb*);
218 void ilbackoff(Ilcb*);
219 void ilsettimeout(Ilcb*);
220 char* ilstart(Conv*, int, int);
221 void ilackproc(void*);
222 void iloutoforder(Conv*, Ilhdr*, Block*);
223 void iliput(Proto*, Ipifc*, Block*);
224 void iladvise(Proto*, Block*, char*);
225 int ilnextqt(Ilcb*);
226 void ilcbinit(Ilcb*);
227 int later(ulong, ulong, char*);
228 void ilreject(Fs*, Ilhdr*);
229 void illocalclose(Conv *c);
230 int ilcksum = 1;
231 static int initseq = 25001;
232 static ulong scalediv, scalemul;
233 static char *etime = "connection timed out";
234
235 static char*
236 ilconnect(Conv *c, char **argv, int argc)
237 {
238 char *e, *p;
239 int fast;
240
241 /* huge hack to quickly try an il connection */
242 fast = 0;
243 if(argc > 1){
244 p = strstr(argv[1], "!fasttimeout");
245 if(p != nil){
246 *p = 0;
247 fast = 1;
248 }
249 }
250
251 e = Fsstdconnect(c, argv, argc);
252 if(e != nil)
253 return e;
254 return ilstart(c, IL_CONNECT, fast);
255 }
256
257 static int
258 ilstate(Conv *c, char *state, int n)
259 {
260 Ilcb *ic;
261
262 ic = (Ilcb*)(c->ptcl);
263 return snprint(state, n, "%s qin %d qout %d del %5.5d Br %5.5d md %5.5d una %5.5lud rex %5.5d rxq %5.5d max %5.5d\n",
264 ilstates[ic->state],
265 c->rq ? qlen(c->rq) : 0,
266 c->wq ? qlen(c->wq) : 0,
267 ic->delay>>LogAGain, ic->rate>>LogAGain, ic->mdev>>LogDGain,
268 ic->unackedbytes, ic->rxtot, ic->rxquery, ic->maxrtt);
269 }
270
271 static int
272 ilinuse(Conv *c)
273 {
274 Ilcb *ic;
275
276 ic = (Ilcb*)(c->ptcl);
277 return ic->state != Ilclosed;
278
279 }
280
281 /* called with c locked */
282 static char*
283 ilannounce(Conv *c, char **argv, int argc)
284 {
285 char *e;
286
287 e = Fsstdannounce(c, argv, argc);
288 if(e != nil)
289 return e;
290 e = ilstart(c, IL_LISTEN, 0);
291 if(e != nil)
292 return e;
293 Fsconnected(c, nil);
294
295 return nil;
296 }
297
298 void
299 illocalclose(Conv *c)
300 {
301 Ilcb *ic;
302 Ilpriv *ipriv;
303
304 ipriv = c->p->priv;
305 ic = (Ilcb*)c->ptcl;
306 ic->state = Ilclosed;
307 iphtrem(&ipriv->ht, c);
308 ipmove(c->laddr, IPnoaddr);
309 c->lport = 0;
310 }
311
312 static void
313 ilclose(Conv *c)
314 {
315 Ilcb *ic;
316
317 ic = (Ilcb*)c->ptcl;
318
319 qclose(c->rq);
320 qclose(c->wq);
321 qclose(c->eq);
322
323 switch(ic->state) {
324 case Ilclosing:
325 case Ilclosed:
326 break;
327 case Ilsyncer:
328 case Ilsyncee:
329 case Ilestablished:
330 ic->state = Ilclosing;
331 ilsettimeout(ic);
332 ilsendctl(c, nil, Ilclose, ic->next, ic->recvd, 0);
333 break;
334 case Illistening:
335 illocalclose(c);
336 break;
337 }
338 ilfreeq(ic);
339 }
340
341 void
342 ilkick(void *x, Block *bp)
343 {
344 Conv *c = x;
345 Ilhdr *ih;
346 Ilcb *ic;
347 int dlen;
348 ulong id, ack;
349 Fs *f;
350 Ilpriv *priv;
351
352 f = c->p->f;
353 priv = c->p->priv;
354 ic = (Ilcb*)c->ptcl;
355
356 if(bp == nil)
357 return;
358
359 switch(ic->state) {
360 case Ilclosed:
361 case Illistening:
362 case Ilclosing:
363 freeblist(bp);
364 qhangup(c->rq, nil);
365 return;
366 }
367
368 dlen = blocklen(bp);
369
370 /* Make space to fit il & ip */
371 bp = padblock(bp, IL_IPSIZE+IL_HDRSIZE);
372 ih = (Ilhdr *)(bp->rp);
373 ih->vihl = IP_VER4;
374
375 /* Ip fields */
376 ih->frag[0] = 0;
377 ih->frag[1] = 0;
378 v6tov4(ih->dst, c->raddr);
379 v6tov4(ih->src, c->laddr);
380 ih->proto = IP_ILPROTO;
381
382 /* Il fields */
383 hnputs(ih->illen, dlen+IL_HDRSIZE);
384 hnputs(ih->ilsrc, c->lport);
385 hnputs(ih->ildst, c->rport);
386
387 qlock(&ic->ackq);
388 id = ic->next++;
389 hnputl(ih->ilid, id);
390 ack = ic->recvd;
391 hnputl(ih->ilack, ack);
392 ic->acksent = ack;
393 ic->acktime = NOW + AckDelay;
394 ih->iltype = Ildata;
395 ih->ilspec = 0;
396 ih->ilsum[0] = 0;
397 ih->ilsum[1] = 0;
398
399 /* Checksum of ilheader plus data (not ip & no pseudo header) */
400 if(ilcksum)
401 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, dlen+IL_HDRSIZE));
402
403 ilackq(ic, bp);
404 qunlock(&ic->ackq);
405
406 /* Start the round trip timer for this packet if the timer is free */
407 if(ic->rttack == 0) {
408 ic->rttack = id;
409 ic->rttstart = fastticks(nil);
410 ic->rttlen = dlen + IL_IPSIZE + IL_HDRSIZE;
411 }
412
413 if(later(NOW, ic->timeout, nil))
414 ilsettimeout(ic);
415 ipoput4(f, bp, 0, c->ttl, c->tos, c);
416 priv->stats[OutMsgs]++;
417 }
418
419 static void
420 ilcreate(Conv *c)
421 {
422 c->rq = qopen(Maxrq, 0, 0, c);
423 c->wq = qbypass(ilkick, c);
424 }
425
426 int
427 ilxstats(Proto *il, char *buf, int len)
428 {
429 Ilpriv *priv;
430 char *p, *e;
431 int i;
432
433 priv = il->priv;
434 p = buf;
435 e = p+len;
436 for(i = 0; i < Nstats; i++)
437 p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]);
438 return p - buf;
439 }
440
441 void
442 ilackq(Ilcb *ic, Block *bp)
443 {
444 Block *np;
445 int n;
446
447 n = blocklen(bp);
448
449 /* Enqueue a copy on the unacked queue in case this one gets lost */
450 np = copyblock(bp, n);
451 if(ic->unacked)
452 ic->unackedtail->list = np;
453 else
454 ic->unacked = np;
455 ic->unackedtail = np;
456 np->list = nil;
457 ic->unackedbytes += n;
458 }
459
460 static
461 void
462 ilrttcalc(Ilcb *ic, Block *bp)
463 {
464 int rtt, tt, pt, delay, rate;
465
466 rtt = fastticks(nil) - ic->rttstart;
467 rtt = (rtt*scalemul)/scalediv;
468 delay = ic->delay;
469 rate = ic->rate;
470
471 /* Guard against zero wrap */
472 if(rtt > 120000 || rtt < 0)
473 return;
474
475 /* this block had to be transmitted after the one acked so count its size */
476 ic->rttlen += blocklen(bp) + IL_IPSIZE + IL_HDRSIZE;
477
478 if(ic->rttlen < 256){
479 /* guess fixed delay as rtt of small packets */
480 delay += rtt - (delay>>LogAGain);
481 if(delay < AGain)
482 delay = AGain;
483 ic->delay = delay;
484 } else {
485 /* if packet took longer than avg rtt delay, recalc rate */
486 tt = rtt - (delay>>LogAGain);
487 if(tt > 0){
488 rate += ic->rttlen/tt - (rate>>LogAGain);
489 if(rate < AGain)
490 rate = AGain;
491 ic->rate = rate;
492 }
493 }
494
495 /* mdev */
496 pt = ic->rttlen/(rate>>LogAGain) + (delay>>LogAGain);
497 ic->mdev += abs(rtt-pt) - (ic->mdev>>LogDGain);
498
499 if(rtt > ic->maxrtt)
500 ic->maxrtt = rtt;
501 }
502
503 void
504 ilackto(Ilcb *ic, ulong ackto, Block *bp)
505 {
506 Ilhdr *h;
507 ulong id;
508
509 if(ic->rttack == ackto)
510 ilrttcalc(ic, bp);
511
512 /* Cancel if we've passed the packet we were interested in */
513 if(ic->rttack <= ackto)
514 ic->rttack = 0;
515
516 qlock(&ic->ackq);
517 while(ic->unacked) {
518 h = (Ilhdr *)ic->unacked->rp;
519 id = nhgetl(h->ilid);
520 if(ackto < id)
521 break;
522
523 bp = ic->unacked;
524 ic->unacked = bp->list;
525 bp->list = nil;
526 ic->unackedbytes -= blocklen(bp);
527 freeblist(bp);
528 ic->rexmit = 0;
529 ilsettimeout(ic);
530 }
531 qunlock(&ic->ackq);
532 }
533
534 void
535 iliput(Proto *il, Ipifc *dummy, Block *bp)
536 {
537 char *st;
538 Ilcb *ic;
539 Ilhdr *ih;
540 uchar raddr[IPaddrlen];
541 uchar laddr[IPaddrlen];
542 ushort sp, dp, csum;
543 int plen, illen;
544 Conv *new, *s;
545 Ilpriv *ipriv;
546
547 ipriv = il->priv;
548
549 ih = (Ilhdr *)bp->rp;
550 plen = blocklen(bp);
551 if(plen < IL_IPSIZE+IL_HDRSIZE){
552 netlog(il->f, Logil, "il: hlenerr\n");
553 ipriv->stats[HlenErrs]++;
554 goto raise;
555 }
556
557 illen = nhgets(ih->illen);
558 if(illen+IL_IPSIZE > plen){
559 netlog(il->f, Logil, "il: lenerr\n");
560 ipriv->stats[LenErrs]++;
561 goto raise;
562 }
563
564 sp = nhgets(ih->ildst);
565 dp = nhgets(ih->ilsrc);
566 v4tov6(raddr, ih->src);
567 v4tov6(laddr, ih->dst);
568
569 if((csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) {
570 if(ih->iltype > Ilclose)
571 st = "?";
572 else
573 st = iltype[ih->iltype];
574 ipriv->stats[CsumErrs]++;
575 netlog(il->f, Logil, "il: cksum %ux %ux, pkt(%s id %lud ack %lud %I/%d->%d)\n",
576 csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp);
577 goto raise;
578 }
579
580 QLOCK(il);
581 s = iphtlook(&ipriv->ht, raddr, dp, laddr, sp);
582 if(s == nil){
583 if(ih->iltype == Ilsync)
584 ilreject(il->f, ih); /* no listener */
585 QUNLOCK(il);
586 goto raise;
587 }
588
589 ic = (Ilcb*)s->ptcl;
590 if(ic->state == Illistening){
591 if(ih->iltype != Ilsync){
592 QUNLOCK(il);
593 if(ih->iltype > Ilclose)
594 st = "?";
595 else
596 st = iltype[ih->iltype];
597 ilreject(il->f, ih); /* no channel and not sync */
598 netlog(il->f, Logil, "il: no channel, pkt(%s id %lud ack %lud %I/%ud->%ud)\n",
599 st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp);
600 goto raise;
601 }
602
603 new = Fsnewcall(s, raddr, dp, laddr, sp, V4);
604 if(new == nil){
605 QUNLOCK(il);
606 netlog(il->f, Logil, "il: bad newcall %I/%ud->%ud\n", raddr, sp, dp);
607 ilsendctl(s, ih, Ilclose, 0, nhgetl(ih->ilid), 0);
608 goto raise;
609 }
610 s = new;
611
612 ic = (Ilcb*)s->ptcl;
613
614 ic->conv = s;
615 ic->state = Ilsyncee;
616 ilcbinit(ic);
617 ic->rstart = nhgetl(ih->ilid);
618 iphtadd(&ipriv->ht, s);
619 }
620
621 QLOCK(s);
622 QUNLOCK(il);
623 if(waserror()){
624 QUNLOCK(s);
625 nexterror();
626 }
627 ilprocess(s, ih, bp);
628 QUNLOCK(s);
629 poperror();
630 return;
631 raise:
632 freeblist(bp);
633 }
634
635 void
636 _ilprocess(Conv *s, Ilhdr *h, Block *bp)
637 {
638 Ilcb *ic;
639 ulong id, ack;
640 Ilpriv *priv;
641
642 id = nhgetl(h->ilid);
643 ack = nhgetl(h->ilack);
644
645 ic = (Ilcb*)s->ptcl;
646
647 ic->lastrecv = NOW;
648 ic->querytime = NOW + QueryTime;
649 priv = s->p->priv;
650 priv->stats[InMsgs]++;
651
652 switch(ic->state) {
653 default:
654 netlog(s->p->f, Logil, "il: unknown state %d\n", ic->state);
655 case Ilclosed:
656 freeblist(bp);
657 break;
658 case Ilsyncer:
659 switch(h->iltype) {
660 default:
661 break;
662 case Ilsync:
663 if(ack != ic->start)
664 ilhangup(s, "connection rejected");
665 else {
666 ic->recvd = id;
667 ic->rstart = id;
668 ilsendctl(s, nil, Ilack, ic->next, ic->recvd, 0);
669 ic->state = Ilestablished;
670 ic->fasttimeout = 0;
671 ic->rexmit = 0;
672 Fsconnected(s, nil);
673 ilpullup(s);
674 }
675 break;
676 case Ilclose:
677 if(ack == ic->start)
678 ilhangup(s, "connection rejected");
679 break;
680 }
681 freeblist(bp);
682 break;
683 case Ilsyncee:
684 switch(h->iltype) {
685 default:
686 break;
687 case Ilsync:
688 if(id != ic->rstart || ack != 0){
689 illocalclose(s);
690 } else {
691 ic->recvd = id;
692 ilsendctl(s, nil, Ilsync, ic->start, ic->recvd, 0);
693 }
694 break;
695 case Ilack:
696 if(ack == ic->start) {
697 ic->state = Ilestablished;
698 ic->fasttimeout = 0;
699 ic->rexmit = 0;
700 ilpullup(s);
701 }
702 break;
703 case Ildata:
704 if(ack == ic->start) {
705 ic->state = Ilestablished;
706 ic->fasttimeout = 0;
707 ic->rexmit = 0;
708 goto established;
709 }
710 break;
711 case Ilclose:
712 if(ack == ic->start)
713 ilhangup(s, "remote close");
714 break;
715 }
716 freeblist(bp);
717 break;
718 case Ilestablished:
719 established:
720 switch(h->iltype) {
721 case Ilsync:
722 if(id != ic->rstart)
723 ilhangup(s, "remote close");
724 else
725 ilsendctl(s, nil, Ilack, ic->next, ic->rstart, 0);
726 freeblist(bp);
727 break;
728 case Ildata:
729 /*
730 * avoid consuming all the mount rpc buffers in the
731 * system. if the input queue is too long, drop this
732 * packet.
733 */
734 if (s->rq && qlen(s->rq) >= Maxrq) {
735 priv->stats[DroppedMsgs]++;
736 freeblist(bp);
737 break;
738 }
739
740 ilackto(ic, ack, bp);
741 iloutoforder(s, h, bp);
742 ilpullup(s);
743 break;
744 case Ildataquery:
745 ilackto(ic, ack, bp);
746 iloutoforder(s, h, bp);
747 ilpullup(s);
748 ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec);
749 break;
750 case Ilack:
751 ilackto(ic, ack, bp);
752 freeblist(bp);
753 break;
754 case Ilquery:
755 ilackto(ic, ack, bp);
756 ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec);
757 freeblist(bp);
758 break;
759 case Ilstate:
760 if(ack >= ic->rttack)
761 ic->rttack = 0;
762 ilackto(ic, ack, bp);
763 if(h->ilspec > Nqt)
764 h->ilspec = 0;
765 if(ic->qt[h->ilspec] > ack){
766 ilrexmit(ic);
767 ilsettimeout(ic);
768 }
769 freeblist(bp);
770 break;
771 case Ilclose:
772 freeblist(bp);
773 if(ack < ic->start || ack > ic->next)
774 break;
775 ic->recvd = id;
776 ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0);
777 ic->state = Ilclosing;
778 ilsettimeout(ic);
779 ilfreeq(ic);
780 break;
781 }
782 break;
783 case Illistening:
784 freeblist(bp);
785 break;
786 case Ilclosing:
787 switch(h->iltype) {
788 case Ilclose:
789 ic->recvd = id;
790 ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0);
791 if(ack == ic->next)
792 ilhangup(s, nil);
793 break;
794 default:
795 break;
796 }
797 freeblist(bp);
798 break;
799 }
800 }
801
802 void
803 ilrexmit(Ilcb *ic)
804 {
805 Ilhdr *h;
806 Block *nb;
807 Conv *c;
808 ulong id;
809 Ilpriv *priv;
810
811 nb = nil;
812 qlock(&ic->ackq);
813 if(ic->unacked)
814 nb = copyblock(ic->unacked, blocklen(ic->unacked));
815 qunlock(&ic->ackq);
816
817 if(nb == nil)
818 return;
819
820 h = (Ilhdr*)nb->rp;
821 h->vihl = IP_VER4;
822
823 h->iltype = Ildataquery;
824 hnputl(h->ilack, ic->recvd);
825 h->ilspec = ilnextqt(ic);
826 h->ilsum[0] = 0;
827 h->ilsum[1] = 0;
828 hnputs(h->ilsum, ptclcsum(nb, IL_IPSIZE, nhgets(h->illen)));
829
830 c = ic->conv;
831 id = nhgetl(h->ilid);
832 netlog(c->p->f, Logil, "il: rexmit %d %ud: %d %d: %i %d/%d\n", id, ic->recvd,
833 ic->rexmit, ic->timeout,
834 c->raddr, c->lport, c->rport);
835
836 ilbackoff(ic);
837
838 ipoput4(c->p->f, nb, 0, c->ttl, c->tos, c);
839
840 /* statistics */
841 ic->rxtot++;
842 priv = c->p->priv;
843 priv->rexmit++;
844 }
845
846 /* DEBUG */
847 void
848 ilprocess(Conv *s, Ilhdr *h, Block *bp)
849 {
850 Ilcb *ic;
851
852 ic = (Ilcb*)s->ptcl;
853
854 USED(ic);
855 netlog(s->p->f, Logilmsg, "%11s rcv %d/%d snt %d/%d pkt(%s id %d ack %d %d->%d) ",
856 ilstates[ic->state], ic->rstart, ic->recvd, ic->start,
857 ic->next, iltype[h->iltype], nhgetl(h->ilid),
858 nhgetl(h->ilack), nhgets(h->ilsrc), nhgets(h->ildst));
859
860 _ilprocess(s, h, bp);
861
862 netlog(s->p->f, Logilmsg, "%11s rcv %d snt %d\n", ilstates[ic->state], ic->recvd, ic->next);
863 }
864
865 void
866 ilhangup(Conv *s, char *msg)
867 {
868 Ilcb *ic;
869 int callout;
870
871 netlog(s->p->f, Logil, "il: hangup! %I %d/%d: %s\n", s->raddr,
872 s->lport, s->rport, msg?msg:"no reason");
873
874 ic = (Ilcb*)s->ptcl;
875 callout = ic->state == Ilsyncer;
876 illocalclose(s);
877
878 qhangup(s->rq, msg);
879 qhangup(s->wq, msg);
880
881 if(callout)
882 Fsconnected(s, msg);
883 }
884
885 void
886 ilpullup(Conv *s)
887 {
888 Ilcb *ic;
889 Ilhdr *oh;
890 Block *bp;
891 ulong oid, dlen;
892 Ilpriv *ipriv;
893
894 ic = (Ilcb*)s->ptcl;
895 if(ic->state != Ilestablished)
896 return;
897
898 qlock(&ic->outo);
899 while(ic->outoforder) {
900 bp = ic->outoforder;
901 oh = (Ilhdr*)bp->rp;
902 oid = nhgetl(oh->ilid);
903 if(oid <= ic->recvd) {
904 ic->outoforder = bp->list;
905 freeblist(bp);
906 continue;
907 }
908 if(oid != ic->recvd+1){
909 ipriv = s->p->priv;
910 ipriv->stats[OutOfOrder]++;
911 break;
912 }
913
914 ic->recvd = oid;
915 ic->outoforder = bp->list;
916
917 bp->list = nil;
918 dlen = nhgets(oh->illen)-IL_HDRSIZE;
919 bp = trimblock(bp, IL_IPSIZE+IL_HDRSIZE, dlen);
920 /*
921 * Upper levels don't know about multiple-block
922 * messages so copy all into one (yick).
923 */
924 bp = concatblock(bp);
925 if(bp == 0)
926 panic("ilpullup");
927 bp = packblock(bp);
928 if(bp == 0)
929 panic("ilpullup2");
930 qpass(s->rq, bp);
931 }
932 qunlock(&ic->outo);
933 }
934
935 void
936 iloutoforder(Conv *s, Ilhdr *h, Block *bp)
937 {
938 Ilcb *ic;
939 uchar *lid;
940 Block *f, **l;
941 ulong id, newid;
942 Ilpriv *ipriv;
943
944 ipriv = s->p->priv;
945 ic = (Ilcb*)s->ptcl;
946 bp->list = nil;
947
948 id = nhgetl(h->ilid);
949 /* Window checks */
950 if(id <= ic->recvd || id > ic->recvd+ic->window) {
951 netlog(s->p->f, Logil, "il: message outside window %ud <%ud-%ud>: %i %d/%d\n",
952 id, ic->recvd, ic->recvd+ic->window, s->raddr, s->lport, s->rport);
953 freeblist(bp);
954 return;
955 }
956
957 /* Packet is acceptable so sort onto receive queue for pullup */
958 qlock(&ic->outo);
959 if(ic->outoforder == nil)
960 ic->outoforder = bp;
961 else {
962 l = &ic->outoforder;
963 for(f = *l; f; f = f->list) {
964 lid = ((Ilhdr*)(f->rp))->ilid;
965 newid = nhgetl(lid);
966 if(id <= newid) {
967 if(id == newid) {
968 ipriv->stats[DupMsg]++;
969 ipriv->stats[DupBytes] += blocklen(bp);
970 qunlock(&ic->outo);
971 freeblist(bp);
972 return;
973 }
974 bp->list = f;
975 *l = bp;
976 qunlock(&ic->outo);
977 return;
978 }
979 l = &f->list;
980 }
981 *l = bp;
982 }
983 qunlock(&ic->outo);
984 }
985
986 void
987 ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec)
988 {
989 Ilhdr *ih;
990 Ilcb *ic;
991 Block *bp;
992 int ttl, tos;
993
994 bp = allocb(IL_IPSIZE+IL_HDRSIZE);
995 bp->wp += IL_IPSIZE+IL_HDRSIZE;
996
997 ih = (Ilhdr *)(bp->rp);
998 ih->vihl = IP_VER4;
999
1000 /* Ip fields */
1001 ih->proto = IP_ILPROTO;
1002 hnputs(ih->illen, IL_HDRSIZE);
1003 ih->frag[0] = 0;
1004 ih->frag[1] = 0;
1005 if(inih) {
1006 hnputl(ih->dst, nhgetl(inih->src));
1007 hnputl(ih->src, nhgetl(inih->dst));
1008 hnputs(ih->ilsrc, nhgets(inih->ildst));
1009 hnputs(ih->ildst, nhgets(inih->ilsrc));
1010 hnputl(ih->ilid, nhgetl(inih->ilack));
1011 hnputl(ih->ilack, nhgetl(inih->ilid));
1012 ttl = MAXTTL;
1013 tos = DFLTTOS;
1014 }
1015 else {
1016 v6tov4(ih->dst, ipc->raddr);
1017 v6tov4(ih->src, ipc->laddr);
1018 hnputs(ih->ilsrc, ipc->lport);
1019 hnputs(ih->ildst, ipc->rport);
1020 hnputl(ih->ilid, id);
1021 hnputl(ih->ilack, ack);
1022 ic = (Ilcb*)ipc->ptcl;
1023 ic->acksent = ack;
1024 ic->acktime = NOW;
1025 ttl = ipc->ttl;
1026 tos = ipc->tos;
1027 }
1028 ih->iltype = type;
1029 ih->ilspec = ilspec;
1030 ih->ilsum[0] = 0;
1031 ih->ilsum[1] = 0;
1032
1033 if(ilcksum)
1034 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE));
1035
1036 if(ipc==nil)
1037 panic("ipc is nil caller is %#p", getcallerpc(&ipc));
1038 if(ipc->p==nil)
1039 panic("ipc->p is nil");
1040
1041 netlog(ipc->p->f, Logilmsg, "ctl(%s id %d ack %d %d->%d)\n",
1042 iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack),
1043 nhgets(ih->ilsrc), nhgets(ih->ildst));
1044
1045 ipoput4(ipc->p->f, bp, 0, ttl, tos, ipc);
1046 }
1047
1048 void
1049 ilreject(Fs *f, Ilhdr *inih)
1050 {
1051 Ilhdr *ih;
1052 Block *bp;
1053
1054 bp = allocb(IL_IPSIZE+IL_HDRSIZE);
1055 bp->wp += IL_IPSIZE+IL_HDRSIZE;
1056
1057 ih = (Ilhdr *)(bp->rp);
1058 ih->vihl = IP_VER4;
1059
1060 /* Ip fields */
1061 ih->proto = IP_ILPROTO;
1062 hnputs(ih->illen, IL_HDRSIZE);
1063 ih->frag[0] = 0;
1064 ih->frag[1] = 0;
1065 hnputl(ih->dst, nhgetl(inih->src));
1066 hnputl(ih->src, nhgetl(inih->dst));
1067 hnputs(ih->ilsrc, nhgets(inih->ildst));
1068 hnputs(ih->ildst, nhgets(inih->ilsrc));
1069 hnputl(ih->ilid, nhgetl(inih->ilack));
1070 hnputl(ih->ilack, nhgetl(inih->ilid));
1071 ih->iltype = Ilclose;
1072 ih->ilspec = 0;
1073 ih->ilsum[0] = 0;
1074 ih->ilsum[1] = 0;
1075
1076 if(ilcksum)
1077 hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE));
1078
1079 ipoput4(f, bp, 0, MAXTTL, DFLTTOS, nil);
1080 }
1081
1082 void
1083 ilsettimeout(Ilcb *ic)
1084 {
1085 ulong pt;
1086
1087 pt = (ic->delay>>LogAGain)
1088 + ic->unackedbytes/(ic->rate>>LogAGain)
1089 + (ic->mdev>>(LogDGain-1))
1090 + AckDelay;
1091 if(pt > MaxTimeout)
1092 pt = MaxTimeout;
1093 ic->timeout = NOW + pt;
1094 }
1095
1096 void
1097 ilbackoff(Ilcb *ic)
1098 {
1099 ulong pt;
1100 int i;
1101
1102 pt = (ic->delay>>LogAGain)
1103 + ic->unackedbytes/(ic->rate>>LogAGain)
1104 + (ic->mdev>>(LogDGain-1))
1105 + AckDelay;
1106 for(i = 0; i < ic->rexmit; i++)
1107 pt = pt + (pt>>1);
1108 if(pt > MaxTimeout)
1109 pt = MaxTimeout;
1110 ic->timeout = NOW + pt;
1111
1112 if(ic->fasttimeout)
1113 ic->timeout = NOW+Iltickms;
1114
1115 ic->rexmit++;
1116 }
1117
1118 // complain if two numbers not within an hour of each other
1119 #define Tfuture (1000*60*60)
1120 int
1121 later(ulong t1, ulong t2, char *x)
1122 {
1123 int dt;
1124
1125 dt = t1 - t2;
1126 if(dt > 0) {
1127 if(x != nil && dt > Tfuture)
1128 print("%s: way future %d\n", x, dt);
1129 return 1;
1130 }
1131 if(dt < -Tfuture) {
1132 if(x != nil)
1133 print("%s: way past %d\n", x, -dt);
1134 return 1;
1135 }
1136 return 0;
1137 }
1138
1139 void
1140 ilackproc(void *x)
1141 {
1142 Ilcb *ic;
1143 Conv **s, *p;
1144 Proto *il;
1145
1146 il = x;
1147
1148 loop:
1149 tsleep(&up->sleep, return0, 0, Iltickms);
1150 for(s = il->conv; s && *s; s++) {
1151 p = *s;
1152 ic = (Ilcb*)p->ptcl;
1153
1154 switch(ic->state) {
1155 case Ilclosed:
1156 case Illistening:
1157 break;
1158 case Ilclosing:
1159 if(later(NOW, ic->timeout, "timeout0")) {
1160 if(ic->rexmit > MaxRexmit){
1161 ilhangup(p, nil);
1162 break;
1163 }
1164 ilsendctl(p, nil, Ilclose, ic->next, ic->recvd, 0);
1165 ilbackoff(ic);
1166 }
1167 break;
1168
1169 case Ilsyncee:
1170 case Ilsyncer:
1171 if(later(NOW, ic->timeout, "timeout1")) {
1172 if(ic->rexmit > MaxRexmit){
1173 ilhangup(p, etime);
1174 break;
1175 }
1176 ilsendctl(p, nil, Ilsync, ic->start, ic->recvd, 0);
1177 ilbackoff(ic);
1178 }
1179 break;
1180
1181 case Ilestablished:
1182 if(ic->recvd != ic->acksent)
1183 if(later(NOW, ic->acktime, "acktime"))
1184 ilsendctl(p, nil, Ilack, ic->next, ic->recvd, 0);
1185
1186 if(later(NOW, ic->querytime, "querytime")){
1187 if(later(NOW, ic->lastrecv+DeathTime, "deathtime")){
1188 netlog(il->f, Logil, "il: hangup: deathtime\n");
1189 ilhangup(p, etime);
1190 break;
1191 }
1192 ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic));
1193 ic->querytime = NOW + QueryTime;
1194 }
1195
1196 if(ic->unacked != nil)
1197 if(later(NOW, ic->timeout, "timeout2")) {
1198 if(ic->rexmit > MaxRexmit){
1199 netlog(il->f, Logil, "il: hangup: too many rexmits\n");
1200 ilhangup(p, etime);
1201 break;
1202 }
1203 ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic));
1204 ic->rxquery++;
1205 ilbackoff(ic);
1206 }
1207 break;
1208 }
1209 }
1210 goto loop;
1211 }
1212
1213 void
1214 ilcbinit(Ilcb *ic)
1215 {
1216 ic->start = nrand(0x1000000);
1217 ic->next = ic->start+1;
1218 ic->recvd = 0;
1219 ic->window = Defaultwin;
1220 ic->unackedbytes = 0;
1221 ic->unacked = nil;
1222 ic->outoforder = nil;
1223 ic->rexmit = 0;
1224 ic->rxtot = 0;
1225 ic->rxquery = 0;
1226 ic->qtx = 1;
1227 ic->fasttimeout = 0;
1228
1229 /* timers */
1230 ic->delay = DefRtt<<LogAGain;
1231 ic->mdev = DefRtt<<LogDGain;
1232 ic->rate = DefByteRate<<LogAGain;
1233 ic->querytime = NOW + QueryTime;
1234 ic->lastrecv = NOW; /* or we'll timeout right away */
1235 ilsettimeout(ic);
1236 }
1237
1238 char*
1239 ilstart(Conv *c, int type, int fasttimeout)
1240 {
1241 Ilcb *ic;
1242 Ilpriv *ipriv;
1243 char kpname[KNAMELEN];
1244
1245 ipriv = c->p->priv;
1246
1247 if(ipriv->ackprocstarted == 0){
1248 qlock(&ipriv->apl);
1249 if(ipriv->ackprocstarted == 0){
1250 sprint(kpname, "#I%dilack", c->p->f->dev);
1251 kproc(kpname, ilackproc, c->p);
1252 ipriv->ackprocstarted = 1;
1253 }
1254 qunlock(&ipriv->apl);
1255 }
1256
1257 ic = (Ilcb*)c->ptcl;
1258 ic->conv = c;
1259
1260 if(ic->state != Ilclosed)
1261 return nil;
1262
1263 ilcbinit(ic);
1264
1265 if(fasttimeout){
1266 /* timeout if we can't connect quickly */
1267 ic->fasttimeout = 1;
1268 ic->timeout = NOW+Iltickms;
1269 ic->rexmit = MaxRexmit - 4;
1270 };
1271
1272 switch(type) {
1273 default:
1274 netlog(c->p->f, Logil, "il: start: type %d\n", type);
1275 break;
1276 case IL_LISTEN:
1277 ic->state = Illistening;
1278 iphtadd(&ipriv->ht, c);
1279 break;
1280 case IL_CONNECT:
1281 ic->state = Ilsyncer;
1282 iphtadd(&ipriv->ht, c);
1283 ilsendctl(c, nil, Ilsync, ic->start, ic->recvd, 0);
1284 break;
1285 }
1286
1287 return nil;
1288 }
1289
1290 void
1291 ilfreeq(Ilcb *ic)
1292 {
1293 Block *bp, *next;
1294
1295 qlock(&ic->ackq);
1296 for(bp = ic->unacked; bp; bp = next) {
1297 next = bp->list;
1298 freeblist(bp);
1299 }
1300 ic->unacked = nil;
1301 qunlock(&ic->ackq);
1302
1303 qlock(&ic->outo);
1304 for(bp = ic->outoforder; bp; bp = next) {
1305 next = bp->list;
1306 freeblist(bp);
1307 }
1308 ic->outoforder = nil;
1309 qunlock(&ic->outo);
1310 }
1311
1312 void
1313 iladvise(Proto *il, Block *bp, char *msg)
1314 {
1315 Ilhdr *h;
1316 Ilcb *ic;
1317 uchar source[IPaddrlen], dest[IPaddrlen];
1318 ushort psource;
1319 Conv *s, **p;
1320
1321 h = (Ilhdr*)(bp->rp);
1322
1323 v4tov6(dest, h->dst);
1324 v4tov6(source, h->src);
1325 psource = nhgets(h->ilsrc);
1326
1327
1328 /* Look for a connection, unfortunately the destination port is missing */
1329 QLOCK(il);
1330 for(p = il->conv; *p; p++) {
1331 s = *p;
1332 if(s->lport == psource)
1333 if(ipcmp(s->laddr, source) == 0)
1334 if(ipcmp(s->raddr, dest) == 0){
1335 QUNLOCK(il);
1336 ic = (Ilcb*)s->ptcl;
1337 switch(ic->state){
1338 case Ilsyncer:
1339 ilhangup(s, msg);
1340 break;
1341 }
1342 freeblist(bp);
1343 return;
1344 }
1345 }
1346 QUNLOCK(il);
1347 freeblist(bp);
1348 }
1349
1350 int
1351 ilnextqt(Ilcb *ic)
1352 {
1353 int x;
1354
1355 qlock(&ic->ackq);
1356 x = ic->qtx;
1357 if(++x > Nqt)
1358 x = 1;
1359 ic->qtx = x;
1360 ic->qt[x] = ic->next-1; /* highest xmitted packet */
1361 ic->qt[0] = ic->qt[x]; /* compatibility with old implementations */
1362 qunlock(&ic->ackq);
1363
1364 return x;
1365 }
1366
1367 /* calculate scale constants that converts fast ticks to ms (more or less) */
1368 static void
1369 inittimescale(void)
1370 {
1371 uvlong hz;
1372
1373 fastticks(&hz);
1374 if(hz > 1000){
1375 scalediv = hz/1000;
1376 scalemul = 1;
1377 } else {
1378 scalediv = 1;
1379 scalemul = 1000/hz;
1380 }
1381 }
1382
1383 void
1384 ilinit(Fs *f)
1385 {
1386 Proto *il;
1387
1388 inittimescale();
1389
1390 il = smalloc(sizeof(Proto));
1391 il->priv = smalloc(sizeof(Ilpriv));
1392 il->name = "il";
1393 il->connect = ilconnect;
1394 il->announce = ilannounce;
1395 il->state = ilstate;
1396 il->create = ilcreate;
1397 il->close = ilclose;
1398 il->rcv = iliput;
1399 il->ctl = nil;
1400 il->advise = iladvise;
1401 il->stats = ilxstats;
1402 il->inuse = ilinuse;
1403 il->gc = nil;
1404 il->ipproto = IP_ILPROTO;
1405 il->nc = scalednconv();
1406 il->ptclsize = sizeof(Ilcb);
1407 Fsproto(f, il);
1408 }