xref: /csrg-svn/sys/netinet/tcp_input.c (revision 4604)
1*4604Swnj /* tcp_input.c 1.3 81/10/25 */
24601Swnj 
34601Swnj #include "../h/param.h"
44601Swnj #include "../h/systm.h"
54601Swnj #include "../bbnnet/net.h"
64601Swnj #include "../bbnnet/mbuf.h"
74601Swnj #include "../bbnnet/host.h"
84601Swnj #include "../bbnnet/imp.h"
94601Swnj #include "../bbnnet/ucb.h"
104601Swnj #include "../bbnnet/tcp.h"
114601Swnj #include "../bbnnet/ip.h"
124601Swnj #include "../h/dir.h"
134601Swnj #include "../h/user.h"
144601Swnj #include "../h/inode.h"
154601Swnj #include "../bbnnet/fsm.h"
164601Swnj 
174601Swnj extern int nosum;
184601Swnj 
194601Swnj tcp_input(mp)
204601Swnj 	register struct mbuf *mp;
214601Swnj {
224601Swnj 	register struct tcb *tp;
234601Swnj 	register struct th *n;
244601Swnj 	int nstate;
254601Swnj 	struct mbuf *m;
264601Swnj 	struct ucb *up;
274601Swnj 	int hlen, tlen, j;
284601Swnj 	u_short lport, fport;
294601Swnj #ifdef TCPDEBUG
304601Swnj 	struct tcp_debug tdb;
314601Swnj #endif
324601Swnj COUNT(TCP_INPUT);
334601Swnj 
344601Swnj 	/*
354601Swnj 	 * Build extended tcp header
364601Swnj 	 */
374601Swnj 	n = (struct th *)((int)mp + mp->m_off);
384601Swnj 	tlen = ((struct ip *)n)->ip_len;
394601Swnj 	n->t_len = htons(tlen);
404601Swnj 	n->t_next = NULL;
414601Swnj 	n->t_prev = NULL;
424601Swnj 	n->t_x1 = 0;
434601Swnj 	lport = ntohs(n->t_dst);
444601Swnj 	fport = ntohs(n->t_src);
454601Swnj 
464601Swnj 	/* WONT BE POSSIBLE WHEN MBUFS ARE 256 BYTES */
474601Swnj 	if ((hlen = n->t_off << 2) > mp->m_len)
484601Swnj 		{ printf("tcp header overflow\n"); m_freem(mp); return; }
494601Swnj 
504601Swnj 	/*
514601Swnj 	 * Checksum extended header and data
524601Swnj 	 */
534601Swnj 	j = n->t_sum; n->t_sum = 0;
544601Swnj 	if (j != cksum(mp, sizeof (struct ip) + tlen)) {
554601Swnj 		netstat.t_badsum++;
564601Swnj 		if (nosum == 0) {
574601Swnj 			m_freem(mp);
584601Swnj 			return;
594601Swnj 		}
604601Swnj 	}
614601Swnj 
624601Swnj 	/*
634601Swnj 	 * Find tcb for message (SHOULDN'T USE LINEAR SEARCH!)
644601Swnj 	 */
654601Swnj 	for (tp = netcb.n_tcb_head; tp != 0; tp = tp->t_tcb_next)
664601Swnj 		if (tp->t_lport == lport && tp->t_fport == fport &&
674601Swnj 		    tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr)
684601Swnj 			goto found;
694601Swnj 	for (tp = netcb.n_tcb_head; tp != 0; tp = tp->t_tcb_next)
704601Swnj 		if (tp->t_lport == lport &&
714601Swnj 		    (tp->t_fport==fport || tp->t_fport==0) &&
724601Swnj 		    (tp->t_ucb->uc_host->h_addr.s_addr == n->t_s.s_addr ||
734601Swnj 		     tp->t_ucb->uc_host->h_addr.s_addr == 0))
744601Swnj 			goto found;
754601Swnj 	goto notwanted;
764601Swnj found:
774601Swnj 
784601Swnj 	/*
794601Swnj 	 * Byte swap header
804601Swnj 	 */
814601Swnj 	n->t_len = tlen - hlen;
824601Swnj 	n->t_src = fport;
834601Swnj 	n->t_dst = lport;
844601Swnj 	n->t_seq = ntohl(n->t_seq);
854601Swnj 	n->t_ackno = ntohl(n->t_ackno);
864601Swnj 	n->t_win = ntohs(n->t_win);
874601Swnj 	n->t_urp = ntohs(n->t_urp);
884601Swnj 
894601Swnj 	/*
904601Swnj 	 * Check segment seq # and do rst processing
914601Swnj 	 */
924601Swnj 	switch (tp->t_state) {
934601Swnj 
944601Swnj 	case LISTEN:
954601Swnj 		if ((n->th_flags&TH_ACK) || !syn_ok(tp, n)) {
964601Swnj 			send_rst(tp, n);
974601Swnj 			goto badseg;
984601Swnj 		}
994601Swnj 		if (n->th_flags&TH_RST)
1004601Swnj 			goto badseg;
1014601Swnj 		goto goodseg;
1024601Swnj 
1034601Swnj 	case SYN_SENT:
1044601Swnj 		if (!ack_ok(tp, n) || !syn_ok(tp, n)) {
1054601Swnj 			send_rst(tp, n);			/* 71,72,75 */
1064601Swnj 			goto badseg;
1074601Swnj 		}
1084601Swnj 		if (n->th_flags&TH_RST) {
1094601Swnj 			t_close(tp, URESET);			/* 70 */
1104601Swnj 			tp->t_state = CLOSED;
1114601Swnj 			goto badseg;
1124601Swnj 		}
1134601Swnj 		goto goodseg;
1144601Swnj 
1154601Swnj 	default:
1164601Swnj         	if ((n->th_flags&TH_RST) == 0)
1174601Swnj 			goto common;
1184601Swnj 		if (n->t_seq < tp->rcv_nxt)		/* bad rst */
1194601Swnj 			goto badseg;				/* 69 */
1204601Swnj 		switch (tp->t_state) {
1214601Swnj 
1224601Swnj 		case L_SYN_RCVD:
1234601Swnj 			if (ack_ok(tp, n) == 0)
1244601Swnj 				goto badseg;			/* 69 */
1254601Swnj 			tp->t_rexmt = 0;
1264601Swnj 			tp->t_rexmttl = 0;
1274601Swnj 			tp->t_persist = 0;
1284601Swnj 			h_free(tp->t_ucb->uc_host);
1294601Swnj 			tp->t_state = LISTEN;
1304601Swnj 			goto badseg;
1314601Swnj 
1324601Swnj 		default:
1334601Swnj 			t_close(tp, URESET);			/* 66 */
1344601Swnj 			tp->t_state = CLOSED;
1354601Swnj 			goto badseg;
1364601Swnj 		}
1374601Swnj 		/*NOTREACHED*/
1384601Swnj 
1394601Swnj 	case SYN_RCVD:
1404601Swnj common:
1414601Swnj 		if (ack_ok(tp, n) == 0) {
1424601Swnj 			send_rst(tp, n);			/* 74 */
1434601Swnj 			goto badseg;
1444601Swnj 		}
1454601Swnj 		if (syn_ok(tp, n) && n->t_seq != tp->irs) {
1464601Swnj 			send_null(tp);				/* 74 */
1474601Swnj 			goto badseg;
1484601Swnj 		}
1494601Swnj 		goto goodseg;
1504601Swnj 	}
1514601Swnj badseg:
1524601Swnj 	m_freem(mp);
1534601Swnj 	return;
1544601Swnj 
1554601Swnj goodseg:
1564601Swnj #ifdef notdef
1574601Swnj 	/*
1584601Swnj 	 * Defer processing if no buffer space for this connection.
1594601Swnj 	 */
1604601Swnj 	up = tp->t_ucb;
1614601Swnj 	if ((int)up->uc_rcv - (int)up->uc_rsize <= 0
1624601Swnj 	     && n->t_len != 0 && netcb.n_bufs < netcb.n_lowat) {
1634601Swnj 		mp->m_act = (struct mbuf *)0;
1644601Swnj 		if ((m = tp->t_rcv_unack) != NULL) {
1654601Swnj 			while (m->m_act != NULL)
1664601Swnj 				m = m->m_act;
1674601Swnj 			m->m_act = mp;
1684601Swnj 		} else
1694601Swnj 			tp->t_rcv_unack = mp;
1704601Swnj 
1714601Swnj 		return;
1724601Swnj 	}
1734601Swnj #endif
1744601Swnj 
1754601Swnj 	/*
1764601Swnj 	 * Discard ip header, and do tcp input processing.
1774601Swnj 	 */
1784601Swnj 	hlen += sizeof(struct ip);
1794601Swnj 	mp->m_off += hlen;
1804601Swnj 	mp->m_len -= hlen;
1814601Swnj 	nstate = tp->t_state;
1824601Swnj 	tp->tc_flags &= ~TC_NET_KEEP;
1834601Swnj 	acounts[tp->t_state][INRECV]++;
1844601Swnj #ifdef TCPDEBUG
1854601Swnj 	if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
186*4604Swnj 		tdb_setup(tp, n, INRECV, &tdb);
1874601Swnj 	} else
1884601Swnj 		tdb.td_tod = 0;
1894601Swnj #endif
1904601Swnj 	switch (tp->t_state) {
1914601Swnj 
1924601Swnj 	case LISTEN:
1934601Swnj 		if (!syn_ok(tp, n) ||
1944601Swnj 		    ((tp->t_ucb->uc_host = h_make(&n->t_s)) == 0)) {
1954601Swnj 			nstate = EFAILEC;
1964601Swnj 			goto done;
1974601Swnj 		}
1984601Swnj 		tp->t_fport = n->t_src;
1994603Sroot 		tp->t_ucb->uc_template = tcp_template(tp);
2004601Swnj 		rcv_ctldat(tp, n, 1);
2014601Swnj 		if (tp->tc_flags&TC_FIN_RCVD) {
2024601Swnj 			tp->t_finack = T_2ML;			/* 3 */
2034601Swnj 			tp->tc_flags &= ~TC_WAITED_2_ML;
2044601Swnj 			nstate = CLOSE_WAIT;
2054601Swnj 		} else {
2064601Swnj 			tp->t_init = T_INIT / 2;		/* 4 */
2074601Swnj 			nstate = L_SYN_RCVD;
2084601Swnj 		}
2094601Swnj 		goto done;
2104601Swnj 
2114601Swnj 	case SYN_SENT:
2124601Swnj 		if (!syn_ok(tp, n)) {
2134601Swnj 			nstate = EFAILEC;
2144601Swnj 			goto done;
2154601Swnj 		}
2164601Swnj 		rcv_ctldat(tp, n, 1);
2174601Swnj 		if (tp->tc_flags&TC_FIN_RCVD) {
2184601Swnj 			if (n->th_flags&TH_ACK) {
2194601Swnj 				if (n->t_ackno > tp->iss)
2204601Swnj 					present_data(tp);	/* 32 */
2214601Swnj 			} else {
2224601Swnj 				tp->t_finack = T_2ML;		/* 9 */
2234601Swnj 				tp->tc_flags &= ~TC_WAITED_2_ML;
2244601Swnj 			}
2254601Swnj 			nstate = CLOSE_WAIT;
2264601Swnj 			goto done;
2274601Swnj 		}
2284601Swnj 		if (n->th_flags&TH_ACK) {
2294601Swnj 			present_data(tp);			/* 11 */
2304601Swnj 			nstate = ESTAB;
2314601Swnj 		} else
2324601Swnj 			nstate = SYN_RCVD;			/* 8 */
2334601Swnj 		goto done;
2344601Swnj 
2354601Swnj 	case SYN_RCVD:
2364601Swnj 	case L_SYN_RCVD:
2374601Swnj 		if ((n->th_flags&TH_ACK) == 0 ||
2384601Swnj 		    (n->th_flags&TH_ACK) && n->t_ackno <= tp->iss) {
2394601Swnj 			nstate = EFAILEC;
2404601Swnj 			goto done;
2414601Swnj 		}
2424601Swnj 		goto input;
2434601Swnj 
2444601Swnj 	case ESTAB:
2454601Swnj 	case FIN_W1:
2464601Swnj 	case FIN_W2:
2474601Swnj 	case TIME_WAIT:
2484601Swnj input:
2494601Swnj 		rcv_ctldat(tp, n, 1);				/* 39 */
2504601Swnj 		present_data(tp);
2514601Swnj 		switch (tp->t_state) {
2524601Swnj 
2534601Swnj 		case ESTAB:
2544601Swnj 			if (tp->tc_flags&TC_FIN_RCVD)
2554601Swnj 				nstate = CLOSE_WAIT;
2564601Swnj 			break;
2574601Swnj 
2584601Swnj 		case SYN_RCVD:
2594601Swnj 		case L_SYN_RCVD:
2604601Swnj 			nstate = (tp->tc_flags&TC_FIN_RCVD) ?
2614601Swnj 			    CLOSE_WAIT : ESTAB;			 /* 33:5 */
2624601Swnj 			break;
2634601Swnj 
2644601Swnj 		case FIN_W1:
2654601Swnj 			j = ack_fin(tp, n);
2664601Swnj 			if ((tp->tc_flags & TC_FIN_RCVD) == 0) {
2674601Swnj 				if (j)
2684601Swnj 					nstate = FIN_W2;	/* 27 */
2694601Swnj 				break;
2704601Swnj 			}
2714601Swnj 			tp->t_finack = T_2ML;
2724601Swnj 			tp->tc_flags &= ~TC_WAITED_2_ML;
2734601Swnj 			nstate = j ? TIME_WAIT : CLOSING1;	/* 28:26 */
2744601Swnj 			break;
2754601Swnj 
2764601Swnj 		case FIN_W2:
2774601Swnj 			if (tp->tc_flags&TC_FIN_RCVD) {
2784601Swnj 				tp->t_finack = T_2ML;		/* 29 */
2794601Swnj 				tp->tc_flags &= ~TC_WAITED_2_ML;
2804601Swnj 				nstate = TIME_WAIT;
2814601Swnj 				break;
2824601Swnj 			}
2834601Swnj 			break;
2844601Swnj 		}
2854601Swnj 		goto done;
2864601Swnj 
2874601Swnj 	case CLOSE_WAIT:
2884601Swnj 		if (n->th_flags&TH_FIN) {
2894601Swnj 			if ((n->th_flags&TH_ACK) &&
2904601Swnj 			    n->t_ackno <= tp->seq_fin) {
2914601Swnj 				rcv_ctldat(tp, n, 0);		/* 30 */
2924601Swnj 				tp->t_finack = T_2ML;
2934601Swnj 				tp->tc_flags &= ~TC_WAITED_2_ML;
2944601Swnj 			} else
2954601Swnj 				send_ctl(tp);			/* 31 */
2964601Swnj 			goto done;
2974601Swnj 		}
2984601Swnj 		goto input;
2994601Swnj 
3004601Swnj 	case CLOSING1:
3014601Swnj 		j = ack_fin(tp, n);
3024601Swnj 		if (n->th_flags&TH_FIN) {
3034601Swnj 			rcv_ctldat(tp, n, 0);
3044601Swnj 			tp->t_finack = T_2ML;
3054601Swnj 			tp->tc_flags &= ~TC_WAITED_2_ML;
3064601Swnj 			if (j)
3074601Swnj 				nstate = TIME_WAIT;		/* 23 */
3084601Swnj 			goto done;
3094601Swnj 		}
3104601Swnj 		if (j) {
3114601Swnj 			if (tp->tc_flags&TC_WAITED_2_ML)
3124601Swnj 				if (rcv_empty(tp)) {
3134601Swnj 					t_close(tp, UCLOSED);	/* 15 */
3144601Swnj 					nstate = CLOSED;
3154601Swnj 				} else
3164601Swnj 					nstate = RCV_WAIT;	/* 18 */
3174601Swnj 			else
3184601Swnj 				nstate = TIME_WAIT;
3194601Swnj 			goto done;
3204601Swnj 		}
3214601Swnj 		goto input;
3224601Swnj 
3234601Swnj 	case CLOSING2:
3244601Swnj 		if (ack_fin(tp, n)) {
3254601Swnj 			if (rcv_empty(tp)) {			/* 16 */
3264601Swnj 				t_close(tp, UCLOSED);
3274601Swnj 				nstate = CLOSED;
3284601Swnj 			} else
3294601Swnj 				nstate = RCV_WAIT;		/* 19 */
3304601Swnj 			goto done;
3314601Swnj 		}
3324601Swnj 		if (n->th_flags&TH_FIN) {
3334601Swnj 			send_ctl(tp);				/* 31 */
3344601Swnj 			goto done;
3354601Swnj 		}
3364601Swnj 		goto input;
3374601Swnj 
3384601Swnj 	case RCV_WAIT:
3394601Swnj 		if ((n->th_flags&TH_FIN) && (n->th_flags&TH_ACK) &&
3404601Swnj 		    n->t_ackno <= tp->seq_fin) {
3414601Swnj 			rcv_ctldat(tp, n, 0);
3424601Swnj 			tp->t_finack = T_2ML;
3434601Swnj 			tp->tc_flags &= ~TC_WAITED_2_ML;	/* 30 */
3444601Swnj 		}
3454601Swnj 		goto done;
3464601Swnj 	}
3474601Swnj 	panic("tcp_input");
3484601Swnj done:
3494601Swnj 
3504601Swnj 	/*
3514601Swnj 	 * Done with state*input specific processing.
3524601Swnj 	 * Form trace records, free input if not needed,
3534601Swnj 	 * and enter new state.
3544601Swnj 	 */
3554601Swnj #ifdef TCPDEBUG
356*4604Swnj 	if (tdb.td_tod)
357*4604Swnj 		tdb_stuff(&tdb, nstate);
3584601Swnj #endif
3594601Swnj 	switch (nstate) {
3604601Swnj 
3614601Swnj 	case EFAILEC:
3624601Swnj 		m_freem(mp);
3634601Swnj 		return;
3644601Swnj 
3654601Swnj 	default:
3664601Swnj 		tp->t_state = nstate;
3674601Swnj 		/* fall into ... */
3684601Swnj 
3694601Swnj 	case CLOSED:
3704601Swnj 		/* IF CLOSED CANT LOOK AT tc_flags */
3714601Swnj 		if ((tp->tc_flags&TC_NET_KEEP) == 0)
3724601Swnj 			m_freem(mp);
3734601Swnj 		return;
3744601Swnj 	}
3754601Swnj 	/* NOTREACHED */
3764601Swnj 
3774601Swnj 	/*
3784601Swnj 	 * Unwanted packed; free everything
3794601Swnj 	 * but the header and return an rst.
3804601Swnj 	 */
3814601Swnj notwanted:
3824601Swnj 	m_freem(mp->m_next);
3834601Swnj 	mp->m_next = NULL;
3844601Swnj 	mp->m_len = sizeof(struct th);
3854601Swnj #define xchg(a,b) j=a; a=b; b=j
3864601Swnj 	xchg(n->t_d.s_addr, n->t_s.s_addr); xchg(n->t_dst, n->t_src);
3874601Swnj #undef xchg
3884601Swnj 	if (n->th_flags&TH_ACK)
3894601Swnj 		n->t_seq = n->t_ackno;
3904601Swnj 	else {
3914601Swnj 		n->t_ackno = htonl(ntohl(n->t_seq) + tlen - hlen);
3924601Swnj 		n->t_seq = 0;
3934601Swnj 	}
3944601Swnj 	n->th_flags = TH_RST; /* not TH_FIN, TH_SYN */
3954601Swnj 	n->th_flags ^= TH_ACK;
3964601Swnj 	n->t_len = htons(TCPSIZE);
3974601Swnj 	n->t_off = 5;
3984601Swnj 	n->t_sum = cksum(mp, sizeof(struct th));
3994601Swnj 	((struct ip *)n)->ip_len = sizeof(struct th);
4004601Swnj 	ip_output(mp);
4014601Swnj 	netstat.t_badsegs++;
4024601Swnj }
4034601Swnj 
4044601Swnj rcv_ctldat(tp, n, dataok)
4054601Swnj 	register struct tcb *tp;
4064601Swnj 	register struct th *n;
4074601Swnj {
4084601Swnj 	register sent;
4094601Swnj 	register struct ucb *up;
4104601Swnj 	register struct mbuf *m, *mn;
4114601Swnj 	register len;
4124601Swnj COUNT(RCV_CTLDAT);
4134601Swnj 
4144601Swnj 	tp->tc_flags &= ~(TC_DROPPED_TXT|TC_ACK_DUE|TC_NEW_WINDOW);
4154601Swnj /* syn */
4164601Swnj 	if ((tp->tc_flags&TC_SYN_RCVD) == 0 && (n->th_flags&TH_SYN)) {
4174601Swnj 		tp->irs = n->t_seq;
4184601Swnj 		tp->rcv_nxt = n->t_seq + 1;
4194601Swnj 		tp->snd_wl = tp->rcv_urp = tp->irs;
4204601Swnj 		tp->tc_flags |= (TC_SYN_RCVD|TC_ACK_DUE);
4214601Swnj 	}
4224601Swnj /* ack */
4234601Swnj 	if ((n->th_flags&TH_ACK) && (tp->tc_flags&TC_SYN_RCVD) &&
4244601Swnj 	    n->t_ackno > tp->snd_una) {
4254601Swnj 		up = tp->t_ucb;
4264601Swnj 
4274601Swnj 		/* update snd_una and snd_nxt */
4284601Swnj 		tp->snd_una = n->t_ackno;
4294601Swnj 		if (tp->snd_una > tp->snd_nxt)
4304601Swnj 			tp->snd_nxt = tp->snd_una;
4314601Swnj 
4324601Swnj 		/* if timed msg acked, set retrans time value */
4334601Swnj 		if ((tp->tc_flags&TC_SYN_ACKED) &&
4344601Swnj 		    tp->snd_una > tp->t_xmt_val) {
4354601Swnj 			tp->t_xmtime = (tp->t_xmt != 0 ? tp->t_xmt : T_REXMT);
4364601Swnj 			if (tp->t_xmtime > T_REMAX)
4374601Swnj 				tp->t_xmtime = T_REMAX;
4384601Swnj 		}
4394601Swnj 
4404601Swnj 		/* remove acked data from send buf */
4414601Swnj 		len = tp->snd_una - tp->snd_off;
4424601Swnj 		m = up->uc_sbuf;
4434601Swnj 		while (len > 0 && m != NULL)
4444601Swnj 			if (m->m_len <= len) {
4454601Swnj 				len -= m->m_len;
4464601Swnj 				if (m->m_off > MMAXOFF)
4474601Swnj 					up->uc_ssize -= NMBPG;
4484601Swnj 				MFREE(m, mn);
4494601Swnj 				m = mn;
4504601Swnj 				up->uc_ssize--;
4514601Swnj 			} else {
4524601Swnj 				m->m_len -= len;
4534601Swnj 				m->m_off += len;
4544601Swnj 				break;
4554601Swnj 			}
4564601Swnj 		up->uc_sbuf = m;
4574601Swnj 		tp->snd_off = tp->snd_una;
4584601Swnj 		if ((tp->tc_flags&TC_SYN_ACKED) == 0 &&
4594601Swnj 		    (tp->snd_una > tp->iss)) {
4604601Swnj 			tp->tc_flags |= TC_SYN_ACKED;
4614601Swnj 			tp->t_init = 0;
4624601Swnj 		}
4634601Swnj 		if (tp->seq_fin != tp->iss && tp->snd_una > tp->seq_fin)
4644601Swnj 			tp->tc_flags &= ~TC_SND_FIN;
4654601Swnj 		tp->t_rexmt = 0;
4664601Swnj 		tp->t_rexmttl = 0;
4674601Swnj 		tp->tc_flags |= TC_CANCELLED;
4684601Swnj 		netwakeup(tp->t_ucb);		/* wasteful */
4694601Swnj 	}
4704601Swnj /* win */
4714601Swnj 	if ((tp->tc_flags & TC_SYN_RCVD) && n->t_seq >= tp->snd_wl) {
4724601Swnj 		tp->snd_wl = n->t_seq;
4734601Swnj 		tp->snd_wnd = n->t_win;
4744601Swnj 		tp->tc_flags |= TC_NEW_WINDOW;
4754601Swnj 		tp->t_persist = 0;
4764601Swnj 	}
4774601Swnj 	if (dataok) {
4784601Swnj /* text */
4794601Swnj 		if (n->t_len != 0)
4804601Swnj 			rcv_text(tp, n);
4814601Swnj /* urg */
4824601Swnj 		if (n->th_flags&TH_URG) {
4834601Swnj 			unsigned urgent;
4844601Swnj 
4854601Swnj 			urgent = n->t_urp + n->t_seq;
4864601Swnj 			if (tp->rcv_nxt < urgent) {
4874601Swnj 				if (tp->rcv_urp <= tp->rcv_nxt)
4884601Swnj 					to_user(tp->t_ucb, UURGENT);
4894601Swnj 				tp->rcv_urp = urgent;
4904601Swnj 			}
4914601Swnj 		}
4924601Swnj /* eol */
4934601Swnj 		if ((n->th_flags&TH_EOL) &&
4944601Swnj 		    (tp->tc_flags&TC_DROPPED_TXT) == 0 &&
4954601Swnj 		    tp->t_rcv_prev != (struct th *)tp) {
4964601Swnj 			/* mark last mbuf */
4974601Swnj 			m = dtom(tp->t_rcv_prev);
4984601Swnj 			if (m != NULL) {
4994601Swnj 				while (m->m_next != NULL)
5004601Swnj 					m = m->m_next;
5014601Swnj 				m->m_act =
5024601Swnj 				    (struct mbuf *)(m->m_off + m->m_len - 1);
5034601Swnj 			}
5044601Swnj 		}
5054601Swnj 	}
5064601Swnj /* fin */
5074601Swnj 	if ((n->th_flags&TH_FIN) && (tp->tc_flags&TC_DROPPED_TXT) == 0) {
5084601Swnj 		int last;
5094601Swnj 
5104601Swnj 		if ((tp->tc_flags&TC_FIN_RCVD) == 0) {
5114601Swnj 			/* do we really have fin ? */
5124601Swnj 			last = firstempty(tp);
5134601Swnj 			if (tp->t_rcv_prev == (struct th *)tp ||
5144601Swnj 			    last == t_end(tp->t_rcv_prev)) {
5154601Swnj 				tp->tc_flags |= TC_FIN_RCVD;
5164601Swnj 				netwakeup(tp->t_ucb);		/* poke */
5174601Swnj 			}
5184601Swnj 			if ((tp->tc_flags&TC_FIN_RCVD) &&
5194601Swnj 			    tp->rcv_nxt >= last) {
5204601Swnj 				tp->rcv_nxt = last + 1;		/* fin seq */
5214601Swnj 				tp->tc_flags |= TC_ACK_DUE;
5224601Swnj 			}
5234601Swnj 		} else
5244601Swnj 			tp->tc_flags |= TC_ACK_DUE;
5254601Swnj 	}
5264601Swnj 
5274601Swnj /* respond */
5284601Swnj 	if (tp->tc_flags&TC_ACK_DUE)
5294601Swnj 		sent = send_ctl(tp);
5304601Swnj 	else if (tp->tc_flags&TC_NEW_WINDOW)
5314601Swnj 		sent = send(tp);
5324601Swnj 	else
5334601Swnj 		sent = 0;
5344601Swnj 
5354601Swnj /* set for retrans */
5364601Swnj 	if (!sent && tp->snd_una < tp->snd_nxt &&
5374601Swnj 	    (tp->tc_flags&TC_CANCELLED)) {
5384601Swnj 		tp->t_rexmt = tp->t_xmtime;
5394601Swnj 		tp->t_rexmttl = T_REXMTTL;
5404601Swnj 		tp->t_rexmt_val = tp->t_rtl_val = tp->snd_lst;
5414601Swnj 		tp->tc_flags &= ~TC_CANCELLED;
5424601Swnj 	}
5434601Swnj }
5444601Swnj 
5454601Swnj rcv_text(tp, t)
5464601Swnj 	register struct tcb *tp;
5474601Swnj 	register struct th *t;
5484601Swnj {
5494601Swnj 	register i;
5504601Swnj 	register struct th *p, *q;
5514601Swnj 	register struct mbuf *m, *n;
5524601Swnj 	struct th *savq;
5534601Swnj 	int last, j, k;
5544601Swnj COUNT(RCV_TEXT);
5554601Swnj 
5564601Swnj 	/* throw away any data we have already received */
5574601Swnj 	if ((i = tp->rcv_nxt - t->t_seq) > 0)  {
5584601Swnj 		if (i >= t->t_len)
5594601Swnj 			return;
5604601Swnj 		t->t_seq += i;
5614601Swnj 		t->t_len -= i;
5624601Swnj 		m_adj(dtom(t), i);
5634601Swnj 	}
5644601Swnj 
5654601Swnj 	last = t_end(t);                /* last seq # in incoming seg */
5664601Swnj 	i = rcv_resource(tp);           /* # buffers available to con */
5674601Swnj 
5684601Swnj 	/* count buffers in segment */
5694601Swnj 
5704601Swnj 	for (m = dtom(t), j = 0; m != NULL; m = m->m_next)
5714601Swnj 		if (m->m_len != 0) {
5724601Swnj         		j++;
5734601Swnj 			if (m->m_off > MMAXOFF)
5744601Swnj 				j += NMBPG;
5754601Swnj 		}
5764601Swnj 
5774601Swnj 	/* not enough resources to process segment */
5784601Swnj 
5794601Swnj 	if (j > i && netcb.n_bufs < netcb.n_lowat) {
5804601Swnj 
5814601Swnj 		/* if segment preceeds top of seqeuncing queue, try to take
5824601Swnj 		   buffers from bottom of queue */
5834601Swnj 
5844601Swnj                 q = tp->t_rcv_next;
5854601Swnj 		if (q != (struct th *)tp && tp->rcv_nxt < q->t_seq &&
5864601Swnj 		    t->t_seq < q->t_seq)
5874601Swnj 
5884601Swnj 			for (k=j-i, p = tp->t_rcv_prev; k > 0 &&
5894601Swnj 			     p != (struct th *)tp; k--) {
5904601Swnj 				savq = p->t_prev;
5914601Swnj 				tcp_deq(p);
5924601Swnj 				i += m_freem(dtom(p));
5934601Swnj 				p = savq;
5944601Swnj 			}
5954601Swnj 
5964601Swnj 		/* if still not enough room, drop text from end of segment */
5974601Swnj 
5984601Swnj 		if (j > i) {
5994601Swnj 
6004601Swnj 			for (m = dtom(t); i > 0 && m != NULL; i--)
6014601Swnj 				m = m->m_next;
6024601Swnj 
6034601Swnj         		while (m != NULL) {
6044601Swnj         			t->t_len -= m->m_len;
6054601Swnj         			last -= m->m_len;
6064601Swnj         			m->m_len = 0;
6074601Swnj         			m = m->m_next;
6084601Swnj         		}
6094601Swnj         		tp->tc_flags |= TC_DROPPED_TXT;
6104601Swnj         		if (last < t->t_seq)
6114601Swnj         			return;
6124601Swnj         	}
6134601Swnj 	}
6144601Swnj 
6154601Swnj 	/* merge incoming data into the sequence queue */
6164601Swnj 
6174601Swnj         q = tp->t_rcv_next;             /* -> top of sequencing queue */
6184601Swnj 
6194601Swnj         /* skip frags which new doesn't overlap at end */
6204601Swnj 
6214601Swnj         while ((q != (struct th *)tp) && (t->t_seq > t_end(q)))
6224601Swnj         	q = q->t_next;
6234601Swnj 
6244601Swnj         if (q == (struct th *)tp) {     /* frag at end of chain */
6254601Swnj 
6264601Swnj 		if (last >= tp->rcv_nxt) {
6274601Swnj 		        tp->tc_flags |= TC_NET_KEEP;
6284601Swnj         	        tcp_enq(t, tp->t_rcv_prev);
6294601Swnj 		}
6304601Swnj 
6314601Swnj         } else {
6324601Swnj 
6334601Swnj 		/* frag doesn't overlap any on chain */
6344601Swnj 
6354601Swnj         	if (last < q->t_seq) {
6364601Swnj 			tp->tc_flags |= TC_NET_KEEP;
6374601Swnj         		tcp_enq(t, q->t_prev);
6384601Swnj 
6394601Swnj         	/* new overlaps beginning of next frag only */
6404601Swnj 
6414601Swnj         	} else if (last < t_end(q)) {
6424601Swnj         		if ((i = last - q->t_seq + 1) < t->t_len) {
6434601Swnj                 		t->t_len -= i;
6444601Swnj         			m_adj(dtom(t), -i);
6454601Swnj 				tp->tc_flags |= TC_NET_KEEP;
6464601Swnj         			tcp_enq(t, q->t_prev);
6474601Swnj         		}
6484601Swnj 
6494601Swnj         	/* new overlaps end of previous frag */
6504601Swnj 
6514601Swnj         	} else {
6524601Swnj         		savq = q;
6534601Swnj         		if (t->t_seq <= q->t_seq) {     /* complete cover */
6544601Swnj         			savq = q->t_prev;
6554601Swnj         			tcp_deq(q);
6564601Swnj         			m_freem(dtom(q));
6574601Swnj 
6584601Swnj         		} else {                        /* overlap */
6594601Swnj         			if ((i = t_end(q) - t->t_seq + 1) < t->t_len) {
6604601Swnj                 			t->t_seq += i;
6614601Swnj                 			t->t_len -= i;
6624601Swnj                 			m_adj(dtom(t), i);
6634601Swnj 				} else
6644601Swnj 					t->t_len = 0;
6654601Swnj         		}
6664601Swnj 
6674601Swnj         	/* new overlaps at beginning of successor frags */
6684601Swnj 
6694601Swnj         		q = savq->t_next;
6704601Swnj         		while ((q != (struct th *)tp) && (t->t_len != 0) &&
6714601Swnj         			(q->t_seq < last))
6724601Swnj 
6734601Swnj         			/* complete cover */
6744601Swnj 
6754601Swnj         			if (t_end(q) <= last) {
6764601Swnj         				p = q->t_next;
6774601Swnj         				tcp_deq(q);
6784601Swnj         				m_freem(dtom(q));
6794601Swnj         				q = p;
6804601Swnj 
6814601Swnj         			} else {        /* overlap */
6824601Swnj 
6834601Swnj         				if ((i = last - q->t_seq + 1) < t->t_len) {
6844601Swnj                 				t->t_len -= i;
6854601Swnj                 				m_adj(dtom(t), -i);
6864601Swnj 					} else
6874601Swnj 						t->t_len = 0;
6884601Swnj         				break;
6894601Swnj         			}
6904601Swnj 
6914601Swnj         	/* enqueue whatever is left of new before successors */
6924601Swnj 
6934601Swnj         		if (t->t_len != 0) {
6944601Swnj 				tp->tc_flags |= TC_NET_KEEP;
6954601Swnj         			tcp_enq(t, savq);
6964601Swnj 			}
6974601Swnj         	}
6984601Swnj         }
6994601Swnj 
7004601Swnj 	/* set to ack completed data (no gaps) */
7014601Swnj 
7024601Swnj 	tp->rcv_nxt = firstempty(tp);
7034601Swnj 	tp->tc_flags |= TC_ACK_DUE;
7044601Swnj 
7054601Swnj #ifdef notdef
7064601Swnj 	/* THIS CODE CANT POSSIBLY WORK */
7074601Swnj 	/* if any room remaining in rcv buf, take any unprocessed
7084601Swnj 	   messages and schedule for later processing */
7094601Swnj 
7104601Swnj 	i = rcv_resource(tp);
7114601Swnj 
7124601Swnj 	while ((m = tp->t_rcv_unack) != NULL && i > 0) {
7134601Swnj 
7144601Swnj 		/* schedule work request */
7154601Swnj 
7164601Swnj 		t = (struct th *)((int)m + m->m_off);
7174601Swnj 		j = (t->t_off << 2) + sizeof(struct ip);
7184601Swnj 		m->m_off += j;
7194601Swnj 		m->m_len -= j;
7204601Swnj 		tp->t_rcv_unack = m->m_act;
7214601Swnj 		m->m_act = (struct mbuf *)0;
7224601Swnj 		netstat.t_unack++;
7234601Swnj 		tcp_work(INRECV, 0, tp, t);
7244601Swnj 
7254601Swnj 		/* remaining buffer space */
7264601Swnj 
7274601Swnj 		for (n = m; n != NULL; n = n->m_next)
7284601Swnj 			i--;
7294601Swnj 	}
7304601Swnj #endif
7314601Swnj }
7324601Swnj 
7334601Swnj present_data(tp)
7344601Swnj 	register struct tcb *tp;
7354601Swnj {
7364601Swnj 	register struct th *t;
7374601Swnj 	register struct ucb *up;
7384601Swnj 	register struct mbuf *m, **mp;
7394601Swnj 	seq_t ready;
7404601Swnj COUNT(PRESENT_DATA);
7414601Swnj 
7424601Swnj 	/* connection must be synced and data available for user */
7434601Swnj 	if (((tp->tc_flags&TC_SYN_ACKED) == 0) ||
7444601Swnj 	    (t = tp->t_rcv_next) == (struct th *)tp)
7454601Swnj 		return;
7464601Swnj 	up = tp->t_ucb;
7474601Swnj 	ready = firstempty(tp);     /* seq # of last complete datum */
7484601Swnj 	mp = &up->uc_rbuf;
7494601Swnj 	while (*mp)
7504601Swnj 		mp = &(*mp)->m_next;
7514601Swnj 	while (up->uc_rsize < up->uc_rcv && t != (struct th *) tp &&
7524601Swnj 	    t_end(t) < ready) {
7534601Swnj 		tcp_deq(t);
7544601Swnj 		m = dtom(t);
7554601Swnj 		t = t->t_next;
7564601Swnj 		while (m) {
7574601Swnj 			if (m->m_len == 0) {
7584601Swnj 				m = m_free(m);
7594601Swnj 				continue;
7604601Swnj 			}
7614601Swnj 			up->uc_rsize++;
7624601Swnj 			if (m->m_off > MMAXOFF)
7634601Swnj 				up->uc_rsize += NMBPG;
7644601Swnj 			if (*mp == 0)
7654601Swnj 				*mp = m;
7664601Swnj 			mp = &m->m_next;
7674601Swnj 			m = *mp;
7684601Swnj 		}
7694601Swnj 	}
7704601Swnj 	if (up->uc_rsize != 0)
7714601Swnj 		netwakeup(up);
7724601Swnj 	/*
7734601Swnj 	 * Let user know about foreign tcp close if no more data.
7744601Swnj 	 */
7754601Swnj 	if ((tp->tc_flags&TC_FIN_RCVD) && (tp->tc_flags&TC_USR_CLOSED) == 0 &&
7764601Swnj 	    rcv_empty(tp))
7774601Swnj 		to_user(up, UCLOSED);
7784601Swnj }
779*4604Swnj 
780*4604Swnj #ifdef TCPDEBUG
781*4604Swnj tdb_setup(tp, n, input, tdp)
782*4604Swnj 	struct tcb *tp;
783*4604Swnj 	register struct th *n;
784*4604Swnj 	int input;
785*4604Swnj 	register struct tcp_debug *tdp;
786*4604Swnj {
787*4604Swnj 
788*4604Swnj 	tdp->td_tod = time;
789*4604Swnj 	tdp->td_tcb = tp;
790*4604Swnj 	tdp->td_old = tp->t_state;
791*4604Swnj 	tdp->td_inp = input;
792*4604Swnj 	tdp->td_tim = 0;
793*4604Swnj 	tdp->td_new = -1;
794*4604Swnj 	if (n) {
795*4604Swnj 		tdp->td_sno = n->t_seq;
796*4604Swnj 		tdp->td_ano = n->t_ackno;
797*4604Swnj 		tdp->td_wno = n->t_win;
798*4604Swnj 		tdp->td_lno = n->t_len;
799*4604Swnj 		tdp->td_flg = n->th_flags;
800*4604Swnj 	} else
801*4604Swnj 		tdp->td_sno = tdp->td_ano = tdp->td_wno = tdp->td_lno =
802*4604Swnj 		    tdp->td_flg = 0;
803*4604Swnj }
804*4604Swnj 
805*4604Swnj tdb_stuff(tdp, nstate)
806*4604Swnj 	struct tcp_debug *tdp;
807*4604Swnj 	int nstate;
808*4604Swnj {
809*4604Swnj 
810*4604Swnj 	tdp->td_new = nstate;
811*4604Swnj 	tcp_debug[tdbx++ % TDBSIZE] = *tdp;
812*4604Swnj 	if (tcpconsdebug & 2)
813*4604Swnj 		tcp_prt(tdp);
814*4604Swnj }
815*4604Swnj #endif
816