plan 9 kernel history: overview | file list | diff list

2001/0922/ip/il.c (diff list | history)

ip/il.c on 1997/0327
1997/0327    
#include	"u.h" 
#include	"../port/lib.h" 
#include	"mem.h" 
#include	"dat.h" 
#include	"fns.h" 
#include	"../port/error.h" 
 
#include	"ip.h" 
 
1998/0929    
enum				/* Connection state */ 
{ 
	Ilclosed, 
	Ilsyncer, 
	Ilsyncee, 
	Ilestablished, 
	Illistening, 
	Ilclosing, 
1998/0930    
	Ilopening,		/* only for file server */ 
1998/0929    
}; 
 
1997/0327    
char	*ilstates[] =  
{  
	"Closed", 
	"Syncer", 
	"Syncee", 
	"Established", 
	"Listening", 
1998/0930    
	"Closing", 
	"Opening",		/* only for file server */ 
1997/0327    
}; 
 
enum				/* Packet types */ 
{ 
	Ilsync, 
	Ildata, 
	Ildataquery, 
	Ilack, 
1997/0804    
	Ilquery, 
1997/0327    
	Ilstate, 
	Ilclose, 
}; 
 
1998/0929    
char	*iltype[] =  
{	 
	"sync", 
	"data", 
	"dataquery", 
	"ack", 
	"query", 
	"state", 
	"close"  
1997/0327    
}; 
 
1998/0930    
enum 
{ 
	Seconds		= 1000, 
	Iltickms 	= 50,		/* time base */ 
	AckDelay	= 2*Iltickms,	/* max time twixt message rcvd & ack sent */ 
1999/0529    
	MaxTimeout 	= 30*Seconds,	/* max time between rexmit */ 
1998/1013    
	QueryTime	= 10*Seconds,	/* time between subsequent queries */ 
2000/1121    
	DeathTime	= 30*QueryTime, 
1998/0929    
 
1998/0930    
	MaxRexmit 	= 16,		/* max retransmissions before hangup */ 
	Defaultwin	= 20, 
 
	LogAGain	= 3, 
	AGain		= 1<<LogAGain, 
	LogDGain	= 2, 
	DGain		= 1<<LogDGain, 
 
	DefByteRate	= 100,		/* assume a megabit link */ 
	DefRtt		= 50,		/* cross country on a great day */ 
}; 
 
1997/0804    
enum 
{ 
	Nqt=	8, 
}; 
 
1997/0327    
typedef struct Ilcb Ilcb; 
struct Ilcb			/* Control block */ 
{ 
	int	state;		/* Connection state */ 
	Conv	*conv; 
	QLock	ackq;		/* Unacknowledged queue */ 
	Block	*unacked; 
	Block	*unackedtail; 
1998/0930    
	ulong	unackedbytes; 
1997/0327    
	QLock	outo;		/* Out of order packet queue */ 
	Block	*outoforder; 
	ulong	next;		/* Id of next to send */ 
	ulong	recvd;		/* Last packet received */ 
1998/0929    
	ulong	acksent;	/* Last packet acked */ 
1997/0327    
	ulong	start;		/* Local start id */ 
	ulong	rstart;		/* Remote start id */ 
1998/0929    
	int	window;		/* Maximum receive window */ 
1998/0930    
	int	rxquery;	/* number of queries on this connection */ 
1998/0929    
	int	rxtot;		/* number of retransmits on this connection */ 
	int	rexmit;		/* number of retransmits of *unacked */ 
	ulong	qt[Nqt+1];	/* state table for query messages */ 
	int	qtx;		/* ... index into qt */ 
 
2001/0227    
	/* if set, fasttimeout causes a connection request to terminate after 4*Iltickms */ 
	int	fasttimeout; 
 
1998/0929    
	/* timers */ 
	ulong	lastxmit;	/* time of last xmit */ 
	ulong	lastrecv;	/* time of last recv */ 
	ulong	timeout;	/* retransmission time for *unacked */ 
	ulong	acktime;	/* time to send next ack */ 
	ulong	querytime;	/* time to send next query */ 
 
	/* adaptive measurements */ 
1997/0730    
	int	delay;		/* Average of the fixed rtt delay */ 
1998/0306    
	int	rate;		/* Average uchar rate */ 
1997/0730    
	int	mdev;		/* Mean deviation of rtt */ 
1997/0802    
	int	maxrtt;		/* largest rtt seen */ 
1997/0327    
	ulong	rttack;		/* The ack we are waiting for */ 
1997/0730    
	int	rttlen;		/* Length of rttack packet */ 
1998/0929    
	uvlong	rttstart;	/* Time we issued rttack packet */ 
1997/0327    
}; 
 
enum 
{ 
	IL_IPSIZE 	= 20, 
	IL_HDRSIZE	= 18,	 
	IL_LISTEN	= 0, 
	IL_CONNECT	= 1, 
	IP_ILPROTO	= 40, 
}; 
 
typedef struct Ilhdr Ilhdr; 
struct Ilhdr 
{ 
1998/0306    
	uchar	vihl;		/* Version and header length */ 
	uchar	tos;		/* Type of service */ 
	uchar	length[2];	/* packet length */ 
	uchar	id[2];		/* Identification */ 
	uchar	frag[2];	/* Fragment information */ 
	uchar	ttl;		/* Time to live */ 
	uchar	proto;		/* Protocol */ 
	uchar	cksum[2];	/* Header checksum */ 
	uchar	src[4];		/* Ip source */ 
	uchar	dst[4];		/* Ip destination */ 
	uchar	ilsum[2];	/* Checksum including header */ 
	uchar	illen[2];	/* Packet length */ 
	uchar	iltype;		/* Packet type */ 
	uchar	ilspec;		/* Special */ 
	uchar	ilsrc[2];	/* Src port */ 
	uchar	ildst[2];	/* Dst port */ 
	uchar	ilid[4];	/* Sequence id */ 
	uchar	ilack[4];	/* Acked sequence */ 
1997/0327    
}; 
 
2000/0706    
enum 
{ 
	InMsgs, 
	OutMsgs, 
	CsumErrs,		/* checksum errors */ 
	HlenErrs,		/* header length error */ 
	LenErrs,		/* short packet */ 
	OutOfOrder,		/* out of order */ 
	Retrans,		/* retransmissions */ 
	DupMsg, 
	DupBytes, 
1998/0313    
 
2000/0706    
	Nstats, 
}; 
 
