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