~kris/9p

9hist

5266fe7f71e1b08924e2e907a08e439e54c8e90a — David du Colombier 24 years ago dd3a2e5
Plan 9 from Bell Labs 2002-07-10
M alphapc/clock.c => alphapc/clock.c +0 -13
@@ 94,16 94,3 @@ clock(Ureg *ureg)

	timerintr(ureg, 0);
}

ulong
TK2MS(ulong ticks)
{
	uvlong t, hz;

	t = ticks;
	hz = HZ;
	t *= 1000L;
	t = t/hz;
	ticks = t;
	return ticks;
}

M alphapc/fns.h => alphapc/fns.h +0 -1
@@ 110,7 110,6 @@ void	upafree(ulong, int);
#define		userureg(ur) ((ur)->status & UMODE)
void		wrent(int, void*);
void		wrvptptr(uvlong);
ulong	TK2MS(ulong);				/* ticks to milliseconds */

#define	waserror()	(up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
#define	kmapperm(x)	kmap(x)

M bitsy/clock.c => bitsy/clock.c +0 -13
@@ 162,16 162,3 @@ microdelay(int µs)
		}
	}
}

ulong
TK2MS(ulong ticks)
{
	uvlong t, hz;

	t = ticks;
	hz = HZ;
	t *= 1000L;
	t = t/hz;
	ticks = t;
	return ticks;
}

M bitsy/fns.h => bitsy/fns.h +0 -1
@@ 121,7 121,6 @@ int	unsac(uchar*, uchar*, int, int);
void	vectors(void);
void	vtable(void);
void	wbflush(void);
ulong	TK2MS(ulong);				/* ticks to milliseconds */
#define KADDR(a) (void*)mmu_kaddr((ulong)(a))
#define PADDR(a) mmu_paddr((ulong)(a))


M ip/arp.c => ip/arp.c +9 -9
@@ 124,11 124,11 @@ newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
	*l = a;

	memmove(a->ip, ip, sizeof(a->ip));
	a->used = msec;
	a->used = NOW;
	a->time = 0;
	a->type = m;

	a->rxtat = msec + ReTransTimer;
	a->rxtat = NOW + ReTransTimer;
	a->rxtsrem = MAX_MULTICAST_SOLICIT;
	a->ifc = ifc;
	a->ifcid = ifc->ifcid;


@@ 227,7 227,7 @@ arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
		a = newarp6(arp, ip, ifc, (version != V4));
		a->state = AWAIT;
	}
	a->used = msec;
	a->used = NOW;
	if(a->state == AWAIT){
		if(bp != nil){
			if(a->hold)


@@ 280,7 280,7 @@ arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
	memmove(a->mac, mac, type->maclen);
	a->type = type;
	a->state = AOK;
	a->used = msec;
	a->used = NOW;
	bp = a->hold;
	a->hold = nil;
	qunlock(arp);


@@ 375,7 375,7 @@ arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
					freeb(bp);
				bp = next;
			}
			a->used = msec;
			a->used = NOW;
			return;
		}
	}


@@ 532,7 532,7 @@ rxmitsols(Arp *arp)
		nrxt = 0;
		goto dodrops; 		//return nrxt;
	}
	nrxt = a->rxtat - msec;
	nrxt = a->rxtat - NOW;
	if(nrxt > 3*ReTransTimer/4) 
		goto dodrops; 		//return nrxt;



@@ 589,14 589,14 @@ rxmitsols(Arp *arp)
	*l = a;
	a->rxtsrem--;
	a->nextrxt = nil;
	a->time = msec;
	a->rxtat = msec + ReTransTimer;
	a->time = NOW;
	a->rxtat = NOW + ReTransTimer;

	a = arp->rxmt;
	if(a==nil)
		nrxt = 0;
	else 
		nrxt = a->rxtat - msec;
		nrxt = a->rxtat - NOW;

dodrops:
	xp = arp->dropf;

M ip/ethermedium.c => ip/ethermedium.c +5 -5
@@ 435,7 435,7 @@ sendarp(Ipifc *ifc, Arpent *a)
	Etherrock *er = ifc->arg;

	/* don't do anything if it's been less than a second since the last */
	if(msec - a->time < 1000){
	if(NOW - a->time < 1000){
		arprelease(er->f->arp, a);
		return;
	}


@@ 449,7 449,7 @@ sendarp(Ipifc *ifc, Arpent *a)
	}

	/* try to keep it around for a second more */
	a->time = msec;
	a->time = NOW;
	arprelease(er->f->arp, a);

	n = sizeof(Etherarp);


@@ 486,7 486,7 @@ resolveaddr6(Ipifc *ifc, Arpent *a)
	uchar ipsrc[IPaddrlen];

	/* don't do anything if it's been less than a second since the last */
	if(msec - a->time < ReTransTimer){
	if(NOW - a->time < ReTransTimer){
		arprelease(er->f->arp, a);
		return;
	}


@@ 500,8 500,8 @@ resolveaddr6(Ipifc *ifc, Arpent *a)
	}

	/* try to keep it around for a second more */
	a->time = msec;
	a->rxtat = msec + ReTransTimer;
	a->time = NOW;
	a->rxtat = NOW + ReTransTimer;
	if(a->rxtsrem <= 0) {
		arprelease(er->f->arp, a);
		return;

M ip/il.c => ip/il.c +18 -18
@@ 387,7 387,7 @@ ilkick(Conv *c)
	ack = ic->recvd;
	hnputl(ih->ilack, ack);
	ic->acksent = ack;
	ic->acktime = msec + AckDelay;
	ic->acktime = NOW + AckDelay;
	ih->iltype = Ildata;
	ih->ilspec = 0;
	ih->ilsum[0] = 0;


@@ 407,7 407,7 @@ ilkick(Conv *c)
		ic->rttlen = dlen + IL_IPSIZE + IL_HDRSIZE;
	}

	if(later(msec, ic->timeout, nil))
	if(later(NOW, ic->timeout, nil))
		ilsettimeout(ic);
	ipoput4(f, bp, 0, c->ttl, c->tos);
	priv->stats[OutMsgs]++;


