xref: /csrg-svn/sys/netinet/tcp_output.c (revision 4885)
1*4885Swnj /* tcp_output.c 4.11 81/11/14 */
24677Swnj 
34677Swnj #include "../h/param.h"
44677Swnj #include "../h/systm.h"
54677Swnj #include "../h/mbuf.h"
64677Swnj #include "../h/socket.h"
74804Swnj #include "../h/socketvar.h"
84804Swnj #include "../net/inet_cksum.h"
94804Swnj #include "../net/inet.h"
104804Swnj #include "../net/inet_host.h"
11*4885Swnj #include "../net/inet_pcb.h"
124804Swnj #include "../net/inet_systm.h"
134804Swnj #include "../net/imp.h"
144804Swnj #include "../net/ip.h"
154804Swnj #include "../net/tcp.h"
164804Swnj #include "../net/tcp_var.h"
174804Swnj #include "../net/tcp_fsm.h"
184804Swnj #include "/usr/include/errno.h"
194677Swnj 
204678Swnj /*
214678Swnj  * Special routines to send control messages.
224678Swnj  */
234678Swnj tcp_sndctl(tp)
24*4885Swnj 	struct tcpcb *tp;
254678Swnj {
264678Swnj COUNT(TCP_SNDCTL);
274678Swnj 
284678Swnj         if (tcp_send(tp))
294678Swnj 		return (1);
304678Swnj 	tcp_sndnull(tp);
314804Swnj 	return (0);
324678Swnj }
334678Swnj 
344678Swnj tcp_sndwin(tp)
35*4885Swnj 	struct tcpcb *tp;
364678Swnj {
374678Swnj 	int ihave, hehas;
384678Swnj COUNT(TCP_SNDWIN);
394678Swnj 
404678Swnj 	if (tp->rcv_adv) {
41*4885Swnj 		register struct socket *so = tp->t_inpcb->inp_socket;
42*4885Swnj 
434804Swnj 		ihave = so->so_rcv.sb_hiwat -
444804Swnj 		    (so->so_rcv.sb_cc + tp->seqcnt);
454678Swnj 		hehas = tp->rcv_adv - tp->rcv_nxt;
464804Swnj 		if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35)
474678Swnj 			return;
484678Swnj 	}
494678Swnj         if (tcp_send(tp))
504678Swnj 		return (1);
514678Swnj 	tcp_sndnull(tp);
524678Swnj 	return (0);
534678Swnj }
544678Swnj 
554678Swnj tcp_sndnull(tp)
56*4885Swnj 	register struct tcpcb *tp;
574677Swnj {
584678Swnj COUNT(TCP_SNDNULL);
594678Swnj 
604678Swnj 	tcp_output(tp, 0, 0, (struct mbuf *)0);
614678Swnj         tp->tc_flags &= ~TC_ACK_DUE;
624678Swnj }
634678Swnj 
644678Swnj tcp_sndrst(tp, n)
65*4885Swnj 	register struct tcpcb *tp;
66*4885Swnj 	register struct tcpiphdr *n;
674678Swnj {
684678Swnj COUNT(TCP_SNDRST);
694678Swnj 
704678Swnj         /* don't send a reset in response to a reset */
714678Swnj 	if (n->th_flags&TH_RST)
724678Swnj 		return;
734678Swnj 	tp->tc_flags |= TC_SND_RST;
744678Swnj 	if (n->th_flags&TH_ACK)
754678Swnj 		tp->snd_nxt = n->t_ackno;
764678Swnj 	tp->tc_flags &= ~TC_SYN_RCVD;
774678Swnj 	tcp_sndnull(tp);
784678Swnj 	tp->tc_flags &= ~TC_SND_RST;
794678Swnj }
804678Swnj 
814678Swnj /*
824678Swnj  * Tcp segment output routine.
834678Swnj  */
844678Swnj tcp_send(tp)
85*4885Swnj 	register struct tcpcb *tp;
864678Swnj {
874677Swnj 	register unsigned long last, wind;
88*4885Swnj 	register struct socket *so = tp->t_inpcb->inp_socket;
894677Swnj 	struct mbuf *m;
90*4885Swnj 	int flags = 0, forced, sent, len;
914677Swnj 
924678Swnj COUNT(TCP_SEND);
934677Swnj 	tp->snd_lst = tp->snd_nxt;
944677Swnj 	forced = 0;
954677Swnj 	m = NULL;
964678Swnj 	if (tp->snd_nxt == tp->iss) {
974677Swnj 		flags |= TH_SYN;
984677Swnj 		tp->snd_lst++;
994677Swnj 	}
1004677Swnj 	last = tp->snd_off;
1014804Swnj 	for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next)
1024677Swnj 		last += m->m_len;
1034677Swnj 	if (tp->snd_nxt > last) {
1044677Swnj 		if ((tp->tc_flags&TC_SND_FIN) &&
1054677Swnj 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
1064677Swnj 
1074677Swnj 			flags |= TH_FIN;
1084677Swnj 			tp->seq_fin = tp->snd_lst++;
1094677Swnj 		}
1104678Swnj 	} else {
1114677Swnj 		if (tp->tc_flags&TC_SYN_ACKED) {
1124677Swnj 			wind = tp->snd_una + tp->snd_wnd;
1134677Swnj 			tp->snd_lst = min(last, wind);
1144677Swnj 			if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
1154677Swnj 				tp->snd_lst -= len - 1024;
1164677Swnj 			if (tp->snd_lst >= wind)
1174677Swnj 				tp->t_persist = T_PERS;
1184677Swnj 		}
1194677Swnj 		if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
1204677Swnj 			tp->snd_lst = tp->snd_nxt + 1;
1214677Swnj 			forced = 1;
1224698Swnj 		} else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0)
1234692Swnj 			return (0);
124*4885Swnj 		m = sb_copy(&so->so_snd,
125*4885Swnj 		      MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off,
126*4885Swnj 		      tp->snd_lst - tp->snd_off);
1274677Swnj 		if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
1284677Swnj 			flags |= TH_EOL;
1294677Swnj 		if ((tp->tc_flags&TC_SND_FIN) && !forced &&
1304677Swnj 		    tp->snd_lst == last &&
1314677Swnj 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
1324677Swnj 			flags |= TH_FIN;
1334677Swnj 			tp->seq_fin = tp->snd_lst++;
1344677Swnj 		}
1354677Swnj 	}
1364698Swnj 	if (tp->snd_nxt >= tp->snd_lst)
1374698Swnj 		return (0);
1384678Swnj 	if (tp->tc_flags & TC_SND_URG)
1394678Swnj 		flags |= TH_URG;
1404678Swnj 	sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m);
1414678Swnj 	if (!forced) {
1424678Swnj 		tp->t_rexmt = tp->t_xmtime;
1434678Swnj 		tp->t_rexmt_val = tp->snd_lst;
1444678Swnj 		if ((tp->tc_flags&TC_REXMT) == 0) {
1454678Swnj 			tp->t_rexmttl = T_REXMTTL;
1464678Swnj 			tp->t_rtl_val = tp->snd_lst;
1474677Swnj 		}
1484677Swnj 	}
1494678Swnj 	if (sent)
1504678Swnj 		tp->snd_nxt = tp->snd_lst;
1514678Swnj 	if ((tp->tc_flags&TC_SYN_ACKED) &&
1524678Swnj 	    tp->snd_una > tp->t_xmt_val) {
1534678Swnj 		tp->t_xmt = 0;
1544678Swnj 		tp->t_xmt_val = tp->snd_lst;
1554677Swnj 	}
1564678Swnj 	tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
1574692Swnj 	tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi);
1584678Swnj 	return (1);
1594677Swnj }
1604677Swnj 
1614677Swnj /*
1624677Swnj  * Create template to be used to send tcp packets on a connection.
1634677Swnj  * Call after host entry created, allocates an mbuf and fills
1644677Swnj  * in a skeletal tcp/ip header, minimizing the amount of work
1654677Swnj  * necessary when the connection is used.
1664677Swnj  */
167*4885Swnj struct tcpiphdr *
1684677Swnj tcp_template(tp)
169*4885Swnj 	struct tcpcb *tp;
1704677Swnj {
171*4885Swnj 	register struct inpcb *inp = tp->t_inpcb;
172*4885Swnj 	register struct in_host *h = inp->inp_fhost;
1734677Swnj 	register struct mbuf *m;
174*4885Swnj 	register struct tcpiphdr *n;
1754677Swnj 
1764677Swnj 	if (h == 0)
1774677Swnj 		return (0);
1784677Swnj 	m = m_get(1);
1794677Swnj 	if (m == 0)
1804677Swnj 		return (0);
181*4885Swnj 	m->m_off = MMAXOFF - sizeof (struct tcpiphdr);
182*4885Swnj 	m->m_len = sizeof (struct tcpiphdr);
183*4885Swnj 	n = mtod(m, struct tcpiphdr *);
1844677Swnj 	n->t_next = n->t_prev = 0;
1854677Swnj 	n->t_x1 = 0;
1864734Swnj 	n->t_pr = IPPROTO_TCP;
187*4885Swnj 	n->t_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
1884677Swnj 	n->t_s.s_addr = n_lhost.s_addr;
1894677Swnj 	n->t_d.s_addr = h->h_addr.s_addr;
190*4885Swnj 	n->t_src = htons(inp->inp_lport);
191*4885Swnj 	n->t_dst = htons(inp->inp_fport);
1924677Swnj 	n->t_seq = 0;
1934677Swnj 	n->t_ackno = 0;
1944677Swnj 	n->t_x2 = 0;
1954677Swnj 	n->t_off = 5;
1964677Swnj 	n->th_flags = 0;
1974677Swnj 	n->t_win = 0;
1984677Swnj 	n->t_sum = 0;
1994677Swnj 	n->t_urp = 0;
2004677Swnj 	return (n);
2014677Swnj }
2024677Swnj 
2034677Swnj tcp_output(tp, flags, len, dat)
204*4885Swnj 	register struct tcpcb *tp;
2054677Swnj 	register int flags;
2064677Swnj 	int len;
2074677Swnj 	struct mbuf *dat;
2084677Swnj {
209*4885Swnj 	register struct tcpiphdr *t;			/* known to be r9 */
2104677Swnj 	register struct mbuf *m;
211*4885Swnj 	struct socket *so = tp->t_inpcb->inp_socket;
2124677Swnj 	register struct ip *ip;
2134677Swnj 	int i;
2144677Swnj #ifdef TCPDEBUG
2154677Swnj 	struct tcp_debug tdb;
2164677Swnj #endif
2174719Swnj COUNT(TCP_OUTPUT);
2184677Swnj 
2194734Swnj 	if ((t = tp->t_template) == 0)
2204677Swnj 		return (0);
2214677Swnj 	MGET(m, 0);
2224677Swnj 	if (m == 0)
2234677Swnj 		return (0);
224*4885Swnj 	m->m_off = MMAXOFF - sizeof(struct tcpiphdr);
225*4885Swnj 	m->m_len = sizeof (struct tcpiphdr);
2264677Swnj 	m->m_next = dat;
2274677Swnj 	if (flags & TH_SYN)
2284677Swnj 		len--;
2294677Swnj 	if (flags & TH_FIN)
2304677Swnj 		len--;
231*4885Swnj 	bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr));
232*4885Swnj 	t = mtod(m, struct tcpiphdr *);
2334677Swnj 	if (tp->tc_flags&TC_SND_RST) {
2344677Swnj 		flags &= ~TH_SYN;
2354677Swnj 		flags |= TH_RST;
2364677Swnj 	}
2374677Swnj 	if (tp->tc_flags&TC_SYN_RCVD)
2384677Swnj 		flags |= TH_ACK;
2394677Swnj 	t->th_flags = flags;
2404677Swnj 	if (flags & TH_URG)
2414677Swnj 		t->t_urp = htons(tp->snd_urp);
2424677Swnj 	t->t_win =
243*4885Swnj 	    so->so_rcv.sb_hiwat -
244*4885Swnj 		(so->so_rcv.sb_cc + tp->seqcnt);
2454677Swnj 	if (tp->rcv_nxt + t->t_win > tp->rcv_adv)
2464677Swnj 		tp->rcv_adv = tp->rcv_nxt + t->t_win;
2474677Swnj 	if (len)
2484677Swnj 		t->t_len = htons(len + TCPSIZE);
2494677Swnj 	t->t_win = htons(t->t_win);
2504677Swnj #ifdef TCPDEBUG
251*4885Swnj 	if ((so->so_options & SO_DEBUG) || tcpconsdebug) {
2524677Swnj 		t->t_seq = tp->snd_nxt;
2534677Swnj 		t->t_ackno = tp->rcv_nxt;
2544677Swnj 		tdb_setup(tp, t, INSEND, &tdb);
2554677Swnj 		tdb_stuff(&tdb, -2);
2564677Swnj 	}
2574677Swnj #endif
2584677Swnj 	t->t_seq = htonl(tp->snd_nxt);
2594677Swnj 	t->t_ackno = htonl(tp->rcv_nxt);
2604696Swnj 	t->t_sum = 0;		/* gratuitous? */
261*4885Swnj 	CKSUM_TCPSET(m, t, r9, sizeof (struct tcpiphdr) + len);
2624677Swnj 	ip = (struct ip *)t;
2634677Swnj 	ip->ip_v = IPVERSION;
2644677Swnj 	ip->ip_hl = 5;
2654677Swnj 	ip->ip_tos = 0;
266*4885Swnj 	ip->ip_len = len + sizeof(struct tcpiphdr);
2674677Swnj 	ip->ip_id = ip_id++;
2684677Swnj 	ip->ip_off = 0;
2694677Swnj 	ip->ip_ttl = MAXTTL;
2704677Swnj 	i = ip_send(ip);
2714804Swnj 	return (i);
2724677Swnj }
2734677Swnj 
2744804Swnj tcp_fasttimo()
2754804Swnj {
2764804Swnj 
2774804Swnj }
278