static char *statnames[] = 
{ 
[InMsgs]	"InMsgs", 
[OutMsgs]	"OutMsgs", 
[CsumErrs]	"CsumErrs", 
[HlenErrs]	"HlenErr", 
[LenErrs]	"LenErrs", 
[OutOfOrder]	"OutOfOrder", 
[Retrans]	"Retrans", 
[DupMsg]	"DupMsg", 
[DupBytes]	"DupBytes", 
}; 
 
1998/0313    
typedef struct Ilpriv Ilpriv; 
struct Ilpriv 
1997/0916    
{ 
2001/0301    
	Ipht	ht; 
 
2000/0706    
	ulong	stats[Nstats]; 
1997/0916    
 
2001/0301    
	ulong	csumerr;		/* checksum errors */ 
	ulong	hlenerr;		/* header length error */ 
	ulong	lenerr;			/* short packet */ 
	ulong	order;			/* out of order */ 
	ulong	rexmit;			/* retransmissions */ 
	ulong	dup; 
	ulong	dupb; 
1998/0313    
 
2001/0301    
	Rendez	ilr; 
1998/0924    
 
	/* keeping track of the ack kproc */ 
	int	ackprocstarted; 
	QLock	apl; 
1998/0313    
}; 
 
1997/0804    
/* state for query/dataquery messages */ 
 
 
1997/0327    
void	ilrcvmsg(Conv*, Block*); 
1997/0804    
void	ilsendctl(Conv*, Ilhdr*, int, ulong, ulong, int); 
1997/0327    
void	ilackq(Ilcb*, Block*); 
void	ilprocess(Conv*, Ilhdr*, Block*); 
void	ilpullup(Conv*); 
void	ilhangup(Conv*, char*); 
void	ilfreeq(Ilcb*); 
void	ilrexmit(Ilcb*); 
void	ilbackoff(Ilcb*); 
1998/0929    
void	ilsettimeout(Ilcb*); 
2001/0227    
char*	ilstart(Conv*, int, int); 
1998/0313    
void	ilackproc(void*); 
1997/0327    
void	iloutoforder(Conv*, Ilhdr*, Block*); 
2001/0623    
void	iliput(Proto*, Ipifc*, Block*); 
1998/0313    
void	iladvise(Proto*, Block*, char*); 
1997/0804    
int	ilnextqt(Ilcb*); 
1998/0929    
void	ilcbinit(Ilcb*); 
1999/0501    
int	later(ulong, ulong, char*); 
1999/0917    
void	ilreject(Fs*, Ilhdr*); 
2001/0301    
void	illocalclose(Conv *c); 
1997/0327    
	int 	ilcksum = 1; 
static 	int 	initseq = 25001; 
1999/0703    
static	ulong	scalediv, scalemul; 
1998/0930    
static	char	*etime = "connection timed out"; 
1997/0327    
 
static char* 
ilconnect(Conv *c, char **argv, int argc) 
{ 
2001/0303    
	char *e, *p; 
2001/0227    
	int fast; 
1997/0327    
 
2001/0303    
	/* huge hack to quickly try an il connection */ 
	fast = 0; 
	if(argc > 1){ 
		p = strstr(argv[1], "!fasttimeout"); 
		if(p != nil){ 
			*p = 0; 
			fast = 1; 
		} 
	} 
 
1997/0521    
	e = Fsstdconnect(c, argv, argc); 
1997/0327    
	if(e != nil) 
		return e; 
2001/0227    
	return ilstart(c, IL_CONNECT, fast); 
1997/0327    
} 
 
1998/0306    
static int 
ilstate(Conv *c, char *state, int n) 
1997/0327    
{ 
	Ilcb *ic; 
 
	ic = (Ilcb*)(c->ptcl); 
1998/0930    
	return snprint(state, n, "%s del %5.5d Br %5.5d md %5.5d una %5.5lud rex %5.5d rxq %5.5d max %5.5d", 
1998/0306    
		ilstates[ic->state], 
		ic->delay>>LogAGain, ic->rate>>LogAGain, ic->mdev>>LogDGain, 
1998/0930    
		ic->unackedbytes, ic->rxtot, ic->rxquery, ic->maxrtt); 
1998/0306    
} 
1997/0327    
 
1998/0306    
static int 
ilinuse(Conv *c) 
{ 
	Ilcb *ic; 
1997/0327    
 
1998/0306    
	ic = (Ilcb*)(c->ptcl); 
	return ic->state != Ilclosed; 
 
1997/0327    
} 
 
/* called with c locked */ 
1997/0403    
static char* 
ilannounce(Conv *c, char **argv, int argc) 
1997/0327    
{ 
	char *e; 
 
1997/0403    
	e = Fsstdannounce(c, argv, argc); 
1997/0404    
	if(e != nil) 
1997/0403    
		return e; 
2001/0227    
	e = ilstart(c, IL_LISTEN, 0); 
1997/0403    
	if(e != nil) 
		return e; 
1998/0313    
	Fsconnected(c, nil); 
1997/0403    
 
	return nil; 
1997/0327    
} 
 
2001/0301    
void 
illocalclose(Conv *c) 
{ 
	Ilcb *ic; 
	Ilpriv *ipriv; 
 
	ipriv = c->p->priv; 
	ic = (Ilcb*)c->ptcl; 
	ic->state = Ilclosed; 
	iphtrem(&ipriv->ht, c); 
	ipmove(c->laddr, IPnoaddr); 
	c->lport = 0; 
} 
 
1997/0327    
static void 
ilclose(Conv *c) 
{ 
	Ilcb *ic; 
 
	ic = (Ilcb*)c->ptcl; 
 
	qclose(c->rq); 
	qclose(c->wq); 
	qclose(c->eq); 
 
	switch(ic->state) { 
	case Ilclosing: 
	case Ilclosed: 
		break; 
	case Ilsyncer: 
	case Ilsyncee: 
	case Ilestablished: 
		ic->state = Ilclosing; 
1999/0429    
		ilsettimeout(ic); 
1997/0804    
		ilsendctl(c, nil, Ilclose, ic->next, ic->recvd, 0); 
1997/0327    
		break; 
	case Illistening: 
2001/0301    
		illocalclose(c); 
1997/0327    
		break; 
	} 
1997/0902    
	ilfreeq(ic); 
1997/0327    
} 
 
