xref: /csrg-svn/sys/netinet/tcp_output.c (revision 4804)
1 /* tcp_output.c 4.10 81/11/08 */
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/mbuf.h"
6 #include "../h/socket.h"
7 #include "../h/socketvar.h"
8 #include "../net/inet_cksum.h"
9 #include "../net/inet.h"
10 #include "../net/inet_host.h"
11 #include "../net/inet_systm.h"
12 #include "../net/imp.h"
13 #include "../net/ip.h"
14 #include "../net/tcp.h"
15 #include "../net/tcp_var.h"
16 #include "../net/tcp_fsm.h"
17 #include "/usr/include/errno.h"
18 
19 /*
20  * Special routines to send control messages.
21  */
22 tcp_sndctl(tp)
23 	struct tcb *tp;
24 {
25 COUNT(TCP_SNDCTL);
26 
27         if (tcp_send(tp))
28 		return (1);
29 	tcp_sndnull(tp);
30 	return (0);
31 }
32 
33 tcp_sndwin(tp)
34 	struct tcb *tp;
35 {
36 	int ihave, hehas;
37 	register struct socket *so = tp->t_socket;
38 COUNT(TCP_SNDWIN);
39 
40 	if (tp->rcv_adv) {
41 		ihave = so->so_rcv.sb_hiwat -
42 		    (so->so_rcv.sb_cc + tp->seqcnt);
43 		hehas = tp->rcv_adv - tp->rcv_nxt;
44 		if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35)
45 			return;
46 	}
47         if (tcp_send(tp))
48 		return (1);
49 	tcp_sndnull(tp);
50 	return (0);
51 }
52 
53 tcp_sndnull(tp)
54 	register struct tcb *tp;
55 {
56 COUNT(TCP_SNDNULL);
57 
58 	tcp_output(tp, 0, 0, (struct mbuf *)0);
59         tp->tc_flags &= ~TC_ACK_DUE;
60 }
61 
62 tcp_sndrst(tp, n)
63 	register struct tcb *tp;
64 	register struct th *n;
65 {
66 COUNT(TCP_SNDRST);
67 
68         /* don't send a reset in response to a reset */
69 	if (n->th_flags&TH_RST)
70 		return;
71 	tp->tc_flags |= TC_SND_RST;
72 	if (n->th_flags&TH_ACK)
73 		tp->snd_nxt = n->t_ackno;
74 	tp->tc_flags &= ~TC_SYN_RCVD;
75 	tcp_sndnull(tp);
76 	tp->tc_flags &= ~TC_SND_RST;
77 }
78 
79 /*
80  * Tcp segment output routine.
81  */
82 tcp_send(tp)
83 	register struct tcb *tp;
84 {
85 	register struct socket *so;
86 	register unsigned long last, wind;
87 	struct mbuf *m;
88 	int flags = 0, forced, sent;
89 	struct mbuf *tcp_sndcopy();
90 	int len;
91 
92 COUNT(TCP_SEND);
93 	so = tp->t_socket;
94 	tp->snd_lst = tp->snd_nxt;
95 	forced = 0;
96 	m = NULL;
97 	if (tp->snd_nxt == tp->iss) {
98 		flags |= TH_SYN;
99 		tp->snd_lst++;
100 	}
101 	last = tp->snd_off;
102 	for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next)
103 		last += m->m_len;
104 	if (tp->snd_nxt > last) {
105 		if ((tp->tc_flags&TC_SND_FIN) &&
106 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
107 
108 			flags |= TH_FIN;
109 			tp->seq_fin = tp->snd_lst++;
110 		}
111 	} else {
112 		if (tp->tc_flags&TC_SYN_ACKED) {
113 			wind = tp->snd_una + tp->snd_wnd;
114 			tp->snd_lst = min(last, wind);
115 			if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
116 				tp->snd_lst -= len - 1024;
117 			if (tp->snd_lst >= wind)
118 				tp->t_persist = T_PERS;
119 		}
120 		if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
121 			tp->snd_lst = tp->snd_nxt + 1;
122 			forced = 1;
123 		} else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0)
124 			return (0);
125 		m = tcp_sndcopy(tp, MAX(tp->iss+1,tp->snd_nxt), tp->snd_lst);
126 		if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
127 			flags |= TH_EOL;
128 		if ((tp->tc_flags&TC_SND_FIN) && !forced &&
129 		    tp->snd_lst == last &&
130 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
131 			flags |= TH_FIN;
132 			tp->seq_fin = tp->snd_lst++;
133 		}
134 	}
135 	if (tp->snd_nxt >= tp->snd_lst)
136 		return (0);
137 	if (tp->tc_flags & TC_SND_URG)
138 		flags |= TH_URG;
139 	sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m);
140 	if (!forced) {
141 		tp->t_rexmt = tp->t_xmtime;
142 		tp->t_rexmt_val = tp->snd_lst;
143 		if ((tp->tc_flags&TC_REXMT) == 0) {
144 			tp->t_rexmttl = T_REXMTTL;
145 			tp->t_rtl_val = tp->snd_lst;
146 		}
147 	}
148 	if (sent)
149 		tp->snd_nxt = tp->snd_lst;
150 	if ((tp->tc_flags&TC_SYN_ACKED) &&
151 	    tp->snd_una > tp->t_xmt_val) {
152 		tp->t_xmt = 0;
153 		tp->t_xmt_val = tp->snd_lst;
154 	}
155 	tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
156 	tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi);
157 	return (1);
158 }
159 
160 /*
161  * Create template to be used to send tcp packets on a connection.
162  * Call after host entry created, allocates an mbuf and fills
163  * in a skeletal tcp/ip header, minimizing the amount of work
164  * necessary when the connection is used.
165  */
166 struct th *
167 tcp_template(tp)
168 	struct tcb *tp;
169 {
170 	register struct host *h = tp->t_host;
171 	register struct mbuf *m;
172 	register struct th *n;
173 	register struct ip *ip;
174 
175 	if (h == 0)
176 		return (0);
177 	m = m_get(1);
178 	if (m == 0)
179 		return (0);
180 	m->m_off = MMAXOFF - sizeof (struct th);
181 	m->m_len = sizeof (struct th);
182 	n = mtod(m, struct th *);
183 	n->t_next = n->t_prev = 0;
184 	n->t_x1 = 0;
185 	n->t_pr = IPPROTO_TCP;
186 	n->t_len = htons(sizeof (struct th) - sizeof (struct ip));
187 	n->t_s.s_addr = n_lhost.s_addr;
188 	n->t_d.s_addr = h->h_addr.s_addr;
189 	n->t_src = htons(tp->t_lport);
190 	n->t_dst = htons(tp->t_fport);
191 	n->t_seq = 0;
192 	n->t_ackno = 0;
193 	n->t_x2 = 0;
194 	n->t_off = 5;
195 	n->th_flags = 0;
196 	n->t_win = 0;
197 	n->t_sum = 0;
198 	n->t_urp = 0;
199 	return (n);
200 }
201 
202 tcp_output(tp, flags, len, dat)
203 	register struct tcb *tp;
204 	register int flags;
205 	int len;
206 	struct mbuf *dat;
207 {
208 	register struct th *t;			/* known to be r9 */
209 	register struct mbuf *m;
210 	register struct ip *ip;
211 	int i;
212 #ifdef TCPDEBUG
213 	struct tcp_debug tdb;
214 #endif
215 COUNT(TCP_OUTPUT);
216 
217 	if ((t = tp->t_template) == 0)
218 		return (0);
219 	MGET(m, 0);
220 	if (m == 0)
221 		return (0);
222 	m->m_off = MMAXOFF - sizeof(struct th);
223 	m->m_len = sizeof (struct th);
224 	m->m_next = dat;
225 	if (flags & TH_SYN)
226 		len--;
227 	if (flags & TH_FIN)
228 		len--;
229 	bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct th));
230 	t = mtod(m, struct th *);
231 	if (tp->tc_flags&TC_SND_RST) {
232 		flags &= ~TH_SYN;
233 		flags |= TH_RST;
234 	}
235 	if (tp->tc_flags&TC_SYN_RCVD)
236 		flags |= TH_ACK;
237 	t->th_flags = flags;
238 	if (flags & TH_URG)
239 		t->t_urp = htons(tp->snd_urp);
240 	t->t_win =
241 	    tp->t_socket->so_rcv.sb_hiwat -
242 		(tp->t_socket->so_rcv.sb_cc + tp->seqcnt);
243 	if (tp->rcv_nxt + t->t_win > tp->rcv_adv)
244 		tp->rcv_adv = tp->rcv_nxt + t->t_win;
245 	if (len)
246 		t->t_len = htons(len + TCPSIZE);
247 	t->t_win = htons(t->t_win);
248 #ifdef TCPDEBUG
249 	if ((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug) {
250 		t->t_seq = tp->snd_nxt;
251 		t->t_ackno = tp->rcv_nxt;
252 		tdb_setup(tp, t, INSEND, &tdb);
253 		tdb_stuff(&tdb, -2);
254 	}
255 #endif
256 	t->t_seq = htonl(tp->snd_nxt);
257 	t->t_ackno = htonl(tp->rcv_nxt);
258 	t->t_sum = 0;		/* gratuitous? */
259 	CKSUM_TCPSET(m, t, r9, sizeof (struct th) + len);
260 	ip = (struct ip *)t;
261 	ip->ip_v = IPVERSION;
262 	ip->ip_hl = 5;
263 	ip->ip_tos = 0;
264 	ip->ip_len = len + sizeof(struct th);
265 	ip->ip_id = ip_id++;
266 	ip->ip_off = 0;
267 	ip->ip_ttl = MAXTTL;
268 	i = ip_send(ip);
269 	return (i);
270 }
271 
272 firstempty(tp)
273 	register struct tcb *tp;
274 {
275 	register struct th *p, *q;
276 COUNT(FIRSTEMPTY);
277 
278 	if ((p = tp->tcb_hd.seg_next) == (struct th *)tp ||
279 	    tp->rcv_nxt < p->t_seq)
280 		return (tp->rcv_nxt);
281 	while ((q = p->t_next) != (struct th *)tp &&
282 	    (t_end(p) + 1) == q->t_seq)
283 		p = q;
284 	return (t_end(p) + 1);
285 }
286 
287 struct mbuf *
288 tcp_sndcopy(tp, start, end)
289 	struct tcb *tp;
290 	u_long start, end;
291 {
292 	register struct mbuf *m, *n, **np;
293 	u_long off;
294 	register int len;
295 	int adj;
296 	struct mbuf *top, *p;
297 COUNT(TCP_SNDCOPY);
298 
299 	if (start >= end)
300 		return (NULL);
301 	off = tp->snd_off;
302 	m = tp->t_socket->so_snd.sb_mb;
303 	while (m != NULL && start >= (off + m->m_len)) {
304 		off += m->m_len;
305 		m = m->m_next;
306 	}
307 	np = &top;
308 	top = 0;
309 	adj = start - off;
310 	len = end - start;
311 	while (m && len > 0) {
312 		MGET(n, 1);
313 		*np = n;
314 		if (n == 0)
315 			goto nospace;
316 		n->m_len = MIN(len, m->m_len - adj);
317 		if (m->m_off > MMAXOFF) {
318 			p = mtod(m, struct mbuf *);
319 			n->m_off = ((int)p - (int)n) + adj;
320 			mprefcnt[mtopf(p)]++;
321 		} else {
322 			n->m_off = MMINOFF;
323 			bcopy(mtod(m, caddr_t)+adj, mtod(n, caddr_t),
324 			    n->m_len);
325 		}
326 		len -= n->m_len;
327 		adj = 0;
328 		m = m->m_next;
329 		/* SHOULD TRY PACKING INTO SMALL MBUFS HERE */
330 		np = &n->m_next;
331 	}
332 	/* SHOULD NEVER RUN OUT OF m WHEN LEN */
333 	if (len)
334 		printf("snd_copy: m %x len %d\n", m, len);
335 	return (top);
336 nospace:
337 	printf("snd_copy: no space\n");
338 	m_freem(top);
339 	return (0);
340 }
341 
342 tcp_fasttimo()
343 {
344 
345 }
346