@@ 641,8 641,8 @@ _ilprocess(Conv *s, Ilhdr *h, Block *bp)

	ic = (Ilcb*)s->ptcl;

	ic->lastrecv = msec;
	ic->querytime = msec + QueryTime;
	ic->lastrecv = NOW;
	ic->querytime = NOW + QueryTime;
	priv = s->p->priv;
	priv->stats[InMsgs]++;



@@ 1007,7 1007,7 @@ ilsendctl(Conv *ipc, Ilhdr *inih, int type, ulong id, ulong ack, int ilspec)
		hnputl(ih->ilack, ack);
		ic = (Ilcb*)ipc->ptcl;
		ic->acksent = ack;
		ic->acktime = msec;
		ic->acktime = NOW;
		ttl = ipc->ttl;
		tos = ipc->tos;
	}


@@ 1076,7 1076,7 @@ ilsettimeout(Ilcb *ic)
		+ AckDelay;
	if(pt > MaxTimeout)
		pt = MaxTimeout;
	ic->timeout = msec + pt;
	ic->timeout = NOW + pt;
}

void


@@ 1093,10 1093,10 @@ ilbackoff(Ilcb *ic)
		pt = pt + (pt>>1);
	if(pt > MaxTimeout)
		pt = MaxTimeout;
	ic->timeout = msec + pt;
	ic->timeout = NOW + pt;

	if(ic->fasttimeout)
		ic->timeout = msec+Iltickms;
		ic->timeout = NOW+Iltickms;

	ic->rexmit++;
}


