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

2002/0710/ip/tcp.c (diff list | history)

2002/0704/sys/src/9/ip/tcp.c:61,662002/0710/sys/src/9/ip/tcp.c:61,67 (short | long | prev | next)
1997/0327    
 
	LOGAGAIN	= 3, 
	LOGDGAIN	= 2, 
2002/0710    
 
1997/0327    
	Closed		= 0,		/* Connection states */ 
	Listen, 
	Syn_sent, 
2002/0704/sys/src/9/ip/tcp.c:71,772002/0710/sys/src/9/ip/tcp.c:72,82
1997/0327    
	Close_wait, 
	Closing, 
	Last_ack, 
	Time_wait 
2002/0710    
	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 
1997/0327    
}; 
 
/* Must correspond to the enumeration above */ 
2002/0704/sys/src/9/ip/tcp.c:95,1002002/0710/sys/src/9/ip/tcp.c:100,109
1997/0327    
	void	*arg; 
}; 
 
2002/0710    
/* 
 *  v4 and v6 pseudo headers used for 
 *  checksuming tcp 
 */ 
2002/0507    
typedef struct Tcp4hdr Tcp4hdr; 
struct Tcp4hdr 
1997/0327    
{ 
2002/0704/sys/src/9/ip/tcp.c:143,1492002/0710/sys/src/9/ip/tcp.c:152,163
2002/0507    
	uchar	tcpmss[2]; 
}; 
 
                 
2002/0710    
/* 
 *  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}(). 
 */ 
1997/0327    
typedef struct Tcp Tcp; 
struct	Tcp 
{ 
2002/0704/sys/src/9/ip/tcp.c:158,1632002/0710/sys/src/9/ip/tcp.c:172,181
2002/0507    
	ushort	len;	/* size of data */ 
1997/0327    
}; 
 
2002/0710    
/* 
 *  this header is malloc'd to thread together fragments 
 *  waiting to be coalesced 
 */ 
1997/0327    
typedef struct Reseq Reseq; 
struct Reseq 
{ 
2002/0704/sys/src/9/ip/tcp.c:202,2082002/0710/sys/src/9/ip/tcp.c:220,225
1997/0327    
	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 */ 
1998/0306    
	uchar	backoff;		/* Exponential backoff counter */ 
1999/0607    
	int	backedoff;		/* ms we've backed off for rexmits */ 
2002/0704/sys/src/9/ip/tcp.c:219,2252002/0710/sys/src/9/ip/tcp.c:236,242
1997/0327    
	uint	sndsyntime;		/* time syn sent */ 
2000/0424    
	ulong	time;			/* time Finwait2 or Syn_received was sent */ 
2001/0119    
	int	nochecksum;		/* non-zero means don't send checksums */ 
2001/0306    
	int	flgcnt;			/* 1 when we're waiting for a SYN/FIN ACK */ 
2002/0710    
	int	flgcnt;			/* number of flags in the sequence (FIN,SEQ) */ 
1998/0306    
 
2002/0507    
	union { 
		Tcp4hdr	tcp4hdr; 
2002/0704/sys/src/9/ip/tcp.c:227,2322002/0710/sys/src/9/ip/tcp.c:244,279
2002/0507    
	} protohdr;		/* prototype header */ 
1997/0327    
}; 
 
2002/0710    
/* 
 *  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 */ 
}; 
 
1997/0327    
int	tcp_irtt = DEF_RTT;	/* Initial guess at round trip time */ 
ushort	tcp_mss  = DEF_MSS;	/* Maximum segment size to be sent */ 
 
2002/0704/sys/src/9/ip/tcp.c:275,2922002/0710/sys/src/9/ip/tcp.c:322,345
1998/0313    
typedef struct Tcppriv Tcppriv; 
struct Tcppriv 
{ 
2002/0507    
	Tcptimer 	*timers;	/* List of active timers */ 
1998/0313    
	QLock 	tl;			/* Protect timer list */ 
2002/0710    
	/* List of active timers */ 
	QLock 	tl; 
	Tcptimer *timers; 
 
1998/0313    
	Rendez	tcpr;			/* used by tcpackproc */ 
 
2001/0301    
	/* hash table for matching conversations */ 
	Ipht	ht; 
 
2000/0706    
	ulong	stats[Nstats]; 
2002/0710    
	/* calls in limbo waiting for an ACK to our SYN ACK */ 
	int	nlimbo; 
	Limbo	*lht[NLHT]; 
1998/0313    
 
1998/0924    
	/* for keeping track of tcpackproc */ 
	int	ackprocstarted; 
	QLock	apl; 
2002/0710    
	int	ackprocstarted; 
 