void 
2001/0306    
ilkick(Conv *c) 
1997/0327    
{ 
	Ilhdr *ih; 
	Ilcb *ic; 
	int dlen; 
1998/0929    
	ulong id, ack; 
1997/0327    
	Block *bp; 
1998/0313    
	Fs *f; 
2000/0706    
	Ilpriv *priv; 
1997/0327    
 
1998/0313    
	f = c->p->f; 
2000/0706    
	priv = c->p->priv; 
1997/0327    
	ic = (Ilcb*)c->ptcl; 
 
	bp = qget(c->wq); 
	if(bp == nil) 
		return; 
 
	switch(ic->state) { 
	case Ilclosed: 
	case Illistening: 
	case Ilclosing: 
		freeblist(bp); 
		qhangup(c->rq, nil); 
		return; 
	} 
 
	dlen = blocklen(bp); 
 
	/* Make space to fit il & ip */ 
	bp = padblock(bp, IL_IPSIZE+IL_HDRSIZE); 
	ih = (Ilhdr *)(bp->rp); 
 
	/* Ip fields */ 
	ih->frag[0] = 0; 
	ih->frag[1] = 0; 
1998/0306    
	v6tov4(ih->dst, c->raddr); 
	v6tov4(ih->src, c->laddr); 
1997/0327    
	ih->proto = IP_ILPROTO; 
 
	/* Il fields */ 
	hnputs(ih->illen, dlen+IL_HDRSIZE); 
	hnputs(ih->ilsrc, c->lport); 
	hnputs(ih->ildst, c->rport); 
 
	qlock(&ic->ackq); 
	id = ic->next++; 
	hnputl(ih->ilid, id); 
1998/0929    
	ack = ic->recvd; 
	hnputl(ih->ilack, ack); 
	ic->acksent = ack; 
	ic->acktime = msec + AckDelay; 
1997/0327    
	ih->iltype = Ildata; 
	ih->ilspec = 0; 
	ih->ilsum[0] = 0; 
	ih->ilsum[1] = 0; 
 
	/* Checksum of ilheader plus data (not ip & no pseudo header) */ 
	if(ilcksum) 
		hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, dlen+IL_HDRSIZE)); 
 
	ilackq(ic, bp); 
	qunlock(&ic->ackq); 
 
	/* Start the round trip timer for this packet if the timer is free */ 
	if(ic->rttack == 0) { 
		ic->rttack = id; 
1998/0929    
		ic->rttstart = fastticks(nil); 
1997/0730    
		ic->rttlen = dlen + IL_IPSIZE + IL_HDRSIZE; 
1997/0327    
	} 
 
1999/0430    
	if(later(msec, ic->timeout, nil)) 
1998/0929    
		ilsettimeout(ic); 
1999/0817    
	ipoput(f, bp, 0, c->ttl, c->tos); 
2000/0706    
	priv->stats[OutMsgs]++; 
1997/0327    
} 
 
static void 
ilcreate(Conv *c) 
{ 
	c->rq = qopen(64*1024, 0, 0, c); 
	c->wq = qopen(64*1024, 0, 0, 0); 
} 
 
1997/0916    
int 
1998/0313    
ilxstats(Proto *il, char *buf, int len) 
1997/0916    
{ 
2000/0706    
	Ilpriv *priv; 
	char *p, *e; 
	int i; 
1998/0306    
 
2000/0706    
	priv = il->priv; 
	p = buf; 
	e = p+len; 
	for(i = 0; i < Nstats; i++) 
		p = seprint(p, e, "%s: %lud\n", statnames[i], priv->stats[i]); 
	return p - buf; 
1997/0916    
} 
 
1997/0327    
void 
ilackq(Ilcb *ic, Block *bp) 
{ 
	Block *np; 
1997/0730    
	int n; 
1997/0327    
 
1997/0730    
	n = blocklen(bp); 
 
1997/0327    
	/* Enqueue a copy on the unacked queue in case this one gets lost */ 
1997/0730    
	np = copyblock(bp, n); 
1997/0327    
	if(ic->unacked) 
		ic->unackedtail->list = np; 
1998/0929    
	else 
1997/0327    
		ic->unacked = np; 
	ic->unackedtail = np; 
	np->list = nil; 
1998/0930    
	ic->unackedbytes += n; 
1997/0327    
} 
 
1997/0805    
static 
1997/0327    
void 
1998/0929    
ilrttcalc(Ilcb *ic, Block *bp) 
1997/0801    
{ 
1998/0930    
	int rtt, tt, pt, delay, rate; 
1997/0801    
 
1999/0703    
	rtt = fastticks(nil) - ic->rttstart; 
	rtt = (rtt*scalemul)/scalediv; 
1997/0802    
	delay = ic->delay; 
	rate = ic->rate; 
1997/0801    
 
1998/0929    
	/* Guard against zero wrap */ 
1999/0703    
	if(rtt > 120000 || rtt < 0) 
1997/0801    
		return; 
 
1998/0930    
	/* this block had to be transmitted after the one acked so count its size */ 
	ic->rttlen += blocklen(bp)  + IL_IPSIZE + IL_HDRSIZE; 
 
	if(ic->rttlen < 256){ 
		/* guess fixed delay as rtt of small packets */ 
		delay += rtt - (delay>>LogAGain); 
1997/0802    
		if(delay < AGain) 
			delay = AGain; 
		ic->delay = delay; 
1998/0930    
	} else { 
		/* if packet took longer than avg rtt delay, recalc rate */ 
		tt = rtt - (delay>>LogAGain); 
		if(tt > 0){ 
			rate += ic->rttlen/tt - (rate>>LogAGain); 
			if(rate < AGain) 
				rate = AGain; 
			ic->rate = rate; 
		} 
1997/0801    
	} 
 
	/* mdev */ 
1997/0802    
	pt = ic->rttlen/(rate>>LogAGain) + (delay>>LogAGain); 
1998/0930    
	ic->mdev += abs(rtt-pt) - (ic->mdev>>LogDGain); 
1997/0801    
 
1998/0930    
	if(rtt > ic->maxrtt) 
		ic->maxrtt = rtt; 
1997/0801    
} 
 
1997/0730    
void 
1998/0929    
ilackto(Ilcb *ic, ulong ackto, Block *bp) 
1997/0327    
{ 
	Ilhdr *h; 
1997/0730    
	ulong id; 
1997/0327    
 
1997/0801    
	if(ic->rttack == ackto) 
1998/0929    
		ilrttcalc(ic, bp); 
1997/0730    
 
1997/0802    
	/* Cancel if we've passed the packet we were interested in */ 
1997/0327    
	if(ic->rttack <= ackto) 
		ic->rttack = 0; 
 
	qlock(&ic->ackq); 
	while(ic->unacked) { 
		h = (Ilhdr *)ic->unacked->rp; 
		id = nhgetl(h->ilid); 
		if(ackto < id) 
			break; 
 
		bp = ic->unacked; 
		ic->unacked = bp->list; 
		bp->list = nil; 
1998/0930    
		ic->unackedbytes -= blocklen(bp); 
1997/0327    
		freeblist(bp); 
2001/0302    
		ic->rexmit = 0; 
1998/0929    
		ilsettimeout(ic); 
1997/0327    
	} 
	qunlock(&ic->ackq); 
} 
 
