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