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