void 
2001/0623    
iliput(Proto *il, Ipifc*, Block *bp) 
1997/0327    
{ 
	char *st; 
	Ilcb *ic; 
	Ilhdr *ih; 
1998/0306    
	uchar raddr[IPaddrlen]; 
	uchar laddr[IPaddrlen]; 
1997/0327    
	ushort sp, dp, csum; 
	int plen, illen; 
2001/0823    
	Conv *new, *s; 
1998/0313    
	Ilpriv *ipriv; 
1997/0327    
 
1998/0313    
	ipriv = il->priv; 
 
1997/0327    
	ih = (Ilhdr *)bp->rp; 
	plen = blocklen(bp); 
	if(plen < IL_IPSIZE+IL_HDRSIZE){ 
1998/0313    
		netlog(il->f, Logil, "il: hlenerr\n"); 
2000/0706    
		ipriv->stats[HlenErrs]++; 
1997/0327    
		goto raise; 
	} 
 
	illen = nhgets(ih->illen); 
	if(illen+IL_IPSIZE > plen){ 
1998/0313    
		netlog(il->f, Logil, "il: lenerr\n"); 
2000/0706    
		ipriv->stats[LenErrs]++; 
1997/0327    
		goto raise; 
	} 
 
	sp = nhgets(ih->ildst); 
	dp = nhgets(ih->ilsrc); 
1998/0306    
	v4tov6(raddr, ih->src); 
2001/0301    
	v4tov6(laddr, ih->dst); 
1997/0327    
 
1998/0313    
	if((csum = ptclcsum(bp, IL_IPSIZE, illen)) != 0) { 
1997/0327    
		if(ih->iltype < 0 || ih->iltype > Ilclose) 
			st = "?"; 
		else 
			st = iltype[ih->iltype]; 
2000/0706    
		ipriv->stats[CsumErrs]++; 
1998/0313    
		netlog(il->f, Logil, "il: cksum %ux %ux, pkt(%s id %lud ack %lud %I/%d->%d)\n", 
1998/0306    
			csum, st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp); 
1997/0327    
		goto raise; 
	} 
 
1999/0302    
	qlock(il); 
2001/0301    
	s = iphtlook(&ipriv->ht, raddr, dp, laddr, sp); 
	if(s == nil){ 
2001/0302    
		if(ih->iltype == Ilsync) 
			ilreject(il->f, ih);		/* no listener */ 
1999/0302    
		qunlock(il); 
1997/0327    
		goto raise; 
	} 
 
2001/0301    
	ic = (Ilcb*)s->ptcl; 
	if(ic->state == Illistening){ 
		if(ih->iltype != Ilsync){ 
			qunlock(il); 
			if(ih->iltype < 0 || ih->iltype > Ilclose) 
				st = "?"; 
			else 
				st = iltype[ih->iltype]; 
			ilreject(il->f, ih);		/* no channel and not sync */ 
			netlog(il->f, Logil, "il: no channel, pkt(%s id %lud ack %lud %I/%ud->%ud)\n", 
				st, nhgetl(ih->ilid), nhgetl(ih->ilack), raddr, sp, dp);  
			goto raise; 
		} 
1997/0327    
 
2001/0823    
		new = Fsnewcall(s, raddr, dp, laddr, sp); 
		if(new == nil){ 
2001/0301    
			qunlock(il); 
			netlog(il->f, Logil, "il: bad newcall %I/%ud->%ud\n", raddr, sp, dp); 
			ilsendctl(s, ih, Ilclose, 0, nhgetl(ih->ilid), 0); 
			goto raise; 
1997/0327    
		} 
2001/0823    
		s = new; 
 
2001/0301    
		ic = (Ilcb*)s->ptcl; 
	 
		ic->conv = s; 
		ic->state = Ilsyncee; 
		ilcbinit(ic); 
		ic->rstart = nhgetl(ih->ilid); 
		iphtadd(&ipriv->ht, s); 
1997/0327    
	} 
 
2001/0301    
	qlock(s); 
1999/0302    
	qunlock(il); 
	if(waserror()){ 
2001/0301    
		qunlock(s); 
1999/0302    
		nexterror(); 
	} 
2001/0301    
	ilprocess(s, ih, bp); 
	qunlock(s); 
1999/0302    
	poperror(); 
1997/0327    
	return; 
raise: 
	freeblist(bp); 
} 
 
