xref: /csrg-svn/sys/netinet/tcp_usrreq.c (revision 4954)
1*4954Swnj /* tcp_usrreq.c 1.31 81/11/20 */
24567Swnj 
34497Swnj #include "../h/param.h"
44567Swnj #include "../h/systm.h"
54664Swnj #include "../h/mbuf.h"
64664Swnj #include "../h/socket.h"
74809Swnj #include "../h/socketvar.h"
84809Swnj #include "../h/protosw.h"
94809Swnj #include "../net/inet.h"
104886Swnj #include "../net/inet_pcb.h"
114809Swnj #include "../net/inet_systm.h"
12*4954Swnj #include "../net/if.h"
134809Swnj #include "../net/imp.h"
144809Swnj #include "../net/ip.h"
154900Swnj #include "../net/ip_var.h"
164809Swnj #include "../net/tcp.h"
174567Swnj #define TCPFSTAB
184584Swnj #ifdef TCPDEBUG
194584Swnj #define TCPSTATES
204584Swnj #endif
214809Swnj #include "../net/tcp_fsm.h"
224809Swnj #include "../net/tcp_var.h"
234809Swnj #include "/usr/include/errno.h"
244497Swnj 
254734Swnj /*
264809Swnj  * Tcp initialization
274809Swnj  */
284809Swnj tcp_init()
294809Swnj {
304809Swnj 
314809Swnj 	tcp_iss = 1;		/* wrong */
324886Swnj 	tcb.inp_next = tcb.inp_prev = &tcb;
334809Swnj }
344809Swnj 
354809Swnj /*
364734Swnj  * Tcp finite state machine entries for timer and user generated
374734Swnj  * requests.  These routines raise the ipl to that of the network
384734Swnj  * to prevent reentry.  In particluar, this requires that the software
394734Swnj  * clock interrupt have lower priority than the network so that
404734Swnj  * we can enter the network from timeout routines without improperly
414734Swnj  * nesting the interrupt stack.
424734Swnj  */
434734Swnj 
444734Swnj /*
454809Swnj  * Tcp protocol timeout routine called every 500 ms.
464734Swnj  * Updates the timers in all active tcb's and
474734Swnj  * causes finite state machine actions if timers expire.
484734Swnj  */
494809Swnj tcp_slowtimo()
504497Swnj {
514886Swnj 	register struct inpcb *ip;
524886Swnj 	register struct tcpcb *tp;
534567Swnj 	int s = splnet();
544809Swnj 	register short *tmp;
554731Swnj 	register int i;
564567Swnj COUNT(TCP_TIMEO);
574497Swnj 
584567Swnj 	/*
594567Swnj 	 * Search through tcb's and update active timers.
604567Swnj 	 */
614886Swnj 	for (ip = tcb.inp_next; ip != &tcb; ip = ip->inp_next) {
624886Swnj 		tp = intotcpcb(ip);
634731Swnj 		tmp = &tp->t_init;
644735Swnj 		for (i = 0; i < TNTIMERS; i++) {
654731Swnj 			if (*tmp && --*tmp == 0)
664911Swnj 				(void) tcp_usrreq(tp->t_inpcb->inp_socket,
674911Swnj 				    PRU_SLOWTIMO, (struct mbuf *)0,
684911Swnj 				    (caddr_t)i);
694735Swnj 			tmp++;
704735Swnj 		}
714567Swnj 		tp->t_xmt++;
724567Swnj 	}
734809Swnj 	tcp_iss += ISSINCR/2;		/* increment iss */
744567Swnj 	splx(s);
754497Swnj }
764497Swnj 
774731Swnj /*
784734Swnj  * Cancel all timers for tcp tp.
794734Swnj  */
804734Swnj tcp_tcancel(tp)
814886Swnj 	struct tcpcb *tp;
824734Swnj {
834809Swnj 	register short *tmp = &tp->t_init;
844734Swnj 	register int i;
854734Swnj 
864734Swnj 	for (i = 0; i < TNTIMERS; i++)
874734Swnj 		*tmp++ = 0;
884734Swnj }
894734Swnj 
90*4954Swnj struct	tcpcb *tcp_newtcpcb();
914734Swnj /*
924731Swnj  * Process a TCP user request for tcp tb.  If this is a send request
934731Swnj  * then m is the mbuf chain of send data.  If this is a timer expiration
944731Swnj  * (called from the software clock routine), then timertype tells which timer.
954731Swnj  */
964809Swnj tcp_usrreq(so, req, m, addr)
974809Swnj 	struct socket *so;
984809Swnj 	int req;
994731Swnj 	struct mbuf *m;
1004809Swnj 	caddr_t addr;
1014497Swnj {
1024886Swnj 	register struct inpcb *inp = sotoinpcb(so);
1034911Swnj 	register struct tcpcb *tp;
1044567Swnj 	int s = splnet();
1054567Swnj 	register int nstate;
1064584Swnj #ifdef TCPDEBUG
1074584Swnj 	struct tcp_debug tdb;
1084584Swnj #endif
1094809Swnj 	int error = 0;
1104567Swnj COUNT(TCP_USRREQ);
1114497Swnj 
1124886Swnj 	/*
1134886Swnj 	 * Make sure attached.  If not,
1144886Swnj 	 * only PRU_ATTACH is valid.
1154886Swnj 	 */
1164911Swnj #ifdef TCPDEBUG
1174911Swnj 	tdb.td_tod = 0;
1184911Swnj #endif
1194911Swnj 	if (inp == 0) {
1204886Swnj 		if (req != PRU_ATTACH) {
1214886Swnj 			splx(s);
1224886Swnj 			return (EINVAL);
1234886Swnj 		}
1244911Swnj 	} else {
1254911Swnj 		tp = intotcpcb(inp);
1264911Swnj 		nstate = tp->t_state;
1274731Swnj #ifdef KPROF
1284911Swnj 		tcp_acounts[nstate][req]++;
1294731Swnj #endif
1304584Swnj #ifdef TCPDEBUG
1314911Swnj 		if (((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug)) {
1324911Swnj 			tdb_setup(tp, (struct tcpiphdr *)0, req, &tdb);
1334911Swnj 			tdb.td_tim = timertype;
1344911Swnj 		}
1354584Swnj #endif
1364911Swnj 		tp->tc_flags &= ~TC_NET_KEEP;
1374911Swnj 	}
1384911Swnj 
1394809Swnj 	switch (req) {
1404497Swnj 
1414809Swnj 	case PRU_ATTACH:
142*4954Swnj 		if (inp) {
1434809Swnj 			error = EISCONN;
1444911Swnj 			break;
1454886Swnj 		}
146*4954Swnj 		tp = tcp_newtcpcb();
147*4954Swnj 		if (tp == 0) {
148*4954Swnj 			error = ENOBUFS;
149*4954Swnj 			break;
150*4954Swnj 		}
151*4954Swnj 		error = in_pcballoc(so, &tcb, 2048, 2048, (struct sockaddr_in *)addr);
152*4954Swnj 		if (error) {
153*4954Swnj 			m_free(dtom(tp));
154*4954Swnj 			break;
155*4954Swnj 		}
156*4954Swnj 		inp = (struct inpcb *)so->so_pcb;
157*4954Swnj 		tp->t_inpcb = inp;
158*4954Swnj 		inp->inp_ppcb = (caddr_t)tp;
159*4954Swnj 		if (so->so_options & SO_ACCEPTCONN)
1604886Swnj 			nstate = LISTEN;
161*4954Swnj 		else
1624886Swnj 			nstate = CLOSED;
1634567Swnj 		break;
1644497Swnj 
1654809Swnj 	case PRU_DETACH:
1664911Swnj 		tcp_detach(tp);
1674809Swnj 		break;
1684809Swnj 
1694809Swnj 	case PRU_CONNECT:
1704886Swnj 		if (tp->t_state != 0 && tp->t_state != CLOSED)
1714731Swnj 			goto bad;
172*4954Swnj 		error = in_pcbsetpeer(inp, (struct sockaddr_in *)addr);
173*4954Swnj 		if (error)
1744886Swnj 			break;
1754911Swnj 		(void) tcp_sndctl(tp);
1764567Swnj 		nstate = SYN_SENT;
1774886Swnj 		soisconnecting(so);
1784567Swnj 		break;
1794497Swnj 
1804925Swnj 	case PRU_ACCEPT:
181*4954Swnj 		soisconnected(so);
182*4954Swnj 		break;
1834925Swnj 
1844809Swnj 	case PRU_DISCONNECT:
1854886Swnj 		if ((tp->tc_flags & TC_FIN_RCVD) == 0)
1864886Swnj 			goto abort;
1874886Swnj 		if (nstate < ESTAB)
1884911Swnj 			tcp_disconnect(tp);
1894886Swnj 		else {
1904886Swnj 			tp->tc_flags |= TC_SND_FIN;
1914911Swnj 			(void) tcp_sndctl(tp);
1924886Swnj 			tp->tc_flags |= TC_USR_CLOSED;
1934886Swnj 			soisdisconnecting(so);
1944886Swnj 		}
1954809Swnj 		break;
1964809Swnj 
1974809Swnj 	case PRU_SHUTDOWN:
1984731Swnj 		switch (nstate) {
1994497Swnj 
2004731Swnj 		case LISTEN:
2014734Swnj 		case SYN_SENT:
2024731Swnj 			nstate = CLOSED;
2034731Swnj 			break;
2044731Swnj 
2054734Swnj 		case SYN_RCVD:
2064731Swnj 		case L_SYN_RCVD:
2074731Swnj 		case ESTAB:
2084734Swnj 		case CLOSE_WAIT:
2094731Swnj 			tp->tc_flags |= TC_SND_FIN;
2104911Swnj 			(void) tcp_sndctl(tp);
2114731Swnj 			tp->tc_flags |= TC_USR_CLOSED;
2124731Swnj 			nstate = nstate != CLOSE_WAIT ? FIN_W1 : LAST_ACK;
2134731Swnj 			break;
2144731Swnj 
2154731Swnj 		case FIN_W1:
2164731Swnj 		case FIN_W2:
2174731Swnj 		case TIME_WAIT:
2184731Swnj 		case CLOSING:
2194731Swnj 		case LAST_ACK:
2204731Swnj 		case RCV_WAIT:
2214731Swnj 			break;
2224731Swnj 
2234731Swnj 		default:
2244731Swnj 			goto bad;
2254731Swnj 		}
2264567Swnj 		break;
2274497Swnj 
2284809Swnj 	case PRU_RCVD:
2294731Swnj 		if (nstate < ESTAB || nstate == CLOSED)
2304731Swnj 			goto bad;
2314734Swnj 		tcp_sndwin(tp);
2324691Swnj 		if ((tp->tc_flags&TC_FIN_RCVD) &&
2334691Swnj 		    (tp->tc_flags&TC_USR_CLOSED) == 0 &&
2344691Swnj 		    rcv_empty(tp))
2354886Swnj 			error = ESHUTDOWN;
2364809Swnj 		if (nstate == RCV_WAIT && rcv_empty(tp))
2374567Swnj 			nstate = CLOSED;
2384567Swnj 		break;
2394497Swnj 
2404809Swnj 	case PRU_SEND:
2414731Swnj 		switch (nstate) {
2424567Swnj 
2434731Swnj 		case ESTAB:
2444731Swnj 		case CLOSE_WAIT:
2454886Swnj 			tcp_usrsend(tp, m);
2464731Swnj 			break;
2474731Swnj 
2484731Swnj 		default:
2494731Swnj 			if (nstate < ESTAB)
2504731Swnj 				goto bad;
2514809Swnj 			m_freem(m);
2524886Swnj 			error = ENOTCONN;
2534731Swnj 			break;
2544731Swnj 		}
2554567Swnj 		break;
2564567Swnj 
2574886Swnj abort:
2584809Swnj 	case PRU_ABORT:
2594886Swnj 		tcp_abort(tp);
2604567Swnj 		nstate = CLOSED;
2614567Swnj 		break;
2624567Swnj 
2634809Swnj 	case PRU_CONTROL:
2644886Swnj 		error = EOPNOTSUPP;
2654809Swnj 		break;
2664809Swnj 
2674809Swnj 	case PRU_SLOWTIMO:
2684809Swnj 		switch (nstate) {
2694809Swnj 
2704809Swnj 		case 0:
2714809Swnj 		case CLOSED:
2724809Swnj 		case LISTEN:
2734809Swnj 			goto bad;
2744809Swnj 
2754809Swnj 		default:
2764809Swnj 			nstate = tcp_timers(tp, (int)addr);
2774809Swnj 		}
2784809Swnj 		break;
2794809Swnj 
2804731Swnj 	default:
2814731Swnj 		panic("tcp_usrreq");
2824731Swnj 	bad:
2834731Swnj 		printf("tcp: bad state: tcb=%x state=%d input=%d\n",
2844809Swnj 		    tp, tp->t_state, req);
2854731Swnj 		nstate = EFAILEC;
2864567Swnj 		break;
2874567Swnj 	}
2884567Swnj #ifdef TCPDEBUG
2894605Swnj 	if (tdb.td_tod)
2904605Swnj 		tdb_stuff(&tdb, nstate);
2914567Swnj #endif
2924567Swnj 	switch (nstate) {
2934567Swnj 
2944584Swnj 	case CLOSED:
2954567Swnj 	case SAME:
2964567Swnj 		break;
2974567Swnj 
2984567Swnj 	case EFAILEC:
2994731Swnj 		if (m)
3004731Swnj 			m_freem(dtom(m));
3014567Swnj 		break;
3024567Swnj 
3034567Swnj 	default:
3044567Swnj 		tp->t_state = nstate;
3054567Swnj 		break;
3064567Swnj 	}
3074567Swnj 	splx(s);
3084886Swnj 	return (error);
3094497Swnj }
3104497Swnj 
311*4954Swnj struct tcpcb *
312*4954Swnj tcp_newtcpcb()
3134809Swnj {
314*4954Swnj 	struct mbuf *m = m_getclr(0);
315*4954Swnj 	register struct tcpcb *tp;
316*4954Swnj COUNT(TCP_NEWTCPCB);
3174497Swnj 
318*4954Swnj 	if (m == 0)
319*4954Swnj 		return (0);
320*4954Swnj 	tp = mtod(m, struct tcpcb *);
321*4954Swnj 
3224682Swnj 	/*
3234886Swnj 	 * Make empty reassembly queue.
3244682Swnj 	 */
3254886Swnj 	tp->seg_next = tp->seg_prev = (struct tcpiphdr *)tp;
3264497Swnj 
3274682Swnj 	/*
3284886Swnj 	 * Initialize sequence numbers and round trip retransmit timer.
3294682Swnj 	 */
3304567Swnj 	tp->t_xmtime = T_REXMT;
3314682Swnj 	tp->snd_end = tp->seq_fin = tp->snd_nxt = tp->snd_hi = tp->snd_una =
3324682Swnj 	    tp->iss = tcp_iss;
3334567Swnj 	tp->snd_off = tp->iss + 1;
3344664Swnj 	tcp_iss += (ISSINCR >> 1) + 1;
335*4954Swnj 	return (tp);
3364497Swnj }
3374497Swnj 
3384911Swnj tcp_detach(tp)
3394911Swnj 	struct tcpcb *tp;
3404497Swnj {
3414809Swnj COUNT(TCP_DETACH);
3424497Swnj 
3434911Swnj 	in_pcbfree(tp->t_inpcb);
3444911Swnj 	(void) m_free(dtom(tp));
3454886Swnj }
3464886Swnj 
3474886Swnj tcp_disconnect(tp)
3484886Swnj 	register struct tcpcb *tp;
3494886Swnj {
3504886Swnj 	register struct tcpiphdr *t;
3514886Swnj 
352*4954Swnj COUNT(TCP_DISCONNECT);
3534734Swnj 	tcp_tcancel(tp);
3544886Swnj 	t = tp->seg_next;
3554900Swnj 	for (; t != (struct tcpiphdr *)tp; t = (struct tcpiphdr *)t->ti_next)
3564567Swnj 		m_freem(dtom(t));
3574886Swnj 	tcp_drainunack(tp);
3584734Swnj 	if (tp->t_template) {
3594911Swnj 		(void) m_free(dtom(tp->t_template));
3604734Swnj 		tp->t_template = 0;
3614664Swnj 	}
3624886Swnj 	in_pcbfree(tp->t_inpcb);
3634497Swnj }
3644497Swnj 
3654911Swnj tcp_abort(tp)
3664911Swnj 	register struct tcpcb *tp;
3674886Swnj {
3684886Swnj 
369*4954Swnj COUNT(TCP_ABORT);
3704886Swnj 	switch (tp->t_state) {
3714886Swnj 
3724886Swnj 	case SYN_RCVD:
3734886Swnj 	case ESTAB:
3744886Swnj 	case FIN_W1:
3754886Swnj 	case FIN_W2:
3764886Swnj 	case CLOSE_WAIT:
3774886Swnj 		tp->tc_flags |= TC_SND_RST;
3784886Swnj 		tcp_sndnull(tp);
3794886Swnj 	}
3804911Swnj 	soisdisconnected(tp->t_inpcb->inp_socket);
3814886Swnj }
3824886Swnj 
3834682Swnj /*
3844734Swnj  * Send data queue headed by m0 into the protocol.
3854682Swnj  */
3864678Swnj tcp_usrsend(tp, m0)
3874886Swnj 	register struct tcpcb *tp;
3884584Swnj 	struct mbuf *m0;
3894497Swnj {
3904886Swnj 	register struct socket *so = tp->t_inpcb->inp_socket;
3914682Swnj COUNT(TCP_USRSEND);
3924497Swnj 
3934886Swnj 	sbappend(&so->so_snd, m0);
3944809Swnj 	if (tp->t_options & TO_EOL)
3954886Swnj 		tp->snd_end = tp->snd_off + so->so_snd.sb_cc;
3964809Swnj 	if (tp->t_options & TO_URG) {
3974886Swnj 		tp->snd_urp = tp->snd_off + so->so_snd.sb_cc + 1;
3984576Swnj 		tp->tc_flags |= TC_SND_URG;
3994567Swnj 	}
4004911Swnj 	(void) tcp_send(tp);
4014497Swnj }
4024497Swnj 
4034682Swnj /*
4044682Swnj  * TCP timer went off processing.
4054682Swnj  */
4064584Swnj tcp_timers(tp, timertype)
4074886Swnj 	register struct tcpcb *tp;
4084584Swnj 	int timertype;
4094497Swnj {
4104497Swnj 
4114567Swnj COUNT(TCP_TIMERS);
4124584Swnj 	switch (timertype) {
4134497Swnj 
4144567Swnj 	case TFINACK:		/* fin-ack timer */
4154567Swnj 		switch (tp->t_state) {
4164497Swnj 
4174567Swnj 		case TIME_WAIT:
4184567Swnj 			/*
4194567Swnj 			 * We can be sure our ACK of foreign FIN was rcvd,
4204567Swnj 			 * and can close if no data left for user.
4214567Swnj 			 */
4224567Swnj 			if (rcv_empty(tp)) {
4234886Swnj 				tcp_disconnect(tp);
4244567Swnj 				return (CLOSED);
4254567Swnj 			}
4264567Swnj 			return (RCV_WAIT);			/* 17 */
4274497Swnj 
4284731Swnj 		case CLOSING:
4294576Swnj 			tp->tc_flags |= TC_WAITED_2_ML;
4304567Swnj 			return (SAME);
4314497Swnj 
4324567Swnj 		default:
4334567Swnj 			return (SAME);
4344567Swnj 		}
4354497Swnj 
4364567Swnj 	case TREXMT:		/* retransmission timer */
4374567Swnj 		if (tp->t_rexmt_val > tp->snd_una) {	 	/* 34 */
4384567Swnj 			/*
4394809Swnj 			 * Set so for a retransmission, increase rexmt time
4404567Swnj 			 * in case of multiple retransmissions.
4414567Swnj 			 */
4424567Swnj 			tp->snd_nxt = tp->snd_una;
4434576Swnj 			tp->tc_flags |= TC_REXMT;
4444567Swnj 			tp->t_xmtime = tp->t_xmtime << 1;
4454567Swnj 			if (tp->t_xmtime > T_REMAX)
4464567Swnj 				tp->t_xmtime = T_REMAX;
4474911Swnj 			(void) tcp_send(tp);
4484567Swnj 		}
4494567Swnj 		return (SAME);
4504497Swnj 
4514567Swnj 	case TREXMTTL:		/* retransmit too long */
4524567Swnj 		if (tp->t_rtl_val > tp->snd_una)		/* 36 */
4534911Swnj 			tcp_error(tp, EIO);		/* URXTIMO !?! */
4544567Swnj 		/*
4554567Swnj 		 * If user has already closed, abort the connection.
4564567Swnj 		 */
4574576Swnj 		if (tp->tc_flags & TC_USR_CLOSED) {
4584886Swnj 			tcp_abort(tp);
4594567Swnj 			return (CLOSED);
4604567Swnj 		}
4614567Swnj 		return (SAME);
4624497Swnj 
4634567Swnj 	case TPERSIST:		/* persist timer */
4644567Swnj 		/*
4654567Swnj 		 * Force a byte send through closed window.
4664567Swnj 		 */
4674576Swnj 		tp->tc_flags |= TC_FORCE_ONE;
4684911Swnj 		(void) tcp_send(tp);
4694567Swnj 		return (SAME);
4704567Swnj 	}
4714567Swnj 	panic("tcp_timers");
4724911Swnj 	/*NOTREACHED*/
4734497Swnj }
4744497Swnj 
4754911Swnj /*ARGSUSED*/
4764886Swnj tcp_sense(m)
4774886Swnj 	struct mbuf *m;
4784886Swnj {
4794886Swnj 
480*4954Swnj COUNT(TCP_SENSE);
4814886Swnj 	return (EOPNOTSUPP);
4824886Swnj }
4834886Swnj 
4844911Swnj tcp_error(tp, errno)
4854911Swnj 	struct tcpcb *tp;
4864809Swnj 	int errno;
4874497Swnj {
4884911Swnj 	struct socket *so = tp->t_inpcb->inp_socket;
489*4954Swnj 
4904911Swnj COUNT(TCP_ERROR);
4914809Swnj 	so->so_error = errno;
4924886Swnj 	sorwakeup(so);
4934886Swnj 	sowwakeup(so);
4944497Swnj }
4954584Swnj 
4964584Swnj #ifdef TCPDEBUG
4974682Swnj /*
4984682Swnj  * TCP debugging utility subroutines.
4994682Swnj  * THE NAMES OF THE FIELDS USED BY THESE ROUTINES ARE STUPID.
5004682Swnj  */
5014670Swnj tdb_setup(tp, n, input, tdp)
5024886Swnj 	struct tcpcb *tp;
5034886Swnj 	register struct tcpiphdr *n;
5044670Swnj 	int input;
5054670Swnj 	register struct tcp_debug *tdp;
5064670Swnj {
5074670Swnj 
5084682Swnj COUNT(TDB_SETUP);
5094670Swnj 	tdp->td_tod = time;
5104670Swnj 	tdp->td_tcb = tp;
5114670Swnj 	tdp->td_old = tp->t_state;
5124670Swnj 	tdp->td_inp = input;
5134670Swnj 	tdp->td_tim = 0;
5144670Swnj 	tdp->td_new = -1;
5154670Swnj 	if (n) {
5164900Swnj 		tdp->td_sno = n->ti_seq;
5174900Swnj 		tdp->td_ano = n->ti_ackno;
5184670Swnj 		tdp->td_wno = n->t_win;
5194900Swnj 		tdp->td_lno = n->ti_len;
5204900Swnj 		tdp->td_flg = n->ti_flags;
5214670Swnj 	} else
5224670Swnj 		tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno =
5234670Swnj 		    tdp->td_flg = 0;
5244670Swnj }
5254670Swnj 
5264670Swnj tdb_stuff(tdp, nstate)
5274670Swnj 	struct tcp_debug *tdp;
5284670Swnj 	int nstate;
5294670Swnj {
5304682Swnj COUNT(TDB_STUFF);
5314670Swnj 
5324670Swnj 	tdp->td_new = nstate;
5334670Swnj 	tcp_debug[tdbx++ % TDBSIZE] = *tdp;
5344670Swnj 	if (tcpconsdebug & 2)
5354670Swnj 		tcp_prt(tdp);
5364670Swnj }
5374682Swnj 
5384682Swnj tcp_prt(tdp)
5394682Swnj 	register struct tcp_debug *tdp;
5404682Swnj {
5414682Swnj COUNT(TCP_PRT);
5424682Swnj 
5434698Swnj 	printf("%x ", ((int)tdp->td_tcb)&0xffffff);
5444698Swnj 	if (tdp->td_inp == INSEND) {
5454698Swnj 		printf("SEND #%x", tdp->td_sno);
5464698Swnj 		tdp->td_lno = ntohs(tdp->td_lno);
5474698Swnj 		tdp->td_wno = ntohs(tdp->td_wno);
5484698Swnj 	} else {
5494698Swnj 		if (tdp->td_inp == INRECV)
5504698Swnj 			printf("RCV #%x ", tdp->td_sno);
5514698Swnj 		printf("%s.%s",
5524698Swnj 		    tcpstates[tdp->td_old], tcpinputs[tdp->td_inp]);
5534698Swnj 		if (tdp->td_inp == ISTIMER)
5544698Swnj 			printf("(%s)", tcptimers[tdp->td_tim]);
5554698Swnj 		printf(" -> %s",
5564698Swnj 		    tcpstates[(tdp->td_new > 0) ? tdp->td_new : tdp->td_old]);
5574698Swnj 		if (tdp->td_new == -1)
5584698Swnj 			printf(" (FAILED)");
5594698Swnj 	}
5604682Swnj 	/* GROSS... DEPENDS ON SIGN EXTENSION OF CHARACTERS */
5614698Swnj 	if (tdp->td_lno)
5624698Swnj 		printf(" len=%d", tdp->td_lno);
5634698Swnj 	if (tdp->td_wno)
5644698Swnj 		printf(" win=%d", tdp->td_wno);
5654698Swnj 	if (tdp->td_flg & TH_FIN) printf(" FIN");
5664698Swnj 	if (tdp->td_flg & TH_SYN) printf(" SYN");
5674698Swnj 	if (tdp->td_flg & TH_RST) printf(" RST");
5684698Swnj 	if (tdp->td_flg & TH_EOL) printf(" EOL");
5694698Swnj 	if (tdp->td_flg & TH_ACK)  printf(" ACK %x", tdp->td_ano);
5704698Swnj 	if (tdp->td_flg & TH_URG) printf(" URG");
5714682Swnj 	printf("\n");
5724682Swnj }
5734670Swnj #endif
574