@@ 1144,7 1144,7 @@ loop:
		case Illistening:
			break;
		case Ilclosing:
			if(later(msec, ic->timeout, "timeout0")) {
			if(later(NOW, ic->timeout, "timeout0")) {
				if(ic->rexmit > MaxRexmit){
					ilhangup(p, nil);
					break;


@@ 1156,7 1156,7 @@ loop:

		case Ilsyncee:
		case Ilsyncer:
			if(later(msec, ic->timeout, "timeout1")) {
			if(later(NOW, ic->timeout, "timeout1")) {
				if(ic->rexmit > MaxRexmit){
					ilhangup(p, etime);
					break;


@@ 1168,21 1168,21 @@ loop:

		case Ilestablished:
			if(ic->recvd != ic->acksent)
			if(later(msec, ic->acktime, "acktime"))
			if(later(NOW, ic->acktime, "acktime"))
				ilsendctl(p, nil, Ilack, ic->next, ic->recvd, 0);

			if(later(msec, ic->querytime, "querytime")){
				if(later(msec, ic->lastrecv+DeathTime, "deathtime")){
			if(later(NOW, ic->querytime, "querytime")){
				if(later(NOW, ic->lastrecv+DeathTime, "deathtime")){
					netlog(il->f, Logil, "il: hangup: deathtime\n");
					ilhangup(p, etime);
					break;
				}
				ilsendctl(p, nil, Ilquery, ic->next, ic->recvd, ilnextqt(ic));
				ic->querytime = msec + QueryTime;
				ic->querytime = NOW + QueryTime;
			}

			if(ic->unacked != nil)
			if(later(msec, ic->timeout, "timeout2")) {
			if(later(NOW, ic->timeout, "timeout2")) {
				if(ic->rexmit > MaxRexmit){
					netlog(il->f, Logil, "il: hangup: too many rexmits\n");
					ilhangup(p, etime);


@@ 1218,8 1218,8 @@ ilcbinit(Ilcb *ic)
	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 */
	ic->querytime = NOW + QueryTime;
	ic->lastrecv = NOW;	/* or we'll timeout right away */
	ilsettimeout(ic);
}



@@ 1253,7 1253,7 @@ ilstart(Conv *c, int type, int fasttimeout)
	if(fasttimeout){
		/* timeout if we can't connect quickly */
		ic->fasttimeout = 1;
		ic->timeout = msec+Iltickms;
		ic->timeout = NOW+Iltickms;
		ic->rexmit = MaxRexmit - 4;
	};


M ip/ip.c => ip/ip.c +2 -2
@@ 585,7 585,7 @@ ip4reassemble(IP *ip, int offset, Block *bp, Ip4hdr *ih)
		fnext = f->next;	/* because ipfragfree4 changes the list */
		if(f->src == src && f->dst == dst && f->id == id)
			break;
		if(f->age < msec){
		if(f->age < NOW){
			ip->stats[ReasmTimeout]++;
			ipfragfree4(ip, f);
		}


@@ 765,7 765,7 @@ ipfragallo4(IP *ip)
	ip->fragfree4 = f->next;
	f->next = ip->flisthead4;
	ip->flisthead4 = f;
	f->age = msec + 30000;
	f->age = NOW + 30000;

	return f;
}

M ip/ip.h => ip/ip.h +10 -8
@@ 68,7 68,7 @@ enum
};

/*
 *  contained in each conversation
 *  one per conversation directory
 */
struct Conv
{


@@ 77,16 77,18 @@ struct Conv
	int	x;			/* conversation index */
	Proto*	p;

	uchar	laddr[IPaddrlen];	/* local IP address */
	uchar	raddr[IPaddrlen];	/* remote IP address */
	int	restricted;		/* remote port is restricted */
	ushort	lport;			/* local port number */
	ushort	rport;			/* remote port number */
	uint	ttl;			/* max time to live */
	uint	tos;			/* type of service */
	uchar	ipversion;		/* IPv4 or IPv6 */
	int	ignoreadvice;		/* don't terminate connection on icmp errors */

	uchar	ipversion;
	uchar	laddr[IPaddrlen];	/* local IP address */
	uchar	raddr[IPaddrlen];	/* remote IP address */
	ushort	lport;			/* local port number */
	ushort	rport;			/* remote port number */


	char	*owner;			/* protections */
	int	perm;
	int	inuse;			/* opens of listen/data/ctl */


@@ 550,8 552,8 @@ extern void	v4tov6(uchar *v6, uchar *v4);
extern int	v6tov4(uchar *v4, uchar *v6);
extern int	eipfmt(Fmt*);

#define	ipcmp(x, y) memcmp(x, y, IPaddrlen)
#define	ipmove(x, y) memmove(x, y, IPaddrlen)
#define	ipcmp(x, y) ( (x)[IPaddrlen-1] != (y)[IPaddrlen-1] || memcmp(x, y, IPaddrlen) )

extern uchar IPv4bcast[IPaddrlen];
extern uchar IPv4bcastobs[IPaddrlen];


@@ 561,7 563,7 @@ extern uchar IPnoaddr[IPaddrlen];
extern uchar v4prefix[IPaddrlen];
extern uchar IPallbits[IPaddrlen];

#define	msec	TK2MS(MACHP(0)->ticks)
#define	NOW	TK2MS(MACHP(0)->ticks)

/*
 *  media

M ip/ipifc.c => ip/ipifc.c +6 -6
@@ 445,7 445,7 @@ ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp)
		lifc->autoflag = 1;
		lifc->validlt = 0xffffffff;
		lifc->preflt = 0xffffffff;
		lifc->origint = msec / 10^3;
		lifc->origint = NOW / 10^3;
	}
	lifc->next = nil;



@@ 940,7 940,7 @@ static void
iplinkfree(Iplink *p)
{
	Iplink **l, *np;
	ulong now = msec;
	ulong now = NOW;

	l = &freeiplink;
	for(np = *l; np; np = *l){


@@ 959,7 959,7 @@ static void
ipselffree(Ipself *p)
{
	Ipself **l, *np;
	ulong now = msec;
	ulong now = NOW;

	l = &freeipself;
	for(np = *l; np; np = *l){


@@ 1205,7 1205,7 @@ v6addrtype(uchar *addr)
	return unknownv6;
}

#define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (msec/10^3) ) || ( (lifc)->preflt == 0xffffffff ))
#define v6addrcurr(lifc) (( (lifc)->origint + (lifc)->preflt >= (NOW/10^3) ) || ( (lifc)->preflt == 0xffffffff ))

void
findprimaryip6(Fs *f, uchar *local)


@@ 1732,7 1732,7 @@ ipifcaddgate6(Fs *f, Ipifc *ifc, char**argv, int argc)
		r[j].ifc = ifc;
		r[j].ifcid = ifc->ifcid;
		ipmove(r[j].routeraddr, routeraddr);
		r[j].ltorigin = msec / 10^3;
		r[j].ltorigin = NOW / 10^3;
		r[j].rp.mflag = (mflag!=0);
		r[j].rp.oflag = (oflag!=0);
		r[j].rp.rxmitra = rxmitra;


@@ 1769,7 1769,7 @@ ipifcaddpref6(Ipifc *ifc, char**argv, int argc)
	uchar	autoflag = 1;
	long 	validlt = 0xffffffff;
	long 	preflt = 0xffffffff;
	long	origint = msec / 10^3;
	long	origint = NOW / 10^3;
	uchar	prefix[IPaddrlen];
	int	plen = 64;
	Iplifc	*lifc;

M ip/ipv6.c => ip/ipv6.c +2 -2
@@ 490,7 490,7 @@ ipfragallo6(IP *ip)
	ip->fragfree6 = f->next;
	f->next = ip->flisthead6;
	ip->flisthead6 = f;
	f->age = msec + 30000;
	f->age = NOW + 30000;

	return f;
}


@@ 599,7 599,7 @@ ip6reassemble(IP* ip, int uflen, Block* bp, Ip6hdr* ih)
		fnext = f->next;
		if(ipcmp(f->src, src)==0 && ipcmp(f->dst, dst)==0 && f->id == id)
			break;
		if(f->age < msec){
		if(f->age < NOW){
			ip->stats[ReasmTimeout]++;
			ipfragfree6(ip, f);
		}

M ip/tcp.c => ip/tcp.c +366 -50
@@ 61,6 61,7 @@ enum

	LOGAGAIN	= 3,
	LOGDGAIN	= 2,

	Closed		= 0,		/* Connection states */
	Listen,
	Syn_sent,


@@ 71,7 72,11 @@ enum
	Close_wait,
	Closing,
	Last_ack,
	Time_wait
	Time_wait,

	Maxlimbo	= 1000,		/* maximum procs waiting for response to SYN ACK */
	NLHT		= 256,		/* hash table size, must be a power of 2 */
	LHTMASK		= NLHT-1
};

/* Must correspond to the enumeration above */


@@ 95,6 100,10 @@ struct Tcptimer
	void	*arg;
};

/*
 *  v4 and v6 pseudo headers used for
 *  checksuming tcp
 */
typedef struct Tcp4hdr Tcp4hdr;
struct Tcp4hdr
{


@@ 143,7 152,12 @@ struct Tcp6hdr
	uchar	tcpmss[2];
};


/*
 *  this represents the control info
 *  for a single packet.  It is derived from
 *  a packet in ntohtcp{4,6}() and stuck into
 *  a packet in htontcp{4,6}().
 */
typedef struct Tcp Tcp;
struct	Tcp
{


@@ 158,6 172,10 @@ struct	Tcp
	ushort	len;	/* size of data */
};

/*
 *  this header is malloc'd to thread together fragments
 *  waiting to be coalesced
 */
typedef struct Reseq Reseq;
struct Reseq
{


@@ 202,7 220,6 @@ struct Tcpctl
	ushort	mss;			/* Mean segment size */
	int	rerecv;			/* Overlap of data rerecevived */
	ushort	window;			/* Recevive window */
	int	max_snd;		/* Max send */
	ulong	last_ack;		/* Last acknowledege received */
	uchar	backoff;		/* Exponential backoff counter */
	int	backedoff;		/* ms we've backed off for rexmits */


@@ 219,7 236,7 @@ struct Tcpctl
	uint	sndsyntime;		/* time syn sent */
	ulong	time;			/* time Finwait2 or Syn_received was sent */
	int	nochecksum;		/* non-zero means don't send checksums */
	int	flgcnt;			/* 1 when we're waiting for a SYN/FIN ACK */
	int	flgcnt;			/* number of flags in the sequence (FIN,SEQ) */

	union {
		Tcp4hdr	tcp4hdr;


@@ 227,6 244,36 @@ struct Tcpctl
	} protohdr;		/* prototype header */
};

/*
 *  New calls are put in limbo rather than having a conversation structure
 *  allocated.  Thus, a SYN attack results in lots of limbo'd calls but not
 *  any real Conv structures mucking things up.  Calls in limbo rexmit their
 *  SYN ACK every 250 ms up to 4 times, i.e., they disappear after 1 second.
 *
 *  In particular they aren't on a listener's queue so that they don't figure
 *  in the input queue limit.
 *
 *  If 1/2 of a T3 was attacking SYN packets, we'ld have a permanent queue
 *  of 70000 limbo'd calls.  Not great for a linear list but doable.  Therefore
 *  there is no hashing of this list.
 */
typedef struct Limbo Limbo;
struct Limbo
{
	Limbo	*next;

	uchar	laddr[IPaddrlen];
	uchar	raddr[IPaddrlen];
	ushort	lport;
	ushort	rport;
	ulong	irs;		/* initial received sequence */
	ulong	iss;		/* initial sent sequence */
	ushort	mss;		/* mss from the other end */
	ulong	lastsend;	/* last time we sent a synack */
	uchar	version;	/* v4 or v6 */
	uchar	rexmits;	/* number of retransmissions */
};

int	tcp_irtt = DEF_RTT;	/* Initial guess at round trip time */
ushort	tcp_mss  = DEF_MSS;	/* Maximum segment size to be sent */



@@ 275,18 322,24 @@ static char *statnames[] =
typedef struct Tcppriv Tcppriv;
struct Tcppriv
{
	Tcptimer 	*timers;	/* List of active timers */
	QLock 	tl;			/* Protect timer list */
	/* List of active timers */
	QLock 	tl;
	Tcptimer *timers;

	Rendez	tcpr;			/* used by tcpackproc */

	/* hash table for matching conversations */
	Ipht	ht;

	ulong	stats[Nstats];
	/* calls in limbo waiting for an ACK to our SYN ACK */
	int	nlimbo;
	Limbo	*lht[NLHT];

	/* for keeping track of tcpackproc */
	int	ackprocstarted;
	QLock	apl;
	int	ackprocstarted;

	ulong	stats[Nstats];
};

int	addreseq(Tcpctl*, Tcp*, Block*, ushort);


@@ 305,6 358,10 @@ void	tcpkeepalive(void*);
void	tcpsetkacounter(Tcpctl*);
void    tcprxmit(Conv*);
void	tcpsettimer(Tcpctl*);
void	tcpsynackrtt(Conv*);

static void limborexmit(Proto*);
static void limbo(Conv*, uchar*, uchar*, Tcp*, int);

void
tcpsetstate(Conv *s, uchar newstate)


@@ 457,11 514,6 @@ tcpkick(Conv *s)
	qlock(s);

	switch(tcb->state) {
	case Listen:
		tcb->flags |= ACTIVE;
		tcpsndsyn(tcb);
		tcpsetstate(s, Syn_sent);
		/* No break */
	case Syn_sent:
	case Syn_received:
	case Established:


@@ 599,6 651,8 @@ tcpackproc(void *a)
				poperror();
			}
		}

		limborexmit(tcp);
	}
}



@@ 672,14 726,12 @@ localclose(Conv *s, char *reason)	 /*  called with tcb locked */

/* mtu (- TCP + IP hdr len) of 1st hop */
int
tcpmtu(Conv *s)
tcpmtu(Proto *tcp, uchar *addr, int version)
{
	Ipifc *ifc;
	int mtu;
	uchar version;

	version = s->ipversion;
	ifc = findipifc(s->p->f, s->raddr, 0);
	ifc = findipifc(tcp->f, addr, 0);
	switch(version){
	default:
	case V4:


@@ 753,7 805,7 @@ inittcpctl(Conv *s, int mode)
		}
	}

	tcb->mss = tcb->cwind = tcpmtu(s);
	tcb->mss = tcb->cwind = tcpmtu(s->p, s->laddr, s->ipversion);
}

/*


@@ 1056,7 1108,10 @@ ntohtcp4(Tcp *tcph, Block **bpp)
	return hdrlen;
}

/* Generate an initial sequence number and put a SYN on the send queue */
/*
 *  For outgiing calls, generate an initial sequence
 *  number and put a SYN on the send queue
 */
void
tcpsndsyn(Tcpctl *tcb)
{


@@ 1068,7 1123,7 @@ tcpsndsyn(Tcpctl *tcb)
	tcb->snd.nxt = tcb->rttseq;
	tcb->flgcnt++;
	tcb->flags |= FORCE;
	tcb->sndsyntime = msec;
	tcb->sndsyntime = NOW;
}

void


@@ 1193,6 1248,200 @@ tcphangup(Conv *s)
	return nil;
}

/*
 *  (re)send a SYN ACK
 */
int
sndsynack(Proto *tcp, Limbo *lp)
{
	Block *hbp;
	Tcp4hdr ph4;
	Tcp6hdr ph6;
	Tcp seg;

	/* make pseudo header */
	switch(lp->version) {
	case V4:
		memset(&ph4, 0, sizeof(ph4));
		ph4.vihl = IP_VER4;
		v6tov4(ph4.tcpsrc, lp->laddr);
		v6tov4(ph4.tcpdst, lp->raddr);
		ph4.proto = IP_TCPPROTO;
		hnputs(ph4.tcplen, TCP4_HDRSIZE);
		hnputs(ph4.tcpsport, lp->lport);
		hnputs(ph4.tcpdport, lp->rport);
		break;
	case V6:
		memset(&ph6, 0, sizeof(ph6));
		ph6.vcf[0] = IP_VER6;
		ipmove(ph6.tcpsrc, lp->laddr);
		ipmove(ph6.tcpdst, lp->raddr);
		ph6.proto = IP_TCPPROTO;
		hnputs(ph6.ploadlen, TCP6_HDRSIZE);
		hnputs(ph6.tcpsport, lp->lport);
		hnputs(ph6.tcpdport, lp->rport);
		break;
	default:
		panic("sndrst: version %d", lp->version);
	}

	seg.seq = lp->iss;
	seg.ack = lp->irs+1;
	seg.flags = SYN|ACK;
	seg.wnd = 0;
	seg.urg = 0;
	seg.mss = tcpmtu(tcp, lp->laddr, lp->version);

	switch(lp->version) {
	case V4:
		hbp = htontcp4(&seg, nil, &ph4, nil);
		if(hbp == nil)
			return -1;
		ipoput4(tcp->f, hbp, 0, MAXTTL, DFLTTOS);
		break;
	case V6:
		hbp = htontcp6(&seg, nil, &ph6, nil);
		if(hbp == nil)
			return -1;
		ipoput6(tcp->f, hbp, 0, MAXTTL, DFLTTOS);
		break;
	default:
		panic("sndsnack: version %d", lp->version);
	}
	lp->lastsend = NOW;
	return 0;
}

/*
 *  hash an address, walk the permutation
 */
static int
limbohash(uchar *perm, uchar *addr)
{
	int i;
	uchar x;

	x = 0;
	for(i = 0; i < IPaddrlen; i++)
		x = perm[(addr[i]+x) & 0xff];
	return x;
}

#define hashipa(a) ( ( (a)[IPaddrlen-2] + (a)[IPaddrlen-1] )&LHTMASK )

/*
 *  put a call into limbo and respond with a SYN ACK
 *
 *  called with proto locked
 */
static void
limbo(Conv *s, uchar *source, uchar *dest, Tcp *seg, int version)
{
	Limbo *lp, **l;
	Tcppriv *tpriv;
	int h;

	tpriv = s->p->priv;
	h = hashipa(source);

	for(l = &tpriv->lht[h]; *l != nil; l = &lp->next){
		lp = *l;
		if(lp->lport != seg->dest || lp->rport != seg->source || lp->version != version)
			continue;
		if(ipcmp(lp->raddr, source) != 0)
			continue;
		if(ipcmp(lp->laddr, dest) != 0)
			continue;

		/* each new SYN restarts the retramsmits */
		lp->irs = seg->seq;
		break;
	}
	lp = *l;
	if(lp == nil){
		if(tpriv->nlimbo >= Maxlimbo && tpriv->lht[h]){
			lp = tpriv->lht[h];
			tpriv->lht[h] = lp->next;
			lp->next = nil;
		} else {
			lp = malloc(sizeof(*lp));
			if(lp == nil)
				return;
			tpriv->nlimbo++;
		}
		*l = lp;
		lp->version = version;
		ipmove(lp->laddr, dest);
		ipmove(lp->raddr, source);
		lp->lport = seg->dest;
		lp->rport = seg->source;
		lp->mss = seg->mss;
		lp->irs = seg->seq;
		lp->iss = (nrand(1<<16)<<16)|nrand(1<<16);
	}

	if(sndsynack(s->p, lp) < 0){
		*l = lp->next;
		tpriv->nlimbo--;
		free(lp);
	}
}

/*
 *  resend SYN ACK's once every 250 ms.
 */
static void
limborexmit(Proto *tcp)
{
	Tcppriv *tpriv;
	Limbo **l, *lp;
	int h;
	int seen;
	ulong now;

	tpriv = tcp->priv;

	if(!canqlock(tcp))
		return;
	seen = 0;
	now = NOW;
	for(h = 0; h < nelem(tpriv->lht) && seen < tpriv->nlimbo; h++){
		for(l = &tpriv->lht[h]; *l != nil && seen < tpriv->nlimbo; ){
			lp = *l;
			seen++;
			if(now - lp->lastsend < 250)
				continue;

			/* time it out after 1 second */
			if(++(lp->rexmits) > 4){
				tpriv->nlimbo--;
				*l = lp->next;
				free(lp);
				continue;
			}

			/* if we're being attacked, don't bother resending SYN ACK's */
			if(tpriv->nlimbo > 100)
				continue;

			if(sndsynack(tcp, lp) < 0){
				tpriv->nlimbo--;
				*l = lp->next;
				free(lp);
				continue;
			}

			l = &lp->next;
		}
	}
	qunlock(tcp);
}

/*
 *  lookup call in limbo.  if found, create a new conversation
 *
 *  called with proto locked
 */
static Conv*
tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst, uchar version)
{


@@ 1201,6 1450,38 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst, uchar version)
	Tcppriv *tpriv;
	Tcp4hdr *h4;
	Tcp6hdr *h6;
	Limbo *lp, **l;
	int h;

	/* unless it's just an ack, it can't be someone coming out of limbo */
	if((segp->flags & SYN) || (segp->flags & ACK) == 0)
		return nil;

	tpriv = s->p->priv;

	/* find a call in limbo */
	lp = nil;
	h = hashipa(src);
	for(l = &tpriv->lht[h]; *l != nil; l = &lp->next){
		lp = *l;
		if(lp->lport != segp->dest || lp->rport != segp->source || lp->version != version)
			continue;
		if(ipcmp(lp->laddr, dst) != 0)
			continue;
		if(ipcmp(lp->raddr, src) != 0)
			continue;

		/* we're assuming no data with the initial SYN */
		if(segp->seq != lp->irs+1 || segp->ack != lp->iss+1)
			lp = nil;
		else{
			tpriv->nlimbo--;
			*l = lp->next;
		}
		break;
	}
	if(lp == nil)
		return nil;

	new = Fsnewcall(s, src, segp->source, dst, segp->dest, version);
	if(new == nil)


@@ 1218,6 1499,34 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst, uchar version)
	tcb->rtt_timer.arg = new;
	tcb->rtt_timer.state = TcptimerOFF;

	tcb->irs = lp->irs;
	tcb->rcv.nxt = tcb->irs+1;
	tcb->rcv.urg = tcb->rcv.nxt;

	tcb->iss = lp->iss;
	tcb->rttseq = tcb->iss;
	tcb->snd.wl2 = tcb->iss;
	tcb->snd.una = tcb->iss+1;
	tcb->snd.ptr = tcb->iss+1;
	tcb->snd.nxt = tcb->iss+1;
	tcb->flgcnt = 0;
	tcb->flags |= SYNACK;

	/* our sending max segment size cannot be bigger than what he asked for */
	if(lp->mss != 0 && lp->mss < tcb->mss)
		tcb->mss = lp->mss;

	/* the congestion window always starts out as a single segment */
	tcb->snd.wnd = segp->wnd;
	tcb->cwind = tcb->mss;

	/* set initial round trip time */
	tcb->sndsyntime = lp->lastsend;
	tcpsynackrtt(new);

	free(lp);

	/* set up proto header */
	switch(version){
	case V4:
		h4 = &tcb->protohdr.tcp4hdr;


@@ 1241,7 1550,8 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst, uchar version)
		panic("tcpincoming: version %d", new->ipversion);
	}

	tpriv = new->p->priv;
	tcpsetstate(new, Established);

	iphtadd(&tpriv->ht, new);

	return new;