void 
_ilprocess(Conv *s, Ilhdr *h, Block *bp) 
{ 
	Ilcb *ic; 
	ulong id, ack; 
2000/0706    
	Ilpriv *priv; 
1997/0327    
 
	id = nhgetl(h->ilid); 
	ack = nhgetl(h->ilack); 
 
	ic = (Ilcb*)s->ptcl; 
 
1998/0929    
	ic->lastrecv = msec; 
1998/1013    
	ic->querytime = msec + QueryTime; 
2000/0706    
	priv = s->p->priv; 
	priv->stats[InMsgs]++; 
1997/0327    
 
	switch(ic->state) { 
	default: 
1998/0313    
		netlog(s->p->f, Logil, "il: unknown state %d\n", ic->state); 
1997/0327    
	case Ilclosed: 
		freeblist(bp); 
		break; 
	case Ilsyncer: 
		switch(h->iltype) { 
		default: 
			break; 
		case Ilsync: 
			if(ack != ic->start) 
				ilhangup(s, "connection rejected"); 
			else { 
				ic->recvd = id; 
				ic->rstart = id; 
1997/0804    
				ilsendctl(s, nil, Ilack, ic->next, ic->recvd, 0); 
1997/0327    
				ic->state = Ilestablished; 
2001/0302    
				ic->fasttimeout = 0; 
				ic->rexmit = 0; 
1998/0313    
				Fsconnected(s, nil); 
1997/0327    
				ilpullup(s); 
			} 
			break; 
		case Ilclose: 
			if(ack == ic->start) 
1999/0917    
				ilhangup(s, "connection rejected"); 
1997/0327    
			break; 
		} 
		freeblist(bp); 
		break; 
	case Ilsyncee: 
		switch(h->iltype) { 
		default: 
			break; 
		case Ilsync: 
2001/0301    
			if(id != ic->rstart || ack != 0){ 
				illocalclose(s); 
			} else { 
1997/0327    
				ic->recvd = id; 
1997/0804    
				ilsendctl(s, nil, Ilsync, ic->start, ic->recvd, 0); 
1997/0327    
			} 
			break; 
		case Ilack: 
			if(ack == ic->start) { 
				ic->state = Ilestablished; 
2001/0302    
				ic->fasttimeout = 0; 
				ic->rexmit = 0; 
1997/0327    
				ilpullup(s); 
			} 
			break; 
1999/0916    
		case Ildata: 
			if(ack == ic->start) { 
				ic->state = Ilestablished; 
2001/0302    
				ic->fasttimeout = 0; 
				ic->rexmit = 0; 
1999/0916    
				goto established; 
			} 
			break; 
1997/0327    
		case Ilclose: 
			if(ack == ic->start) 
				ilhangup(s, "remote close"); 
			break; 
		} 
		freeblist(bp); 
		break; 
	case Ilestablished: 
1999/0916    
	established: 
1997/0327    
		switch(h->iltype) { 
		case Ilsync: 
			if(id != ic->rstart) 
				ilhangup(s, "remote close"); 
1998/0929    
			else 
1997/0804    
				ilsendctl(s, nil, Ilack, ic->next, ic->rstart, 0); 
1997/0327    
			freeblist(bp);	 
			break; 
		case Ildata: 
1998/0929    
			ilackto(ic, ack, bp); 
1997/0327    
			iloutoforder(s, h, bp); 
			ilpullup(s); 
			break; 
		case Ildataquery: 
1998/0929    
			ilackto(ic, ack, bp); 
1997/0327    
			iloutoforder(s, h, bp); 
			ilpullup(s); 
1997/0804    
			ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec); 
1997/0327    
			break; 
		case Ilack: 
1998/0929    
			ilackto(ic, ack, bp); 
1997/0327    
			freeblist(bp); 
			break; 
1997/0804    
		case Ilquery: 
1998/0929    
			ilackto(ic, ack, bp); 
1997/0804    
			ilsendctl(s, nil, Ilstate, ic->next, ic->recvd, h->ilspec); 
1997/0327    
			freeblist(bp); 
			break; 
		case Ilstate: 
1998/0930    
			if(ack >= ic->rttack) 
				ic->rttack = 0; 
1998/0929    
			ilackto(ic, ack, bp); 
1997/0804    
			if(h->ilspec > Nqt) 
				h->ilspec = 0; 
1998/0929    
			if(ic->qt[h->ilspec] > ack){ 
1997/0804    
				ilrexmit(ic); 
1998/0929    
				ilsettimeout(ic); 
			} 
1997/0327    
			freeblist(bp); 
			break; 
		case Ilclose: 
			freeblist(bp); 
			if(ack < ic->start || ack > ic->next)  
				break; 
1999/0917    
			ic->recvd = id; 
1997/0804    
			ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0); 
1997/0327    
			ic->state = Ilclosing; 
1999/0429    
			ilsettimeout(ic); 
1997/0327    
			ilfreeq(ic); 
			break; 
		} 
		break; 
	case Illistening: 
		freeblist(bp); 
		break; 
	case Ilclosing: 
		switch(h->iltype) { 
		case Ilclose: 
			ic->recvd = id; 
1997/0804    
			ilsendctl(s, nil, Ilclose, ic->next, ic->recvd, 0); 
1997/0327    
			if(ack == ic->next) 
				ilhangup(s, nil); 
			break; 
		default: 
			break; 
		} 
		freeblist(bp); 
		break; 
	} 
} 
 
void 
ilrexmit(Ilcb *ic) 
{ 
	Ilhdr *h; 
	Block *nb; 
1997/0803    
	Conv *c; 
	ulong id; 
1998/0930    
	Ilpriv *priv; 
1997/0327    
 
	nb = nil; 
	qlock(&ic->ackq); 
	if(ic->unacked) 
		nb = copyblock(ic->unacked, blocklen(ic->unacked)); 
	qunlock(&ic->ackq); 
 
1999/0821    
	if(nb == nil) 
1997/0327    
		return; 
 
	h = (Ilhdr*)nb->rp; 
 
	h->iltype = Ildataquery; 
	hnputl(h->ilack, ic->recvd); 
1997/0804    
	h->ilspec = ilnextqt(ic); 
1997/0327    
	h->ilsum[0] = 0; 
	h->ilsum[1] = 0; 
1998/0313    
	hnputs(h->ilsum, ptclcsum(nb, IL_IPSIZE, nhgets(h->illen))); 
1997/0327    
 
1997/0803    
	c = ic->conv; 
	id = nhgetl(h->ilid); 
1998/0929    
	netlog(c->p->f, Logil, "il: rexmit %d %ud: %d %d: %i %d/%d\n", id, ic->recvd, 
		ic->rexmit, ic->timeout, 
1997/0803    
		c->raddr, c->lport, c->rport); 
 
1998/0929    
	ilbackoff(ic); 
 
1999/0817    
	ipoput(c->p->f, nb, 0, ic->conv->ttl, ic->conv->tos); 
1998/0930    
 
	/* statistics */ 
	ic->rxtot++; 
	priv = c->p->priv; 
	priv->rexmit++; 
1997/0327    
} 
 
/* DEBUG */ 
void 
ilprocess(Conv *s, Ilhdr *h, Block *bp) 
{ 
	Ilcb *ic; 
 
	ic = (Ilcb*)s->ptcl; 
 
	USED(ic); 
1998/0313    
	netlog(s->p->f, Logilmsg, "%11s rcv %d/%d snt %d/%d pkt(%s id %d ack %d %d->%d) ", 
1997/0327    
		ilstates[ic->state],  ic->rstart, ic->recvd, ic->start,  
		ic->next, iltype[h->iltype], nhgetl(h->ilid),  
		nhgetl(h->ilack), nhgets(h->ilsrc), nhgets(h->ildst)); 
 
	_ilprocess(s, h, bp); 
 
1998/0313    
	netlog(s->p->f, Logilmsg, "%11s rcv %d snt %d\n", ilstates[ic->state], ic->recvd, ic->next); 
1997/0327    
} 
 
void 
ilhangup(Conv *s, char *msg) 
{ 
	Ilcb *ic; 
	int callout; 
 
1998/0929    
	netlog(s->p->f, Logil, "il: hangup! %I %d/%d: %s\n", s->raddr, 
		s->lport, s->rport, msg?msg:"no reason"); 
1997/0327    
 
	ic = (Ilcb*)s->ptcl; 
	callout = ic->state == Ilsyncer; 
2001/0301    
	illocalclose(s); 
1997/0327    
 
	qhangup(s->rq, msg); 
	qhangup(s->wq, msg); 
 
	if(callout) 
1998/0313    
		Fsconnected(s, msg); 
1997/0327    
} 
 
