vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | 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 }