@@ 1299,7 1609,7 @@ tcpsynackrtt(Conv *s)
	tcb = (Tcpctl*)s->ptcl;
	tpriv = s->p->priv;

	delta = msec - tcb->sndsyntime;
	delta = NOW - tcb->sndsyntime;
	tcb->srtt = delta<<LOGAGAIN;
	tcb->mdev = delta<<LOGDGAIN;



@@ 1357,7 1667,6 @@ update(Conv *s, Tcp *seg)
		tcb->snd.wl2 = seg->ack;
	}


	if(!seq_gt(seg->ack, tcb->snd.una)){
		/*
		 *  don't let us hangup if sending into a closed window and


@@ 1491,6 1800,7 @@ tcpiput(Proto *tcp, Ipifc*, Block *bp)
			ptclcsum(bp, TCP4_IPLEN, length-TCP4_IPLEN)) {
			tpriv->stats[CsumErrs]++;
			tpriv->stats[InErrs]++;
print("cksum is %ux\n", ptclcsum(bp, TCP4_IPLEN, length-TCP4_IPLEN));
			netlog(f, Logtcp, "bad tcp proto cksum\n");
			freeblist(bp);
			return;


@@ 1578,9 1888,19 @@ reset:
			freeblist(bp);
			return;
		}
		if((seg.flags & SYN) == 0 || (seg.flags & ACK) != 0)
			goto reset;

		/* if this is a new SYN, put the call into limbo */
		if((seg.flags & SYN) && (seg.flags & ACK) == 0){
			limbo(s, source, dest, &seg, version);
			qunlock(tcp);
			freeblist(bp);
			return;
		}

		/*
		 *  if there's a matching call in limbo, tcpincoming will
		 *  return it in state Syn_received
		 */
		s = tcpincoming(s, &seg, source, dest, version);
		if(s == nil)
			goto reset;


@@ 1607,16 1927,6 @@ reset:
	case Closed:
		sndrst(tcp, source, dest, length, &seg, version);
		goto raise;
	case Listen:
		if(seg.flags & SYN) {
			procsyn(s, &seg);
			tcpsndsyn(tcb);
			tcb->time = msec;
			tcpsetstate(s, Syn_received);
			if(length != 0 || (seg.flags & FIN))
				break;
		}
		goto raise;
	case Syn_sent:
		if(seg.flags & ACK) {
			if(!seq_within(seg.ack, tcb->iss+1, tcb->snd.nxt)) {


@@ 1638,7 1948,7 @@ reset:
				tcpsetstate(s, Established);
			}
			else {
				tcb->time = msec;
				tcb->time = NOW;
				tcpsetstate(s, Syn_received);
			}



@@ 1661,15 1971,16 @@ reset:
		break;
	}

	/*
	 *  One DOS attack is to open connections to us and then forget about them,
	 *  thereby tying up a conv at no long term cost to the attacker.
	 *  This is an attempt to defeat these stateless DOS attacks.  See
	 *  corresponding code in tcpsendka().
	 */
	if(tcb->state != Syn_received){
		/*
		 *  One DOS attack is to open connections to us and then forget about them,
		 *  thereby tying up a conv at no long term cost to the attacker.
		 *  This is an attempt to defeat these stateless DOS attacks.  See
		 *  corresponding code in tcpsendka().
		 */
		if(seq_within(seg.ack, tcb->snd.una-(1<<31), tcb->snd.una-(1<<29))){
			print("stateless hog %lux - %lux - %lux\n", tcb->snd.una-(1<<31), seg.ack, tcb->snd.una-(1<<29));
			print("stateless hog %lux - %lux - %lux\n", tcb->snd.una-(1<<31), seg.ack,
				tcb->snd.una-(1<<29));
			localclose(s, "stateless hog");
		}
	}


@@ 1747,7 2058,7 @@ reset:
				tcphalt(tpriv, &tcb->rtt_timer);
				tcphalt(tpriv, &tcb->acktimer);
				tcpsetkacounter(tcb);
				tcb->time = msec;
				tcb->time = NOW;
				tcpsetstate(s, Finwait2);
				tcb->katimer.start = MSL2 * (1000 / MSPTICK);
				tcpgo(tpriv, &tcb->katimer);


@@ 2011,7 2322,7 @@ tcpoutput(Conv *s)
			if(tcb->snd.ptr == tcb->iss){
				seg.flags |= SYN;
				dsize--;
				seg.mss = tcpmtu(s);
				seg.mss = tcpmtu(s->p, s->laddr, s->ipversion);
			}
			break;
		case Syn_received:


@@ 2024,7 2335,7 @@ tcpoutput(Conv *s)
				seg.flags |= SYN;
				dsize = 0;
				ssize = 1;
				seg.mss = tcpmtu(s);
				seg.mss = tcpmtu(s->p, s->laddr, s->ipversion);
			}
			break;
		}