void 
ilpullup(Conv *s) 
{ 
	Ilcb *ic; 
	Ilhdr *oh; 
	Block *bp; 
	ulong oid, dlen; 
1998/0313    
	Ilpriv *ipriv; 
1997/0327    
 
	ic = (Ilcb*)s->ptcl; 
	if(ic->state != Ilestablished) 
		return; 
 
	qlock(&ic->outo); 
	while(ic->outoforder) { 
		bp = ic->outoforder; 
		oh = (Ilhdr*)bp->rp; 
		oid = nhgetl(oh->ilid); 
		if(oid <= ic->recvd) { 
			ic->outoforder = bp->list; 
			freeblist(bp); 
			continue; 
		} 
1997/0916    
		if(oid != ic->recvd+1){ 
1998/0313    
			ipriv = s->p->priv; 
2000/0706    
			ipriv->stats[OutOfOrder]++; 
1997/0327    
			break; 
1997/0916    
		} 
1997/0327    
 
		ic->recvd = oid; 
		ic->outoforder = bp->list; 
 
		bp->list = nil; 
		dlen = nhgets(oh->illen)-IL_HDRSIZE; 
		bp = trimblock(bp, IL_IPSIZE+IL_HDRSIZE, dlen); 
		/* 
		 * Upper levels don't know about multiple-block 
		 * messages so copy all into one (yick). 
		 */ 
		bp = concatblock(bp); 
		if(bp == 0) 
			panic("ilpullup"); 
1998/0923    
		bp = packblock(bp); 
		if(bp == 0) 
			panic("ilpullup2"); 
		qpassnolim(s->rq, bp); 
1997/0327    
	} 
	qunlock(&ic->outo); 
} 
 
void 
iloutoforder(Conv *s, Ilhdr *h, Block *bp) 
{ 
	Ilcb *ic; 
1998/0306    
	uchar *lid; 
1997/0327    
	Block *f, **l; 
	ulong id, newid; 
1998/0313    
	Ilpriv *ipriv; 
1997/0327    
 
1998/0313    
	ipriv = s->p->priv; 
1997/0327    
	ic = (Ilcb*)s->ptcl; 
	bp->list = nil; 
 
	id = nhgetl(h->ilid); 
	/* Window checks */ 
	if(id <= ic->recvd || id > ic->recvd+ic->window) { 
1998/0313    
		netlog(s->p->f, Logil, "il: message outside window %ud <%ud-%ud>: %i %d/%d\n", 
1997/0327    
			id, ic->recvd, ic->recvd+ic->window, s->raddr, s->lport, s->rport); 
		freeblist(bp); 
		return; 
	} 
 
	/* Packet is acceptable so sort onto receive queue for pullup */ 
	qlock(&ic->outo); 
	if(ic->outoforder == nil) 
		ic->outoforder = bp; 
	else { 
		l = &ic->outoforder; 
		for(f = *l; f; f = f->list) { 
			lid = ((Ilhdr*)(f->rp))->ilid; 
			newid = nhgetl(lid); 
			if(id <= newid) { 
				if(id == newid) { 
2000/0706    
					ipriv->stats[DupMsg]++; 
					ipriv->stats[DupBytes] += blocklen(bp); 
1997/0327    
					qunlock(&ic->outo); 
					freeblist(bp); 
					return; 
				} 
				bp->list = f; 
				*l = bp; 
				qunlock(&ic->outo); 
				return; 
			} 
			l = &f->list; 
		} 
		*l = bp; 
	} 
	qunlock(&ic->outo); 
} 
 
void 
1997/0804    
ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec) 
1997/0327    
{ 
	Ilhdr *ih; 
	Ilcb *ic; 
	Block *bp; 
1999/0817    
	int ttl, tos; 
1997/0327    
 
	bp = allocb(IL_IPSIZE+IL_HDRSIZE); 
	bp->wp += IL_IPSIZE+IL_HDRSIZE; 
 
	ih = (Ilhdr *)(bp->rp); 
 
	/* Ip fields */ 
	ih->proto = IP_ILPROTO; 
	hnputs(ih->illen, IL_HDRSIZE); 
	ih->frag[0] = 0; 
	ih->frag[1] = 0; 
	if(inih) { 
		hnputl(ih->dst, nhgetl(inih->src)); 
		hnputl(ih->src, nhgetl(inih->dst)); 
		hnputs(ih->ilsrc, nhgets(inih->ildst)); 
		hnputs(ih->ildst, nhgets(inih->ilsrc)); 
		hnputl(ih->ilid, nhgetl(inih->ilack)); 
		hnputl(ih->ilack, nhgetl(inih->ilid)); 
		ttl = MAXTTL; 
1999/0817    
		tos = DFLTTOS; 
1997/0327    
	} 
	else { 
1998/0306    
		v6tov4(ih->dst, ipc->raddr); 
		v6tov4(ih->src, ipc->laddr); 
1997/0327    
		hnputs(ih->ilsrc, ipc->lport); 
		hnputs(ih->ildst, ipc->rport); 
		hnputl(ih->ilid, id); 
		hnputl(ih->ilack, ack); 
		ic = (Ilcb*)ipc->ptcl; 
1998/0929    
		ic->acksent = ack; 
		ic->acktime = msec; 
1997/0327    
		ttl = ipc->ttl; 
1999/0817    
		tos = ipc->tos; 
1997/0327    
	} 
	ih->iltype = type; 
1997/0804    
	ih->ilspec = ilspec; 
1997/0327    
	ih->ilsum[0] = 0; 
	ih->ilsum[1] = 0; 
 
	if(ilcksum) 
		hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE)); 
2001/0823    
if(ipc==nil) 
	panic("ipc is nil caller is %.8lux", getcallerpc(&ipc)); 
if(ipc->p==nil) 
	panic("ipc->p is nil"); 
1997/0327    
 
1999/0630    
	netlog(ipc->p->f, Logilmsg, "ctl(%s id %d ack %d %d->%d)\n", 
1997/0327    
		iltype[ih->iltype], nhgetl(ih->ilid), nhgetl(ih->ilack),  
		nhgets(ih->ilsrc), nhgets(ih->ildst)); 
 
1999/0817    
	ipoput(ipc->p->f, bp, 0, ttl, tos); 
1999/0917    
} 
 
