xref: /csrg-svn/sys/netinet/tcp_output.c (revision 4900)
1*4900Swnj /* tcp_output.c 4.12 81/11/15 */
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"
114885Swnj #include "../net/inet_pcb.h"
124804Swnj #include "../net/inet_systm.h"
134804Swnj #include "../net/imp.h"
144804Swnj #include "../net/ip.h"
15*4900Swnj #include "../net/ip_var.h"
164804Swnj #include "../net/tcp.h"
174804Swnj #include "../net/tcp_var.h"
184804Swnj #include "../net/tcp_fsm.h"
194804Swnj #include "/usr/include/errno.h"
204677Swnj 
214678Swnj /*
224678Swnj  * Special routines to send control messages.
234678Swnj  */
244678Swnj tcp_sndctl(tp)
254885Swnj 	struct tcpcb *tp;
264678Swnj {
274678Swnj COUNT(TCP_SNDCTL);
284678Swnj 
294678Swnj         if (tcp_send(tp))
304678Swnj 		return (1);
314678Swnj 	tcp_sndnull(tp);
324804Swnj 	return (0);
334678Swnj }
344678Swnj 
354678Swnj tcp_sndwin(tp)
364885Swnj 	struct tcpcb *tp;
374678Swnj {
384678Swnj 	int ihave, hehas;
394678Swnj COUNT(TCP_SNDWIN);
404678Swnj 
414678Swnj 	if (tp->rcv_adv) {
424885Swnj 		register struct socket *so = tp->t_inpcb->inp_socket;
434885Swnj 
444804Swnj 		ihave = so->so_rcv.sb_hiwat -
454804Swnj 		    (so->so_rcv.sb_cc + tp->seqcnt);
464678Swnj 		hehas = tp->rcv_adv - tp->rcv_nxt;
474804Swnj 		if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35)
484678Swnj 			return;
494678Swnj 	}
504678Swnj         if (tcp_send(tp))
514678Swnj 		return (1);
524678Swnj 	tcp_sndnull(tp);
534678Swnj 	return (0);
544678Swnj }
554678Swnj 
564678Swnj tcp_sndnull(tp)
574885Swnj 	register struct tcpcb *tp;
584677Swnj {
594678Swnj COUNT(TCP_SNDNULL);
604678Swnj 
614678Swnj 	tcp_output(tp, 0, 0, (struct mbuf *)0);
624678Swnj         tp->tc_flags &= ~TC_ACK_DUE;
634678Swnj }
644678Swnj 
654678Swnj tcp_sndrst(tp, n)
664885Swnj 	register struct tcpcb *tp;
674885Swnj 	register struct tcpiphdr *n;
684678Swnj {
694678Swnj COUNT(TCP_SNDRST);
704678Swnj 
714678Swnj         /* don't send a reset in response to a reset */
72*4900Swnj 	if (n->ti_flags&TH_RST)
734678Swnj 		return;
744678Swnj 	tp->tc_flags |= TC_SND_RST;
75*4900Swnj 	if (n->ti_flags&TH_ACK)
76*4900Swnj 		tp->snd_nxt = n->ti_ackno;
774678Swnj 	tp->tc_flags &= ~TC_SYN_RCVD;
784678Swnj 	tcp_sndnull(tp);
794678Swnj 	tp->tc_flags &= ~TC_SND_RST;
804678Swnj }
814678Swnj 
824678Swnj /*
834678Swnj  * Tcp segment output routine.
844678Swnj  */
854678Swnj tcp_send(tp)
864885Swnj 	register struct tcpcb *tp;
874678Swnj {
884677Swnj 	register unsigned long last, wind;
894885Swnj 	register struct socket *so = tp->t_inpcb->inp_socket;
904677Swnj 	struct mbuf *m;
914885Swnj 	int flags = 0, forced, sent, len;
924677Swnj 
934678Swnj COUNT(TCP_SEND);
944677Swnj 	tp->snd_lst = tp->snd_nxt;
954677Swnj 	forced = 0;
964677Swnj 	m = NULL;
974678Swnj 	if (tp->snd_nxt == tp->iss) {
984677Swnj 		flags |= TH_SYN;
994677Swnj 		tp->snd_lst++;
1004677Swnj 	}
1014677Swnj 	last = tp->snd_off;
1024804Swnj 	for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next)
1034677Swnj 		last += m->m_len;
1044677Swnj 	if (tp->snd_nxt > last) {
1054677Swnj 		if ((tp->tc_flags&TC_SND_FIN) &&
1064677Swnj 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
1074677Swnj 
1084677Swnj 			flags |= TH_FIN;
1094677Swnj 			tp->seq_fin = tp->snd_lst++;
1104677Swnj 		}
1114678Swnj 	} else {
1124677Swnj 		if (tp->tc_flags&TC_SYN_ACKED) {
1134677Swnj 			wind = tp->snd_una + tp->snd_wnd;
1144677Swnj 			tp->snd_lst = min(last, wind);
1154677Swnj 			if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
1164677Swnj 				tp->snd_lst -= len - 1024;
1174677Swnj 			if (tp->snd_lst >= wind)
1184677Swnj 				tp->t_persist = T_PERS;
1194677Swnj 		}
1204677Swnj 		if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
1214677Swnj 			tp->snd_lst = tp->snd_nxt + 1;
1224677Swnj 			forced = 1;
1234698Swnj 		} else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0)
1244692Swnj 			return (0);
1254885Swnj 		m = sb_copy(&so->so_snd,
1264885Swnj 		      MAX(tp->iss+1,tp->snd_nxt) - tp->snd_off,
1274885Swnj 		      tp->snd_lst - tp->snd_off);
1284677Swnj 		if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
1294677Swnj 			flags |= TH_EOL;
1304677Swnj 		if ((tp->tc_flags&TC_SND_FIN) && !forced &&
1314677Swnj 		    tp->snd_lst == last &&
1324677Swnj 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
1334677Swnj 			flags |= TH_FIN;
1344677Swnj 			tp->seq_fin = tp->snd_lst++;
1354677Swnj 		}
1364677Swnj 	}
1374698Swnj 	if (tp->snd_nxt >= tp->snd_lst)
1384698Swnj 		return (0);
1394678Swnj 	if (tp->tc_flags & TC_SND_URG)
1404678Swnj 		flags |= TH_URG;
1414678Swnj 	sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m);
1424678Swnj 	if (!forced) {
1434678Swnj 		tp->t_rexmt = tp->t_xmtime;
1444678Swnj 		tp->t_rexmt_val = tp->snd_lst;
1454678Swnj 		if ((tp->tc_flags&TC_REXMT) == 0) {
1464678Swnj 			tp->t_rexmttl = T_REXMTTL;
1474678Swnj 			tp->t_rtl_val = tp->snd_lst;
1484677Swnj 		}
1494677Swnj 	}
1504678Swnj 	if (sent)
1514678Swnj 		tp->snd_nxt = tp->snd_lst;
1524678Swnj 	if ((tp->tc_flags&TC_SYN_ACKED) &&
1534678Swnj 	    tp->snd_una > tp->t_xmt_val) {
1544678Swnj 		tp->t_xmt = 0;
1554678Swnj 		tp->t_xmt_val = tp->snd_lst;
1564677Swnj 	}
1574678Swnj 	tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
1584692Swnj 	tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi);
1594678Swnj 	return (1);
1604677Swnj }
1614677Swnj 
1624677Swnj /*
1634677Swnj  * Create template to be used to send tcp packets on a connection.
1644677Swnj  * Call after host entry created, allocates an mbuf and fills
1654677Swnj  * in a skeletal tcp/ip header, minimizing the amount of work
1664677Swnj  * necessary when the connection is used.
1674677Swnj  */
1684885Swnj struct tcpiphdr *
1694677Swnj tcp_template(tp)
1704885Swnj 	struct tcpcb *tp;
1714677Swnj {
1724885Swnj 	register struct inpcb *inp = tp->t_inpcb;
1734885Swnj 	register struct in_host *h = inp->inp_fhost;
1744677Swnj 	register struct mbuf *m;
1754885Swnj 	register struct tcpiphdr *n;
1764677Swnj 
1774677Swnj 	if (h == 0)
1784677Swnj 		return (0);
1794677Swnj 	m = m_get(1);
1804677Swnj 	if (m == 0)
1814677Swnj 		return (0);
1824885Swnj 	m->m_off = MMAXOFF - sizeof (struct tcpiphdr);
1834885Swnj 	m->m_len = sizeof (struct tcpiphdr);
1844885Swnj 	n = mtod(m, struct tcpiphdr *);
185*4900Swnj 	n->ti_next = n->ti_prev = 0;
186*4900Swnj 	n->ti_x1 = 0;
187*4900Swnj 	n->ti_pr = IPPROTO_TCP;
188*4900Swnj 	n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip));
189*4900Swnj 	n->ti_src.s_addr = n_lhost.s_addr;
190*4900Swnj 	n->ti_dst.s_addr = h->h_addr.s_addr;
191*4900Swnj 	n->ti_sport = htons(inp->inp_lport);
192*4900Swnj 	n->ti_dport = htons(inp->inp_fport);
193*4900Swnj 	n->ti_seq = 0;
194*4900Swnj 	n->ti_ackno = 0;
195*4900Swnj 	n->ti_x2 = 0;
196*4900Swnj 	n->ti_off = 5;
197*4900Swnj 	n->ti_flags = 0;
198*4900Swnj 	n->ti_win = 0;
199*4900Swnj 	n->ti_sum = 0;
200*4900Swnj 	n->ti_urp = 0;
2014677Swnj 	return (n);
2024677Swnj }
2034677Swnj 
2044677Swnj tcp_output(tp, flags, len, dat)
2054885Swnj 	register struct tcpcb *tp;
2064677Swnj 	register int flags;
2074677Swnj 	int len;
2084677Swnj 	struct mbuf *dat;
2094677Swnj {
2104885Swnj 	register struct tcpiphdr *t;			/* known to be r9 */
2114677Swnj 	register struct mbuf *m;
2124885Swnj 	struct socket *so = tp->t_inpcb->inp_socket;
2134677Swnj 	register struct ip *ip;
2144677Swnj 	int i;
2154677Swnj #ifdef TCPDEBUG
2164677Swnj 	struct tcp_debug tdb;
2174677Swnj #endif
2184719Swnj COUNT(TCP_OUTPUT);
2194677Swnj 
2204734Swnj 	if ((t = tp->t_template) == 0)
2214677Swnj 		return (0);
2224677Swnj 	MGET(m, 0);
2234677Swnj 	if (m == 0)
2244677Swnj 		return (0);
2254885Swnj 	m->m_off = MMAXOFF - sizeof(struct tcpiphdr);
2264885Swnj 	m->m_len = sizeof (struct tcpiphdr);
2274677Swnj 	m->m_next = dat;
2284677Swnj 	if (flags & TH_SYN)
2294677Swnj 		len--;
2304677Swnj 	if (flags & TH_FIN)
2314677Swnj 		len--;
2324885Swnj 	bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct tcpiphdr));
2334885Swnj 	t = mtod(m, struct tcpiphdr *);
2344677Swnj 	if (tp->tc_flags&TC_SND_RST) {
2354677Swnj 		flags &= ~TH_SYN;
2364677Swnj 		flags |= TH_RST;
2374677Swnj 	}
2384677Swnj 	if (tp->tc_flags&TC_SYN_RCVD)
2394677Swnj 		flags |= TH_ACK;
240*4900Swnj 	t->ti_flags = flags;
2414677Swnj 	if (flags & TH_URG)
242*4900Swnj 		t->ti_urp = htons(tp->snd_urp);
243*4900Swnj 	t->ti_win =
2444885Swnj 	    so->so_rcv.sb_hiwat -
2454885Swnj 		(so->so_rcv.sb_cc + tp->seqcnt);
246*4900Swnj 	if (tp->rcv_nxt + t->ti_win > tp->rcv_adv)
247*4900Swnj 		tp->rcv_adv = tp->rcv_nxt + t->ti_win;
2484677Swnj 	if (len)
249*4900Swnj 		t->ti_len = htons(len + TCPSIZE);
250*4900Swnj 	t->ti_win = htons(t->ti_win);
2514677Swnj #ifdef TCPDEBUG
2524885Swnj 	if ((so->so_options & SO_DEBUG) || tcpconsdebug) {
253*4900Swnj 		t->ti_seq = tp->snd_nxt;
254*4900Swnj 		t->ti_ackno = tp->rcv_nxt;
2554677Swnj 		tdb_setup(tp, t, INSEND, &tdb);
2564677Swnj 		tdb_stuff(&tdb, -2);
2574677Swnj 	}
2584677Swnj #endif
259*4900Swnj 	t->ti_seq = htonl(tp->snd_nxt);
260*4900Swnj 	t->ti_ackno = htonl(tp->rcv_nxt);
261*4900Swnj 	t->ti_sum = 0;		/* gratuitous? */
2624885Swnj 	CKSUM_TCPSET(m, t, r9, sizeof (struct tcpiphdr) + len);
2634677Swnj 	ip = (struct ip *)t;
2644677Swnj 	ip->ip_v = IPVERSION;
2654677Swnj 	ip->ip_hl = 5;
2664677Swnj 	ip->ip_tos = 0;
2674885Swnj 	ip->ip_len = len + sizeof(struct tcpiphdr);
2684677Swnj 	ip->ip_id = ip_id++;
2694677Swnj 	ip->ip_off = 0;
2704677Swnj 	ip->ip_ttl = MAXTTL;
2714677Swnj 	i = ip_send(ip);
2724804Swnj 	return (i);
2734677Swnj }
2744677Swnj 
2754804Swnj tcp_fasttimo()
2764804Swnj {
2774804Swnj 
2784804Swnj }
279