	ulong	stats[Nstats]; 
1998/0313    
}; 
 
1999/1006    
int	addreseq(Tcpctl*, Tcp*, Block*, ushort); 
2002/0704/sys/src/9/ip/tcp.c:305,3112002/0710/sys/src/9/ip/tcp.c:358,368
1999/0529    
void	tcpsetkacounter(Tcpctl*); 
2000/0102    
void    tcprxmit(Conv*); 
2001/0530    
void	tcpsettimer(Tcpctl*); 
2002/0710    
void	tcpsynackrtt(Conv*); 
1997/0327    
 
2002/0710    
static void limborexmit(Proto*); 
static void limbo(Conv*, uchar*, uchar*, Tcp*, int); 
 
1997/0327    
void 
1998/0306    
tcpsetstate(Conv *s, uchar newstate) 
1997/0327    
{ 
2002/0704/sys/src/9/ip/tcp.c:457,4672002/0710/sys/src/9/ip/tcp.c:514,519
2000/1220    
	qlock(s); 
1997/0327    
 
	switch(tcb->state) { 
	case Listen: 
		tcb->flags |= ACTIVE; 
		tcpsndsyn(tcb); 
		tcpsetstate(s, Syn_sent); 
		/* No break */ 
	case Syn_sent: 
	case Syn_received: 
	case Established: 
2002/0704/sys/src/9/ip/tcp.c:599,6042002/0710/sys/src/9/ip/tcp.c:651,658
2001/0504    
				poperror(); 
			} 
1997/0327    
		} 
2002/0710    
 
		limborexmit(tcp); 
1997/0327    
	} 
} 
 
2002/0704/sys/src/9/ip/tcp.c:672,6852002/0710/sys/src/9/ip/tcp.c:726,737
1997/0327    
 
1999/0401    
/* mtu (- TCP + IP hdr len) of 1st hop */ 
int 
tcpmtu(Conv *s) 
2002/0710    
tcpmtu(Proto *tcp, uchar *addr, int version) 
1999/0401    
{ 
	Ipifc *ifc; 
	int mtu; 
2002/0601    
	uchar version; 
1999/0401    
 
2002/0601    
	version = s->ipversion; 
1999/0401    
	ifc = findipifc(s->p->f, s->raddr, 0); 
2002/0710    
	ifc = findipifc(tcp->f, addr, 0); 
2002/0704    
	switch(version){ 
	default: 
	case V4: 
2002/0704/sys/src/9/ip/tcp.c:753,7592002/0710/sys/src/9/ip/tcp.c:805,811
2002/0601    
		} 
2002/0507    
	} 
 
1999/0401    
	tcb->mss = tcb->cwind = tcpmtu(s); 
2002/0710    
	tcb->mss = tcb->cwind = tcpmtu(s->p, s->laddr, s->ipversion); 
1997/0327    
} 
 
2000/1220    
/* 
2002/0704/sys/src/9/ip/tcp.c:1056,10622002/0710/sys/src/9/ip/tcp.c:1108,1117
1997/0327    
	return hdrlen; 
} 
 
/* Generate an initial sequence number and put a SYN on the send queue */ 
2002/0710    
/* 
 *  For outgiing calls, generate an initial sequence 
 *  number and put a SYN on the send queue 
 */ 
1997/0327    
void 
tcpsndsyn(Tcpctl *tcb) 
{ 
2002/0704/sys/src/9/ip/tcp.c:1068,10742002/0710/sys/src/9/ip/tcp.c:1123,1129
1997/0327    
	tcb->snd.nxt = tcb->rttseq; 
2001/0306    
	tcb->flgcnt++; 
1997/0327    
	tcb->flags |= FORCE; 
	tcb->sndsyntime = msec; 
2002/0710    
	tcb->sndsyntime = NOW; 
1997/0327    
} 
 
void 
2002/0704/sys/src/9/ip/tcp.c:1193,11982002/0710/sys/src/9/ip/tcp.c:1248,1447
1997/0327    
	return nil; 
} 
 
2002/0710    
/* 
 *  (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 
 */ 