void 
ilreject(Fs *f, Ilhdr *inih) 
{ 
	Ilhdr *ih; 
	Block *bp; 
 
	bp = allocb(IL_IPSIZE+IL_HDRSIZE); 
	bp->wp += IL_IPSIZE+IL_HDRSIZE; 
 
	ih = (Ilhdr *)(bp->rp); 
 
	/* Ip fields */ 
	ih->proto = IP_ILPROTO; 
	hnputs(ih->illen, IL_HDRSIZE); 
	ih->frag[0] = 0; 
	ih->frag[1] = 0; 
	hnputl(ih->dst, nhgetl(inih->src)); 
	hnputl(ih->src, nhgetl(inih->dst)); 
	hnputs(ih->ilsrc, nhgets(inih->ildst)); 
	hnputs(ih->ildst, nhgets(inih->ilsrc)); 
	hnputl(ih->ilid, nhgetl(inih->ilack)); 
	hnputl(ih->ilack, nhgetl(inih->ilid)); 
	ih->iltype = Ilclose; 
	ih->ilspec = 0; 
	ih->ilsum[0] = 0; 
	ih->ilsum[1] = 0; 
 
	if(ilcksum) 
		hnputs(ih->ilsum, ptclcsum(bp, IL_IPSIZE, IL_HDRSIZE)); 
 
	ipoput(f, bp, 0, MAXTTL, DFLTTOS); 
1997/0327    
} 
 
void 
1998/0929    
ilsettimeout(Ilcb *ic) 
{ 
	ulong pt; 
 
1998/0930    
	pt = (ic->delay>>LogAGain) 
		+ ic->unackedbytes/(ic->rate>>LogAGain) 
1999/0703    
		+ (ic->mdev>>(LogDGain-1)) 
1998/0930    
		+ AckDelay; 
1998/0929    
	if(pt > MaxTimeout) 
		pt = MaxTimeout; 
	ic->timeout = msec + pt; 
} 
 
void 
ilbackoff(Ilcb *ic) 
{ 
	ulong pt; 
	int i; 
 
1998/0930    
	pt = (ic->delay>>LogAGain) 
		+ ic->unackedbytes/(ic->rate>>LogAGain) 
1999/0703    
		+ (ic->mdev>>(LogDGain-1)) 
1998/0930    
		+ AckDelay; 
1998/0929    
	for(i = 0; i < ic->rexmit; i++) 
		pt = pt + (pt>>1); 
	if(pt > MaxTimeout) 
		pt = MaxTimeout; 
	ic->timeout = msec + pt; 
 
2001/0227    
	if(ic->fasttimeout) 
		ic->timeout = msec+Iltickms; 
 
1998/0929    
	ic->rexmit++; 
} 
 
1999/0424    
// complain if two numbers not within an hour of each other 
#define Tfuture (1000*60*60) 
int 
later(ulong t1, ulong t2, char *x) 
{ 
	int dt; 
 
	dt = t1 - t2; 
	if(dt > 0) { 
1999/0430    
		if(x != nil && dt > Tfuture) 
1999/0424    
			print("%s: way future %d\n", x, dt); 
		return 1; 
	} 
	if(dt < -Tfuture) { 
1999/0430    
		if(x != nil) 
			print("%s: way past %d\n", x, -dt); 
1999/0424    
		return 1; 
	} 
	return 0; 
} 
 
1998/0929    
void 
1998/0313    
ilackproc(void *x) 
1997/0327    
{ 
	Ilcb *ic; 
	Conv **s, *p; 
1998/0313    
	Proto *il; 
	Ilpriv *ipriv; 
1997/0327    
 
1998/0313    
	il = x; 
	ipriv = il->priv; 
 
1997/0327    
loop: 
1998/0313    
	tsleep(&ipriv->ilr, return0, 0, Iltickms); 
	for(s = il->conv; s && *s; s++) { 
1997/0327    
		p = *s; 
		ic = (Ilcb*)p->ptcl; 
 
		switch(ic->state) { 
		case Ilclosed: 
		case Illistening: 
			break; 
		case Ilclosing: 
1999/0429    
			if(later(msec, ic->timeout, "timeout0")) { 
1998/0929    
				if(ic->rexmit > MaxRexmit){ 
					ilhangup(p, nil); 
					break; 
				} 
1997/0804    
				ilsendctl(p, nil, Ilclose, ic->next, ic->recvd, 0); 
1997/0327    
				ilbackoff(ic); 
			} 
			break; 
1999/0331    
 
1997/0327    
		case Ilsyncee: 
		case Ilsyncer: 
1999/0429    
			if(later(msec, ic->timeout, "timeout1")) { 
1998/0929    
				if(ic->rexmit > MaxRexmit){ 
					ilhangup(p, etime); 
					break; 
				} 
1997/0804    
				ilsendctl(p, nil, Ilsync, ic->start, ic->recvd, 0); 
1997/0327    
				ilbackoff(ic); 
			} 
			break; 
1999/0331    
 
1997/0327    
		case Ilestablished: 
1999/0424    
			if(ic->recvd != ic->acksent) 
			if(later(msec, ic->acktime, "acktime")) 
1997/0804    
				ilsendctl(p, nil, Ilack, ic->next, ic->recvd, 0); 
1997/0327    
 
1999/0424    
			if(later(msec, ic->querytime, "querytime")){ 
				if(later(msec, ic->lastrecv+DeathTime, "deathtime")){ 
1998/0929    
					netlog(il->f, Logil, "il: hangup: deathtime\n"); 
1997/0327    
					ilhangup(p, etime); 
					break; 
				} 
1997/0804    
				ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic)); 
1998/0929    
				ic->querytime = msec + QueryTime; 
1997/0327    
			} 
1998/0929    
 
1999/0424    
			if(ic->unacked != nil) 
1999/0429    
			if(later(msec, ic->timeout, "timeout2")) { 
1998/0929    
				if(ic->rexmit > MaxRexmit){ 
					netlog(il->f, Logil, "il: hangup: too many rexmits\n"); 
					ilhangup(p, etime); 
					break; 
				} 
1998/0930    
				ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic)); 
				ic->rxquery++; 
				ilbackoff(ic); 
1997/0327    
			} 
			break; 
		} 
	} 
	goto loop; 
} 
 
