xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 4734)
1*4734Swnj /* tcp_usrreq.c 1.24 81/11/04 */
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 
18*4734Swnj /*
19*4734Swnj  * Tcp finite state machine entries for timer and user generated
20*4734Swnj  * requests.  These routines raise the ipl to that of the network
21*4734Swnj  * to prevent reentry.  In particluar, this requires that the software
22*4734Swnj  * clock interrupt have lower priority than the network so that
23*4734Swnj  * we can enter the network from timeout routines without improperly
24*4734Swnj  * nesting the interrupt stack.
25*4734Swnj  */
26*4734Swnj 
27*4734Swnj /*
28*4734Swnj  * Tcp protocol timeout routine called once per second.
29*4734Swnj  * Updates the timers in all active tcb's and
30*4734Swnj  * causes finite state machine actions if timers expire.
31*4734Swnj  */
324567Swnj tcp_timeo()
334497Swnj {
344567Swnj 	register struct tcb *tp;
354567Swnj 	int s = splnet();
364731Swnj 	register u_char *tmp;
374731Swnj 	register int i;
384567Swnj COUNT(TCP_TIMEO);
394497Swnj 
404567Swnj 	/*
414567Swnj 	 * Search through tcb's and update active timers.
424567Swnj 	 */
434682Swnj 	for (tp = tcb.tcb_next; tp != (struct tcb *)&tcb; tp = tp->tcb_next) {
444731Swnj 		tmp = &tp->t_init;
454731Swnj 		for (i = 0; i < TNTIMERS; i++)
464731Swnj 			if (*tmp && --*tmp == 0)
474731Swnj 				tcp_usrreq(ISTIMER, i, tp, 0);
484567Swnj 		tp->t_xmt++;
494567Swnj 	}
504664Swnj 	tcp_iss += ISSINCR;		/* increment iss */
514567Swnj 	timeout(tcp_timeo, 0, hz);      /* reschedule every second */
524567Swnj 	splx(s);
534497Swnj }
544497Swnj 
554731Swnj /*
56*4734Swnj  * Cancel all timers for tcp tp.
57*4734Swnj  */
58*4734Swnj tcp_tcancel(tp)
59*4734Swnj 	struct tcb *tp;
60*4734Swnj {
61*4734Swnj 	register u_char *tmp = &tp->t_init;
62*4734Swnj 	register int i;
63*4734Swnj 
64*4734Swnj 	for (i = 0; i < TNTIMERS; i++)
65*4734Swnj 		*tmp++ = 0;
66*4734Swnj }
67*4734Swnj 
68*4734Swnj /*
694731Swnj  * Process a TCP user request for tcp tb.  If this is a send request
704731Swnj  * then m is the mbuf chain of send data.  If this is a timer expiration
714731Swnj  * (called from the software clock routine), then timertype tells which timer.
724731Swnj  */
734731Swnj tcp_usrreq(input, timertype, tp, m)
744584Swnj 	int input, timertype;
754567Swnj 	register struct tcb *tp;
764731Swnj 	struct mbuf *m;
774497Swnj {
784567Swnj 	int s = splnet();
794567Swnj 	register int nstate;
804584Swnj #ifdef TCPDEBUG
814584Swnj 	struct tcp_debug tdb;
824584Swnj #endif
834567Swnj COUNT(TCP_USRREQ);
844497Swnj 
854567Swnj 	nstate = tp->t_state;
864576Swnj 	tp->tc_flags &= ~TC_NET_KEEP;
874731Swnj #ifdef KPROF
884567Swnj 	acounts[nstate][input]++;
894731Swnj #endif
904584Swnj #ifdef TCPDEBUG
914584Swnj 	if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
924605Swnj 		tdb_setup(tp, (struct th *)0, input, &tdb);
934584Swnj 		tdb.td_tim = timertype;
944584Swnj 	} else
954584Swnj 		tdb.td_tod = 0;
964584Swnj #endif
974731Swnj 	switch (input) {
984497Swnj 
994731Swnj 	/*
1004731Swnj 	 * Passive open.  Create a tcp control block
1014731Swnj 	 * and enter listen state.
1024731Swnj 	 */
103*4734Swnj 	case IUOPENA:
1044731Swnj 		if (nstate != 0 && nstate != CLOSED)
1054731Swnj 			goto bad;
1064676Swnj 		tcp_open(tp, PASSIVE);
1074567Swnj 		nstate = LISTEN;
1084567Swnj 		break;
1094497Swnj 
1104731Swnj 	/*
1114731Swnj 	 * Active open.  Create a tcp control block,
1124731Swnj 	 * send a SYN and enter SYN_SENT state.
1134731Swnj 	 */
114*4734Swnj 	case IUOPENR:
1154731Swnj 		if (nstate != 0 && nstate != CLOSED)
1164731Swnj 			goto bad;
1174676Swnj 		tcp_open(tp, ACTIVE);
1184676Swnj 		tcp_sndctl(tp);
1194567Swnj 		nstate = SYN_SENT;
1204567Swnj 		break;
1214497Swnj 
1224731Swnj 	/*
1234731Swnj 	 * Tcp close call.  Can be generated by a user ioctl (half-close),
1244731Swnj 	 * or when higher level close occurs, if a close hasn't happened
1254731Swnj 	 * already.
1264731Swnj 	 */
1274731Swnj 	case IUCLOSE:
1284731Swnj 		switch (nstate) {
1294497Swnj 
1304731Swnj 		/*
1314731Swnj 		 * If we are aborting out of a listener or a active
1324731Swnj 		 * connection which has not yet completed we can just
1334731Swnj 		 * delete the tcb.
1344731Swnj 		 */
1354731Swnj 		case LISTEN:
136*4734Swnj 		case SYN_SENT:
1374731Swnj 			tcp_close(tp, UCLOSED);
1384731Swnj 			nstate = CLOSED;
1394731Swnj 			break;
1404731Swnj 
1414731Swnj 		/*
1424731Swnj 		 * If we have gotten as far as receiving a syn from
1434731Swnj 		 * our foreign peer, we must be sure to send a FIN.
1444731Swnj 		 * If we have gotten a FIN from the foreign peer already
1454731Swnj 		 * (CLOSE_WAIT state), then all that remains is to wait
1464731Swnj 		 * for his ack of the FIN (LAST_ACK state).  If we have
1474731Swnj 		 * not gotten a FIN from the foreign peer then we need
1484731Swnj 		 * to either:
1494731Swnj 		 *	1. rcv ack of our FIN (to FIN_W2) and then
1504731Swnj 		 *	   send an ACK (to TIME_WAIT) and timeout at 2*MSL.
1514731Swnj 		 * or	2. receive hist FIN (to CLOSING), send an ACK
1524731Swnj 		 *	   (to TIME_WAIT), and then timeout.
1534731Swnj 		 * In any case this starts with a transition to FIN_W1 here.
1544731Swnj 		 */
155*4734Swnj 		case SYN_RCVD:
1564731Swnj 		case L_SYN_RCVD:
1574731Swnj 		case ESTAB:
158*4734Swnj 		case CLOSE_WAIT:
1594731Swnj 			tp->tc_flags |= TC_SND_FIN;
1604731Swnj 			tcp_sndctl(tp);
1614731Swnj 			tp->tc_flags |= TC_USR_CLOSED;
1624731Swnj 			nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK;
1634731Swnj 			break;
1644731Swnj 
1654731Swnj 		/*
1664731Swnj 		 * In these states the user has already closed;
1674731Swnj 		 * trying to close again is an error.
1684731Swnj 		 */
1694731Swnj 		case FIN_W1:
1704731Swnj 		case FIN_W2:
1714731Swnj 		case TIME_WAIT:
1724731Swnj 		case CLOSING:
1734731Swnj 		case LAST_ACK:
1744731Swnj 		case RCV_WAIT:
1754731Swnj 			to_user(tp->t_ucb, UCLSERR);
1764731Swnj 			break;
1774731Swnj 
1784731Swnj 		default:
1794731Swnj 			goto bad;
1804731Swnj 		}
1814567Swnj 		break;
1824497Swnj 
1834731Swnj 	/*
1844731Swnj 	 * TCP Timer processing.
1854731Swnj 	 * Timers should expire only on open connections
1864731Swnj 	 * not in LISTEN state.
1874731Swnj 	 */
188*4734Swnj 	case ISTIMER:
1894731Swnj 		switch (nstate) {
1904731Swnj 
1914731Swnj 		case 0:
1924731Swnj 		case CLOSED:
1934731Swnj 		case LISTEN:
1944731Swnj 			goto bad;
1954731Swnj 
1964731Swnj 		default:
1974731Swnj 			nstate = tcp_timers(tp, timertype);
1984731Swnj 		}
1994567Swnj 		break;
2004497Swnj 
2014731Swnj 	/*
2024731Swnj 	 * User notification of more window availability after
2034731Swnj 	 * reading out data.  This should not happen before a connection
2044731Swnj 	 * is established or after it is closed.
2054731Swnj 	 * If the foreign peer has closed and the local entity
2064731Swnj 	 * has not, inform him of the FIN (give end of file).
2074731Swnj 	 * If the local entity is in RCV_WAIT state (draining data
2084731Swnj 	 * out of the TCP buffers after foreign close) and there
2094731Swnj 	 * is no more data, institute a close.
2104731Swnj 	 */
211*4734Swnj 	case IURECV:
2124731Swnj 		if (nstate < ESTAB || nstate == CLOSED)
2134731Swnj 			goto bad;
214*4734Swnj 		tcp_sndwin(tp);
2154691Swnj 		if ((tp->tc_flags&TC_FIN_RCVD) &&
2164691Swnj 		    (tp->tc_flags&TC_USR_CLOSED) == 0 &&
2174691Swnj 		    rcv_empty(tp))
2184691Swnj 			to_user(tp, UCLOSED);
2194731Swnj 		if (nstate == RCV_WAIT && rcv_empty(tp)) {
2204676Swnj 			tcp_close(tp, UCLOSED);
2214567Swnj 			nstate = CLOSED;
2224731Swnj 		}
2234567Swnj 		break;
2244497Swnj 
2254731Swnj 	/*
2264731Swnj 	 * Send request on open connection.
2274731Swnj 	 * Should not happen if the connection is not yet established.
2284731Swnj 	 * Allowed only on ESTAB connection and after FIN from
2294731Swnj 	 * foreign peer.
2304731Swnj 	 */
231*4734Swnj 	case IUSEND:
2324731Swnj 		switch (nstate) {
2334567Swnj 
2344731Swnj 		case ESTAB:
2354731Swnj 		case CLOSE_WAIT:
2364731Swnj 			nstate = tcp_usrsend(tp, m);
2374731Swnj 			break;
2384731Swnj 
2394731Swnj 		default:
2404731Swnj 			if (nstate < ESTAB)
2414731Swnj 				goto bad;
2424731Swnj 			to_user(tp, UCLSERR);
2434731Swnj 			break;
2444731Swnj 		}
2454567Swnj 		break;
2464567Swnj 
2474731Swnj 	/*
2484731Swnj 	 * User abort of connection.
2494731Swnj 	 * If a SYN has been received, but we have not exchanged FINs
2504731Swnj 	 * then we need to send an RST.  In any case we then
2514731Swnj 	 * enter closed state.
2524731Swnj 	 */
253*4734Swnj 	case IUABORT:
2544731Swnj 		if (nstate == 0 || nstate == CLOSED)
2554731Swnj 			break;
2564731Swnj 		switch (nstate) {
2574567Swnj 
2584731Swnj 		case 0:
2594731Swnj 		case CLOSED:
2604731Swnj 			break;
2614567Swnj 
2624731Swnj 		case SYN_RCVD:
2634731Swnj 		case ESTAB:
2644731Swnj 		case FIN_W1:
2654731Swnj 		case FIN_W2:
2664731Swnj 		case CLOSE_WAIT:
2674731Swnj 			tp->tc_flags |= TC_SND_RST;
2684731Swnj 			tcp_sndnull(tp);
2694731Swnj 			/* fall into ... */
2704731Swnj 
2714731Swnj 		default:
2724731Swnj 			tcp_close(tp, UABORT);
2734731Swnj 			nstate = CLOSED;
2744731Swnj 		}
2754567Swnj 		break;
2764567Swnj 
2774731Swnj 	/*
2784731Swnj 	 * Network down entry.  Discard the tcb and force
2794731Swnj 	 * the state to be closed, ungracefully.
2804731Swnj 	 */
281*4734Swnj 	case INCLEAR:
2824731Swnj 		if (nstate == 0 || nstate == CLOSED)
2834731Swnj 			break;
2844676Swnj 		tcp_close(tp, UNETDWN);
2854567Swnj 		nstate = CLOSED;
2864567Swnj 		break;
2874567Swnj 
2884731Swnj 	default:
2894731Swnj 		panic("tcp_usrreq");
2904731Swnj 	bad:
2914731Swnj 		printf("tcp: bad state: tcb=%x state=%d input=%d\n",
2924731Swnj 		    tp, tp->t_state, input);
2934731Swnj 		nstate = EFAILEC;
2944567Swnj 		break;
2954567Swnj 	}
2964567Swnj #ifdef TCPDEBUG
2974605Swnj 	if (tdb.td_tod)
2984605Swnj 		tdb_stuff(&tdb, nstate);
2994567Swnj #endif
3004567Swnj 	/* YECH */
3014567Swnj 	switch (nstate) {
3024567Swnj 
3034584Swnj 	case CLOSED:
3044567Swnj 	case SAME:
3054567Swnj 		break;
3064567Swnj 
3074567Swnj 	case EFAILEC:
3084731Swnj 		if (m)
3094731Swnj 			m_freem(dtom(m));
3104567Swnj 		break;
3114567Swnj 
3124567Swnj 	default:
3134567Swnj 		tp->t_state = nstate;
3144567Swnj 		break;
3154567Swnj 	}
3164567Swnj 	splx(s);
3174497Swnj }
3184497Swnj 
3194682Swnj /*
3204682Swnj  * Open routine, called to initialize newly created tcb fields.
3214682Swnj  */
3224682Swnj tcp_open(tp, mode)
3234567Swnj 	register struct tcb *tp;
3244567Swnj 	int mode;
3254497Swnj {
3264682Swnj 	register struct ucb *up = tp->t_ucb;
3274682Swnj COUNT(TCP_OPEN);
3284497Swnj 
3294682Swnj 	/*
3304682Swnj 	 * Link in tcb queue and make
3314682Swnj 	 * initialize empty reassembly queue.
3324682Swnj 	 */
3334682Swnj 	tp->tcb_next = tcb.tcb_next;
3344682Swnj 	tcb.tcb_next->tcb_prev = tp;
3354682Swnj 	tp->tcb_prev = (struct tcb *)&tcb;
3364682Swnj 	tcb.tcb_next = tp;
3374682Swnj 	tp->t_rcv_next = tp->t_rcv_prev = (struct th *)tp;
3384497Swnj 
3394682Swnj 	/*
3404682Swnj 	 * Initialize sequence numbers and
3414682Swnj 	 * round trip retransmit timer.
3424682Swnj 	 * (Other fields were init'd to zero when tcb allocated.)
3434682Swnj 	 */
3444567Swnj 	tp->t_xmtime = T_REXMT;
3454682Swnj 	tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una =
3464682Swnj 	    tp->iss = tcp_iss;
3474567Swnj 	tp->snd_off = tp->iss + 1;
3484664Swnj 	tcp_iss += (ISSINCR >> 1) + 1;
3494567Swnj 
3504682Swnj 	/*
3514682Swnj 	 * Set timeout for open.
3524682Swnj 	 * SHOULD THIS BE A HIGHER LEVEL FUNCTION!?! THINK SO.
3534682Swnj 	 */
3544682Swnj 	if (up->uc_timeo)
3554682Swnj 		tp->t_init = up->uc_timeo;
3564682Swnj 	else if (mode == ACTIVE)
3574682Swnj 		tp->t_init = T_INIT;
3584682Swnj 	/* else
3594682Swnj 		tp->t_init = 0; */
3604682Swnj 	up->uc_timeo = 0;				/* ### */
3614497Swnj }
3624497Swnj 
3634682Swnj /*
3644682Swnj  * Internal close of a connection, shutting down the tcb.
3654682Swnj  */
3664676Swnj tcp_close(tp, state)
3674567Swnj 	register struct tcb *tp;
3684567Swnj 	short state;
3694497Swnj {
3704682Swnj 	register struct ucb *up = tp->t_ucb;
3714567Swnj 	register struct th *t;
3724567Swnj 	register struct mbuf *m;
3734682Swnj COUNT(TCP_CLOSE);
3744497Swnj 
3754682Swnj 	/*
376*4734Swnj 	 * Remove from tcb queue and cancel timers.
3774682Swnj 	 */
3784682Swnj 	tp->tcb_prev->tcb_next = tp->tcb_next;
3794682Swnj 	tp->tcb_next->tcb_prev = tp->tcb_prev;
380*4734Swnj 	tcp_tcancel(tp);
3814567Swnj 
3824682Swnj 	/*
383*4734Swnj 	 * Discard all buffers.
3844682Swnj 	 */
3854567Swnj 	for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next)
3864567Swnj 		m_freem(dtom(t));
387*4734Swnj 	if (up->uc_rbuf) {
3884567Swnj 		m_freem(up->uc_rbuf);
3894567Swnj 		up->uc_rbuf = NULL;
3904567Swnj 	}
3914657Swnj 	up->uc_rcc = 0;
392*4734Swnj 	if (up->uc_sbuf) {
3934567Swnj 		m_freem(up->uc_sbuf);
3944567Swnj 		up->uc_sbuf = NULL;
3954567Swnj 	}
3964592Swnj 	up->uc_ssize = 0;
3974567Swnj 	for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) {
3984567Swnj 		m_freem(m);
3994567Swnj 		tp->t_rcv_unack = NULL;
4004567Swnj 	}
4014682Swnj 
4024682Swnj 	/*
403*4734Swnj 	 * Free tcp send template, the tcb itself,
404*4734Swnj 	 * the routing table entry, and the space we had reserved
405*4734Swnj 	 * in the meory pool.
4064682Swnj 	 */
407*4734Swnj 	if (tp->t_template) {
408*4734Swnj 		m_free(dtom(tp->t_template));
409*4734Swnj 		tp->t_template = 0;
4104664Swnj 	}
4114670Swnj 	wmemfree((caddr_t)tp, 1024);
412*4734Swnj 	up->uc_pcb = 0;
413*4734Swnj 	if (up->uc_host) {
4144567Swnj 		h_free(up->uc_host);
415*4734Swnj 		up->uc_host = 0;
4164567Swnj 	}
417*4734Swnj 	m_release(up->uc_snd + (up->uc_rhiwat/MSIZE) + 2);
4184567Swnj 
4194682Swnj 	/*
4204682Swnj 	 * If user has initiated close (via close call), delete ucb
4214682Swnj 	 * entry, otherwise just wakeup so user can issue close call
4224682Swnj 	 */
423*4734Swnj 	if (tp->tc_flags&TC_USR_ABORT)			/* ### */
424*4734Swnj         	up->uc_proc = NULL;			/* ### */
425*4734Swnj 	else						/* ### */
4264682Swnj         	to_user(up, state);			/* ### */
4274497Swnj }
4284497Swnj 
4294682Swnj /*
430*4734Swnj  * Send data queue headed by m0 into the protocol.
4314682Swnj  */
4324678Swnj tcp_usrsend(tp, m0)
4334584Swnj 	register struct tcb *tp;
4344584Swnj 	struct mbuf *m0;
4354497Swnj {
4364497Swnj 	register struct mbuf *m, *n;
4374584Swnj 	register struct ucb *up = tp->t_ucb;
4384497Swnj 	register off;
4394574Swnj 	seq_t last;
4404682Swnj COUNT(TCP_USRSEND);
4414497Swnj 
4424497Swnj 	last = tp->snd_off;
4434584Swnj 	for (m = n = m0; m != NULL; m = m->m_next) {
4444497Swnj 		up->uc_ssize++;
4454591Swnj 		if (m->m_off > MMAXOFF)
4464588Swnj 			up->uc_ssize += NMBPG;
4474497Swnj 		last += m->m_len;
4484497Swnj 	}
4494588Swnj 	if ((m = up->uc_sbuf) == NULL)
4504588Swnj 		up->uc_sbuf = n;
4514588Swnj 	else {
4524588Swnj 		while (m->m_next != NULL) {
4534497Swnj 			m = m->m_next;
4544497Swnj 			last += m->m_len;
4554497Swnj 		}
4564591Swnj 		if (m->m_off <= MMAXOFF) {
4574588Swnj 			last += m->m_len;
4584588Swnj 			off = m->m_off + m->m_len;
4594591Swnj 			while (n && n->m_off <= MMAXOFF &&
4604591Swnj 			    (MMAXOFF - off) >= n->m_len) {
4614588Swnj 				bcopy((caddr_t)((int)n + n->m_off),
4624588Swnj 				      (caddr_t)((int)m + off), n->m_len);
4634588Swnj 				m->m_len += n->m_len;
4644588Swnj 				off += n->m_len;
4654588Swnj 				up->uc_ssize--;
4664588Swnj 				n = m_free(n);
4674588Swnj 			}
4684497Swnj 		}
4694497Swnj 		m->m_next = n;
4704588Swnj 	}
4714588Swnj 	if (up->uc_flags & UEOL)
4724497Swnj 		tp->snd_end = last;
4734588Swnj 	if (up->uc_flags & UURG) {
4744497Swnj 		tp->snd_urp = last+1;
4754576Swnj 		tp->tc_flags |= TC_SND_URG;
4764567Swnj 	}
4774678Swnj 	tcp_send(tp);
4784567Swnj 	return (SAME);
4794497Swnj }
4804497Swnj 
4814682Swnj /*
4824682Swnj  * TCP timer went off processing.
4834682Swnj  */
4844584Swnj tcp_timers(tp, timertype)
4854584Swnj 	register struct tcb *tp;
4864584Swnj 	int timertype;
4874497Swnj {
4884497Swnj 
4894567Swnj COUNT(TCP_TIMERS);
4904584Swnj 	switch (timertype) {
4914497Swnj 
4924567Swnj 	case TINIT:		/* initialization timer */
4934576Swnj 		if ((tp->tc_flags&TC_SYN_ACKED) == 0) {		/* 35 */
4944676Swnj 			tcp_close(tp, UINTIMO);
4954567Swnj 			return (CLOSED);
4964567Swnj 		}
4974567Swnj 		return (SAME);
4984497Swnj 
4994567Swnj 	case TFINACK:		/* fin-ack timer */
5004567Swnj 		switch (tp->t_state) {
5014497Swnj 
5024567Swnj 		case TIME_WAIT:
5034567Swnj 			/*
5044567Swnj 			 * We can be sure our ACK of foreign FIN was rcvd,
5054567Swnj 			 * and can close if no data left for user.
5064567Swnj 			 */
5074567Swnj 			if (rcv_empty(tp)) {
5084676Swnj 				tcp_close(tp, UCLOSED);		/* 14 */
5094567Swnj 				return (CLOSED);
5104567Swnj 			}
5114567Swnj 			return (RCV_WAIT);			/* 17 */
5124497Swnj 
5134731Swnj 		case CLOSING:
5144576Swnj 			tp->tc_flags |= TC_WAITED_2_ML;
5154567Swnj 			return (SAME);
5164497Swnj 
5174567Swnj 		default:
5184567Swnj 			return (SAME);
5194567Swnj 		}
5204497Swnj 
5214567Swnj 	case TREXMT:		/* retransmission timer */
5224567Swnj 		if (tp->t_rexmt_val > tp->snd_una) {	 	/* 34 */
5234567Swnj 			/*
5244567Swnj 			 * Set up for a retransmission, increase rexmt time
5254567Swnj 			 * in case of multiple retransmissions.
5264567Swnj 			 */
5274567Swnj 			tp->snd_nxt = tp->snd_una;
5284576Swnj 			tp->tc_flags |= TC_REXMT;
5294567Swnj 			tp->t_xmtime = tp->t_xmtime << 1;
5304567Swnj 			if (tp->t_xmtime > T_REMAX)
5314567Swnj 				tp->t_xmtime = T_REMAX;
5324678Swnj 			tcp_send(tp);
5334567Swnj 		}
5344567Swnj 		return (SAME);
5354497Swnj 
5364567Swnj 	case TREXMTTL:		/* retransmit too long */
5374567Swnj 		if (tp->t_rtl_val > tp->snd_una)		/* 36 */
5384567Swnj 			to_user(tp->t_ucb, URXTIMO);
5394567Swnj 		/*
5404567Swnj 		 * If user has already closed, abort the connection.
5414567Swnj 		 */
5424576Swnj 		if (tp->tc_flags & TC_USR_CLOSED) {
5434676Swnj 			tcp_close(tp, URXTIMO);
5444567Swnj 			return (CLOSED);
5454567Swnj 		}
5464567Swnj 		return (SAME);
5474497Swnj 
5484567Swnj 	case TPERSIST:		/* persist timer */
5494567Swnj 		/*
5504567Swnj 		 * Force a byte send through closed window.
5514567Swnj 		 */
5524576Swnj 		tp->tc_flags |= TC_FORCE_ONE;
5534678Swnj 		tcp_send(tp);
5544567Swnj 		return (SAME);
5554567Swnj 	}
5564567Swnj 	panic("tcp_timers");
5574497Swnj }
5584497Swnj 
5594567Swnj /* THIS ROUTINE IS A CROCK */
5604567Swnj to_user(up, state)
5614567Swnj 	register struct ucb *up;
5624567Swnj 	register short state;
5634497Swnj {
5644567Swnj COUNT(TO_USER);
5654497Swnj 
5664567Swnj 	up->uc_state |= state;
5674567Swnj 	netwakeup(up);
5684567Swnj   	if (state == UURGENT)
5694567Swnj 		psignal(up->uc_proc, SIGURG);
5704497Swnj }
5714584Swnj 
5724584Swnj #ifdef TCPDEBUG
5734682Swnj /*
5744682Swnj  * TCP debugging utility subroutines.
5754682Swnj  * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID.
5764682Swnj  */
5774670Swnj tdb_setup(tp, n, input, tdp)
5784670Swnj 	struct tcb *tp;
5794670Swnj 	register struct th *n;
5804670Swnj 	int input;
5814670Swnj 	register struct tcp_debug *tdp;
5824670Swnj {
5834670Swnj 
5844682Swnj COUNT(TDB_SETUP);
5854670Swnj 	tdp->td_tod = time;
5864670Swnj 	tdp->td_tcb = tp;
5874670Swnj 	tdp->td_old = tp->t_state;
5884670Swnj 	tdp->td_inp = input;
5894670Swnj 	tdp->td_tim = 0;
5904670Swnj 	tdp->td_new = -1;
5914670Swnj 	if (n) {
5924670Swnj 		tdp->td_sno = n->t_seq;
5934670Swnj 		tdp->td_ano = n->t_ackno;
5944670Swnj 		tdp->td_wno = n->t_win;
5954670Swnj 		tdp->td_lno = n->t_len;
5964670Swnj 		tdp->td_flg = n->th_flags;
5974670Swnj 	} else
5984670Swnj 		tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno =
5994670Swnj 		    tdp->td_flg = 0;
6004670Swnj }
6014670Swnj 
6024670Swnj tdb_stuff(tdp, nstate)
6034670Swnj 	struct tcp_debug *tdp;
6044670Swnj 	int nstate;
6054670Swnj {
6064682Swnj COUNT(TDB_STUFF);
6074670Swnj 
6084670Swnj 	tdp->td_new = nstate;
6094670Swnj 	tcp_debug[tdbx++ % TDBSIZE] = *tdp;
6104670Swnj 	if (tcpconsdebug & 2)
6114670Swnj 		tcp_prt(tdp);
6124670Swnj }
6134682Swnj 
6144682Swnj tcp_prt(tdp)
6154682Swnj 	register struct tcp_debug *tdp;
6164682Swnj {
6174682Swnj COUNT(TCP_PRT);
6184682Swnj 
6194698Swnj 	printf("%x ", ((int)tdp->td_tcb)&0xffffff);
6204698Swnj 	if (tdp->td_inp == INSEND) {
6214698Swnj 		printf("SEND #%x", tdp->td_sno);
6224698Swnj 		tdp->td_lno = ntohs(tdp->td_lno);
6234698Swnj 		tdp->td_wno = ntohs(tdp->td_wno);
6244698Swnj 	} else {
6254698Swnj 		if (tdp->td_inp == INRECV)
6264698Swnj 			printf("RCV #%x ", tdp->td_sno);
6274698Swnj 		printf("%s.%s",
6284698Swnj 		    tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]);
6294698Swnj 		if (tdp->td_inp == ISTIMER)
6304698Swnj 			printf("(%s)", tcptimers[tdp->td_tim]);
6314698Swnj 		printf(" -> %s",
6324698Swnj 		    tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]);
6334698Swnj 		if (tdp->td_new == -1)
6344698Swnj 			printf(" (FAILED)");
6354698Swnj 	}
6364682Swnj 	/* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */
6374698Swnj 	if (tdp->td_lno)
6384698Swnj 		printf(" len=%d", tdp->td_lno);
6394698Swnj 	if (tdp->td_wno)
6404698Swnj 		printf(" win=%d", tdp->td_wno);
6414698Swnj 	if (tdp->td_flg & TH_FIN) printf(" FIN");
6424698Swnj 	if (tdp->td_flg & TH_SYN) printf(" SYN");
6434698Swnj 	if (tdp->td_flg & TH_RST) printf(" RST");
6444698Swnj 	if (tdp->td_flg & TH_EOL) printf(" EOL");
6454698Swnj 	if (tdp->td_flg & TH_ACK)  printf(" ACK %x", tdp->td_ano);
6464698Swnj 	if (tdp->td_flg & TH_URG) printf(" URG");
6474682Swnj 	printf("\n");
6484682Swnj }
6494670Swnj #endif
650