xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 4731)
1*4731Swnj /* tcp_usrreq.c 1.23 81/11/03 */
24567Swnj 
34497Swnj #include "../h/param.h"
44567Swnj #include "../h/systm.h"
54664Swnj #include "../h/mbuf.h"
64664Swnj #include "../h/socket.h"
74664Swnj #include "../inet/inet.h"
84664Swnj #include "../inet/inet_systm.h"
94664Swnj #include "../inet/imp.h"
104664Swnj #include "../inet/ip.h"
114664Swnj #include "../inet/tcp.h"
124567Swnj #define TCPFSTAB
134584Swnj #ifdef TCPDEBUG
144584Swnj #define TCPSTATES
154584Swnj #endif
164664Swnj #include "../inet/tcp_fsm.h"
174497Swnj 
184567Swnj tcp_timeo()
194497Swnj {
204567Swnj 	register struct tcb *tp;
214567Swnj 	int s = splnet();
22*4731Swnj 	register u_char *tmp;
23*4731Swnj 	register int i;
244567Swnj COUNT(TCP_TIMEO);
254497Swnj 
264567Swnj 	/*
274567Swnj 	 * Search through tcb's and update active timers.
284567Swnj 	 */
294682Swnj 	for (tp = tcb.tcb_next; tp != (struct tcb *)&tcb; tp = tp->tcb_next) {
30*4731Swnj 		tmp = &tp->t_init;
31*4731Swnj 		for (i = 0; i < TNTIMERS; i++)
32*4731Swnj 			if (*tmp && --*tmp == 0)
33*4731Swnj 				tcp_usrreq(ISTIMER, i, tp, 0);
344567Swnj 		tp->t_xmt++;
354567Swnj 	}
364664Swnj 	tcp_iss += ISSINCR;		/* increment iss */
374567Swnj 	timeout(tcp_timeo, 0, hz);      /* reschedule every second */
384567Swnj 	splx(s);
394497Swnj }
404497Swnj 
41*4731Swnj /*
42*4731Swnj  * Process a TCP user request for tcp tb.  If this is a send request
43*4731Swnj  * then m is the mbuf chain of send data.  If this is a timer expiration
44*4731Swnj  * (called from the software clock routine), then timertype tells which timer.
45*4731Swnj  */
46*4731Swnj tcp_usrreq(input, timertype, tp, m)
474584Swnj 	int input, timertype;
484567Swnj 	register struct tcb *tp;
49*4731Swnj 	struct mbuf *m;
504497Swnj {
514567Swnj 	int s = splnet();
524567Swnj 	register int nstate;
534584Swnj #ifdef TCPDEBUG
544584Swnj 	struct tcp_debug tdb;
554584Swnj #endif
564567Swnj COUNT(TCP_USRREQ);
574497Swnj 
584567Swnj 	nstate = tp->t_state;
594576Swnj 	tp->tc_flags &= ~TC_NET_KEEP;
60*4731Swnj #ifdef KPROF
614567Swnj 	acounts[nstate][input]++;
62*4731Swnj #endif
634584Swnj #ifdef TCPDEBUG
644584Swnj 	if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
654605Swnj 		tdb_setup(tp, (struct th *)0, input, &tdb);
664584Swnj 		tdb.td_tim = timertype;
674584Swnj 	} else
684584Swnj 		tdb.td_tod = 0;
694584Swnj #endif
70*4731Swnj 	switch (input) {
714497Swnj 
72*4731Swnj 	/*
73*4731Swnj 	 * Passive open.  Create a tcp control block
74*4731Swnj 	 * and enter listen state.
75*4731Swnj 	 */
76*4731Swnj 	case IUOPENA:				/* 2 */
77*4731Swnj 		if (nstate != 0 && nstate != CLOSED)
78*4731Swnj 			goto bad;
794676Swnj 		tcp_open(tp, PASSIVE);
804567Swnj 		nstate = LISTEN;
814567Swnj 		break;
824497Swnj 
83*4731Swnj 	/*
84*4731Swnj 	 * Active open.  Create a tcp control block,
85*4731Swnj 	 * send a SYN and enter SYN_SENT state.
86*4731Swnj 	 */
87*4731Swnj 	case IUOPENR:				/* 1 */
88*4731Swnj 		if (nstate != 0 && nstate != CLOSED)
89*4731Swnj 			goto bad;
904676Swnj 		tcp_open(tp, ACTIVE);
914676Swnj 		tcp_sndctl(tp);
924567Swnj 		nstate = SYN_SENT;
934567Swnj 		break;
944497Swnj 
95*4731Swnj 	/*
96*4731Swnj 	 * Tcp close call.  Can be generated by a user ioctl (half-close),
97*4731Swnj 	 * or when higher level close occurs, if a close hasn't happened
98*4731Swnj 	 * already.
99*4731Swnj 	 */
100*4731Swnj 	case IUCLOSE:
101*4731Swnj 		switch (nstate) {
1024497Swnj 
103*4731Swnj 		/*
104*4731Swnj 		 * If we are aborting out of a listener or a active
105*4731Swnj 		 * connection which has not yet completed we can just
106*4731Swnj 		 * delete the tcb.
107*4731Swnj 		 */
108*4731Swnj 		case LISTEN:
109*4731Swnj 		case SYN_SENT:			/* 10 */
110*4731Swnj 			tcp_close(tp, UCLOSED);
111*4731Swnj 			nstate = CLOSED;
112*4731Swnj 			break;
113*4731Swnj 
114*4731Swnj 		/*
115*4731Swnj 		 * If we have gotten as far as receiving a syn from
116*4731Swnj 		 * our foreign peer, we must be sure to send a FIN.
117*4731Swnj 		 * If we have gotten a FIN from the foreign peer already
118*4731Swnj 		 * (CLOSE_WAIT state), then all that remains is to wait
119*4731Swnj 		 * for his ack of the FIN (LAST_ACK state).  If we have
120*4731Swnj 		 * not gotten a FIN from the foreign peer then we need
121*4731Swnj 		 * to either:
122*4731Swnj 		 *	1. rcv ack of our FIN (to FIN_W2) and then
123*4731Swnj 		 *	   send an ACK (to TIME_WAIT) and timeout at 2*MSL.
124*4731Swnj 		 * or	2. receive hist FIN (to CLOSING), send an ACK
125*4731Swnj 		 *	   (to TIME_WAIT), and then timeout.
126*4731Swnj 		 * In any case this starts with a transition to FIN_W1 here.
127*4731Swnj 		 */
128*4731Swnj 		case SYN_RCVD:			/* 24,25 */
129*4731Swnj 		case L_SYN_RCVD:
130*4731Swnj 		case ESTAB:
131*4731Swnj 		case CLOSE_WAIT:		/* 10 */
132*4731Swnj 			tp->tc_flags |= TC_SND_FIN;
133*4731Swnj 			tcp_sndctl(tp);
134*4731Swnj 			tp->tc_flags |= TC_USR_CLOSED;
135*4731Swnj 			nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK;
136*4731Swnj 			break;
137*4731Swnj 
138*4731Swnj 		/*
139*4731Swnj 		 * In these states the user has already closed;
140*4731Swnj 		 * trying to close again is an error.
141*4731Swnj 		 */
142*4731Swnj 		case FIN_W1:
143*4731Swnj 		case FIN_W2:
144*4731Swnj 		case TIME_WAIT:
145*4731Swnj 		case CLOSING:
146*4731Swnj 		case LAST_ACK:
147*4731Swnj 		case RCV_WAIT:
148*4731Swnj 			to_user(tp->t_ucb, UCLSERR);
149*4731Swnj 			break;
150*4731Swnj 
151*4731Swnj 		default:
152*4731Swnj 			goto bad;
153*4731Swnj 		}
1544567Swnj 		break;
1554497Swnj 
156*4731Swnj 	/*
157*4731Swnj 	 * TCP Timer processing.
158*4731Swnj 	 * Timers should expire only on open connections
159*4731Swnj 	 * not in LISTEN state.
160*4731Swnj 	 */
161*4731Swnj 	case ISTIMER:				/* 14,17,34,35,36,37,38 */
162*4731Swnj 		switch (nstate) {
163*4731Swnj 
164*4731Swnj 		case 0:
165*4731Swnj 		case CLOSED:
166*4731Swnj 		case LISTEN:
167*4731Swnj 			goto bad;
168*4731Swnj 
169*4731Swnj 		default:
170*4731Swnj 			nstate = tcp_timers(tp, timertype);
171*4731Swnj 		}
1724567Swnj 		break;
1734497Swnj 
174*4731Swnj 	/*
175*4731Swnj 	 * User notification of more window availability after
176*4731Swnj 	 * reading out data.  This should not happen before a connection
177*4731Swnj 	 * is established or after it is closed.
178*4731Swnj 	 * If the foreign peer has closed and the local entity
179*4731Swnj 	 * has not, inform him of the FIN (give end of file).
180*4731Swnj 	 * If the local entity is in RCV_WAIT state (draining data
181*4731Swnj 	 * out of the TCP buffers after foreign close) and there
182*4731Swnj 	 * is no more data, institute a close.
183*4731Swnj 	 */
184*4731Swnj 	case IURECV:				/* 42 */
185*4731Swnj 		if (nstate < ESTAB || nstate == CLOSED)
186*4731Swnj 			goto bad;
187*4731Swnj 		tcp_sndwin(tp);		/* send new window */
1884691Swnj 		if ((tp->tc_flags&TC_FIN_RCVD) &&
1894691Swnj 		    (tp->tc_flags&TC_USR_CLOSED) == 0 &&
1904691Swnj 		    rcv_empty(tp))
1914691Swnj 			to_user(tp, UCLOSED);
192*4731Swnj 		if (nstate == RCV_WAIT && rcv_empty(tp)) {
1934676Swnj 			tcp_close(tp, UCLOSED);
1944567Swnj 			nstate = CLOSED;
195*4731Swnj 		}
1964567Swnj 		break;
1974497Swnj 
198*4731Swnj 	/*
199*4731Swnj 	 * Send request on open connection.
200*4731Swnj 	 * Should not happen if the connection is not yet established.
201*4731Swnj 	 * Allowed only on ESTAB connection and after FIN from
202*4731Swnj 	 * foreign peer.
203*4731Swnj 	 */
204*4731Swnj 	case IUSEND:				/* 40,41 */
205*4731Swnj 		switch (nstate) {
2064567Swnj 
207*4731Swnj 		case ESTAB:
208*4731Swnj 		case CLOSE_WAIT:
209*4731Swnj 			nstate = tcp_usrsend(tp, m);
210*4731Swnj 			break;
211*4731Swnj 
212*4731Swnj 		default:
213*4731Swnj 			if (nstate < ESTAB)
214*4731Swnj 				goto bad;
215*4731Swnj 			to_user(tp, UCLSERR);
216*4731Swnj 			break;
217*4731Swnj 		}
2184567Swnj 		break;
2194567Swnj 
220*4731Swnj 	/*
221*4731Swnj 	 * User abort of connection.
222*4731Swnj 	 * If a SYN has been received, but we have not exchanged FINs
223*4731Swnj 	 * then we need to send an RST.  In any case we then
224*4731Swnj 	 * enter closed state.
225*4731Swnj 	 */
226*4731Swnj 	case IUABORT:				/* 44,45 */
227*4731Swnj 		if (nstate == 0 || nstate == CLOSED)
228*4731Swnj 			break;
229*4731Swnj 		switch (nstate) {
2304567Swnj 
231*4731Swnj 		case 0:
232*4731Swnj 		case CLOSED:
233*4731Swnj 			break;
2344567Swnj 
235*4731Swnj 		case SYN_RCVD:
236*4731Swnj 		case ESTAB:
237*4731Swnj 		case FIN_W1:
238*4731Swnj 		case FIN_W2:
239*4731Swnj 		case CLOSE_WAIT:
240*4731Swnj 			tp->tc_flags |= TC_SND_RST;
241*4731Swnj 			tcp_sndnull(tp);
242*4731Swnj 			/* fall into ... */
243*4731Swnj 
244*4731Swnj 		default:
245*4731Swnj 			tcp_close(tp, UABORT);
246*4731Swnj 			nstate = CLOSED;
247*4731Swnj 		}
2484567Swnj 		break;
2494567Swnj 
250*4731Swnj 	/*
251*4731Swnj 	 * Network down entry.  Discard the tcb and force
252*4731Swnj 	 * the state to be closed, ungracefully.
253*4731Swnj 	 */
254*4731Swnj 	case INCLEAR:				/* 47 */
255*4731Swnj 		if (nstate == 0 || nstate == CLOSED)
256*4731Swnj 			break;
2574676Swnj 		tcp_close(tp, UNETDWN);
2584567Swnj 		nstate = CLOSED;
2594567Swnj 		break;
2604567Swnj 
261*4731Swnj 	default:
262*4731Swnj 		panic("tcp_usrreq");
263*4731Swnj 	bad:
264*4731Swnj 		printf("tcp: bad state: tcb=%x state=%d input=%d\n",
265*4731Swnj 		    tp, tp->t_state, input);
266*4731Swnj 		nstate = EFAILEC;
2674567Swnj 		break;
2684567Swnj 	}
2694567Swnj #ifdef TCPDEBUG
2704605Swnj 	if (tdb.td_tod)
2714605Swnj 		tdb_stuff(&tdb, nstate);
2724567Swnj #endif
2734567Swnj 	/* YECH */
2744567Swnj 	switch (nstate) {
2754567Swnj 
2764584Swnj 	case CLOSED:
2774567Swnj 	case SAME:
2784567Swnj 		break;
2794567Swnj 
2804567Swnj 	case EFAILEC:
281*4731Swnj 		if (m)
282*4731Swnj 			m_freem(dtom(m));
2834567Swnj 		break;
2844567Swnj 
2854567Swnj 	default:
2864567Swnj 		tp->t_state = nstate;
2874567Swnj 		break;
2884567Swnj 	}
2894567Swnj 	splx(s);
2904497Swnj }
2914497Swnj 
2924682Swnj /*
2934682Swnj  * Open routine, called to initialize newly created tcb fields.
2944682Swnj  */
2954682Swnj tcp_open(tp, mode)
2964567Swnj 	register struct tcb *tp;
2974567Swnj 	int mode;
2984497Swnj {
2994682Swnj 	register struct ucb *up = tp->t_ucb;
3004682Swnj COUNT(TCP_OPEN);
3014497Swnj 
3024682Swnj 	/*
3034682Swnj 	 * Link in tcb queue and make
3044682Swnj 	 * initialize empty reassembly queue.
3054682Swnj 	 */
3064682Swnj 	tp->tcb_next = tcb.tcb_next;
3074682Swnj 	tcb.tcb_next->tcb_prev = tp;
3084682Swnj 	tp->tcb_prev = (struct tcb *)&tcb;
3094682Swnj 	tcb.tcb_next = tp;
3104682Swnj 	tp->t_rcv_next = tp->t_rcv_prev = (struct th *)tp;
3114497Swnj 
3124682Swnj 	/*
3134682Swnj 	 * Initialize sequence numbers and
3144682Swnj 	 * round trip retransmit timer.
3154682Swnj 	 * (Other fields were init'd to zero when tcb allocated.)
3164682Swnj 	 */
3174567Swnj 	tp->t_xmtime = T_REXMT;
3184682Swnj 	tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una =
3194682Swnj 	    tp->iss = tcp_iss;
3204567Swnj 	tp->snd_off = tp->iss + 1;
3214664Swnj 	tcp_iss += (ISSINCR >> 1) + 1;
3224567Swnj 
3234682Swnj 	/*
3244682Swnj 	 * Set timeout for open.
3254682Swnj 	 * SHOULD THIS BE A HIGHER LEVEL FUNCTION!?! THINK SO.
3264682Swnj 	 */
3274682Swnj 	if (up->uc_timeo)
3284682Swnj 		tp->t_init = up->uc_timeo;
3294682Swnj 	else if (mode == ACTIVE)
3304682Swnj 		tp->t_init = T_INIT;
3314682Swnj 	/* else
3324682Swnj 		tp->t_init = 0; */
3334682Swnj 	up->uc_timeo = 0;				/* ### */
3344497Swnj }
3354497Swnj 
3364682Swnj /*
3374682Swnj  * Internal close of a connection, shutting down the tcb.
3384682Swnj  */
3394676Swnj tcp_close(tp, state)
3404567Swnj 	register struct tcb *tp;
3414567Swnj 	short state;
3424497Swnj {
3434682Swnj 	register struct ucb *up = tp->t_ucb;
3444567Swnj 	register struct th *t;
3454567Swnj 	register struct mbuf *m;
3464682Swnj COUNT(TCP_CLOSE);
3474497Swnj 
3484682Swnj 	/*
3494682Swnj 	 * Cancel all timers.
3504682Swnj 	 * SHOULD LOOP HERE !?!
3514682Swnj 	 */
3524567Swnj 	tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist =
3534567Swnj 	    tp->t_finack = 0;
3544497Swnj 
3554682Swnj 	/*
3564682Swnj 	 * Remque the tcb
3574682Swnj 	 */
3584682Swnj 	tp->tcb_prev->tcb_next = tp->tcb_next;
3594682Swnj 	tp->tcb_next->tcb_prev = tp->tcb_prev;
3604567Swnj 
3614682Swnj 	/*
3624682Swnj 	 * Discard all buffers...
3634682Swnj 	 *
3644682Swnj 	 * SHOULD COUNT EACH RESOURCE TO 0 AND PANIC IF CONFUSED
3654682Swnj 	 */
3664567Swnj 	for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next)
3674567Swnj 		m_freem(dtom(t));
3684567Swnj 	if (up->uc_rbuf != NULL) {
3694567Swnj 		m_freem(up->uc_rbuf);
3704567Swnj 		up->uc_rbuf = NULL;
3714567Swnj 	}
3724657Swnj 	up->uc_rcc = 0;
3734567Swnj 	if (up->uc_sbuf != NULL) {
3744567Swnj 		m_freem(up->uc_sbuf);
3754567Swnj 		up->uc_sbuf = NULL;
3764567Swnj 	}
3774592Swnj 	up->uc_ssize = 0;
3784567Swnj 	for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) {
3794567Swnj 		m_freem(m);
3804567Swnj 		tp->t_rcv_unack = NULL;
3814567Swnj 	}
3824682Swnj 
3834682Swnj 	/*
3844682Swnj 	 * Free tcp send template.
3854682Swnj 	 */
3864664Swnj 	if (up->uc_template) {
3874664Swnj 		m_free(dtom(up->uc_template));
3884664Swnj 		up->uc_template = 0;
3894664Swnj 	}
3904682Swnj 
3914682Swnj 	/*
3924682Swnj 	 * Free the tcb
3934682Swnj 	 * WOULD THIS BETTER BE DONE AT USER CLOSE?
3944682Swnj 	 */
3954670Swnj 	wmemfree((caddr_t)tp, 1024);
3964567Swnj 	up->uc_tcb = NULL;
3974567Swnj 
3984682Swnj 	/*
3994682Swnj 	 * Lower buffer allocation.
4004682Swnj 	 * SHOULD BE A M_ROUTINE CALL.
4014682Swnj 	 */
4024664Swnj 	mbstat.m_lowat -= up->uc_snd + (up->uc_rhiwat/MSIZE) + 2;
4034664Swnj 	mbstat.m_hiwat = 2 * mbstat.m_lowat;
4044682Swnj 
4054682Swnj 	/*
4064682Swnj 	 * Free routing table entry.
4074682Swnj 	 */
4084567Swnj 	if (up->uc_host != NULL) {
4094567Swnj 		h_free(up->uc_host);
4104567Swnj 		up->uc_host = NULL;
4114567Swnj 	}
4124567Swnj 
4134682Swnj 	/*
4144682Swnj 	 * If user has initiated close (via close call), delete ucb
4154682Swnj 	 * entry, otherwise just wakeup so user can issue close call
4164682Swnj 	 */
4174576Swnj 	if (tp->tc_flags&TC_USR_ABORT)
4184567Swnj         	up->uc_proc = NULL;
4194567Swnj 	else
4204682Swnj         	to_user(up, state);			/* ### */
4214497Swnj }
4224497Swnj 
4234682Swnj /*
4244682Swnj  * User routine to send data queue headed by m0 into the protocol.
4254682Swnj  */
4264678Swnj tcp_usrsend(tp, m0)
4274584Swnj 	register struct tcb *tp;
4284584Swnj 	struct mbuf *m0;
4294497Swnj {
4304497Swnj 	register struct mbuf *m, *n;
4314584Swnj 	register struct ucb *up = tp->t_ucb;
4324497Swnj 	register off;
4334574Swnj 	seq_t last;
4344682Swnj COUNT(TCP_USRSEND);
4354497Swnj 
4364497Swnj 	last = tp->snd_off;
4374584Swnj 	for (m = n = m0; m != NULL; m = m->m_next) {
4384497Swnj 		up->uc_ssize++;
4394591Swnj 		if (m->m_off > MMAXOFF)
4404588Swnj 			up->uc_ssize += NMBPG;
4414497Swnj 		last += m->m_len;
4424497Swnj 	}
4434588Swnj 	if ((m = up->uc_sbuf) == NULL)
4444588Swnj 		up->uc_sbuf = n;
4454588Swnj 	else {
4464588Swnj 		while (m->m_next != NULL) {
4474497Swnj 			m = m->m_next;
4484497Swnj 			last += m->m_len;
4494497Swnj 		}
4504591Swnj 		if (m->m_off <= MMAXOFF) {
4514588Swnj 			last += m->m_len;
4524588Swnj 			off = m->m_off + m->m_len;
4534591Swnj 			while (n && n->m_off <= MMAXOFF &&
4544591Swnj 			    (MMAXOFF - off) >= n->m_len) {
4554588Swnj 				bcopy((caddr_t)((int)n + n->m_off),
4564588Swnj 				      (caddr_t)((int)m + off), n->m_len);
4574588Swnj 				m->m_len += n->m_len;
4584588Swnj 				off += n->m_len;
4594588Swnj 				up->uc_ssize--;
4604588Swnj 				n = m_free(n);
4614588Swnj 			}
4624497Swnj 		}
4634497Swnj 		m->m_next = n;
4644588Swnj 	}
4654588Swnj 	if (up->uc_flags & UEOL)
4664497Swnj 		tp->snd_end = last;
4674588Swnj 	if (up->uc_flags & UURG) {
4684497Swnj 		tp->snd_urp = last+1;
4694576Swnj 		tp->tc_flags |= TC_SND_URG;
4704567Swnj 	}
4714678Swnj 	tcp_send(tp);
4724567Swnj 	return (SAME);
4734497Swnj }
4744497Swnj 
4754682Swnj /*
4764682Swnj  * TCP timer went off processing.
4774682Swnj  */
4784584Swnj tcp_timers(tp, timertype)
4794584Swnj 	register struct tcb *tp;
4804584Swnj 	int timertype;
4814497Swnj {
4824497Swnj 
4834567Swnj COUNT(TCP_TIMERS);
4844584Swnj 	switch (timertype) {
4854497Swnj 
4864567Swnj 	case TINIT:		/* initialization timer */
4874576Swnj 		if ((tp->tc_flags&TC_SYN_ACKED) == 0) {		/* 35 */
4884676Swnj 			tcp_close(tp, UINTIMO);
4894567Swnj 			return (CLOSED);
4904567Swnj 		}
4914567Swnj 		return (SAME);
4924497Swnj 
4934567Swnj 	case TFINACK:		/* fin-ack timer */
4944567Swnj 		switch (tp->t_state) {
4954497Swnj 
4964567Swnj 		case TIME_WAIT:
4974567Swnj 			/*
4984567Swnj 			 * We can be sure our ACK of foreign FIN was rcvd,
4994567Swnj 			 * and can close if no data left for user.
5004567Swnj 			 */
5014567Swnj 			if (rcv_empty(tp)) {
5024676Swnj 				tcp_close(tp, UCLOSED);		/* 14 */
5034567Swnj 				return (CLOSED);
5044567Swnj 			}
5054567Swnj 			return (RCV_WAIT);			/* 17 */
5064497Swnj 
507*4731Swnj 		case CLOSING:
5084576Swnj 			tp->tc_flags |= TC_WAITED_2_ML;
5094567Swnj 			return (SAME);
5104497Swnj 
5114567Swnj 		default:
5124567Swnj 			return (SAME);
5134567Swnj 		}
5144497Swnj 
5154567Swnj 	case TREXMT:		/* retransmission timer */
5164567Swnj 		if (tp->t_rexmt_val > tp->snd_una) {	 	/* 34 */
5174567Swnj 			/*
5184567Swnj 			 * Set up for a retransmission, increase rexmt time
5194567Swnj 			 * in case of multiple retransmissions.
5204567Swnj 			 */
5214567Swnj 			tp->snd_nxt = tp->snd_una;
5224576Swnj 			tp->tc_flags |= TC_REXMT;
5234567Swnj 			tp->t_xmtime = tp->t_xmtime << 1;
5244567Swnj 			if (tp->t_xmtime > T_REMAX)
5254567Swnj 				tp->t_xmtime = T_REMAX;
5264678Swnj 			tcp_send(tp);
5274567Swnj 		}
5284567Swnj 		return (SAME);
5294497Swnj 
5304567Swnj 	case TREXMTTL:		/* retransmit too long */
5314567Swnj 		if (tp->t_rtl_val > tp->snd_una)		/* 36 */
5324567Swnj 			to_user(tp->t_ucb, URXTIMO);
5334567Swnj 		/*
5344567Swnj 		 * If user has already closed, abort the connection.
5354567Swnj 		 */
5364576Swnj 		if (tp->tc_flags & TC_USR_CLOSED) {
5374676Swnj 			tcp_close(tp, URXTIMO);
5384567Swnj 			return (CLOSED);
5394567Swnj 		}
5404567Swnj 		return (SAME);
5414497Swnj 
5424567Swnj 	case TPERSIST:		/* persist timer */
5434567Swnj 		/*
5444567Swnj 		 * Force a byte send through closed window.
5454567Swnj 		 */
5464576Swnj 		tp->tc_flags |= TC_FORCE_ONE;
5474678Swnj 		tcp_send(tp);
5484567Swnj 		return (SAME);
5494567Swnj 	}
5504567Swnj 	panic("tcp_timers");
5514497Swnj }
5524497Swnj 
5534567Swnj /* THIS ROUTINE IS A CROCK */
5544567Swnj to_user(up, state)
5554567Swnj 	register struct ucb *up;
5564567Swnj 	register short state;
5574497Swnj {
5584567Swnj COUNT(TO_USER);
5594497Swnj 
5604567Swnj 	up->uc_state |= state;
5614567Swnj 	netwakeup(up);
5624567Swnj   	if (state == UURGENT)
5634567Swnj 		psignal(up->uc_proc, SIGURG);
5644497Swnj }
5654584Swnj 
5664584Swnj #ifdef TCPDEBUG
5674682Swnj /*
5684682Swnj  * TCP debugging utility subroutines.
5694682Swnj  * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID.
5704682Swnj  */
5714670Swnj tdb_setup(tp, n, input, tdp)
5724670Swnj 	struct tcb *tp;
5734670Swnj 	register struct th *n;
5744670Swnj 	int input;
5754670Swnj 	register struct tcp_debug *tdp;
5764670Swnj {
5774670Swnj 
5784682Swnj COUNT(TDB_SETUP);
5794670Swnj 	tdp->td_tod = time;
5804670Swnj 	tdp->td_tcb = tp;
5814670Swnj 	tdp->td_old = tp->t_state;
5824670Swnj 	tdp->td_inp = input;
5834670Swnj 	tdp->td_tim = 0;
5844670Swnj 	tdp->td_new = -1;
5854670Swnj 	if (n) {
5864670Swnj 		tdp->td_sno = n->t_seq;
5874670Swnj 		tdp->td_ano = n->t_ackno;
5884670Swnj 		tdp->td_wno = n->t_win;
5894670Swnj 		tdp->td_lno = n->t_len;
5904670Swnj 		tdp->td_flg = n->th_flags;
5914670Swnj 	} else
5924670Swnj 		tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno =
5934670Swnj 		    tdp->td_flg = 0;
5944670Swnj }
5954670Swnj 
5964670Swnj tdb_stuff(tdp, nstate)
5974670Swnj 	struct tcp_debug *tdp;
5984670Swnj 	int nstate;
5994670Swnj {
6004682Swnj COUNT(TDB_STUFF);
6014670Swnj 
6024670Swnj 	tdp->td_new = nstate;
6034670Swnj 	tcp_debug[tdbx++ % TDBSIZE] = *tdp;
6044670Swnj 	if (tcpconsdebug & 2)
6054670Swnj 		tcp_prt(tdp);
6064670Swnj }
6074682Swnj 
6084682Swnj tcp_prt(tdp)
6094682Swnj 	register struct tcp_debug *tdp;
6104682Swnj {
6114682Swnj COUNT(TCP_PRT);
6124682Swnj 
6134698Swnj 	printf("%x ", ((int)tdp->td_tcb)&0xffffff);
6144698Swnj 	if (tdp->td_inp == INSEND) {
6154698Swnj 		printf("SEND #%x", tdp->td_sno);
6164698Swnj 		tdp->td_lno = ntohs(tdp->td_lno);
6174698Swnj 		tdp->td_wno = ntohs(tdp->td_wno);
6184698Swnj 	} else {
6194698Swnj 		if (tdp->td_inp == INRECV)
6204698Swnj 			printf("RCV #%x ", tdp->td_sno);
6214698Swnj 		printf("%s.%s",
6224698Swnj 		    tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]);
6234698Swnj 		if (tdp->td_inp == ISTIMER)
6244698Swnj 			printf("(%s)", tcptimers[tdp->td_tim]);
6254698Swnj 		printf(" -> %s",
6264698Swnj 		    tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]);
6274698Swnj 		if (tdp->td_new == -1)
6284698Swnj 			printf(" (FAILED)");
6294698Swnj 	}
6304682Swnj 	/* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */
6314698Swnj 	if (tdp->td_lno)
6324698Swnj 		printf(" len=%d", tdp->td_lno);
6334698Swnj 	if (tdp->td_wno)
6344698Swnj 		printf(" win=%d", tdp->td_wno);
6354698Swnj 	if (tdp->td_flg & TH_FIN) printf(" FIN");
6364698Swnj 	if (tdp->td_flg & TH_SYN) printf(" SYN");
6374698Swnj 	if (tdp->td_flg & TH_RST) printf(" RST");
6384698Swnj 	if (tdp->td_flg & TH_EOL) printf(" EOL");
6394698Swnj 	if (tdp->td_flg & TH_ACK)  printf(" ACK %x", tdp->td_ano);
6404698Swnj 	if (tdp->td_flg & TH_URG) printf(" URG");
6414682Swnj 	printf("\n");
6424682Swnj }
6434670Swnj #endif
644