void 
1998/0929    
ilcbinit(Ilcb *ic) 
1997/0327    
{ 
1998/0929    
	ic->start = nrand(0x1000000); 
	ic->next = ic->start+1; 
	ic->recvd = 0; 
	ic->window = Defaultwin; 
1998/0930    
	ic->unackedbytes = 0; 
1998/0929    
	ic->unacked = nil; 
	ic->outoforder = nil; 
	ic->rexmit = 0; 
	ic->rxtot = 0; 
1998/1001    
	ic->rxquery = 0; 
1998/0929    
	ic->qtx = 1; 
2001/0227    
	ic->fasttimeout = 0; 
1998/0929    
 
	/* timers */ 
	ic->delay = DefRtt<<LogAGain; 
	ic->mdev = DefRtt<<LogDGain; 
	ic->rate = DefByteRate<<LogAGain; 
	ic->querytime = msec + QueryTime; 
	ic->lastrecv = msec;	/* or we'll timeout right away */ 
	ilsettimeout(ic); 
1997/0327    
} 
 
char* 
2001/0227    
ilstart(Conv *c, int type, int fasttimeout) 
1997/0327    
{ 
	Ilcb *ic; 
1998/0924    
	Ilpriv *ipriv; 
2001/0527    
	char kpname[KNAMELEN]; 
1998/0924    
 
	ipriv = c->p->priv; 
 
	if(ipriv->ackprocstarted == 0){ 
		qlock(&ipriv->apl); 
		if(ipriv->ackprocstarted == 0){ 
			sprint(kpname, "#I%dilack", c->p->f->dev); 
			kproc(kpname, ilackproc, c->p); 
			ipriv->ackprocstarted = 1; 
		} 
		qunlock(&ipriv->apl); 
	} 
1997/0327    
 
	ic = (Ilcb*)c->ptcl; 
	ic->conv = c; 
 
	if(ic->state != Ilclosed) 
1998/0929    
		return nil; 
1997/0327    
 
1998/0929    
	ilcbinit(ic); 
2001/0227    
 
	if(fasttimeout){ 
		/* timeout if we can't connect quickly */ 
		ic->fasttimeout = 1; 
		ic->timeout = msec+Iltickms; 
		ic->rexmit = MaxRexmit - 4; 
	}; 
1997/0327    
 
	switch(type) { 
	default: 
1998/0313    
		netlog(c->p->f, Logil, "il: start: type %d\n", type); 
1997/0327    
		break; 
	case IL_LISTEN: 
		ic->state = Illistening; 
2001/0301    
		iphtadd(&ipriv->ht, c); 
1997/0327    
		break; 
	case IL_CONNECT: 
		ic->state = Ilsyncer; 
2001/0301    
		iphtadd(&ipriv->ht, c); 
1997/0804    
		ilsendctl(c, nil, Ilsync, ic->start, ic->recvd, 0); 
1997/0327    
		break; 
	} 
 
1998/0929    
	return nil; 
1997/0327    
} 
 
void 
ilfreeq(Ilcb *ic) 
{ 
	Block *bp, *next; 
 
	qlock(&ic->ackq); 
	for(bp = ic->unacked; bp; bp = next) { 
		next = bp->list; 
		freeblist(bp); 
	} 
	ic->unacked = nil; 
	qunlock(&ic->ackq); 
 
	qlock(&ic->outo); 
	for(bp = ic->outoforder; bp; bp = next) { 
		next = bp->list; 
		freeblist(bp); 
	} 
	ic->outoforder = nil; 
	qunlock(&ic->outo); 
} 
 
void 
1998/0313    
iladvise(Proto *il, Block *bp, char *msg) 
1997/0327    
{ 
	Ilhdr *h; 
	Ilcb *ic;		 
1998/0306    
	uchar source[IPaddrlen], dest[IPaddrlen]; 
1997/0327    
	ushort psource; 
	Conv *s, **p; 
 
	h = (Ilhdr*)(bp->rp); 
 
1998/0306    
	v4tov6(dest, h->dst); 
	v4tov6(source, h->src); 
1997/0327    
	psource = nhgets(h->ilsrc); 
 
 
	/* Look for a connection, unfortunately the destination port is missing */ 
1999/0302    
	qlock(il); 
1998/0313    
	for(p = il->conv; *p; p++) { 
1997/0327    
		s = *p; 
1998/0306    
		if(s->lport == psource) 
		if(ipcmp(s->laddr, source) == 0) 
		if(ipcmp(s->raddr, dest) == 0){ 
1999/0302    
			qunlock(il); 
1997/0327    
			ic = (Ilcb*)s->ptcl; 
			switch(ic->state){ 
			case Ilsyncer: 
				ilhangup(s, msg); 
				break; 
			} 
1999/0302    
			freeblist(bp); 
			return; 
1997/0327    
		} 
	} 
1999/0302    
	qunlock(il); 
1997/0327    
	freeblist(bp); 
1997/0804    
} 
 
int 
ilnextqt(Ilcb *ic) 
{ 
	int x; 
 
	qlock(&ic->ackq); 
	x = ic->qtx; 
	if(++x > Nqt) 
		x = 1; 
	ic->qtx = x; 
1998/1013    
	ic->qt[x] = ic->next-1;	/* highest xmitted packet */ 
	ic->qt[0] = ic->qt[x];	/* compatibility with old implementations */ 
1997/0804    
	qunlock(&ic->ackq); 
 
	return x; 
1998/0929    
} 
 
1999/0703    
/* calculate scale constants that converts fast ticks to ms (more or less) */ 
1998/0929    
static void 
1999/0703    
inittimescale(void) 
1998/0929    
{ 
1999/0703    
	uvlong hz; 
1998/0929    
 
	fastticks(&hz); 
1999/0703    
	if(hz > 1000){ 
		scalediv = hz/1000; 
		scalemul = 1; 
	} else { 
		scalediv = 1; 
		scalemul = 1000/hz; 
1998/0929    
	} 
} 
 
void 
ilinit(Fs *f) 
{ 
	Proto *il; 
 
1999/0703    
	inittimescale(); 
1998/0929    
 
	il = smalloc(sizeof(Proto)); 
	il->priv = smalloc(sizeof(Ilpriv)); 
	il->name = "il"; 
	il->kick = ilkick; 
	il->connect = ilconnect; 
	il->announce = ilannounce; 
	il->state = ilstate; 
	il->create = ilcreate; 
	il->close = ilclose; 
	il->rcv = iliput; 
	il->ctl = nil; 
	il->advise = iladvise; 
	il->stats = ilxstats; 
	il->inuse = ilinuse; 
2000/0424    
	il->gc = nil; 
1998/0929    
	il->ipproto = IP_ILPROTO; 
2001/0922    
	il->nc = scalednconv(); 
1998/0929    
	il->ptclsize = sizeof(Ilcb); 
	Fsproto(f, il); 
1997/0327    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)