@@ 2329,6 2640,9 @@ inwindow(Tcpctl *tcb, int seq)
	return seq_within(seq, tcb->rcv.nxt, tcb->rcv.nxt+tcb->rcv.wnd-1);
}

/*
 *  set up state for a received SYN (or SYN ACK) packet
 */
void
procsyn(Conv *s, Tcp *seg)
{


@@ 2340,11 2654,13 @@ procsyn(Conv *s, Tcp *seg)
	tcb->rcv.nxt = seg->seq + 1;
	tcb->rcv.urg = tcb->rcv.nxt;
	tcb->irs = seg->seq;
	tcb->snd.wnd = seg->wnd;

	/* our sending max segment size cannot be bigger than what he asked for */
	if(seg->mss != 0 && seg->mss < tcb->mss)
		tcb->mss = seg->mss;
	tcb->max_snd = seg->wnd;

	/* the congestion window always starts out as a single segment */
	tcb->snd.wnd = seg->wnd;
	tcb->cwind = tcb->mss;
}



@@ 2591,13 2907,13 @@ tcpgc(Proto *tcp)
		tcb = (Tcpctl*)c->ptcl;
		switch(tcb->state){
		case Syn_received:
			if(msec - tcb->time > 5000){
			if(NOW - tcb->time > 5000){
				localclose(c, "timed out");
				n++;
			}
			break;
		case Finwait2:
			if(msec - tcb->time > 5*60*1000){
			if(NOW - tcb->time > 5*60*1000){
				localclose(c, "timed out");
				n++;
			}

M mtx/mem.h => mtx/mem.h +0 -2
@@ 32,9 32,7 @@
 * Time
 */
#define	HZ		100			/* clock frequency */
#define	MS2HZ	(1000/HZ)
#define	TK2SEC(t)	((t)/HZ)		/* ticks to seconds */
#define	TK2MS(t)	((t)*MS2HZ)		/* ticks to milliseconds */

/*
 * Standard PPC Special Purpose Registers (OEA and VEA)

M pc/clock.c => pc/clock.c +0 -13
@@ 43,16 43,3 @@ microdelay(int microsecs)
		microsecs = 1;
	aamloop(microsecs);
}

ulong
TK2MS(ulong ticks)
{
	uvlong t, hz;

	t = ticks;
	hz = HZ;
	t *= 1000L;
	t = t/hz;
	ticks = t;
	return ticks;
}

M pc/devether.c => pc/devether.c +3 -3
@@ 414,14 414,14 @@ etherprobe(int cardno, int ctlrno)
	print(buf);

	if(ether->mbps >= 100){
		netifinit(ether, name, Ntypes, 256*1024);
		netifinit(ether, name, Ntypes, 512*1024);
		if(ether->oq == 0)
			ether->oq = qopen(256*1024, 1, 0, 0);
	}
	else{
		netifinit(ether, name, Ntypes, 65*1024);
		netifinit(ether, name, Ntypes, 128*1024);
		if(ether->oq == 0)
			ether->oq = qopen(65*1024, 1, 0, 0);
			ether->oq = qopen(128*1024, 1, 0, 0);
	}
	if(ether->oq == 0)
		panic("etherreset %s", name);

M pc/fns.h => pc/fns.h +0 -1
@@ 146,7 146,6 @@ void	wrmsr(int, vlong);
void	wbflush(void);
void	wbinvd(void);
int	xchgw(ushort*, int);
ulong	TK2MS(ulong);				/* ticks to milliseconds */

#define	waserror()	(up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1]))
#define KADDR(a)	((void*)((ulong)(a)|KZERO))

M pc/i8253.c => pc/i8253.c +0 -13
@@ 322,16 322,3 @@ microdelay(int microsecs)
		microsecs = 1;
	aamloop(microsecs);
}

ulong
TK2MS(ulong ticks)
{
	uvlong t, hz;

	t = ticks;
	hz = HZ;
	t *= 1000L;
	t = t/hz;
	ticks = t;
	return ticks;
}

M port/alarm.c => port/alarm.c +1 -1
@@ 82,7 82,7 @@ procalarm(ulong time)
	ulong when, old;

	if(up->alarm)
		old = TK2MS(up->alarm - MACHP(0)->ticks);
		old = tk2ms(up->alarm - MACHP(0)->ticks);
	else
		old = 0;
	if(time == 0) {

M port/portclock.c => port/portclock.c +36 -0
@@ 141,6 141,13 @@ timerintr(Ureg *u, uvlong)
	Timers *tt;
	uvlong when, now;
	int callhzclock;
	static int intimer;

	if(intimer){
		print("!");
		return;
	}
	intimer = 1;

	intrcount[m->machno]++;
	callhzclock = 0;


@@ 154,6 161,7 @@ timerintr(Ureg *u, uvlong)
			timerset(when);
			if(callhzclock)
				hzclock(u);
			intimer = 0;
			return;
		}
		tt->head = t->next;


@@ 171,6 179,7 @@ timerintr(Ureg *u, uvlong)
		}
	}
	iunlock(tt);
	intimer = 0;
}