2002/0601    
static Conv* 
tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst, uchar version) 
1997/0327    
{ 
2002/0704/sys/src/9/ip/tcp.c:1201,12072002/0710/sys/src/9/ip/tcp.c:1450,1488
2001/0301    
	Tcppriv *tpriv; 
2002/0601    
	Tcp4hdr *h4; 
	Tcp6hdr *h6; 
2002/0710    
	Limbo *lp, **l; 
	int h; 
1997/0327    
 
2002/0710    
	/* 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; 
 
2002/0601    
	new = Fsnewcall(s, src, segp->source, dst, segp->dest, version); 
1997/0327    
	if(new == nil) 
		return nil; 
2002/0704/sys/src/9/ip/tcp.c:1218,12232002/0710/sys/src/9/ip/tcp.c:1499,1532
1998/1204    
	tcb->rtt_timer.arg = new; 
2002/0405    
	tcb->rtt_timer.state = TcptimerOFF; 
1997/0327    
 
2002/0710    
	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 */ 
2002/0601    
	switch(version){ 
	case V4: 
		h4 = &tcb->protohdr.tcp4hdr; 
2002/0704/sys/src/9/ip/tcp.c:1241,12472002/0710/sys/src/9/ip/tcp.c:1550,1557
2002/0601    
		panic("tcpincoming: version %d", new->ipversion); 
2002/0507    
	} 
1998/0306    
 
2001/0301    
	tpriv = new->p->priv; 
2002/0710    
	tcpsetstate(new, Established); 
 
2001/0301    
	iphtadd(&tpriv->ht, new); 
 
1997/0327    
	return new; 
2002/0704/sys/src/9/ip/tcp.c:1299,13052002/0710/sys/src/9/ip/tcp.c:1609,1615
1997/0327    
	tcb = (Tcpctl*)s->ptcl; 
1998/0313    
	tpriv = s->p->priv; 
1997/0327    
 
	delta = msec - tcb->sndsyntime; 
2002/0710    
	delta = NOW - tcb->sndsyntime; 
1997/0327    
	tcb->srtt = delta<<LOGAGAIN; 
	tcb->mdev = delta<<LOGDGAIN; 
 
2002/0704/sys/src/9/ip/tcp.c:1357,13632002/0710/sys/src/9/ip/tcp.c:1667,1672
1997/0327    
		tcb->snd.wl2 = seg->ack; 
	} 
 
2001/0119    
                 
2001/0308    
	if(!seq_gt(seg->ack, tcb->snd.una)){ 
		/* 
		 *  don't let us hangup if sending into a closed window and 
2002/0704/sys/src/9/ip/tcp.c:1491,14962002/0710/sys/src/9/ip/tcp.c:1800,1806
2002/0507    
			ptclcsum(bp, TCP4_IPLEN, length-TCP4_IPLEN)) { 
			tpriv->stats[CsumErrs]++; 
			tpriv->stats[InErrs]++; 
2002/0710    
print("cksum is %ux\n", ptclcsum(bp, TCP4_IPLEN, length-TCP4_IPLEN)); 
2002/0507    
			netlog(f, Logtcp, "bad tcp proto cksum\n"); 
			freeblist(bp); 
			return; 
2002/0704/sys/src/9/ip/tcp.c:1578,15862002/0710/sys/src/9/ip/tcp.c:1888,1906
1997/0327    
			freeblist(bp); 
			return; 
		} 
2001/0301    
		if((seg.flags & SYN) == 0 || (seg.flags & ACK) != 0) 
			goto reset; 
1999/0302    
 
2002/0710    
		/* 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 
		 */ 
2002/0601    
		s = tcpincoming(s, &seg, source, dest, version); 
2001/0301    
		if(s == nil) 
			goto reset; 
2002/0704/sys/src/9/ip/tcp.c:1607,16222002/0710/sys/src/9/ip/tcp.c:1927,1932
1997/0327    
	case Closed: 
2002/0507    
		sndrst(tcp, source, dest, length, &seg, version); 
1997/0327    
		goto raise; 
	case Listen: 
		if(seg.flags & SYN) { 
			procsyn(s, &seg); 
			tcpsndsyn(tcb); 
2000/0424    
			tcb->time = msec; 
1997/0327    
			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)) { 
2002/0704/sys/src/9/ip/tcp.c:1638,16442002/0710/sys/src/9/ip/tcp.c:1948,1954
1997/0327    
				tcpsetstate(s, Established); 
			} 
