xref: /csrg-svn/sys/netinet/tcp_input.c (revision 4690)
1*4690Swnj /* tcp_input.c 1.14 81/10/31 */
24601Swnj 
34601Swnj #include "../h/param.h"
44601Swnj #include "../h/systm.h"
54663Swnj #include "../h/mbuf.h"
64663Swnj #include "../h/socket.h"
74663Swnj #include "../inet/inet.h"
84663Swnj #include "../inet/inet_systm.h"
94663Swnj #include "../inet/imp.h"
104663Swnj #include "../inet/inet_host.h"
114663Swnj #include "../inet/ip.h"
124663Swnj #include "../inet/tcp.h"
134663Swnj #include "../inet/tcp_fsm.h"
144601Swnj 
154679Swnj int	tcpcksum = 1;
164601Swnj 
174601Swnj tcp_input(mp)
184601Swnj 	register struct mbuf *mp;
194601Swnj {
204673Swnj 	register struct th *n;		/* known to be r10 */
214673Swnj 	register int j;			/* known to be r9 */
224601Swnj 	register struct tcb *tp;
234601Swnj 	int nstate;
244601Swnj 	struct mbuf *m;
254601Swnj 	struct ucb *up;
264673Swnj 	int hlen, tlen;
274601Swnj 	u_short lport, fport;
284601Swnj #ifdef TCPDEBUG
294601Swnj 	struct tcp_debug tdb;
304601Swnj #endif
314601Swnj COUNT(TCP_INPUT);
324601Swnj 
334601Swnj 	/*
344601Swnj 	 * Build extended tcp header
354601Swnj 	 */
364601Swnj 	n = (struct th *)((int)mp + mp->m_off);
374601Swnj 	tlen = ((struct ip *)n)->ip_len;
384601Swnj 	n->t_len = htons(tlen);
394601Swnj 	n->t_next = NULL;
404601Swnj 	n->t_prev = NULL;
414601Swnj 	n->t_x1 = 0;
424601Swnj 	lport = ntohs(n->t_dst);
434601Swnj 	fport = ntohs(n->t_src);
444601Swnj 
454601Swnj 	/* WONT BE POSSIBLE WHEN MBUFS ARE 256 BYTES */
464601Swnj 	if ((hlen = n->t_off << 2) > mp->m_len)
474601Swnj 		{ printf("tcp header overflow\n"); m_freem(mp); return; }
484601Swnj 
494679Swnj 	if (tcpcksum) {
504679Swnj 		/*
514679Swnj 		 * Checksum extended header and data
524679Swnj 		 */
534679Swnj 		j = n->t_sum; n->t_sum = 0;
544673Swnj #ifdef vax
554679Swnj 		if (tlen == 20) {
564679Swnj 			asm("addl3 $8,r10,r0; movl (r0)+,r1; addl2 (r0)+,r1");
574679Swnj 			asm("adwc (r0)+,r1; adwc (r0)+,r1; adwc (r0)+,r1");
584679Swnj 			asm("adwc (r0)+,r1; adwc (r0)+,r1; adwc (r0)+,r1");
594679Swnj 			asm("adwc $0,r1; ashl $-16,r1,r0; addw2 r0,r1");
604679Swnj 			asm("adwc $0,r1");		/* ### */
614679Swnj 			asm("mcoml r1,r1; movzwl r1,r1; subl2 r1,r9");
624679Swnj 		} else
634673Swnj #endif
644679Swnj 			j -= cksum(mp, sizeof (struct ip) + tlen);
654679Swnj 		if (j != 0) {
664679Swnj 			netstat.t_badsum++;
674601Swnj 			m_freem(mp);
684601Swnj 			return;
694601Swnj 		}
704601Swnj 	}
714601Swnj 
724601Swnj 	/*
734601Swnj 	 * Find tcb for message (SHOULDN'T USE LINEAR SEARCH!)
744601Swnj 	 */
754681Swnj 	for (tp = tcb.tcb_next; tp != (struct tcb *)&tcb; tp = tp->tcb_next)
764601Swnj 		if (tp->t_lport == lport && tp->t_fport == fport &&
774601Swnj 		    tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr)
784601Swnj 			goto found;
794681Swnj 	for (tp = tcb.tcb_next; tp != (struct tcb *)&tcb; tp = tp->tcb_next)
804601Swnj 		if (tp->t_lport == lport &&
814601Swnj 		    (tp->t_fport==fport || tp->t_fport==0) &&
824601Swnj 		    (tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr ||
834601Swnj 		     tp->t_ucb->uc_host->h_addr.s_addr == 0))
844601Swnj 			goto found;
854601Swnj 	goto notwanted;
864601Swnj found:
874601Swnj 
884601Swnj 	/*
894601Swnj 	 * Byte swap header
904601Swnj 	 */
914601Swnj 	n->t_len = tlen - hlen;
924601Swnj 	n->t_src = fport;
934601Swnj 	n->t_dst = lport;
944601Swnj 	n->t_seq = ntohl(n->t_seq);
954601Swnj 	n->t_ackno = ntohl(n->t_ackno);
964601Swnj 	n->t_win = ntohs(n->t_win);
974601Swnj 	n->t_urp = ntohs(n->t_urp);
984601Swnj 
994601Swnj 	/*
1004601Swnj 	 * Check segment seq # and do rst processing
1014601Swnj 	 */
1024601Swnj 	switch (tp->t_state) {
1034601Swnj 
1044601Swnj 	case LISTEN:
1054601Swnj 		if ((n->th_flags&TH_ACK) || !syn_ok(tp, n)) {
1064675Swnj 			tcp_sndrst(tp, n);
1074601Swnj 			goto badseg;
1084601Swnj 		}
1094601Swnj 		if (n->th_flags&TH_RST)
1104601Swnj 			goto badseg;
1114601Swnj 		goto goodseg;
1124601Swnj 
1134601Swnj 	case SYN_SENT:
1144601Swnj 		if (!ack_ok(tp, n) || !syn_ok(tp, n)) {
1154675Swnj 			tcp_sndrst(tp, n);			/* 71,72,75 */
1164601Swnj 			goto badseg;
1174601Swnj 		}
1184601Swnj 		if (n->th_flags&TH_RST) {
1194675Swnj 			tcp_close(tp, URESET);			/* 70 */
1204601Swnj 			tp->t_state = CLOSED;
1214601Swnj 			goto badseg;
1224601Swnj 		}
1234601Swnj 		goto goodseg;
1244601Swnj 
1254601Swnj 	default:
1264601Swnj         	if ((n->th_flags&TH_RST) == 0)
1274601Swnj 			goto common;
1284601Swnj 		if (n->t_seq < tp->rcv_nxt)		/* bad rst */
1294601Swnj 			goto badseg;				/* 69 */
1304601Swnj 		switch (tp->t_state) {
1314601Swnj 
1324601Swnj 		case L_SYN_RCVD:
1334601Swnj 			if (ack_ok(tp, n) == 0)
1344601Swnj 				goto badseg;			/* 69 */
1354601Swnj 			tp->t_rexmt = 0;
1364601Swnj 			tp->t_rexmttl = 0;
1374601Swnj 			tp->t_persist = 0;
1384601Swnj 			h_free(tp->t_ucb->uc_host);
1394601Swnj 			tp->t_state = LISTEN;
1404601Swnj 			goto badseg;
1414601Swnj 
1424601Swnj 		default:
1434675Swnj 			tcp_close(tp, URESET);			/* 66 */
1444601Swnj 			tp->t_state = CLOSED;
1454601Swnj 			goto badseg;
1464601Swnj 		}
1474601Swnj 		/*NOTREACHED*/
1484601Swnj 
1494601Swnj 	case SYN_RCVD:
1504601Swnj common:
1514601Swnj 		if (ack_ok(tp, n) == 0) {
1524675Swnj 			tcp_sndrst(tp, n);			/* 74 */
1534601Swnj 			goto badseg;
1544601Swnj 		}
1554601Swnj 		if (syn_ok(tp, n) && n->t_seq != tp->irs) {
1564679Swnj 			tcp_sndnull(tp);			/* 74 */
1574601Swnj 			goto badseg;
1584601Swnj 		}
1594601Swnj 		goto goodseg;
1604601Swnj 	}
1614601Swnj badseg:
1624601Swnj 	m_freem(mp);
1634601Swnj 	return;
1644601Swnj 
1654601Swnj goodseg:
1664601Swnj #ifdef notdef
1674679Swnj 	/* DO SOMETHING ABOUT UNACK!!! */
1684601Swnj 	/*
1694601Swnj 	 * Defer processing if no buffer space for this connection.
1704601Swnj 	 */
1714601Swnj 	up = tp->t_ucb;
1724656Swnj 	if (up->uc_rcc > up->uc_rhiwat &&
1734663Swnj 	     && n->t_len != 0 && mbstat.m_bufs < mbstat.m_lowat) {
1744601Swnj 		mp->m_act = (struct mbuf *)0;
1754601Swnj 		if ((m = tp->t_rcv_unack) != NULL) {
1764601Swnj 			while (m->m_act != NULL)
1774601Swnj 				m = m->m_act;
1784601Swnj 			m->m_act = mp;
1794601Swnj 		} else
1804601Swnj 			tp->t_rcv_unack = mp;
1814601Swnj 		return;
1824601Swnj 	}
1834601Swnj #endif
1844601Swnj 
1854601Swnj 	/*
1864601Swnj 	 * Discard ip header, and do tcp input processing.
1874601Swnj 	 */
1884601Swnj 	hlen += sizeof(struct ip);
1894601Swnj 	mp->m_off += hlen;
1904601Swnj 	mp->m_len -= hlen;
1914601Swnj 	nstate = tp->t_state;
1924601Swnj 	tp->tc_flags &= ~TC_NET_KEEP;
1934601Swnj 	acounts[tp->t_state][INRECV]++;
1944601Swnj #ifdef TCPDEBUG
1954601Swnj 	if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
1964604Swnj 		tdb_setup(tp, n, INRECV, &tdb);
1974601Swnj 	} else
1984601Swnj 		tdb.td_tod = 0;
1994601Swnj #endif
2004601Swnj 	switch (tp->t_state) {
2014601Swnj 
2024601Swnj 	case LISTEN:
2034601Swnj 		if (!syn_ok(tp, n) ||
2044601Swnj 		    ((tp->t_ucb->uc_host = h_make(&n->t_s)) == 0)) {
2054601Swnj 			nstate = EFAILEC;
2064601Swnj 			goto done;
2074601Swnj 		}
2084601Swnj 		tp->t_fport = n->t_src;
2094603Sroot 		tp->t_ucb->uc_template = tcp_template(tp);
2104675Swnj 		tcp_ctldat(tp, n, 1);
2114601Swnj 		if (tp->tc_flags&TC_FIN_RCVD) {
2124601Swnj 			tp->t_finack = T_2ML;			/* 3 */
2134601Swnj 			tp->tc_flags &= ~TC_WAITED_2_ML;
2144601Swnj 			nstate = CLOSE_WAIT;
2154601Swnj 		} else {
2164601Swnj 			tp->t_init = T_INIT / 2;		/* 4 */
2174601Swnj 			nstate = L_SYN_RCVD;
2184601Swnj 		}
2194601Swnj 		goto done;
2204601Swnj 
2214601Swnj 	case SYN_SENT:
2224601Swnj 		if (!syn_ok(tp, n)) {
2234601Swnj 			nstate = EFAILEC;
2244601Swnj 			goto done;
2254601Swnj 		}
2264675Swnj 		tcp_ctldat(tp, n, 1);
2274601Swnj 		if (tp->tc_flags&TC_FIN_RCVD) {
228*4690Swnj 			if ((n->th_flags&TH_ACK) == 0) {
2294601Swnj 				tp->t_finack = T_2ML;		/* 9 */
2304601Swnj 				tp->tc_flags &= ~TC_WAITED_2_ML;
2314601Swnj 			}
2324601Swnj 			nstate = CLOSE_WAIT;
2334601Swnj 			goto done;
2344601Swnj 		}
235*4690Swnj 		nstate = (n->th_flags&TH_ACK) ? ESTAB : SYN_RCVD; /* 11:8 */
2364601Swnj 		goto done;
2374601Swnj 
2384601Swnj 	case SYN_RCVD:
2394601Swnj 	case L_SYN_RCVD:
2404601Swnj 		if ((n->th_flags&TH_ACK) == 0 ||
2414601Swnj 		    (n->th_flags&TH_ACK) && n->t_ackno <= tp->iss) {
2424601Swnj 			nstate = EFAILEC;
2434601Swnj 			goto done;
2444601Swnj 		}
2454601Swnj 		goto input;
2464601Swnj 
2474601Swnj 	case ESTAB:
2484601Swnj 	case FIN_W1:
2494601Swnj 	case FIN_W2:
2504601Swnj 	case TIME_WAIT:
2514601Swnj input:
2524675Swnj 		tcp_ctldat(tp, n, 1);				/* 39 */
2534601Swnj 		switch (tp->t_state) {
2544601Swnj 
2554601Swnj 		case ESTAB:
2564601Swnj 			if (tp->tc_flags&TC_FIN_RCVD)
2574601Swnj 				nstate = CLOSE_WAIT;
2584601Swnj 			break;
2594601Swnj 
2604601Swnj 		case SYN_RCVD:
2614601Swnj 		case L_SYN_RCVD:
2624601Swnj 			nstate = (tp->tc_flags&TC_FIN_RCVD) ?
2634601Swnj 			    CLOSE_WAIT : ESTAB;			 /* 33:5 */
2644601Swnj 			break;
2654601Swnj 
2664601Swnj 		case FIN_W1:
2674601Swnj 			j = ack_fin(tp, n);
2684601Swnj 			if ((tp->tc_flags & TC_FIN_RCVD) == 0) {
2694601Swnj 				if (j)
2704601Swnj 					nstate = FIN_W2;	/* 27 */
2714601Swnj 				break;
2724601Swnj 			}
2734601Swnj 			tp->t_finack = T_2ML;
2744601Swnj 			tp->tc_flags &= ~TC_WAITED_2_ML;
2754601Swnj 			nstate = j ? TIME_WAIT : CLOSING1;	/* 28:26 */
2764601Swnj 			break;
2774601Swnj 
2784601Swnj 		case FIN_W2:
2794601Swnj 			if (tp->tc_flags&TC_FIN_RCVD) {
2804601Swnj 				tp->t_finack = T_2ML;		/* 29 */
2814601Swnj 				tp->tc_flags &= ~TC_WAITED_2_ML;
2824601Swnj 				nstate = TIME_WAIT;
2834601Swnj 				break;
2844601Swnj 			}
2854601Swnj 			break;
2864601Swnj 		}
2874601Swnj 		goto done;
2884601Swnj 
2894601Swnj 	case CLOSE_WAIT:
2904601Swnj 		if (n->th_flags&TH_FIN) {
2914601Swnj 			if ((n->th_flags&TH_ACK) &&
2924601Swnj 			    n->t_ackno <= tp->seq_fin) {
2934675Swnj 				tcp_ctldat(tp, n, 0);		/* 30 */
2944601Swnj 				tp->t_finack = T_2ML;
2954601Swnj 				tp->tc_flags &= ~TC_WAITED_2_ML;
2964601Swnj 			} else
2974675Swnj 				tcp_sndctl(tp);			/* 31 */
2984601Swnj 			goto done;
2994601Swnj 		}
3004601Swnj 		goto input;
3014601Swnj 
3024601Swnj 	case CLOSING1:
3034601Swnj 		j = ack_fin(tp, n);
3044601Swnj 		if (n->th_flags&TH_FIN) {
3054675Swnj 			tcp_ctldat(tp, n, 0);
3064601Swnj 			tp->t_finack = T_2ML;
3074601Swnj 			tp->tc_flags &= ~TC_WAITED_2_ML;
3084601Swnj 			if (j)
3094601Swnj 				nstate = TIME_WAIT;		/* 23 */
3104601Swnj 			goto done;
3114601Swnj 		}
3124601Swnj 		if (j) {
3134601Swnj 			if (tp->tc_flags&TC_WAITED_2_ML)
3144601Swnj 				if (rcv_empty(tp)) {
3154675Swnj 					tcp_close(tp, UCLOSED);	/* 15 */
3164601Swnj 					nstate = CLOSED;
3174601Swnj 				} else
3184601Swnj 					nstate = RCV_WAIT;	/* 18 */
3194601Swnj 			else
3204601Swnj 				nstate = TIME_WAIT;
3214601Swnj 			goto done;
3224601Swnj 		}
3234601Swnj 		goto input;
3244601Swnj 
3254601Swnj 	case CLOSING2:
3264601Swnj 		if (ack_fin(tp, n)) {
3274601Swnj 			if (rcv_empty(tp)) {			/* 16 */
3284675Swnj 				tcp_close(tp, UCLOSED);
3294601Swnj 				nstate = CLOSED;
3304601Swnj 			} else
3314601Swnj 				nstate = RCV_WAIT;		/* 19 */
3324601Swnj 			goto done;
3334601Swnj 		}
3344601Swnj 		if (n->th_flags&TH_FIN) {
3354675Swnj 			tcp_sndctl(tp);				/* 31 */
3364601Swnj 			goto done;
3374601Swnj 		}
3384601Swnj 		goto input;
3394601Swnj 
3404601Swnj 	case RCV_WAIT:
3414601Swnj 		if ((n->th_flags&TH_FIN) && (n->th_flags&TH_ACK) &&
3424601Swnj 		    n->t_ackno <= tp->seq_fin) {
3434675Swnj 			tcp_ctldat(tp, n, 0);
3444601Swnj 			tp->t_finack = T_2ML;
3454601Swnj 			tp->tc_flags &= ~TC_WAITED_2_ML;	/* 30 */
3464601Swnj 		}
3474601Swnj 		goto done;
3484601Swnj 	}
3494601Swnj 	panic("tcp_input");
3504601Swnj done:
3514601Swnj 
3524601Swnj 	/*
3534601Swnj 	 * Done with state*input specific processing.
3544601Swnj 	 * Form trace records, free input if not needed,
3554601Swnj 	 * and enter new state.
3564601Swnj 	 */
3574601Swnj #ifdef TCPDEBUG
3584604Swnj 	if (tdb.td_tod)
3594604Swnj 		tdb_stuff(&tdb, nstate);
3604601Swnj #endif
3614601Swnj 	switch (nstate) {
3624601Swnj 
3634601Swnj 	case EFAILEC:
3644601Swnj 		m_freem(mp);
3654601Swnj 		return;
3664601Swnj 
3674601Swnj 	default:
3684601Swnj 		tp->t_state = nstate;
3694601Swnj 		/* fall into ... */
3704601Swnj 
3714601Swnj 	case CLOSED:
3724601Swnj 		/* IF CLOSED CANT LOOK AT tc_flags */
3734601Swnj 		if ((tp->tc_flags&TC_NET_KEEP) == 0)
374*4690Swnj 			/* inline expansion of m_freem */
375*4690Swnj 			while (mp) {
376*4690Swnj 				MFREE(mp, m);
377*4690Swnj 				mp = m;
378*4690Swnj 			}
3794601Swnj 		return;
3804601Swnj 	}
3814601Swnj 	/* NOTREACHED */
3824601Swnj 
3834601Swnj 	/*
3844601Swnj 	 * Unwanted packed; free everything
3854601Swnj 	 * but the header and return an rst.
3864601Swnj 	 */
3874601Swnj notwanted:
3884601Swnj 	m_freem(mp->m_next);
3894601Swnj 	mp->m_next = NULL;
3904601Swnj 	mp->m_len = sizeof(struct th);
3914601Swnj #define xchg(a,b) j=a; a=b; b=j
3924601Swnj 	xchg(n->t_d.s_addr, n->t_s.s_addr); xchg(n->t_dst, n->t_src);
3934601Swnj #undef xchg
3944601Swnj 	if (n->th_flags&TH_ACK)
3954601Swnj 		n->t_seq = n->t_ackno;
3964601Swnj 	else {
3974601Swnj 		n->t_ackno = htonl(ntohl(n->t_seq) + tlen - hlen);
3984601Swnj 		n->t_seq = 0;
3994601Swnj 	}
4004601Swnj 	n->th_flags = TH_RST; /* not TH_FIN, TH_SYN */
4014601Swnj 	n->th_flags ^= TH_ACK;
4024601Swnj 	n->t_len = htons(TCPSIZE);
4034601Swnj 	n->t_off = 5;
4044601Swnj 	n->t_sum = cksum(mp, sizeof(struct th));
4054601Swnj 	((struct ip *)n)->ip_len = sizeof(struct th);
4064601Swnj 	ip_output(mp);
4074601Swnj 	netstat.t_badsegs++;
4084601Swnj }
4094601Swnj 
4104675Swnj tcp_ctldat(tp, n, dataok)
4114601Swnj 	register struct tcb *tp;
4124601Swnj 	register struct th *n;
4134601Swnj {
4144679Swnj 	register struct mbuf *m;
4154679Swnj 	int sent;
4164679Swnj COUNT(TCP_CTLDAT);
4174601Swnj 
4184601Swnj 	tp->tc_flags &= ~(TC_DROPPED_TXT|TC_ACK_DUE|TC_NEW_WINDOW);
4194601Swnj /* syn */
4204601Swnj 	if ((tp->tc_flags&TC_SYN_RCVD) == 0 && (n->th_flags&TH_SYN)) {
4214601Swnj 		tp->irs = n->t_seq;
4224601Swnj 		tp->rcv_nxt = n->t_seq + 1;
4234601Swnj 		tp->snd_wl = tp->rcv_urp = tp->irs;
4244601Swnj 		tp->tc_flags |= (TC_SYN_RCVD|TC_ACK_DUE);
4254601Swnj 	}
4264601Swnj /* ack */
4274601Swnj 	if ((n->th_flags&TH_ACK) && (tp->tc_flags&TC_SYN_RCVD) &&
4284601Swnj 	    n->t_ackno > tp->snd_una) {
4294679Swnj 		register struct mbuf *mn;
4304679Swnj 		register struct ucb *up;
431*4690Swnj 		int len;
4324679Swnj 
4334601Swnj 		up = tp->t_ucb;
4344601Swnj 
4354601Swnj 		/* update snd_una and snd_nxt */
4364601Swnj 		tp->snd_una = n->t_ackno;
4374601Swnj 		if (tp->snd_una > tp->snd_nxt)
4384601Swnj 			tp->snd_nxt = tp->snd_una;
4394601Swnj 		/* if timed msg acked, set retrans time value */
4404601Swnj 		if ((tp->tc_flags&TC_SYN_ACKED) &&
4414601Swnj 		    tp->snd_una > tp->t_xmt_val) {
4424601Swnj 			tp->t_xmtime = (tp->t_xmt != 0 ? tp->t_xmt : T_REXMT);
4434601Swnj 			if (tp->t_xmtime > T_REMAX)
4444601Swnj 				tp->t_xmtime = T_REMAX;
4454601Swnj 		}
4464601Swnj 
4474601Swnj 		/* remove acked data from send buf */
4484601Swnj 		len = tp->snd_una - tp->snd_off;
4494601Swnj 		m = up->uc_sbuf;
4504601Swnj 		while (len > 0 && m != NULL)
4514601Swnj 			if (m->m_len <= len) {
4524601Swnj 				len -= m->m_len;
4534601Swnj 				if (m->m_off > MMAXOFF)
4544601Swnj 					up->uc_ssize -= NMBPG;
4554601Swnj 				MFREE(m, mn);
4564601Swnj 				m = mn;
4574601Swnj 				up->uc_ssize--;
4584601Swnj 			} else {
4594601Swnj 				m->m_len -= len;
4604601Swnj 				m->m_off += len;
4614601Swnj 				break;
4624601Swnj 			}
4634601Swnj 		up->uc_sbuf = m;
4644601Swnj 		tp->snd_off = tp->snd_una;
4654601Swnj 		if ((tp->tc_flags&TC_SYN_ACKED) == 0 &&
4664601Swnj 		    (tp->snd_una > tp->iss)) {
4674601Swnj 			tp->tc_flags |= TC_SYN_ACKED;
4684601Swnj 			tp->t_init = 0;
4694601Swnj 		}
4704601Swnj 		if (tp->seq_fin != tp->iss && tp->snd_una > tp->seq_fin)
4714601Swnj 			tp->tc_flags &= ~TC_SND_FIN;
4724601Swnj 		tp->t_rexmt = 0;
4734601Swnj 		tp->t_rexmttl = 0;
4744601Swnj 		tp->tc_flags |= TC_CANCELLED;
4754601Swnj 		netwakeup(tp->t_ucb);		/* wasteful */
4764601Swnj 	}
4774601Swnj /* win */
4784601Swnj 	if ((tp->tc_flags & TC_SYN_RCVD) && n->t_seq >= tp->snd_wl) {
4794601Swnj 		tp->snd_wl = n->t_seq;
4804601Swnj 		tp->snd_wnd = n->t_win;
4814601Swnj 		tp->tc_flags |= TC_NEW_WINDOW;
4824601Swnj 		tp->t_persist = 0;
4834601Swnj 	}
4844679Swnj 	if (dataok == 0)
4854679Swnj 		goto ctlonly;
4864601Swnj /* text */
4874679Swnj 	if (n->t_len == 0)
4884679Swnj 		goto notext;
4894679Swnj 	{ register int i;
4904679Swnj 	  register struct th *p, *q;
4914679Swnj 	  register struct mbuf *m;
4924679Swnj 	  int overage;
4934601Swnj 
4944645Swnj 	/*
4954645Swnj 	 * Discard duplicate data already passed to user.
4964645Swnj 	 */
4974648Swnj 	if (SEQ_LT(n->t_seq, tp->rcv_nxt)) {
4984645Swnj 		i = tp->rcv_nxt - n->t_seq;
4994645Swnj 		if (i >= n->t_len)
5004679Swnj 			goto notext;
5014645Swnj 		n->t_seq += i;
5024645Swnj 		n->t_len -= i;
5034645Swnj 		m_adj(dtom(n), i);
5044601Swnj 	}
5054601Swnj 
5064645Swnj 	/*
5074645Swnj 	 * Find a segment which begins after this one does.
5084645Swnj 	 */
5094645Swnj 	for (q = tp->t_rcv_next; q != (struct th *)tp; q = q->t_next)
5104648Swnj 		if (SEQ_GT(q->t_seq, n->t_seq))
5114645Swnj 			break;
5124601Swnj 
5134645Swnj 	/*
5144645Swnj 	 * If there is a preceding segment, it may provide some of
5154645Swnj 	 * our data already.  If so, drop the data from the incoming
5164645Swnj 	 * segment.  If it provides all of our data, drop us.
5174645Swnj 	 */
5184645Swnj 	if (q->t_prev != (struct th *)tp) {
5194648Swnj 		/* conversion to int (in i) handles seq wraparound */
5204645Swnj 		i = q->t_prev->t_seq + q->t_prev->t_len - n->t_seq;
5214645Swnj 		if (i > 0) {
5224645Swnj 			if (i >= n->t_len)
5234679Swnj 				goto notext;	/* w/o setting TC_NET_KEEP */
5244645Swnj 			m_adj(dtom(tp), i);
5254645Swnj 			n->t_len -= i;
5264645Swnj 			n->t_seq += i;
5274601Swnj 		}
5284601Swnj 	}
5294601Swnj 
5304645Swnj 	/*
5314645Swnj 	 * While we overlap succeeding segments trim them or,
5324645Swnj 	 * if they are completely covered, dequeue them.
5334645Swnj 	 */
5344648Swnj 	while (q != (struct th *)tp && SEQ_GT(n->t_seq + n->t_len, q->t_seq)) {
5354645Swnj 		i = (n->t_seq + n->t_len) - q->t_seq;
5364645Swnj 		if (i < q->t_len) {
5374645Swnj 			q->t_len -= i;
5384645Swnj 			m_adj(dtom(q), i);
5394645Swnj 			break;
5404601Swnj 		}
5414645Swnj 		q = q->t_next;
5424645Swnj 		m_freem(dtom(q->t_prev));
5434645Swnj 		remque(q->t_prev);
5444645Swnj 	}
5454601Swnj 
5464645Swnj 	/*
5474645Swnj 	 * Stick new segment in its place.
5484645Swnj 	 */
5494645Swnj 	insque(n, q->t_prev);
5504656Swnj 	tp->seqcnt += n->t_len;
5514601Swnj 
5524601Swnj #ifdef notdef
5534645Swnj 	/*
5544645Swnj 	 * Calculate available space and discard segments for
5554645Swnj 	 * which there is too much.
5564645Swnj 	 */
5574645Swnj 	q = tp->t_rcv_prev;
5584648Swnj 	overage =
5594679Swnj 	    (tp->t_ucb->uc_rcc + tp->rcv_seqcnt) - tp->t_ucb->uc_rhiwat;
5604645Swnj 	if (overage > 0)
5614645Swnj 		for (;;) {
5624645Swnj 			i = MIN(q->t_len, overage);
5634645Swnj 			overage -= i;
5644645Swnj 			q->t_len -= i;
5654645Swnj 			m_adj(q, -i);
5664645Swnj 			if (q == n)
5674645Swnj 				tp->tc_flags |= TC_DROPPED_TXT;
5684645Swnj 			if (q->t_len)
5694645Swnj 				break;
5704645Swnj 			if (q == n)
5714648Swnj 				panic("tcp_text dropall");
5724645Swnj 			q = q->t_prev;
5734645Swnj 			remque(q->t_next);
5744645Swnj 		}
5754645Swnj #endif
5764601Swnj 
5774645Swnj 	/*
5784648Swnj 	 * Advance rcv_next through
5794648Swnj 	 * newly completed sequence space
5804648Swnj 	 * and return forcing an ack.
5814645Swnj 	 */
5824645Swnj 	while (n->t_seq == tp->rcv_nxt) {
5834648Swnj 		/* present data belongs here */
5844645Swnj 		tp->rcv_nxt += n->t_len;
5854645Swnj 		n = n->t_next;
5864645Swnj 		if (n == (struct th *)tp)
5874645Swnj 			break;
5884645Swnj 	}
5894645Swnj 	tp->tc_flags |= (TC_ACK_DUE|TC_NET_KEEP);
5904679Swnj 	}
5914679Swnj notext:
592*4690Swnj urgeolfin:
5934679Swnj /* urg */
5944679Swnj 	if (n->th_flags&TH_URG) {
5954679Swnj 		unsigned urgent;
5964601Swnj 
5974679Swnj 		urgent = n->t_urp + n->t_seq;
5984679Swnj 		if (tp->rcv_nxt < urgent) {
5994679Swnj 			if (tp->rcv_urp <= tp->rcv_nxt)
6004679Swnj 				to_user(tp->t_ucb, UURGENT);
6014679Swnj 			tp->rcv_urp = urgent;
6024679Swnj 		}
6034679Swnj 	}
6044679Swnj /* eol */
6054679Swnj 	if ((n->th_flags&TH_EOL) &&
6064679Swnj 	    (tp->tc_flags&TC_DROPPED_TXT) == 0 &&
6074679Swnj 	    tp->t_rcv_prev != (struct th *)tp) {
6084679Swnj 		/* mark last mbuf */
6094679Swnj 		m = dtom(tp->t_rcv_prev);
6104679Swnj 		if (m != NULL) {
6114679Swnj 			while (m->m_next != NULL)
6124679Swnj 				m = m->m_next;
6134679Swnj 			m->m_act =
6144679Swnj 			    (struct mbuf *)(m->m_off + m->m_len - 1);
6154679Swnj 		}
6164679Swnj 	}
6174679Swnj ctlonly:
6184679Swnj /* fin */
6194679Swnj 	if ((n->th_flags&TH_FIN) && (tp->tc_flags&TC_DROPPED_TXT) == 0) {
6204679Swnj 		seq_t last;
6214679Swnj 
6224679Swnj 		if ((tp->tc_flags&TC_FIN_RCVD) == 0) {
6234679Swnj 			/* do we really have fin ? */
6244679Swnj 			last = firstempty(tp);
6254679Swnj 			if (tp->t_rcv_prev == (struct th *)tp ||
6264679Swnj 			    last == t_end(tp->t_rcv_prev)) {
6274679Swnj 				tp->tc_flags |= TC_FIN_RCVD;
6284679Swnj 				netwakeup(tp->t_ucb);		/* poke */
6294679Swnj 			}
6304679Swnj 			if ((tp->tc_flags&TC_FIN_RCVD) &&
6314679Swnj 			    tp->rcv_nxt >= last) {
6324679Swnj 				tp->rcv_nxt = last + 1;		/* fin seq */
6334679Swnj 				tp->tc_flags |= TC_ACK_DUE;
6344679Swnj 			}
6354679Swnj 		} else
6364679Swnj 			tp->tc_flags |= TC_ACK_DUE;
6374679Swnj 	}
6384679Swnj 
6394679Swnj /* respond */
6404679Swnj 	sent = 0;
6414679Swnj 	if (tp->tc_flags&TC_ACK_DUE)
6424679Swnj 		sent = tcp_sndctl(tp);
6434679Swnj 	else if (tp->tc_flags&TC_NEW_WINDOW) {
6444679Swnj 		seq_t last = tp->snd_off;
6454679Swnj 		for (m = tp->t_ucb->uc_sbuf; m != NULL; m = m->m_next)	/*###*/
6464679Swnj 			last += m->m_len;				/*###*/
6474679Swnj 		if (tp->snd_nxt <= last || (tp->tc_flags&TC_SND_FIN))
6484679Swnj 			sent = tcp_send(tp);
6494679Swnj 	}
6504679Swnj 
6514679Swnj /* set for retrans */
6524679Swnj 	if (!sent && tp->snd_una < tp->snd_nxt &&
6534679Swnj 	    (tp->tc_flags&TC_CANCELLED)) {
6544679Swnj 		tp->t_rexmt = tp->t_xmtime;
6554679Swnj 		tp->t_rexmttl = T_REXMTTL;
6564679Swnj 		tp->t_rexmt_val = tp->t_rtl_val = tp->snd_lst;
6574679Swnj 		tp->tc_flags &= ~TC_CANCELLED;
6584679Swnj 	}
659*4690Swnj /* present data to user */
660*4690Swnj 	{ register struct mbuf **mp;
661*4690Swnj 	  register struct ucb *up = tp->t_ucb;
662*4690Swnj 	  seq_t ready;
6634601Swnj 
6644601Swnj 	/* connection must be synced and data available for user */
6654656Swnj 	if ((tp->tc_flags&TC_SYN_ACKED) == 0)
6664601Swnj 		return;
6674679Swnj 	up = tp->t_ucb;
6684601Swnj 	mp = &up->uc_rbuf;
6694601Swnj 	while (*mp)
6704601Swnj 		mp = &(*mp)->m_next;
671*4690Swnj 	n = tp->t_rcv_next;
6724656Swnj 	/* SHOULD PACK DATA IN HERE */
673*4690Swnj 	while (n != (struct th *)tp && n->t_seq < tp->rcv_nxt) {
674*4690Swnj 		remque(n);
675*4690Swnj 		m = dtom(n);
676*4690Swnj 		up->uc_rcc += n->t_len;
677*4690Swnj 		tp->seqcnt -= n->t_len;
6784656Swnj 		if (tp->seqcnt < 0) panic("present_data");
679*4690Swnj 		n = n->t_next;
6804601Swnj 		while (m) {
6814601Swnj 			if (m->m_len == 0) {
6824601Swnj 				m = m_free(m);
6834601Swnj 				continue;
6844601Swnj 			}
6854656Swnj 			*mp = m;
6864601Swnj 			mp = &m->m_next;
6874601Swnj 			m = *mp;
6884601Swnj 		}
6894601Swnj 	}
6904656Swnj 	if (up->uc_rcc != 0)
6914601Swnj 		netwakeup(up);
6924656Swnj 	if ((tp->tc_flags&TC_FIN_RCVD) &&			/* ### */
6934656Swnj 	    (tp->tc_flags&TC_USR_CLOSED) == 0 &&		/* ### */
6944656Swnj 	    rcv_empty(tp))					/* ### */
6954656Swnj 		to_user(up, UCLOSED);				/* ### */
696*4690Swnj 	}
6974601Swnj }
698