xref: /csrg-svn/sys/netinet/tcp_output.c (revision 4678)
1*4678Swnj /* tcp_output.c 4.2 81/10/30 */
24677Swnj 
34677Swnj #include "../h/param.h"
44677Swnj #include "../h/systm.h"
54677Swnj #include "../h/mbuf.h"
64677Swnj #include "../h/socket.h"
74677Swnj #include "../inet/inet.h"
84677Swnj #include "../inet/inet_host.h"
94677Swnj #include "../inet/inet_systm.h"
104677Swnj #include "../inet/imp.h"
114677Swnj #include "../inet/ip.h"
124677Swnj #include "../inet/tcp.h"
134677Swnj #include "../inet/tcp_fsm.h"
144677Swnj 
15*4678Swnj /*
16*4678Swnj  * Special routines to send control messages.
17*4678Swnj  */
18*4678Swnj tcp_sndctl(tp)
19*4678Swnj 	struct tcb *tp;
20*4678Swnj {
21*4678Swnj COUNT(TCP_SNDCTL);
22*4678Swnj 
23*4678Swnj         if (tcp_send(tp))
24*4678Swnj 		return (1);
25*4678Swnj 	tcp_sndnull(tp);
26*4678Swnj 	return(0);
27*4678Swnj }
28*4678Swnj 
29*4678Swnj tcp_sndwin(tp)
30*4678Swnj 	struct tcb *tp;
31*4678Swnj {
32*4678Swnj 	int ihave, hehas;
33*4678Swnj COUNT(TCP_SNDWIN);
34*4678Swnj 
35*4678Swnj 	if (tp->rcv_adv) {
36*4678Swnj 		ihave = tp->t_ucb->uc_rhiwat -
37*4678Swnj 		    (tp->t_ucb->uc_rcc + tp->seqcnt);
38*4678Swnj 		hehas = tp->rcv_adv - tp->rcv_nxt;
39*4678Swnj 		if (hehas > 32 &&
40*4678Swnj 		   (100*(ihave-hehas)/tp->t_ucb->uc_rhiwat) < 35)
41*4678Swnj 			return;
42*4678Swnj 	}
43*4678Swnj         if (tcp_send(tp))
44*4678Swnj 		return (1);
45*4678Swnj 	tcp_sndnull(tp);
46*4678Swnj 	return (0);
47*4678Swnj }
48*4678Swnj 
49*4678Swnj tcp_sndnull(tp)
504677Swnj 	register struct tcb *tp;
514677Swnj {
52*4678Swnj COUNT(TCP_SNDNULL);
53*4678Swnj 
54*4678Swnj 	tcp_output(tp, 0, 0, (struct mbuf *)0);
55*4678Swnj         tp->tc_flags &= ~TC_ACK_DUE;
56*4678Swnj }
57*4678Swnj 
58*4678Swnj tcp_sndrst(tp, n)
59*4678Swnj 	register struct tcb *tp;
60*4678Swnj 	register struct th *n;
61*4678Swnj {
62*4678Swnj COUNT(TCP_SNDRST);
63*4678Swnj 
64*4678Swnj         /* don't send a reset in response to a reset */
65*4678Swnj 	if (n->th_flags&TH_RST)
66*4678Swnj 		return;
67*4678Swnj 	tp->tc_flags |= TC_SND_RST;
68*4678Swnj 	if (n->th_flags&TH_ACK)
69*4678Swnj 		tp->snd_nxt = n->t_ackno;
70*4678Swnj 	tp->tc_flags &= ~TC_SYN_RCVD;
71*4678Swnj 	tcp_sndnull(tp);
72*4678Swnj 	tp->tc_flags &= ~TC_SND_RST;
73*4678Swnj }
74*4678Swnj 
75*4678Swnj /*
76*4678Swnj  * Tcp segment output routine.
77*4678Swnj  */
78*4678Swnj tcp_send(tp)
79*4678Swnj 	register struct tcb *tp;
80*4678Swnj {
814677Swnj 	register struct ucb *up;
824677Swnj 	register unsigned long last, wind;
834677Swnj 	struct mbuf *m;
844677Swnj 	int flags = 0, forced, sent;
854677Swnj 	struct mbuf *tcp_sndcopy();
864677Swnj 	int len;
874677Swnj 
88*4678Swnj COUNT(TCP_SEND);
894677Swnj 	up = tp->t_ucb;
904677Swnj 	tp->snd_lst = tp->snd_nxt;
914677Swnj 	forced = 0;
924677Swnj 	m = NULL;
93*4678Swnj 	if (tp->snd_nxt == tp->iss) {
944677Swnj 		flags |= TH_SYN;
954677Swnj 		tp->snd_lst++;
964677Swnj 	}
974677Swnj 	last = tp->snd_off;
984677Swnj 	for (m = up->uc_sbuf; m != NULL; m = m->m_next)
994677Swnj 		last += m->m_len;
1004677Swnj 	if (tp->snd_nxt > last) {
1014677Swnj 		if ((tp->tc_flags&TC_SND_FIN) &&
1024677Swnj 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
1034677Swnj 
1044677Swnj 			flags |= TH_FIN;
1054677Swnj 			tp->seq_fin = tp->snd_lst++;
1064677Swnj 		}
107*4678Swnj 	} else {
1084677Swnj 		if (tp->tc_flags&TC_SYN_ACKED) {
1094677Swnj 			wind = tp->snd_una + tp->snd_wnd;
1104677Swnj 			tp->snd_lst = min(last, wind);
1114677Swnj 			if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
1124677Swnj 				tp->snd_lst -= len - 1024;
1134677Swnj 			if (tp->snd_lst >= wind)
1144677Swnj 				tp->t_persist = T_PERS;
1154677Swnj 		}
1164677Swnj 		if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
1174677Swnj 			tp->snd_lst = tp->snd_nxt + 1;
1184677Swnj 			forced = 1;
1194677Swnj 		}
1204677Swnj 		m = tcp_sndcopy(tp, max(tp->iss+1,tp->snd_nxt), tp->snd_lst);
1214677Swnj 		if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
1224677Swnj 			flags |= TH_EOL;
1234677Swnj 		if ((tp->tc_flags&TC_SND_FIN) && !forced &&
1244677Swnj 		    tp->snd_lst == last &&
1254677Swnj 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
1264677Swnj 			flags |= TH_FIN;
1274677Swnj 			tp->seq_fin = tp->snd_lst++;
1284677Swnj 		}
1294677Swnj 	}
130*4678Swnj 	if (tp->snd_nxt >= tp->snd_lst)
131*4678Swnj 		return (0);
132*4678Swnj 	if (tp->tc_flags & TC_SND_URG)
133*4678Swnj 		flags |= TH_URG;
134*4678Swnj 	sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m);
135*4678Swnj 	if (!forced) {
136*4678Swnj 		tp->t_rexmt = tp->t_xmtime;
137*4678Swnj 		tp->t_rexmt_val = tp->snd_lst;
138*4678Swnj 		if ((tp->tc_flags&TC_REXMT) == 0) {
139*4678Swnj 			tp->t_rexmttl = T_REXMTTL;
140*4678Swnj 			tp->t_rtl_val = tp->snd_lst;
1414677Swnj 		}
1424677Swnj 	}
143*4678Swnj 	if (sent)
144*4678Swnj 		tp->snd_nxt = tp->snd_lst;
145*4678Swnj 	if ((tp->tc_flags&TC_SYN_ACKED) &&
146*4678Swnj 	    tp->snd_una > tp->t_xmt_val) {
147*4678Swnj 		tp->t_xmt = 0;
148*4678Swnj 		tp->t_xmt_val = tp->snd_lst;
1494677Swnj 	}
150*4678Swnj 	tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
151*4678Swnj 	tp->snd_hi = max(tp->snd_nxt, tp->snd_hi);
152*4678Swnj 	return (1);
1534677Swnj }
1544677Swnj 
1554677Swnj /*
1564677Swnj  * Create template to be used to send tcp packets on a connection.
1574677Swnj  * Call after host entry created, allocates an mbuf and fills
1584677Swnj  * in a skeletal tcp/ip header, minimizing the amount of work
1594677Swnj  * necessary when the connection is used.
1604677Swnj  */
1614677Swnj struct th *
1624677Swnj tcp_template(tp)
1634677Swnj 	struct tcb *tp;
1644677Swnj {
1654677Swnj 	register struct host *h = tp->t_ucb->uc_host;
1664677Swnj 	register struct mbuf *m;
1674677Swnj 	register struct th *n;
1684677Swnj 	register struct ip *ip;
1694677Swnj 
1704677Swnj 	if (h == 0)
1714677Swnj 		return (0);
1724677Swnj 	m = m_get(1);
1734677Swnj 	if (m == 0)
1744677Swnj 		return (0);
1754677Swnj 	m->m_off = MMAXOFF - sizeof (struct th);
1764677Swnj 	m->m_len = sizeof (struct th);
1774677Swnj 	n = mtod(m, struct th *);
1784677Swnj 	n->t_next = n->t_prev = 0;
1794677Swnj 	n->t_x1 = 0;
1804677Swnj 	n->t_pr = TCPROTO;
1814677Swnj 	n->t_len = htons(sizeof (struct th) - sizeof (struct ip));
1824677Swnj 	n->t_s.s_addr = n_lhost.s_addr;
1834677Swnj 	n->t_d.s_addr = h->h_addr.s_addr;
1844677Swnj 	n->t_src = htons(tp->t_lport);
1854677Swnj 	n->t_dst = htons(tp->t_fport);
1864677Swnj 	n->t_seq = 0;
1874677Swnj 	n->t_ackno = 0;
1884677Swnj 	n->t_x2 = 0;
1894677Swnj 	n->t_off = 5;
1904677Swnj 	n->th_flags = 0;
1914677Swnj 	n->t_win = 0;
1924677Swnj 	n->t_sum = 0;
1934677Swnj 	n->t_urp = 0;
1944677Swnj 	return (n);
1954677Swnj }
1964677Swnj 
1974677Swnj tcp_output(tp, flags, len, dat)
1984677Swnj 	register struct tcb *tp;
1994677Swnj 	register int flags;
2004677Swnj 	int len;
2014677Swnj 	struct mbuf *dat;
2024677Swnj {
2034677Swnj 	register struct mbuf *m;
2044677Swnj 	register struct th *t;
2054677Swnj 	register struct ip *ip;
2064677Swnj 	int i;
2074677Swnj #ifdef TCPDEBUG
2084677Swnj 	struct tcp_debug tdb;
2094677Swnj #endif
2104677Swnj COUNT(SEND_TCP);
2114677Swnj 
2124677Swnj 	if ((t = tp->t_ucb->uc_template) == 0)
2134677Swnj 		return (0);
2144677Swnj 	MGET(m, 0);
2154677Swnj 	if (m == 0)
2164677Swnj 		return (0);
2174677Swnj 	m->m_off = MMAXOFF - sizeof(struct th);
2184677Swnj 	m->m_len = sizeof (struct th);
2194677Swnj 	m->m_next = dat;
2204677Swnj 	if (flags & TH_SYN)
2214677Swnj 		len--;
2224677Swnj 	if (flags & TH_FIN)
2234677Swnj 		len--;
2244677Swnj 	bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct th));
2254677Swnj 	t = mtod(m, struct th *);
2264677Swnj 	if (tp->tc_flags&TC_SND_RST) {
2274677Swnj 		flags &= ~TH_SYN;
2284677Swnj 		flags |= TH_RST;
2294677Swnj 	}
2304677Swnj 	if (tp->tc_flags&TC_SYN_RCVD)
2314677Swnj 		flags |= TH_ACK;
2324677Swnj 	t->th_flags = flags;
2334677Swnj 	if (flags & TH_URG)
2344677Swnj 		t->t_urp = htons(tp->snd_urp);
2354677Swnj 	t->t_win =
2364677Swnj 	    tp->t_ucb->uc_rhiwat - (tp->t_ucb->uc_rcc + tp->seqcnt);
2374677Swnj 	if (tp->rcv_nxt + t->t_win > tp->rcv_adv)
2384677Swnj 		tp->rcv_adv = tp->rcv_nxt + t->t_win;
2394677Swnj 	if (len)
2404677Swnj 		t->t_len = htons(len + TCPSIZE);
2414677Swnj 	t->t_win = htons(t->t_win);
2424677Swnj #ifdef TCPDEBUG
2434677Swnj 	if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
2444677Swnj 		t->t_seq = tp->snd_nxt;
2454677Swnj 		t->t_ackno = tp->rcv_nxt;
2464677Swnj 		tdb_setup(tp, t, INSEND, &tdb);
2474677Swnj 		tdb_stuff(&tdb, -2);
2484677Swnj 	}
2494677Swnj #endif
2504677Swnj 	t->t_seq = htonl(tp->snd_nxt);
2514677Swnj 	t->t_ackno = htonl(tp->rcv_nxt);
2524677Swnj 	t->t_sum = cksum(m, len + sizeof(struct th));
2534677Swnj 	ip = (struct ip *)t;
2544677Swnj 	ip->ip_v = IPVERSION;
2554677Swnj 	ip->ip_hl = 5;
2564677Swnj 	ip->ip_tos = 0;
2574677Swnj 	ip->ip_len = len + sizeof(struct th);
2584677Swnj 	ip->ip_id = ip_id++;
2594677Swnj 	ip->ip_off = 0;
2604677Swnj 	ip->ip_ttl = MAXTTL;
2614677Swnj 	i = ip_send(ip);
2624677Swnj 	return(i);
2634677Swnj }
2644677Swnj 
2654677Swnj firstempty(tp)
2664677Swnj 	register struct tcb *tp;
2674677Swnj {
2684677Swnj 	register struct th *p, *q;
2694677Swnj COUNT(FIRSTEMPTY);
2704677Swnj 
2714677Swnj 	if ((p = tp->t_rcv_next) == (struct th *)tp || tp->rcv_nxt < p->t_seq)
2724677Swnj 		return (tp->rcv_nxt);
2734677Swnj 	while ((q = p->t_next) != (struct th *)tp &&
2744677Swnj 	    (t_end(p) + 1) == q->t_seq)
2754677Swnj 		p = q;
2764677Swnj 	return (t_end(p) + 1);
2774677Swnj }
2784677Swnj 
2794677Swnj struct mbuf *
2804677Swnj tcp_sndcopy(tp, start, end)
2814677Swnj 	struct tcb *tp;
2824677Swnj 	u_long start, end;
2834677Swnj {
2844677Swnj 	register struct mbuf *m, *n, **np;
2854677Swnj 	u_long off;
2864677Swnj 	register int len;
2874677Swnj 	int adj;
2884677Swnj 	struct mbuf *top, *p;
2894677Swnj COUNT(SND_COPY);
2904677Swnj 
2914677Swnj 	if (start >= end)
2924677Swnj 		return(NULL);
2934677Swnj 	off = tp->snd_off;
2944677Swnj 	m = tp->t_ucb->uc_sbuf;
2954677Swnj 	while (m != NULL && start >= (off + m->m_len)) {
2964677Swnj 		off += m->m_len;
2974677Swnj 		m = m->m_next;
2984677Swnj 	}
2994677Swnj 	np = &top;
3004677Swnj 	top = 0;
3014677Swnj 	adj = start - off;
3024677Swnj 	len = end - start;
3034677Swnj 	while (m && len > 0) {
3044677Swnj 		MGET(n, 1);
3054677Swnj 		*np = n;
3064677Swnj 		if (n == 0)
3074677Swnj 			goto nospace;
3084677Swnj 		n->m_len = MIN(len, m->m_len - adj);
3094677Swnj 		if (m->m_off > MMAXOFF) {
3104677Swnj 			p = mtod(m, struct mbuf *);
3114677Swnj 			n->m_off = ((int)p - (int)n) + adj;
3124677Swnj 			mprefcnt[mtopf(p)]++;
3134677Swnj 		} else {
3144677Swnj 			n->m_off = MMINOFF;
3154677Swnj 			bcopy(mtod(m, caddr_t)+adj, mtod(n, caddr_t),
3164677Swnj 			    n->m_len);
3174677Swnj 		}
3184677Swnj 		len -= n->m_len;
3194677Swnj 		adj = 0;
3204677Swnj 		m = m->m_next;
3214677Swnj 		/* SHOULD TRY PACKING INTO SMALL MBUFS HERE */
3224677Swnj 		np = &n->m_next;
3234677Swnj 	}
3244677Swnj 	/* SHOULD NEVER RUN OUT OF m WHEN LEN */
3254677Swnj 	if (len)
3264677Swnj 		printf("snd_copy: m %x len %d\n", m, len);
3274677Swnj 	return (top);
3284677Swnj nospace:
3294677Swnj 	printf("snd_copy: no space\n");
3304677Swnj 	m_freem(top);
3314677Swnj 	return (0);
3324677Swnj }
3334677Swnj 
3344677Swnj tcp_enq(p, prev)
3354677Swnj 	register struct th *p;
3364677Swnj 	register struct th *prev;
3374677Swnj {
3384677Swnj 
3394677Swnj 	p->t_prev = prev;
3404677Swnj 	p->t_next = prev->t_next;
3414677Swnj 	prev->t_next->t_prev = p;
3424677Swnj 	prev->t_next = p;
3434677Swnj }
3444677Swnj 
3454677Swnj tcp_deq(p)
3464677Swnj 	register struct th *p;
3474677Swnj {
3484677Swnj 
3494677Swnj 	p->t_prev->t_next = p->t_next;
3504677Swnj 	p->t_next->t_prev = p->t_prev;
3514677Swnj }
352