uvlong hzperiod;


@@ 209,3 218,30 @@ addclock0link(void (*f)(void))
	 */
	iunlock(&timers[0]);
}

/*
 *  This tk2ms avoids overflows that the macro version is prone to.
 *  It is a LOT slower so shouldn't be used if you're just converting
 *  a delta.
 */
ulong
tk2ms(ulong ticks)
{
	uvlong t, hz;

	t = ticks;
	hz = HZ;
	t *= 1000L;
	t = t/hz;
	ticks = t;
	return ticks;
}

ulong
ms2tk(ulong ms)
{
	/* avoid overflows at the cost of precision */
	if(ms >= 1000000000/HZ)
		return (ms/1000)*HZ;
	return (ms*HZ+500)/1000;
}

M port/portfns.h => port/portfns.h +4 -2
@@ 157,7 157,7 @@ char*		logctl(Log*, int, char**, Logflag*);
void		logn(Log*, int, void*, int);
long		logread(Log*, void*, ulong, long);
void		log(Log*, int, char*, ...);
Cmdtab*	lookupcmd(Cmdbuf*, Cmdtab*, int);
Cmdtab*		lookupcmd(Cmdbuf*, Cmdtab*, int);
Page*		lookpage(Image*, ulong);
void		machinit(void);
void*		mallocz(ulong, int);


