xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 4698)
1*4698Swnj /* tcp_usrreq.c 1.22 81/10/31 */
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();
224567Swnj COUNT(TCP_TIMEO);
234497Swnj 
244567Swnj 	/*
254567Swnj 	 * Search through tcb's and update active timers.
264567Swnj 	 */
274682Swnj 	for (tp = tcb.tcb_next; tp != (struct tcb *)&tcb; tp = tp->tcb_next) {
284567Swnj 		if (tp->t_init != 0 && --tp->t_init == 0)
294567Swnj 			tcp_usrreq(ISTIMER, TINIT, tp, 0);
304567Swnj 		if (tp->t_rexmt != 0 && --tp->t_rexmt == 0)
314567Swnj 			tcp_usrreq(ISTIMER, TREXMT, tp, 0);
324567Swnj 		if (tp->t_rexmttl != 0 && --tp->t_rexmttl == 0)
334567Swnj 			tcp_usrreq(ISTIMER, TREXMTTL, tp, 0);
344567Swnj 		if (tp->t_persist != 0 && --tp->t_persist == 0)
354567Swnj 			tcp_usrreq(ISTIMER, TPERSIST, tp, 0);
364567Swnj 		if (tp->t_finack != 0 && --tp->t_finack == 0)
374567Swnj 			tcp_usrreq(ISTIMER, TFINACK, tp, 0);
384567Swnj 		tp->t_xmt++;
394567Swnj 	}
404664Swnj 	tcp_iss += ISSINCR;		/* increment iss */
414567Swnj 	timeout(tcp_timeo, 0, hz);      /* reschedule every second */
424567Swnj 	splx(s);
434497Swnj }
444497Swnj 
454584Swnj tcp_usrreq(input, timertype, tp, mp)
464584Swnj 	int input, timertype;
474567Swnj 	register struct tcb *tp;
484584Swnj 	struct mbuf *mp;
494497Swnj {
504567Swnj 	int s = splnet();
514567Swnj 	register int nstate;
524584Swnj #ifdef TCPDEBUG
534584Swnj 	struct tcp_debug tdb;
544584Swnj #endif
554567Swnj COUNT(TCP_USRREQ);
564497Swnj 
574567Swnj 	nstate = tp->t_state;
584576Swnj 	tp->tc_flags &= ~TC_NET_KEEP;
594567Swnj 	acounts[nstate][input]++;
604584Swnj #ifdef TCPDEBUG
614584Swnj 	if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
624605Swnj 		tdb_setup(tp, (struct th *)0, input, &tdb);
634584Swnj 		tdb.td_tim = timertype;
644584Swnj 	} else
654584Swnj 		tdb.td_tod = 0;
664584Swnj #endif
674567Swnj 	switch (tcp_fstab[nstate][input]) {
684497Swnj 
694567Swnj 	default:
704567Swnj 		printf("tcp: bad state: tcb=%x state=%d input=%d\n",
714567Swnj 		    tp, tp->t_state, input);
724567Swnj 		nstate = EFAILEC;
734567Swnj 		break;
744497Swnj 
754567Swnj 	case LIS_CLS:				/* 1 */
764676Swnj 		tcp_open(tp, PASSIVE);
774567Swnj 		nstate = LISTEN;
784567Swnj 		break;
794497Swnj 
804567Swnj 	case SYS_CLS:				/* 2 */
814676Swnj 		tcp_open(tp, ACTIVE);
824676Swnj 		tcp_sndctl(tp);
834567Swnj 		nstate = SYN_SENT;
844567Swnj 		break;
854497Swnj 
864567Swnj 	case CLS_OPN:				/* 10 */
874676Swnj 		tcp_close(tp, UCLOSED);
884567Swnj 		nstate = CLOSED;
894567Swnj 		break;
904497Swnj 
914567Swnj 	case CL2_CLW:				/* 10 */
924576Swnj 		tp->tc_flags |= TC_SND_FIN;
934676Swnj 		tcp_sndctl(tp);
944576Swnj 		tp->tc_flags |= TC_USR_CLOSED;
954567Swnj 		nstate = CLOSING2;
964567Swnj 		break;
974497Swnj 
984567Swnj 	case TIMERS:				/* 14,17,34,35,36,37,38 */
994584Swnj 		nstate = tcp_timers(tp, timertype);
1004567Swnj 		break;
1014497Swnj 
1024567Swnj 	case CLS_RWT:				/* 20 */
1034691Swnj 		if ((tp->tc_flags&TC_FIN_RCVD) &&
1044691Swnj 		    (tp->tc_flags&TC_USR_CLOSED) == 0 &&
1054691Swnj 		    rcv_empty(tp))
1064691Swnj 			to_user(tp, UCLOSED);
1074567Swnj 		if (rcv_empty(tp)) {
1084676Swnj 			tcp_close(tp, UCLOSED);
1094567Swnj 			nstate = CLOSED;
1104567Swnj 		} else
1114567Swnj 			nstate = RCV_WAIT;
1124567Swnj 		break;
1134497Swnj 
1144567Swnj 	case FW1_SYR:				/* 24,25 */
1154576Swnj 		tp->tc_flags |= TC_SND_FIN;
1164676Swnj 		tcp_sndctl(tp);
1174576Swnj 		tp->tc_flags |= TC_USR_CLOSED;
1184567Swnj 		nstate = FIN_W1;
1194567Swnj 		break;
1204567Swnj 
1214567Swnj 	case SSS_SND:				/* 40,41 */
1224678Swnj 		nstate = tcp_usrsend(tp, mp);
1234567Swnj 		break;
1244567Swnj 
1254567Swnj 	case SSS_RCV:				/* 42 */
1264676Swnj 		tcp_sndwin(tp);		/* send new window */
1274691Swnj 		if ((tp->tc_flags&TC_FIN_RCVD) &&
1284691Swnj 		    (tp->tc_flags&TC_USR_CLOSED) == 0 &&
1294691Swnj 		    rcv_empty(tp))
1304691Swnj 			to_user(tp, UCLOSED);
1314567Swnj 		break;
1324567Swnj 
1334567Swnj 	case CLS_NSY:				/* 44 */
1344676Swnj 		tcp_close(tp, UABORT);
1354567Swnj 		nstate = CLOSED;
1364567Swnj 		break;
1374567Swnj 
1384567Swnj 	case CLS_SYN:				/* 45 */
1394576Swnj 		tp->tc_flags |= TC_SND_RST;
1404676Swnj 		tcp_sndnull(tp);
1414676Swnj 		tcp_close(tp, UABORT);
1424567Swnj 		nstate = CLOSED;
1434567Swnj 		break;
1444567Swnj 
1454567Swnj 	case CLS_ACT:				/* 47 */
1464676Swnj 		tcp_close(tp, UNETDWN);
1474567Swnj 		nstate = CLOSED;
1484567Swnj 		break;
1494567Swnj 
1504567Swnj 	case NOP:
1514567Swnj 		break;
1524567Swnj 
1534567Swnj 	case CLS_ERR:
1544567Swnj 		to_user(tp->t_ucb, UCLSERR);
1554567Swnj 		break;
1564567Swnj 	}
1574567Swnj #ifdef TCPDEBUG
1584605Swnj 	if (tdb.td_tod)
1594605Swnj 		tdb_stuff(&tdb, nstate);
1604567Swnj #endif
1614567Swnj 	/* YECH */
1624567Swnj 	switch (nstate) {
1634567Swnj 
1644584Swnj 	case CLOSED:
1654567Swnj 	case SAME:
1664567Swnj 		break;
1674567Swnj 
1684567Swnj 	case EFAILEC:
1694584Swnj 		if (mp)
1704584Swnj 			m_freem(dtom(mp));
1714567Swnj 		break;
1724567Swnj 
1734567Swnj 	default:
1744567Swnj 		tp->t_state = nstate;
1754567Swnj 		break;
1764567Swnj 	}
1774567Swnj 	splx(s);
1784497Swnj }
1794497Swnj 
1804682Swnj /*
1814682Swnj  * Open routine, called to initialize newly created tcb fields.
1824682Swnj  */
1834682Swnj tcp_open(tp, mode)
1844567Swnj 	register struct tcb *tp;
1854567Swnj 	int mode;
1864497Swnj {
1874682Swnj 	register struct ucb *up = tp->t_ucb;
1884682Swnj COUNT(TCP_OPEN);
1894497Swnj 
1904682Swnj 	/*
1914682Swnj 	 * Link in tcb queue and make
1924682Swnj 	 * initialize empty reassembly queue.
1934682Swnj 	 */
1944682Swnj 	tp->tcb_next = tcb.tcb_next;
1954682Swnj 	tcb.tcb_next->tcb_prev = tp;
1964682Swnj 	tp->tcb_prev = (struct tcb *)&tcb;
1974682Swnj 	tcb.tcb_next = tp;
1984682Swnj 	tp->t_rcv_next = tp->t_rcv_prev = (struct th *)tp;
1994497Swnj 
2004682Swnj 	/*
2014682Swnj 	 * Initialize sequence numbers and
2024682Swnj 	 * round trip retransmit timer.
2034682Swnj 	 * (Other fields were init'd to zero when tcb allocated.)
2044682Swnj 	 */
2054567Swnj 	tp->t_xmtime = T_REXMT;
2064682Swnj 	tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una =
2074682Swnj 	    tp->iss = tcp_iss;
2084567Swnj 	tp->snd_off = tp->iss + 1;
2094664Swnj 	tcp_iss += (ISSINCR >> 1) + 1;
2104567Swnj 
2114682Swnj 	/*
2124682Swnj 	 * Set timeout for open.
2134682Swnj 	 * SHOULD THIS BE A HIGHER LEVEL FUNCTION!?! THINK SO.
2144682Swnj 	 */
2154682Swnj 	if (up->uc_timeo)
2164682Swnj 		tp->t_init = up->uc_timeo;
2174682Swnj 	else if (mode == ACTIVE)
2184682Swnj 		tp->t_init = T_INIT;
2194682Swnj 	/* else
2204682Swnj 		tp->t_init = 0; */
2214682Swnj 	up->uc_timeo = 0;				/* ### */
2224497Swnj }
2234497Swnj 
2244682Swnj /*
2254682Swnj  * Internal close of a connection, shutting down the tcb.
2264682Swnj  */
2274676Swnj tcp_close(tp, state)
2284567Swnj 	register struct tcb *tp;
2294567Swnj 	short state;
2304497Swnj {
2314682Swnj 	register struct ucb *up = tp->t_ucb;
2324567Swnj 	register struct th *t;
2334567Swnj 	register struct mbuf *m;
2344682Swnj COUNT(TCP_CLOSE);
2354497Swnj 
2364682Swnj 	/*
2374682Swnj 	 * Cancel all timers.
2384682Swnj 	 * SHOULD LOOP HERE !?!
2394682Swnj 	 */
2404567Swnj 	tp->t_init = tp->t_rexmt = tp->t_rexmttl = tp->t_persist =
2414567Swnj 	    tp->t_finack = 0;
2424497Swnj 
2434682Swnj 	/*
2444682Swnj 	 * Remque the tcb
2454682Swnj 	 */
2464682Swnj 	tp->tcb_prev->tcb_next = tp->tcb_next;
2474682Swnj 	tp->tcb_next->tcb_prev = tp->tcb_prev;
2484567Swnj 
2494682Swnj 	/*
2504682Swnj 	 * Discard all buffers...
2514682Swnj 	 *
2524682Swnj 	 * SHOULD COUNT EACH RESOURCE TO 0 AND PANIC IF CONFUSED
2534682Swnj 	 */
2544567Swnj 	for (t = tp->t_rcv_next; t != (struct th *)tp; t = t->t_next)
2554567Swnj 		m_freem(dtom(t));
2564567Swnj 	if (up->uc_rbuf != NULL) {
2574567Swnj 		m_freem(up->uc_rbuf);
2584567Swnj 		up->uc_rbuf = NULL;
2594567Swnj 	}
2604657Swnj 	up->uc_rcc = 0;
2614567Swnj 	if (up->uc_sbuf != NULL) {
2624567Swnj 		m_freem(up->uc_sbuf);
2634567Swnj 		up->uc_sbuf = NULL;
2644567Swnj 	}
2654592Swnj 	up->uc_ssize = 0;
2664567Swnj 	for (m = tp->t_rcv_unack; m != NULL; m = m->m_act) {
2674567Swnj 		m_freem(m);
2684567Swnj 		tp->t_rcv_unack = NULL;
2694567Swnj 	}
2704682Swnj 
2714682Swnj 	/*
2724682Swnj 	 * Free tcp send template.
2734682Swnj 	 */
2744664Swnj 	if (up->uc_template) {
2754664Swnj 		m_free(dtom(up->uc_template));
2764664Swnj 		up->uc_template = 0;
2774664Swnj 	}
2784682Swnj 
2794682Swnj 	/*
2804682Swnj 	 * Free the tcb
2814682Swnj 	 * WOULD THIS BETTER BE DONE AT USER CLOSE?
2824682Swnj 	 */
2834670Swnj 	wmemfree((caddr_t)tp, 1024);
2844567Swnj 	up->uc_tcb = NULL;
2854567Swnj 
2864682Swnj 	/*
2874682Swnj 	 * Lower buffer allocation.
2884682Swnj 	 * SHOULD BE A M_ROUTINE CALL.
2894682Swnj 	 */
2904664Swnj 	mbstat.m_lowat -= up->uc_snd + (up->uc_rhiwat/MSIZE) + 2;
2914664Swnj 	mbstat.m_hiwat = 2 * mbstat.m_lowat;
2924682Swnj 
2934682Swnj 	/*
2944682Swnj 	 * Free routing table entry.
2954682Swnj 	 */
2964567Swnj 	if (up->uc_host != NULL) {
2974567Swnj 		h_free(up->uc_host);
2984567Swnj 		up->uc_host = NULL;
2994567Swnj 	}
3004567Swnj 
3014682Swnj 	/*
3024682Swnj 	 * If user has initiated close (via close call), delete ucb
3034682Swnj 	 * entry, otherwise just wakeup so user can issue close call
3044682Swnj 	 */
3054576Swnj 	if (tp->tc_flags&TC_USR_ABORT)
3064567Swnj         	up->uc_proc = NULL;
3074567Swnj 	else
3084682Swnj         	to_user(up, state);			/* ### */
3094497Swnj }
3104497Swnj 
3114682Swnj /*
3124682Swnj  * User routine to send data queue headed by m0 into the protocol.
3134682Swnj  */
3144678Swnj tcp_usrsend(tp, m0)
3154584Swnj 	register struct tcb *tp;
3164584Swnj 	struct mbuf *m0;
3174497Swnj {
3184497Swnj 	register struct mbuf *m, *n;
3194584Swnj 	register struct ucb *up = tp->t_ucb;
3204497Swnj 	register off;
3214574Swnj 	seq_t last;
3224682Swnj COUNT(TCP_USRSEND);
3234497Swnj 
3244497Swnj 	last = tp->snd_off;
3254584Swnj 	for (m = n = m0; m != NULL; m = m->m_next) {
3264497Swnj 		up->uc_ssize++;
3274591Swnj 		if (m->m_off > MMAXOFF)
3284588Swnj 			up->uc_ssize += NMBPG;
3294497Swnj 		last += m->m_len;
3304497Swnj 	}
3314588Swnj 	if ((m = up->uc_sbuf) == NULL)
3324588Swnj 		up->uc_sbuf = n;
3334588Swnj 	else {
3344588Swnj 		while (m->m_next != NULL) {
3354497Swnj 			m = m->m_next;
3364497Swnj 			last += m->m_len;
3374497Swnj 		}
3384591Swnj 		if (m->m_off <= MMAXOFF) {
3394588Swnj 			last += m->m_len;
3404588Swnj 			off = m->m_off + m->m_len;
3414591Swnj 			while (n && n->m_off <= MMAXOFF &&
3424591Swnj 			    (MMAXOFF - off) >= n->m_len) {
3434588Swnj 				bcopy((caddr_t)((int)n + n->m_off),
3444588Swnj 				      (caddr_t)((int)m + off), n->m_len);
3454588Swnj 				m->m_len += n->m_len;
3464588Swnj 				off += n->m_len;
3474588Swnj 				up->uc_ssize--;
3484588Swnj 				n = m_free(n);
3494588Swnj 			}
3504497Swnj 		}
3514497Swnj 		m->m_next = n;
3524588Swnj 	}
3534588Swnj 	if (up->uc_flags & UEOL)
3544497Swnj 		tp->snd_end = last;
3554588Swnj 	if (up->uc_flags & UURG) {
3564497Swnj 		tp->snd_urp = last+1;
3574576Swnj 		tp->tc_flags |= TC_SND_URG;
3584567Swnj 	}
3594678Swnj 	tcp_send(tp);
3604567Swnj 	return (SAME);
3614497Swnj }
3624497Swnj 
3634682Swnj /*
3644682Swnj  * TCP timer went off processing.
3654682Swnj  */
3664584Swnj tcp_timers(tp, timertype)
3674584Swnj 	register struct tcb *tp;
3684584Swnj 	int timertype;
3694497Swnj {
3704497Swnj 
3714567Swnj COUNT(TCP_TIMERS);
3724584Swnj 	switch (timertype) {
3734497Swnj 
3744567Swnj 	case TINIT:		/* initialization timer */
3754576Swnj 		if ((tp->tc_flags&TC_SYN_ACKED) == 0) {		/* 35 */
3764676Swnj 			tcp_close(tp, UINTIMO);
3774567Swnj 			return (CLOSED);
3784567Swnj 		}
3794567Swnj 		return (SAME);
3804497Swnj 
3814567Swnj 	case TFINACK:		/* fin-ack timer */
3824567Swnj 		switch (tp->t_state) {
3834497Swnj 
3844567Swnj 		case TIME_WAIT:
3854567Swnj 			/*
3864567Swnj 			 * We can be sure our ACK of foreign FIN was rcvd,
3874567Swnj 			 * and can close if no data left for user.
3884567Swnj 			 */
3894567Swnj 			if (rcv_empty(tp)) {
3904676Swnj 				tcp_close(tp, UCLOSED);		/* 14 */
3914567Swnj 				return (CLOSED);
3924567Swnj 			}
3934567Swnj 			return (RCV_WAIT);			/* 17 */
3944497Swnj 
3954567Swnj 		case CLOSING1:
3964576Swnj 			tp->tc_flags |= TC_WAITED_2_ML;
3974567Swnj 			return (SAME);
3984497Swnj 
3994567Swnj 		default:
4004567Swnj 			return (SAME);
4014567Swnj 		}
4024497Swnj 
4034567Swnj 	case TREXMT:		/* retransmission timer */
4044567Swnj 		if (tp->t_rexmt_val > tp->snd_una) {	 	/* 34 */
4054567Swnj 			/*
4064567Swnj 			 * Set up for a retransmission, increase rexmt time
4074567Swnj 			 * in case of multiple retransmissions.
4084567Swnj 			 */
4094567Swnj 			tp->snd_nxt = tp->snd_una;
4104576Swnj 			tp->tc_flags |= TC_REXMT;
4114567Swnj 			tp->t_xmtime = tp->t_xmtime << 1;
4124567Swnj 			if (tp->t_xmtime > T_REMAX)
4134567Swnj 				tp->t_xmtime = T_REMAX;
4144678Swnj 			tcp_send(tp);
4154567Swnj 		}
4164567Swnj 		return (SAME);
4174497Swnj 
4184567Swnj 	case TREXMTTL:		/* retransmit too long */
4194567Swnj 		if (tp->t_rtl_val > tp->snd_una)		/* 36 */
4204567Swnj 			to_user(tp->t_ucb, URXTIMO);
4214567Swnj 		/*
4224567Swnj 		 * If user has already closed, abort the connection.
4234567Swnj 		 */
4244576Swnj 		if (tp->tc_flags & TC_USR_CLOSED) {
4254676Swnj 			tcp_close(tp, URXTIMO);
4264567Swnj 			return (CLOSED);
4274567Swnj 		}
4284567Swnj 		return (SAME);
4294497Swnj 
4304567Swnj 	case TPERSIST:		/* persist timer */
4314567Swnj 		/*
4324567Swnj 		 * Force a byte send through closed window.
4334567Swnj 		 */
4344576Swnj 		tp->tc_flags |= TC_FORCE_ONE;
4354678Swnj 		tcp_send(tp);
4364567Swnj 		return (SAME);
4374567Swnj 	}
4384567Swnj 	panic("tcp_timers");
4394497Swnj }
4404497Swnj 
4414567Swnj /* THIS ROUTINE IS A CROCK */
4424567Swnj to_user(up, state)
4434567Swnj 	register struct ucb *up;
4444567Swnj 	register short state;
4454497Swnj {
4464567Swnj COUNT(TO_USER);
4474497Swnj 
4484567Swnj 	up->uc_state |= state;
4494567Swnj 	netwakeup(up);
4504567Swnj   	if (state == UURGENT)
4514567Swnj 		psignal(up->uc_proc, SIGURG);
4524497Swnj }
4534584Swnj 
4544584Swnj #ifdef TCPDEBUG
4554682Swnj /*
4564682Swnj  * TCP debugging utility subroutines.
4574682Swnj  * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID.
4584682Swnj  */
4594670Swnj tdb_setup(tp, n, input, tdp)
4604670Swnj 	struct tcb *tp;
4614670Swnj 	register struct th *n;
4624670Swnj 	int input;
4634670Swnj 	register struct tcp_debug *tdp;
4644670Swnj {
4654670Swnj 
4664682Swnj COUNT(TDB_SETUP);
4674670Swnj 	tdp->td_tod = time;
4684670Swnj 	tdp->td_tcb = tp;
4694670Swnj 	tdp->td_old = tp->t_state;
4704670Swnj 	tdp->td_inp = input;
4714670Swnj 	tdp->td_tim = 0;
4724670Swnj 	tdp->td_new = -1;
4734670Swnj 	if (n) {
4744670Swnj 		tdp->td_sno = n->t_seq;
4754670Swnj 		tdp->td_ano = n->t_ackno;
4764670Swnj 		tdp->td_wno = n->t_win;
4774670Swnj 		tdp->td_lno = n->t_len;
4784670Swnj 		tdp->td_flg = n->th_flags;
4794670Swnj 	} else
4804670Swnj 		tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno =
4814670Swnj 		    tdp->td_flg = 0;
4824670Swnj }
4834670Swnj 
4844670Swnj tdb_stuff(tdp, nstate)
4854670Swnj 	struct tcp_debug *tdp;
4864670Swnj 	int nstate;
4874670Swnj {
4884682Swnj COUNT(TDB_STUFF);
4894670Swnj 
4904670Swnj 	tdp->td_new = nstate;
4914670Swnj 	tcp_debug[tdbx++ % TDBSIZE] = *tdp;
4924670Swnj 	if (tcpconsdebug & 2)
4934670Swnj 		tcp_prt(tdp);
4944670Swnj }
4954682Swnj 
4964682Swnj tcp_prt(tdp)
4974682Swnj 	register struct tcp_debug *tdp;
4984682Swnj {
4994682Swnj COUNT(TCP_PRT);
5004682Swnj 
501*4698Swnj 	printf("%x ", ((int)tdp->td_tcb)&0xffffff);
502*4698Swnj 	if (tdp->td_inp == INSEND) {
503*4698Swnj 		printf("SEND #%x", tdp->td_sno);
504*4698Swnj 		tdp->td_lno = ntohs(tdp->td_lno);
505*4698Swnj 		tdp->td_wno = ntohs(tdp->td_wno);
506*4698Swnj 	} else {
507*4698Swnj 		if (tdp->td_inp == INRECV)
508*4698Swnj 			printf("RCV #%x ", tdp->td_sno);
509*4698Swnj 		printf("%s.%s",
510*4698Swnj 		    tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]);
511*4698Swnj 		if (tdp->td_inp == ISTIMER)
512*4698Swnj 			printf("(%s)", tcptimers[tdp->td_tim]);
513*4698Swnj 		printf(" -> %s",
514*4698Swnj 		    tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]);
515*4698Swnj 		if (tdp->td_new == -1)
516*4698Swnj 			printf(" (FAILED)");
517*4698Swnj 	}
5184682Swnj 	/* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */
519*4698Swnj 	if (tdp->td_lno)
520*4698Swnj 		printf(" len=%d", tdp->td_lno);
521*4698Swnj 	if (tdp->td_wno)
522*4698Swnj 		printf(" win=%d", tdp->td_wno);
523*4698Swnj 	if (tdp->td_flg & TH_FIN) printf(" FIN");
524*4698Swnj 	if (tdp->td_flg & TH_SYN) printf(" SYN");
525*4698Swnj 	if (tdp->td_flg & TH_RST) printf(" RST");
526*4698Swnj 	if (tdp->td_flg & TH_EOL) printf(" EOL");
527*4698Swnj 	if (tdp->td_flg & TH_ACK)  printf(" ACK %x", tdp->td_ano);
528*4698Swnj 	if (tdp->td_flg & TH_URG) printf(" URG");
5294682Swnj 	printf("\n");
5304682Swnj }
5314670Swnj #endif
532