date and time created 81/10/30 19:56:58 by wnj
[unix-history] / usr / src / sys / netinet / tcp_output.c
CommitLineData
76ee76df
BJ
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
15send(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
25COUNT(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
145tcp_sndctl(tp) /* send a control msg */
146 struct tcb *tp;
147{
148COUNT(SEND_CTL);
149 if (!send(tp)) {
150 tcp_sndnull(tp);
151 return(0);
152 }
153 return(1);
154}
155
156int printhave = 0;
157
158tcp_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}
182tcp_sndnull(tp) /* send only control information */
183 register struct tcb *tp;
184{
185COUNT(SEND_NULL);
186
187 tcp_output(tp, 0, 0, (struct mbuf *)0);
188 tp->tc_flags &= ~TC_ACK_DUE;
189}
190
191tcp_sndrst(tp, n) /* send a reset */
192 register struct tcb *tp;
193 register struct th *n;
194{
195COUNT(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 */
217struct th *
218tcp_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
253tcp_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
266COUNT(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
328firstempty(tp)
329 register struct tcb *tp;
330{
331 register struct th *p, *q;
332COUNT(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
344struct mbuf *
345tcp_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;
354COUNT(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);
396nospace:
397 printf("snd_copy: no space\n");
398 m_freem(top);
399 return (0);
400}
401
402tcp_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
413tcp_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}