make labels look different from function names.
[unix-history] / usr / src / sys / netinet / tcp_output.c
CommitLineData
d52566dd 1/* tcp_output.c 4.10 81/11/08 */
76ee76df
BJ
2
3#include "../h/param.h"
4#include "../h/systm.h"
5#include "../h/mbuf.h"
6#include "../h/socket.h"
d52566dd
BJ
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"
76ee76df 18
ea727f86
BJ
19/*
20 * Special routines to send control messages.
21 */
22tcp_sndctl(tp)
23 struct tcb *tp;
24{
25COUNT(TCP_SNDCTL);
26
27 if (tcp_send(tp))
28 return (1);
29 tcp_sndnull(tp);
d52566dd 30 return (0);
ea727f86
BJ
31}
32
33tcp_sndwin(tp)
34 struct tcb *tp;
35{
36 int ihave, hehas;
d52566dd 37 register struct socket *so = tp->t_socket;
ea727f86
BJ
38COUNT(TCP_SNDWIN);
39
40 if (tp->rcv_adv) {
d52566dd
BJ
41 ihave = so->so_rcv.sb_hiwat -
42 (so->so_rcv.sb_cc + tp->seqcnt);
ea727f86 43 hehas = tp->rcv_adv - tp->rcv_nxt;
d52566dd 44 if ((100*(ihave-hehas)/so->so_rcv.sb_hiwat) < 35)
ea727f86
BJ
45 return;
46 }
47 if (tcp_send(tp))
48 return (1);
49 tcp_sndnull(tp);
50 return (0);
51}
52
53tcp_sndnull(tp)
54 register struct tcb *tp;
55{
56COUNT(TCP_SNDNULL);
57
58 tcp_output(tp, 0, 0, (struct mbuf *)0);
59 tp->tc_flags &= ~TC_ACK_DUE;
60}
61
62tcp_sndrst(tp, n)
63 register struct tcb *tp;
64 register struct th *n;
65{
66COUNT(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 */
82tcp_send(tp)
76ee76df
BJ
83 register struct tcb *tp;
84{
d52566dd 85 register struct socket *so;
76ee76df
BJ
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
ea727f86 92COUNT(TCP_SEND);
d52566dd 93 so = tp->t_socket;
76ee76df
BJ
94 tp->snd_lst = tp->snd_nxt;
95 forced = 0;
96 m = NULL;
ea727f86 97 if (tp->snd_nxt == tp->iss) {
76ee76df
BJ
98 flags |= TH_SYN;
99 tp->snd_lst++;
100 }
76ee76df 101 last = tp->snd_off;
d52566dd 102 for (m = so->so_snd.sb_mb; m != NULL; m = m->m_next)
76ee76df 103 last += m->m_len;
76ee76df 104 if (tp->snd_nxt > last) {
76ee76df
BJ
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 }
ea727f86 111 } else {
76ee76df 112 if (tp->tc_flags&TC_SYN_ACKED) {
76ee76df 113 wind = tp->snd_una + tp->snd_wnd;
76ee76df 114 tp->snd_lst = min(last, wind);
76ee76df
BJ
115 if ((len = tp->snd_lst - tp->snd_nxt) > 1024)
116 tp->snd_lst -= len - 1024;
76ee76df
BJ
117 if (tp->snd_lst >= wind)
118 tp->t_persist = T_PERS;
119 }
76ee76df
BJ
120 if ((tp->tc_flags&TC_FORCE_ONE) && (tp->snd_lst == wind)) {
121 tp->snd_lst = tp->snd_nxt + 1;
122 forced = 1;
ddfd844e 123 } else if (tp->snd_nxt >= tp->snd_lst && (tp->tc_flags&TC_SND_FIN) == 0)
7be5ba08
BJ
124 return (0);
125 m = tcp_sndcopy(tp, MAX(tp->iss+1,tp->snd_nxt), tp->snd_lst);
76ee76df
BJ
126 if (tp->snd_end > tp->iss && tp->snd_end <= tp->snd_lst)
127 flags |= TH_EOL;
76ee76df
BJ
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)) {
76ee76df
BJ
131 flags |= TH_FIN;
132 tp->seq_fin = tp->snd_lst++;
133 }
134 }
ddfd844e
BJ
135 if (tp->snd_nxt >= tp->snd_lst)
136 return (0);
ea727f86
BJ
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;
76ee76df 146 }
76ee76df 147 }
ea727f86
BJ
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;
76ee76df 154 }
ea727f86 155 tp->tc_flags &= ~(TC_ACK_DUE|TC_REXMT|TC_FORCE_ONE);
7be5ba08 156 tp->snd_hi = MAX(tp->snd_nxt, tp->snd_hi);
ea727f86 157 return (1);
76ee76df
BJ
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 */
166struct th *
167tcp_template(tp)
168 struct tcb *tp;
169{
d52566dd 170 register struct host *h = tp->t_host;
76ee76df
BJ
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;
e1506033 185 n->t_pr = IPPROTO_TCP;
76ee76df
BJ
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
202tcp_output(tp, flags, len, dat)
203 register struct tcb *tp;
204 register int flags;
205 int len;
206 struct mbuf *dat;
207{
6d6a2c70 208 register struct th *t; /* known to be r9 */
76ee76df 209 register struct mbuf *m;
76ee76df
BJ
210 register struct ip *ip;
211 int i;
212#ifdef TCPDEBUG
213 struct tcp_debug tdb;
214#endif
3552a746 215COUNT(TCP_OUTPUT);
76ee76df 216
e1506033 217 if ((t = tp->t_template) == 0)
76ee76df
BJ
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 =
d52566dd
BJ
241 tp->t_socket->so_rcv.sb_hiwat -
242 (tp->t_socket->so_rcv.sb_cc + tp->seqcnt);
76ee76df
BJ
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
d52566dd 249 if ((tp->t_socket->so_options & SO_DEBUG) || tcpconsdebug) {
76ee76df
BJ
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);
6d6a2c70
BJ
258 t->t_sum = 0; /* gratuitous? */
259 CKSUM_TCPSET(m, t, r9, sizeof (struct th) + len);
76ee76df
BJ
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);
d52566dd 269 return (i);
76ee76df
BJ
270}
271
272firstempty(tp)
273 register struct tcb *tp;
274{
275 register struct th *p, *q;
276COUNT(FIRSTEMPTY);
277
d52566dd
BJ
278 if ((p = tp->tcb_hd.seg_next) == (struct th *)tp ||
279 tp->rcv_nxt < p->t_seq)
76ee76df
BJ
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
76ee76df
BJ
287struct mbuf *
288tcp_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;
3552a746 297COUNT(TCP_SNDCOPY);
76ee76df 298
76ee76df 299 if (start >= end)
d52566dd 300 return (NULL);
76ee76df 301 off = tp->snd_off;
d52566dd 302 m = tp->t_socket->so_snd.sb_mb;
76ee76df
BJ
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);
336nospace:
337 printf("snd_copy: no space\n");
338 m_freem(top);
339 return (0);
340}
d52566dd
BJ
341
342tcp_fasttimo()
343{
344
345}