@@ 173,7 173,7 @@ Chan*		mntauth(Chan*, char*);
void		mntdump(void);
long		mntversion(Chan*, char*, int, int);
void		mountfree(Mount*);
ulong	ms2tk(ulong);
ulong		ms2tk(ulong);
ulong		msize(void*);
ulong		ms2tk(ulong);
uvlong		ms2fastticks(ulong);


@@ 318,6 318,8 @@ void		timerdel(Timer*);
void		timersinit(void);
void		timerintr(Ureg*, uvlong);
void		timerset(uvlong);
ulong		tk2ms(ulong);
#define		TK2MS(x) ((x)*(1000/HZ))
vlong		todget(vlong*);
void		todfix(void);
void		todsetfreq(vlong);

M port/proc.c => port/proc.c +3 -12
@@ 529,15 529,6 @@ tfn(void *arg)
	return MACHP(0)->ticks >= up->twhen || up->tfn(arg);
}

ulong
ms2tk(ulong ms)
{
	/* avoid overflows at the cost of precision */
	if(ms >= 1000000000/HZ)
		return (ms/1000)*HZ;
	return (ms*HZ+500)/1000;
}

void
tsleep(Rendez *r, int (*fn)(void*), void *arg, int ms)
{


@@ 818,9 809,9 @@ pexit(char *exitstr, int freemem)
		wq->w.pid = up->pid;
		utime = up->time[TUser] + up->time[TCUser];
		stime = up->time[TSys] + up->time[TCSys];
		wq->w.time[TUser] = TK2MS(utime);
		wq->w.time[TSys] = TK2MS(stime);
		wq->w.time[TReal] = TK2MS(MACHP(0)->ticks - up->time[TReal]);
		wq->w.time[TUser] = tk2ms(utime);
		wq->w.time[TSys] = tk2ms(stime);
		wq->w.time[TReal] = tk2ms(MACHP(0)->ticks - up->time[TReal]);
		if(exitstr && exitstr[0])
			snprint(wq->w.msg, sizeof(wq->w.msg), "%s %lud: %s", up->text, up->pid, exitstr);
		else