2000/0424    
			else { 
				tcb->time = msec; 
2002/0710    
				tcb->time = NOW; 
1997/0327    
				tcpsetstate(s, Syn_received); 
2000/0424    
			} 
1997/0327    
 
2002/0704/sys/src/9/ip/tcp.c:1661,16752002/0710/sys/src/9/ip/tcp.c:1971,1986
1997/0327    
		break; 
	} 
 
2002/0710    
	/* 
	 *  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(). 
	 */ 
2002/0704    
	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)); 
2002/0710    
			print("stateless hog %lux - %lux - %lux\n", tcb->snd.una-(1<<31), seg.ack, 
				tcb->snd.una-(1<<29)); 
2002/0704    
			localclose(s, "stateless hog"); 
		} 
	} 
2002/0704/sys/src/9/ip/tcp.c:1747,17532002/0710/sys/src/9/ip/tcp.c:2058,2064
1998/1204    
				tcphalt(tpriv, &tcb->rtt_timer); 
				tcphalt(tpriv, &tcb->acktimer); 
1999/0529    
				tcpsetkacounter(tcb); 
2000/0424    
				tcb->time = msec; 
2002/0710    
				tcb->time = NOW; 
1997/0327    
				tcpsetstate(s, Finwait2); 
1998/1118    
				tcb->katimer.start = MSL2 * (1000 / MSPTICK); 
1998/1202    
				tcpgo(tpriv, &tcb->katimer); 
2002/0704/sys/src/9/ip/tcp.c:2011,20172002/0710/sys/src/9/ip/tcp.c:2322,2328
1997/0327    
			if(tcb->snd.ptr == tcb->iss){ 
				seg.flags |= SYN; 
				dsize--; 
1998/0813    
				seg.mss = tcpmtu(s); 
2002/0710    
				seg.mss = tcpmtu(s->p, s->laddr, s->ipversion); 
1998/0813    
			} 
			break; 
		case Syn_received: 
2002/0704/sys/src/9/ip/tcp.c:2024,20302002/0710/sys/src/9/ip/tcp.c:2335,2341
1998/0813    
				seg.flags |= SYN; 
				dsize = 0; 
1998/0831    
				ssize = 1; 
1997/0327    
				seg.mss = tcpmtu(s); 
2002/0710    
				seg.mss = tcpmtu(s->p, s->laddr, s->ipversion); 
1997/0327    
			} 
			break; 
		} 
2002/0704/sys/src/9/ip/tcp.c:2329,23342002/0710/sys/src/9/ip/tcp.c:2640,2648
1997/0327    
	return seq_within(seq, tcb->rcv.nxt, tcb->rcv.nxt+tcb->rcv.wnd-1); 
} 
 
2002/0710    
/* 
 *  set up state for a received SYN (or SYN ACK) packet 
 */ 
1997/0327    
void 
procsyn(Conv *s, Tcp *seg) 
{ 
2002/0704/sys/src/9/ip/tcp.c:2340,23502002/0710/sys/src/9/ip/tcp.c:2654,2666
1997/0327    
	tcb->rcv.nxt = seg->seq + 1; 
	tcb->rcv.urg = tcb->rcv.nxt; 
	tcb->irs = seg->seq; 
	tcb->snd.wnd = seg->wnd; 
 
2002/0710    
	/* our sending max segment size cannot be bigger than what he asked for */ 
2002/0704    
	if(seg->mss != 0 && seg->mss < tcb->mss) 
1997/0327    
		tcb->mss = seg->mss; 
	tcb->max_snd = seg->wnd; 
2002/0710    
 
	/* the congestion window always starts out as a single segment */ 
	tcb->snd.wnd = seg->wnd; 
1997/0327    
	tcb->cwind = tcb->mss; 
} 
 
2002/0704/sys/src/9/ip/tcp.c:2591,26032002/0710/sys/src/9/ip/tcp.c:2907,2919
2000/0424    
		tcb = (Tcpctl*)c->ptcl; 
		switch(tcb->state){ 
		case Syn_received: 
			if(msec - tcb->time > 5000){ 
2002/0710    
			if(NOW - tcb->time > 5000){ 
2000/0424    
				localclose(c, "timed out"); 
				n++; 
			} 
			break; 
		case Finwait2: 
			if(msec - tcb->time > 5*60*1000){ 
2002/0710    
			if(NOW - tcb->time > 5*60*1000){ 
2000/0424    
				localclose(c, "timed out"); 
				n++; 
			} 


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