xref: /csrg-svn/sys/netinet/tcp_output.c (revision 4677)
1 /* tcp_output.c 4.1 81/10/30 */
2 
3 #include "../h/param.h"
4 #include "../h/systm.h"
5 #include "../h/mbuf.h"
6 #include "../h/socket.h"
7 #include "../inet/inet.h"
8 #include "../inet/inet_host.h"
9 #include "../inet/inet_systm.h"
10 #include "../inet/imp.h"
11 #include "../inet/ip.h"
12 #include "../inet/tcp.h"
13 #include "../inet/tcp_fsm.h"
14 
15 send(tp)                        /* send data */
16 	register struct tcb *tp;
17 {
18 	register struct ucb *up;
19 	register unsigned long last, wind;
20 	struct mbuf *m;
21 	int flags = 0, forced, sent;
22 	struct mbuf *tcp_sndcopy();
23 	int len;
24 
25 COUNT(SEND);
26 	up = tp->t_ucb;
27 	tp->snd_lst = tp->snd_nxt;
28 	forced = 0;
29 	m = NULL;
30 
31 	if (tp->snd_nxt == tp->iss) {           /* first data to be sent */
32 		flags |= TH_SYN;
33 		tp->snd_lst++;
34 	}
35 
36 	/* get seq # of last datum in send buffer */
37 
38 	last = tp->snd_off;
39 	for (m = up->uc_sbuf; m != NULL; m = m->m_next)
40 		last += m->m_len;
41 
42         /* no data to send in buffer */
43 
44 	if (tp->snd_nxt > last) {
45 
46 		/* should we send FIN?  don't unless haven't already sent one */
47 
48 		if ((tp->tc_flags&TC_SND_FIN) &&
49 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
50 
51 			flags |= TH_FIN;
52 			tp->seq_fin = tp->snd_lst++;
53 		}
54 
55 	} else {                                  /* there is data to send */
56 
57 		/* send data only if there is a window defined */
58 
59 		if (tp->tc_flags&TC_SYN_ACKED) {
60 
61 			wind = tp->snd_una + tp->snd_wnd;
62 
63 			/* use window to limit send */
64 
65 			tp->snd_lst = min(last, wind);
66 
67 			/* make sure we don't do ip fragmentation */
68 
69 			if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
70 				tp->snd_lst -= len - 1024;
71 
72 			/* set persist timer */
73 
74 			if (tp->snd_lst >= wind)
75 				tp->t_persist = T_PERS;
76 		}
77 
78 		/* check if window is closed and must force a byte out */
79 
80 		if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
81 			tp->snd_lst = tp->snd_nxt + 1;
82 			forced = 1;
83 		}
84 
85 		/* copy data to send from send buffer */
86 
87 		m = tcp_sndcopy(tp, max(tp->iss+1,tp->snd_nxt), tp->snd_lst);
88 
89 		/* see if EOL should be sent */
90 
91 		if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
92 			flags |= TH_EOL;
93 
94 		/* must send FIN and no more data left to send after this */
95 
96 		if ((tp->tc_flags&TC_SND_FIN) && !forced &&
97 		    tp->snd_lst == last &&
98 		    (tp->seq_fin == tp->iss || tp->snd_nxt <= tp->seq_fin)) {
99 
100 			flags |= TH_FIN;
101 			tp->seq_fin = tp->snd_lst++;
102 		}
103 	}
104 
105 	if (tp->snd_nxt < tp->snd_lst) {        /* something to send */
106 
107 		if (tp->tc_flags & TC_SND_URG)
108 			flags |= TH_URG;
109 		sent = tcp_output(tp, flags, tp->snd_lst - tp->snd_nxt, m);
110 		/* set timers for retransmission if necessary */
111 
112 		if (!forced) {
113 			tp->t_rexmt = tp->t_xmtime;
114 			tp->t_rexmt_val = tp->snd_lst;
115 
116 			if ((tp->tc_flags&TC_REXMT) == 0) {
117 				tp->t_rexmttl = T_REXMTTL;
118 				tp->t_rtl_val = tp->snd_lst;
119 			}
120 
121 		}
122 
123 		/* update seq for next send if this one got out */
124 
125 		if (sent)
126 			tp->snd_nxt = tp->snd_lst;
127 
128 
129 		/* if last timed message has been acked, start timing
130 		   this one */
131 
132 		if ((tp->tc_flags&TC_SYN_ACKED) && tp->snd_una > tp->t_xmt_val) {
133 			tp->t_xmt = 0;
134 			tp->t_xmt_val = tp->snd_lst;
135 		}
136 
137 		tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
138 		tp->snd_hi = max(tp->snd_nxt, tp->snd_hi);
139 		return (1);
140 	}
141 
142 	return(0);
143 }
144 
145 tcp_sndctl(tp)                            /* send a control msg */
146 	struct tcb *tp;
147 {
148 COUNT(SEND_CTL);
149         if (!send(tp)) {
150 		tcp_sndnull(tp);
151 		return(0);
152 	}
153 	return(1);
154 }
155 
156 int	printhave = 0;
157 
158 tcp_sndwin(tp)
159 	struct tcb *tp;
160 {
161 	int ihave;
162 	int hehas;
163 
164 	if (tp->rcv_adv) {
165 		/* figure out window we would advertise */
166 		ihave = tp->t_ucb->uc_rhiwat -
167 		    (tp->t_ucb->uc_rcc + tp->seqcnt);
168 		hehas = tp->rcv_adv - tp->rcv_nxt;
169 		if (printhave)
170 		printf("ihave %d, hehas %d\n", ihave, hehas);
171 		if (hehas > 32 &&
172 		   (100*(ihave-hehas)/tp->t_ucb->uc_rhiwat) < 35)
173 			return;
174 		if (printhave)
175 		printf("update him\n");
176 	}
177         if (send(tp))
178 		return (1);
179 	tcp_sndnull(tp);
180 	return (0);
181 }
182 tcp_sndnull(tp)				/* send only control information */
183 	register struct tcb *tp;
184 {
185 COUNT(SEND_NULL);
186 
187 	tcp_output(tp, 0, 0, (struct mbuf *)0);
188         tp->tc_flags &= ~TC_ACK_DUE;
189 }
190 
191 tcp_sndrst(tp, n)                         /* send a reset */
192 	register struct tcb *tp;
193 	register struct th *n;
194 {
195 COUNT(SEND_RST);
196         /* don't send a reset in response to a reset */
197 
198 	if (n->th_flags&TH_RST)
199 		return;
200 
201 	tp->tc_flags |= TC_SND_RST;
202 
203 	if (n->th_flags&TH_ACK)
204 		tp->snd_nxt = n->t_ackno;
205 
206 	tp->tc_flags &= ~TC_SYN_RCVD;
207 	tcp_sndnull(tp);
208 	tp->tc_flags &= ~TC_SND_RST;
209 }
210 
211 /*
212  * Create template to be used to send tcp packets on a connection.
213  * Call after host entry created, allocates an mbuf and fills
214  * in a skeletal tcp/ip header, minimizing the amount of work
215  * necessary when the connection is used.
216  */
217 struct th *
218 tcp_template(tp)
219 	struct tcb *tp;
220 {
221 	register struct host *h = tp->t_ucb->uc_host;
222 	register struct mbuf *m;
223 	register struct th *n;
224 	register struct ip *ip;
225 
226 	if (h == 0)
227 		return (0);
228 	m = m_get(1);
229 	if (m == 0)
230 		return (0);
231 	m->m_off = MMAXOFF - sizeof (struct th);
232 	m->m_len = sizeof (struct th);
233 	n = mtod(m, struct th *);
234 	n->t_next = n->t_prev = 0;
235 	n->t_x1 = 0;
236 	n->t_pr = TCPROTO;
237 	n->t_len = htons(sizeof (struct th) - sizeof (struct ip));
238 	n->t_s.s_addr = n_lhost.s_addr;
239 	n->t_d.s_addr = h->h_addr.s_addr;
240 	n->t_src = htons(tp->t_lport);
241 	n->t_dst = htons(tp->t_fport);
242 	n->t_seq = 0;
243 	n->t_ackno = 0;
244 	n->t_x2 = 0;
245 	n->t_off = 5;
246 	n->th_flags = 0;
247 	n->t_win = 0;
248 	n->t_sum = 0;
249 	n->t_urp = 0;
250 	return (n);
251 }
252 
253 tcp_output(tp, flags, len, dat)
254 	register struct tcb *tp;
255 	register int flags;
256 	int len;
257 	struct mbuf *dat;
258 {
259 	register struct mbuf *m;
260 	register struct th *t;
261 	register struct ip *ip;
262 	int i;
263 #ifdef TCPDEBUG
264 	struct tcp_debug tdb;
265 #endif
266 COUNT(SEND_TCP);
267 
268 	if ((t = tp->t_ucb->uc_template) == 0)
269 		return (0);
270 	MGET(m, 0);
271 	if (m == 0)
272 		return (0);
273 	m->m_off = MMAXOFF - sizeof(struct th);
274 	m->m_len = sizeof (struct th);
275 	m->m_next = dat;
276 	if (flags & TH_SYN)
277 		len--;
278 	if (flags & TH_FIN)
279 		len--;
280 	bcopy((caddr_t)t, mtod(m, caddr_t), sizeof (struct th));
281 	t = mtod(m, struct th *);
282 	if (tp->tc_flags&TC_SND_RST) {
283 		flags &= ~TH_SYN;
284 		flags |= TH_RST;
285 	}
286 	if (tp->tc_flags&TC_SYN_RCVD)
287 		flags |= TH_ACK;
288 	t->th_flags = flags;
289 	if (flags & TH_URG)
290 		t->t_urp = htons(tp->snd_urp);
291 	t->t_win =
292 	    tp->t_ucb->uc_rhiwat - (tp->t_ucb->uc_rcc + tp->seqcnt);
293 	if (tp->rcv_nxt + t->t_win > tp->rcv_adv)
294 		tp->rcv_adv = tp->rcv_nxt + t->t_win;
295 	if (len)
296 		t->t_len = htons(len + TCPSIZE);
297 	t->t_win = htons(t->t_win);
298 #ifdef TCPDEBUG
299 	if ((tp->t_ucb->uc_flags & UDEBUG) || tcpconsdebug) {
300 		t->t_seq = tp->snd_nxt;
301 		t->t_ackno = tp->rcv_nxt;
302 		tdb_setup(tp, t, INSEND, &tdb);
303 		tdb_stuff(&tdb, -2);
304 	}
305 #endif
306 	t->t_seq = htonl(tp->snd_nxt);
307 	t->t_ackno = htonl(tp->rcv_nxt);
308 	t->t_sum = cksum(m, len + sizeof(struct th));
309 	ip = (struct ip *)t;
310 	ip->ip_v = IPVERSION;
311 	ip->ip_hl = 5;
312 	ip->ip_tos = 0;
313 	ip->ip_len = len + sizeof(struct th);
314 	ip->ip_id = ip_id++;
315 	ip->ip_off = 0;
316 	ip->ip_ttl = MAXTTL;
317 	i = ip_send(ip);
318 #ifdef notdef
319 	if (tp->t_ucb->uc_flags & UDEBUG) {
320 		w.w_dat = (char *)t;
321 		w.w_stype = i;
322 		tcp_debug(tp, &w, INRECV, -1);
323 	}
324 #endif
325 	return(i);
326 }
327 
328 firstempty(tp)
329 	register struct tcb *tp;
330 {
331 	register struct th *p, *q;
332 COUNT(FIRSTEMPTY);
333 
334 	if ((p = tp->t_rcv_next) == (struct th *)tp || tp->rcv_nxt < p->t_seq)
335 		return (tp->rcv_nxt);
336 	while ((q = p->t_next) != (struct th *)tp &&
337 	    (t_end(p) + 1) == q->t_seq)
338 		p = q;
339 	return (t_end(p) + 1);
340 }
341 
342 /* SHOULD BE A MACRO, AFTER KEEP TRACK OF ASS Q SPACE */
343 
344 struct mbuf *
345 tcp_sndcopy(tp, start, end)
346 	struct tcb *tp;
347 	u_long start, end;
348 {
349 	register struct mbuf *m, *n, **np;
350 	u_long off;
351 	register int len;
352 	int adj;
353 	struct mbuf *top, *p;
354 COUNT(SND_COPY);
355 
356 /*
357 	printf("st %x end %x off %x\n", start, end, tp->snd_off);
358 */
359 	if (start >= end)
360 		return(NULL);
361 	off = tp->snd_off;
362 	m = tp->t_ucb->uc_sbuf;
363 	while (m != NULL && start >= (off + m->m_len)) {
364 		off += m->m_len;
365 		m = m->m_next;
366 	}
367 	np = &top;
368 	top = 0;
369 	adj = start - off;
370 	len = end - start;
371 	while (m && len > 0) {
372 		MGET(n, 1);
373 		*np = n;
374 		if (n == 0)
375 			goto nospace;
376 		n->m_len = MIN(len, m->m_len - adj);
377 		if (m->m_off > MMAXOFF) {
378 			p = mtod(m, struct mbuf *);
379 			n->m_off = ((int)p - (int)n) + adj;
380 			mprefcnt[mtopf(p)]++;
381 		} else {
382 			n->m_off = MMINOFF;
383 			bcopy(mtod(m, caddr_t)+adj, mtod(n, caddr_t),
384 			    n->m_len);
385 		}
386 		len -= n->m_len;
387 		adj = 0;
388 		m = m->m_next;
389 		/* SHOULD TRY PACKING INTO SMALL MBUFS HERE */
390 		np = &n->m_next;
391 	}
392 	/* SHOULD NEVER RUN OUT OF m WHEN LEN */
393 	if (len)
394 		printf("snd_copy: m %x len %d\n", m, len);
395 	return (top);
396 nospace:
397 	printf("snd_copy: no space\n");
398 	m_freem(top);
399 	return (0);
400 }
401 
402 tcp_enq(p, prev)
403 	register struct th *p;
404 	register struct th *prev;
405 {
406 
407 	p->t_prev = prev;
408 	p->t_next = prev->t_next;
409 	prev->t_next->t_prev = p;
410 	prev->t_next = p;
411 }
412 
413 tcp_deq(p)
414 	register struct th *p;
415 {
416 
417 	p->t_prev->t_next = p->t_next;
418 	p->t_next->t_prev = p->t_prev;
419 }
420