root / slirp / tcp_output.c @ c4dfa5b7
History | View | Annotate | Download (17.2 kB)
1 | f0cbd3ec | bellard | /*
|
---|---|---|---|
2 | f0cbd3ec | bellard | * Copyright (c) 1982, 1986, 1988, 1990, 1993
|
3 | f0cbd3ec | bellard | * The Regents of the University of California. All rights reserved.
|
4 | f0cbd3ec | bellard | *
|
5 | f0cbd3ec | bellard | * Redistribution and use in source and binary forms, with or without
|
6 | f0cbd3ec | bellard | * modification, are permitted provided that the following conditions
|
7 | f0cbd3ec | bellard | * are met:
|
8 | f0cbd3ec | bellard | * 1. Redistributions of source code must retain the above copyright
|
9 | f0cbd3ec | bellard | * notice, this list of conditions and the following disclaimer.
|
10 | f0cbd3ec | bellard | * 2. Redistributions in binary form must reproduce the above copyright
|
11 | f0cbd3ec | bellard | * notice, this list of conditions and the following disclaimer in the
|
12 | f0cbd3ec | bellard | * documentation and/or other materials provided with the distribution.
|
13 | f0cbd3ec | bellard | * 3. All advertising materials mentioning features or use of this software
|
14 | f0cbd3ec | bellard | * must display the following acknowledgement:
|
15 | f0cbd3ec | bellard | * This product includes software developed by the University of
|
16 | f0cbd3ec | bellard | * California, Berkeley and its contributors.
|
17 | f0cbd3ec | bellard | * 4. Neither the name of the University nor the names of its contributors
|
18 | f0cbd3ec | bellard | * may be used to endorse or promote products derived from this software
|
19 | f0cbd3ec | bellard | * without specific prior written permission.
|
20 | f0cbd3ec | bellard | *
|
21 | f0cbd3ec | bellard | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
22 | f0cbd3ec | bellard | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
23 | f0cbd3ec | bellard | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
24 | f0cbd3ec | bellard | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
25 | f0cbd3ec | bellard | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
26 | f0cbd3ec | bellard | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
27 | f0cbd3ec | bellard | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
28 | f0cbd3ec | bellard | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
29 | f0cbd3ec | bellard | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
30 | f0cbd3ec | bellard | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
31 | f0cbd3ec | bellard | * SUCH DAMAGE.
|
32 | f0cbd3ec | bellard | *
|
33 | f0cbd3ec | bellard | * @(#)tcp_output.c 8.3 (Berkeley) 12/30/93
|
34 | f0cbd3ec | bellard | * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp
|
35 | f0cbd3ec | bellard | */
|
36 | f0cbd3ec | bellard | |
37 | f0cbd3ec | bellard | /*
|
38 | f0cbd3ec | bellard | * Changes and additions relating to SLiRP
|
39 | f0cbd3ec | bellard | * Copyright (c) 1995 Danny Gasparovski.
|
40 | f0cbd3ec | bellard | *
|
41 | f0cbd3ec | bellard | * Please read the file COPYRIGHT for the
|
42 | f0cbd3ec | bellard | * terms and conditions of the copyright.
|
43 | f0cbd3ec | bellard | */
|
44 | f0cbd3ec | bellard | |
45 | f0cbd3ec | bellard | #include <slirp.h> |
46 | f0cbd3ec | bellard | |
47 | f0cbd3ec | bellard | /*
|
48 | f0cbd3ec | bellard | * Since this is only used in "stats socket", we give meaning
|
49 | f0cbd3ec | bellard | * names instead of the REAL names
|
50 | f0cbd3ec | bellard | */
|
51 | f0cbd3ec | bellard | char *tcpstates[] = {
|
52 | f0cbd3ec | bellard | /* "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", */
|
53 | f0cbd3ec | bellard | "REDIRECT", "LISTEN", "SYN_SENT", "SYN_RCVD", |
54 | f0cbd3ec | bellard | "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", |
55 | f0cbd3ec | bellard | "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", |
56 | f0cbd3ec | bellard | }; |
57 | f0cbd3ec | bellard | |
58 | f0cbd3ec | bellard | u_char tcp_outflags[TCP_NSTATES] = { |
59 | f0cbd3ec | bellard | TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK,
|
60 | f0cbd3ec | bellard | TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, |
61 | f0cbd3ec | bellard | TH_FIN|TH_ACK, TH_ACK, TH_ACK, |
62 | f0cbd3ec | bellard | }; |
63 | f0cbd3ec | bellard | |
64 | f0cbd3ec | bellard | |
65 | f0cbd3ec | bellard | #define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ |
66 | f0cbd3ec | bellard | |
67 | f0cbd3ec | bellard | /*
|
68 | f0cbd3ec | bellard | * Tcp output routine: figure out what should be sent and send it.
|
69 | f0cbd3ec | bellard | */
|
70 | f0cbd3ec | bellard | int
|
71 | f0cbd3ec | bellard | tcp_output(tp) |
72 | f0cbd3ec | bellard | register struct tcpcb *tp; |
73 | f0cbd3ec | bellard | { |
74 | f0cbd3ec | bellard | register struct socket *so = tp->t_socket; |
75 | f0cbd3ec | bellard | register long len, win; |
76 | f0cbd3ec | bellard | int off, flags, error;
|
77 | f0cbd3ec | bellard | register struct mbuf *m; |
78 | f0cbd3ec | bellard | register struct tcpiphdr *ti; |
79 | f0cbd3ec | bellard | u_char opt[MAX_TCPOPTLEN]; |
80 | f0cbd3ec | bellard | unsigned optlen, hdrlen;
|
81 | f0cbd3ec | bellard | int idle, sendalot;
|
82 | f0cbd3ec | bellard | |
83 | f0cbd3ec | bellard | DEBUG_CALL("tcp_output");
|
84 | f0cbd3ec | bellard | DEBUG_ARG("tp = %lx", (long )tp); |
85 | f0cbd3ec | bellard | |
86 | f0cbd3ec | bellard | /*
|
87 | f0cbd3ec | bellard | * Determine length of data that should be transmitted,
|
88 | f0cbd3ec | bellard | * and flags that will be used.
|
89 | f0cbd3ec | bellard | * If there is some data or critical controls (SYN, RST)
|
90 | f0cbd3ec | bellard | * to send, then transmit; otherwise, investigate further.
|
91 | f0cbd3ec | bellard | */
|
92 | f0cbd3ec | bellard | idle = (tp->snd_max == tp->snd_una); |
93 | f0cbd3ec | bellard | if (idle && tp->t_idle >= tp->t_rxtcur)
|
94 | f0cbd3ec | bellard | /*
|
95 | f0cbd3ec | bellard | * We have been idle for "a while" and no acks are
|
96 | f0cbd3ec | bellard | * expected to clock out any data we send --
|
97 | f0cbd3ec | bellard | * slow start to get ack "clock" running again.
|
98 | f0cbd3ec | bellard | */
|
99 | f0cbd3ec | bellard | tp->snd_cwnd = tp->t_maxseg; |
100 | f0cbd3ec | bellard | again:
|
101 | f0cbd3ec | bellard | sendalot = 0;
|
102 | f0cbd3ec | bellard | off = tp->snd_nxt - tp->snd_una; |
103 | f0cbd3ec | bellard | win = min(tp->snd_wnd, tp->snd_cwnd); |
104 | f0cbd3ec | bellard | |
105 | f0cbd3ec | bellard | flags = tcp_outflags[tp->t_state]; |
106 | f0cbd3ec | bellard | |
107 | f0cbd3ec | bellard | DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags));
|
108 | f0cbd3ec | bellard | |
109 | f0cbd3ec | bellard | /*
|
110 | f0cbd3ec | bellard | * If in persist timeout with window of 0, send 1 byte.
|
111 | f0cbd3ec | bellard | * Otherwise, if window is small but nonzero
|
112 | f0cbd3ec | bellard | * and timer expired, we will send what we can
|
113 | f0cbd3ec | bellard | * and go to transmit state.
|
114 | f0cbd3ec | bellard | */
|
115 | f0cbd3ec | bellard | if (tp->t_force) {
|
116 | f0cbd3ec | bellard | if (win == 0) { |
117 | f0cbd3ec | bellard | /*
|
118 | f0cbd3ec | bellard | * If we still have some data to send, then
|
119 | f0cbd3ec | bellard | * clear the FIN bit. Usually this would
|
120 | f0cbd3ec | bellard | * happen below when it realizes that we
|
121 | f0cbd3ec | bellard | * aren't sending all the data. However,
|
122 | f0cbd3ec | bellard | * if we have exactly 1 byte of unset data,
|
123 | f0cbd3ec | bellard | * then it won't clear the FIN bit below,
|
124 | f0cbd3ec | bellard | * and if we are in persist state, we wind
|
125 | f0cbd3ec | bellard | * up sending the packet without recording
|
126 | f0cbd3ec | bellard | * that we sent the FIN bit.
|
127 | f0cbd3ec | bellard | *
|
128 | f0cbd3ec | bellard | * We can't just blindly clear the FIN bit,
|
129 | f0cbd3ec | bellard | * because if we don't have any more data
|
130 | f0cbd3ec | bellard | * to send then the probe will be the FIN
|
131 | f0cbd3ec | bellard | * itself.
|
132 | f0cbd3ec | bellard | */
|
133 | f0cbd3ec | bellard | if (off < so->so_snd.sb_cc)
|
134 | f0cbd3ec | bellard | flags &= ~TH_FIN; |
135 | f0cbd3ec | bellard | win = 1;
|
136 | f0cbd3ec | bellard | } else {
|
137 | f0cbd3ec | bellard | tp->t_timer[TCPT_PERSIST] = 0;
|
138 | f0cbd3ec | bellard | tp->t_rxtshift = 0;
|
139 | f0cbd3ec | bellard | } |
140 | f0cbd3ec | bellard | } |
141 | f0cbd3ec | bellard | |
142 | f0cbd3ec | bellard | len = min(so->so_snd.sb_cc, win) - off; |
143 | f0cbd3ec | bellard | |
144 | f0cbd3ec | bellard | if (len < 0) { |
145 | f0cbd3ec | bellard | /*
|
146 | f0cbd3ec | bellard | * If FIN has been sent but not acked,
|
147 | f0cbd3ec | bellard | * but we haven't been called to retransmit,
|
148 | f0cbd3ec | bellard | * len will be -1. Otherwise, window shrank
|
149 | f0cbd3ec | bellard | * after we sent into it. If window shrank to 0,
|
150 | f0cbd3ec | bellard | * cancel pending retransmit and pull snd_nxt
|
151 | f0cbd3ec | bellard | * back to (closed) window. We will enter persist
|
152 | f0cbd3ec | bellard | * state below. If the window didn't close completely,
|
153 | f0cbd3ec | bellard | * just wait for an ACK.
|
154 | f0cbd3ec | bellard | */
|
155 | f0cbd3ec | bellard | len = 0;
|
156 | f0cbd3ec | bellard | if (win == 0) { |
157 | f0cbd3ec | bellard | tp->t_timer[TCPT_REXMT] = 0;
|
158 | f0cbd3ec | bellard | tp->snd_nxt = tp->snd_una; |
159 | f0cbd3ec | bellard | } |
160 | f0cbd3ec | bellard | } |
161 | f0cbd3ec | bellard | |
162 | f0cbd3ec | bellard | if (len > tp->t_maxseg) {
|
163 | f0cbd3ec | bellard | len = tp->t_maxseg; |
164 | f0cbd3ec | bellard | sendalot = 1;
|
165 | f0cbd3ec | bellard | } |
166 | f0cbd3ec | bellard | if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc))
|
167 | f0cbd3ec | bellard | flags &= ~TH_FIN; |
168 | f0cbd3ec | bellard | |
169 | f0cbd3ec | bellard | win = sbspace(&so->so_rcv); |
170 | f0cbd3ec | bellard | |
171 | f0cbd3ec | bellard | /*
|
172 | f0cbd3ec | bellard | * Sender silly window avoidance. If connection is idle
|
173 | f0cbd3ec | bellard | * and can send all data, a maximum segment,
|
174 | f0cbd3ec | bellard | * at least a maximum default-size segment do it,
|
175 | f0cbd3ec | bellard | * or are forced, do it; otherwise don't bother.
|
176 | f0cbd3ec | bellard | * If peer's buffer is tiny, then send
|
177 | f0cbd3ec | bellard | * when window is at least half open.
|
178 | f0cbd3ec | bellard | * If retransmitting (possibly after persist timer forced us
|
179 | f0cbd3ec | bellard | * to send into a small window), then must resend.
|
180 | f0cbd3ec | bellard | */
|
181 | f0cbd3ec | bellard | if (len) {
|
182 | f0cbd3ec | bellard | if (len == tp->t_maxseg)
|
183 | f0cbd3ec | bellard | goto send;
|
184 | f0cbd3ec | bellard | if ((1 || idle || tp->t_flags & TF_NODELAY) && |
185 | f0cbd3ec | bellard | len + off >= so->so_snd.sb_cc) |
186 | f0cbd3ec | bellard | goto send;
|
187 | f0cbd3ec | bellard | if (tp->t_force)
|
188 | f0cbd3ec | bellard | goto send;
|
189 | f0cbd3ec | bellard | if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) |
190 | f0cbd3ec | bellard | goto send;
|
191 | f0cbd3ec | bellard | if (SEQ_LT(tp->snd_nxt, tp->snd_max))
|
192 | f0cbd3ec | bellard | goto send;
|
193 | f0cbd3ec | bellard | } |
194 | f0cbd3ec | bellard | |
195 | f0cbd3ec | bellard | /*
|
196 | f0cbd3ec | bellard | * Compare available window to amount of window
|
197 | f0cbd3ec | bellard | * known to peer (as advertised window less
|
198 | f0cbd3ec | bellard | * next expected input). If the difference is at least two
|
199 | f0cbd3ec | bellard | * max size segments, or at least 50% of the maximum possible
|
200 | f0cbd3ec | bellard | * window, then want to send a window update to peer.
|
201 | f0cbd3ec | bellard | */
|
202 | f0cbd3ec | bellard | if (win > 0) { |
203 | f0cbd3ec | bellard | /*
|
204 | f0cbd3ec | bellard | * "adv" is the amount we can increase the window,
|
205 | f0cbd3ec | bellard | * taking into account that we are limited by
|
206 | f0cbd3ec | bellard | * TCP_MAXWIN << tp->rcv_scale.
|
207 | f0cbd3ec | bellard | */
|
208 | f0cbd3ec | bellard | long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - |
209 | f0cbd3ec | bellard | (tp->rcv_adv - tp->rcv_nxt); |
210 | f0cbd3ec | bellard | |
211 | f0cbd3ec | bellard | if (adv >= (long) (2 * tp->t_maxseg)) |
212 | f0cbd3ec | bellard | goto send;
|
213 | f0cbd3ec | bellard | if (2 * adv >= (long) so->so_rcv.sb_datalen) |
214 | f0cbd3ec | bellard | goto send;
|
215 | f0cbd3ec | bellard | } |
216 | f0cbd3ec | bellard | |
217 | f0cbd3ec | bellard | /*
|
218 | f0cbd3ec | bellard | * Send if we owe peer an ACK.
|
219 | f0cbd3ec | bellard | */
|
220 | f0cbd3ec | bellard | if (tp->t_flags & TF_ACKNOW)
|
221 | f0cbd3ec | bellard | goto send;
|
222 | f0cbd3ec | bellard | if (flags & (TH_SYN|TH_RST))
|
223 | f0cbd3ec | bellard | goto send;
|
224 | f0cbd3ec | bellard | if (SEQ_GT(tp->snd_up, tp->snd_una))
|
225 | f0cbd3ec | bellard | goto send;
|
226 | f0cbd3ec | bellard | /*
|
227 | f0cbd3ec | bellard | * If our state indicates that FIN should be sent
|
228 | f0cbd3ec | bellard | * and we have not yet done so, or we're retransmitting the FIN,
|
229 | f0cbd3ec | bellard | * then we need to send.
|
230 | f0cbd3ec | bellard | */
|
231 | f0cbd3ec | bellard | if (flags & TH_FIN &&
|
232 | f0cbd3ec | bellard | ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una))
|
233 | f0cbd3ec | bellard | goto send;
|
234 | f0cbd3ec | bellard | |
235 | f0cbd3ec | bellard | /*
|
236 | f0cbd3ec | bellard | * TCP window updates are not reliable, rather a polling protocol
|
237 | f0cbd3ec | bellard | * using ``persist'' packets is used to insure receipt of window
|
238 | f0cbd3ec | bellard | * updates. The three ``states'' for the output side are:
|
239 | f0cbd3ec | bellard | * idle not doing retransmits or persists
|
240 | f0cbd3ec | bellard | * persisting to move a small or zero window
|
241 | f0cbd3ec | bellard | * (re)transmitting and thereby not persisting
|
242 | f0cbd3ec | bellard | *
|
243 | f0cbd3ec | bellard | * tp->t_timer[TCPT_PERSIST]
|
244 | f0cbd3ec | bellard | * is set when we are in persist state.
|
245 | f0cbd3ec | bellard | * tp->t_force
|
246 | f0cbd3ec | bellard | * is set when we are called to send a persist packet.
|
247 | f0cbd3ec | bellard | * tp->t_timer[TCPT_REXMT]
|
248 | f0cbd3ec | bellard | * is set when we are retransmitting
|
249 | f0cbd3ec | bellard | * The output side is idle when both timers are zero.
|
250 | f0cbd3ec | bellard | *
|
251 | f0cbd3ec | bellard | * If send window is too small, there is data to transmit, and no
|
252 | f0cbd3ec | bellard | * retransmit or persist is pending, then go to persist state.
|
253 | f0cbd3ec | bellard | * If nothing happens soon, send when timer expires:
|
254 | f0cbd3ec | bellard | * if window is nonzero, transmit what we can,
|
255 | f0cbd3ec | bellard | * otherwise force out a byte.
|
256 | f0cbd3ec | bellard | */
|
257 | f0cbd3ec | bellard | if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 && |
258 | f0cbd3ec | bellard | tp->t_timer[TCPT_PERSIST] == 0) {
|
259 | f0cbd3ec | bellard | tp->t_rxtshift = 0;
|
260 | f0cbd3ec | bellard | tcp_setpersist(tp); |
261 | f0cbd3ec | bellard | } |
262 | f0cbd3ec | bellard | |
263 | f0cbd3ec | bellard | /*
|
264 | f0cbd3ec | bellard | * No reason to send a segment, just return.
|
265 | f0cbd3ec | bellard | */
|
266 | f0cbd3ec | bellard | tcpstat.tcps_didnuttin++; |
267 | f0cbd3ec | bellard | |
268 | f0cbd3ec | bellard | return (0); |
269 | f0cbd3ec | bellard | |
270 | f0cbd3ec | bellard | send:
|
271 | f0cbd3ec | bellard | /*
|
272 | f0cbd3ec | bellard | * Before ESTABLISHED, force sending of initial options
|
273 | f0cbd3ec | bellard | * unless TCP set not to do any options.
|
274 | f0cbd3ec | bellard | * NOTE: we assume that the IP/TCP header plus TCP options
|
275 | f0cbd3ec | bellard | * always fit in a single mbuf, leaving room for a maximum
|
276 | f0cbd3ec | bellard | * link header, i.e.
|
277 | f0cbd3ec | bellard | * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN
|
278 | f0cbd3ec | bellard | */
|
279 | f0cbd3ec | bellard | optlen = 0;
|
280 | f0cbd3ec | bellard | hdrlen = sizeof (struct tcpiphdr); |
281 | f0cbd3ec | bellard | if (flags & TH_SYN) {
|
282 | f0cbd3ec | bellard | tp->snd_nxt = tp->iss; |
283 | f0cbd3ec | bellard | if ((tp->t_flags & TF_NOOPT) == 0) { |
284 | f0cbd3ec | bellard | u_int16_t mss; |
285 | f0cbd3ec | bellard | |
286 | f0cbd3ec | bellard | opt[0] = TCPOPT_MAXSEG;
|
287 | f0cbd3ec | bellard | opt[1] = 4; |
288 | f0cbd3ec | bellard | mss = htons((u_int16_t) tcp_mss(tp, 0));
|
289 | f0cbd3ec | bellard | memcpy((caddr_t)(opt + 2), (caddr_t)&mss, sizeof(mss)); |
290 | f0cbd3ec | bellard | optlen = 4;
|
291 | f0cbd3ec | bellard | |
292 | f0cbd3ec | bellard | /* if ((tp->t_flags & TF_REQ_SCALE) &&
|
293 | f0cbd3ec | bellard | * ((flags & TH_ACK) == 0 ||
|
294 | f0cbd3ec | bellard | * (tp->t_flags & TF_RCVD_SCALE))) {
|
295 | f0cbd3ec | bellard | * *((u_int32_t *) (opt + optlen)) = htonl(
|
296 | f0cbd3ec | bellard | * TCPOPT_NOP << 24 |
|
297 | f0cbd3ec | bellard | * TCPOPT_WINDOW << 16 |
|
298 | f0cbd3ec | bellard | * TCPOLEN_WINDOW << 8 |
|
299 | f0cbd3ec | bellard | * tp->request_r_scale);
|
300 | f0cbd3ec | bellard | * optlen += 4;
|
301 | f0cbd3ec | bellard | * }
|
302 | f0cbd3ec | bellard | */
|
303 | f0cbd3ec | bellard | } |
304 | f0cbd3ec | bellard | } |
305 | f0cbd3ec | bellard | |
306 | f0cbd3ec | bellard | /*
|
307 | f0cbd3ec | bellard | * Send a timestamp and echo-reply if this is a SYN and our side
|
308 | f0cbd3ec | bellard | * wants to use timestamps (TF_REQ_TSTMP is set) or both our side
|
309 | f0cbd3ec | bellard | * and our peer have sent timestamps in our SYN's.
|
310 | f0cbd3ec | bellard | */
|
311 | f0cbd3ec | bellard | /* if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP &&
|
312 | f0cbd3ec | bellard | * (flags & TH_RST) == 0 &&
|
313 | f0cbd3ec | bellard | * ((flags & (TH_SYN|TH_ACK)) == TH_SYN ||
|
314 | f0cbd3ec | bellard | * (tp->t_flags & TF_RCVD_TSTMP))) {
|
315 | f0cbd3ec | bellard | * u_int32_t *lp = (u_int32_t *)(opt + optlen);
|
316 | f0cbd3ec | bellard | *
|
317 | f0cbd3ec | bellard | * / * Form timestamp option as shown in appendix A of RFC 1323. * /
|
318 | f0cbd3ec | bellard | * *lp++ = htonl(TCPOPT_TSTAMP_HDR);
|
319 | f0cbd3ec | bellard | * *lp++ = htonl(tcp_now);
|
320 | f0cbd3ec | bellard | * *lp = htonl(tp->ts_recent);
|
321 | f0cbd3ec | bellard | * optlen += TCPOLEN_TSTAMP_APPA;
|
322 | f0cbd3ec | bellard | * }
|
323 | f0cbd3ec | bellard | */
|
324 | f0cbd3ec | bellard | hdrlen += optlen; |
325 | f0cbd3ec | bellard | |
326 | f0cbd3ec | bellard | /*
|
327 | f0cbd3ec | bellard | * Adjust data length if insertion of options will
|
328 | f0cbd3ec | bellard | * bump the packet length beyond the t_maxseg length.
|
329 | f0cbd3ec | bellard | */
|
330 | f0cbd3ec | bellard | if (len > tp->t_maxseg - optlen) {
|
331 | f0cbd3ec | bellard | len = tp->t_maxseg - optlen; |
332 | f0cbd3ec | bellard | sendalot = 1;
|
333 | f0cbd3ec | bellard | } |
334 | f0cbd3ec | bellard | |
335 | f0cbd3ec | bellard | /*
|
336 | f0cbd3ec | bellard | * Grab a header mbuf, attaching a copy of data to
|
337 | f0cbd3ec | bellard | * be transmitted, and initialize the header from
|
338 | f0cbd3ec | bellard | * the template for sends on this connection.
|
339 | f0cbd3ec | bellard | */
|
340 | f0cbd3ec | bellard | if (len) {
|
341 | f0cbd3ec | bellard | if (tp->t_force && len == 1) |
342 | f0cbd3ec | bellard | tcpstat.tcps_sndprobe++; |
343 | f0cbd3ec | bellard | else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { |
344 | f0cbd3ec | bellard | tcpstat.tcps_sndrexmitpack++; |
345 | f0cbd3ec | bellard | tcpstat.tcps_sndrexmitbyte += len; |
346 | f0cbd3ec | bellard | } else {
|
347 | f0cbd3ec | bellard | tcpstat.tcps_sndpack++; |
348 | f0cbd3ec | bellard | tcpstat.tcps_sndbyte += len; |
349 | f0cbd3ec | bellard | } |
350 | f0cbd3ec | bellard | |
351 | f0cbd3ec | bellard | m = m_get(); |
352 | f0cbd3ec | bellard | if (m == NULL) { |
353 | f0cbd3ec | bellard | /* error = ENOBUFS; */
|
354 | f0cbd3ec | bellard | error = 1;
|
355 | f0cbd3ec | bellard | goto out;
|
356 | f0cbd3ec | bellard | } |
357 | f0cbd3ec | bellard | m->m_data += if_maxlinkhdr; |
358 | f0cbd3ec | bellard | m->m_len = hdrlen; |
359 | f0cbd3ec | bellard | |
360 | f0cbd3ec | bellard | /*
|
361 | f0cbd3ec | bellard | * This will always succeed, since we make sure our mbufs
|
362 | f0cbd3ec | bellard | * are big enough to hold one MSS packet + header + ... etc.
|
363 | f0cbd3ec | bellard | */
|
364 | f0cbd3ec | bellard | /* if (len <= MHLEN - hdrlen - max_linkhdr) { */
|
365 | f0cbd3ec | bellard | |
366 | f0cbd3ec | bellard | sbcopy(&so->so_snd, off, (int) len, mtod(m, caddr_t) + hdrlen);
|
367 | f0cbd3ec | bellard | m->m_len += len; |
368 | f0cbd3ec | bellard | |
369 | f0cbd3ec | bellard | /* } else {
|
370 | f0cbd3ec | bellard | * m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len);
|
371 | f0cbd3ec | bellard | * if (m->m_next == 0)
|
372 | f0cbd3ec | bellard | * len = 0;
|
373 | f0cbd3ec | bellard | * }
|
374 | f0cbd3ec | bellard | */
|
375 | f0cbd3ec | bellard | /*
|
376 | f0cbd3ec | bellard | * If we're sending everything we've got, set PUSH.
|
377 | f0cbd3ec | bellard | * (This will keep happy those implementations which only
|
378 | f0cbd3ec | bellard | * give data to the user when a buffer fills or
|
379 | f0cbd3ec | bellard | * a PUSH comes in.)
|
380 | f0cbd3ec | bellard | */
|
381 | f0cbd3ec | bellard | if (off + len == so->so_snd.sb_cc)
|
382 | f0cbd3ec | bellard | flags |= TH_PUSH; |
383 | f0cbd3ec | bellard | } else {
|
384 | f0cbd3ec | bellard | if (tp->t_flags & TF_ACKNOW)
|
385 | f0cbd3ec | bellard | tcpstat.tcps_sndacks++; |
386 | f0cbd3ec | bellard | else if (flags & (TH_SYN|TH_FIN|TH_RST)) |
387 | f0cbd3ec | bellard | tcpstat.tcps_sndctrl++; |
388 | f0cbd3ec | bellard | else if (SEQ_GT(tp->snd_up, tp->snd_una)) |
389 | f0cbd3ec | bellard | tcpstat.tcps_sndurg++; |
390 | f0cbd3ec | bellard | else
|
391 | f0cbd3ec | bellard | tcpstat.tcps_sndwinup++; |
392 | f0cbd3ec | bellard | |
393 | f0cbd3ec | bellard | m = m_get(); |
394 | f0cbd3ec | bellard | if (m == NULL) { |
395 | f0cbd3ec | bellard | /* error = ENOBUFS; */
|
396 | f0cbd3ec | bellard | error = 1;
|
397 | f0cbd3ec | bellard | goto out;
|
398 | f0cbd3ec | bellard | } |
399 | f0cbd3ec | bellard | m->m_data += if_maxlinkhdr; |
400 | f0cbd3ec | bellard | m->m_len = hdrlen; |
401 | f0cbd3ec | bellard | } |
402 | f0cbd3ec | bellard | |
403 | f0cbd3ec | bellard | ti = mtod(m, struct tcpiphdr *);
|
404 | f0cbd3ec | bellard | |
405 | f0cbd3ec | bellard | memcpy((caddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr)); |
406 | f0cbd3ec | bellard | |
407 | f0cbd3ec | bellard | /*
|
408 | f0cbd3ec | bellard | * Fill in fields, remembering maximum advertised
|
409 | f0cbd3ec | bellard | * window for use in delaying messages about window sizes.
|
410 | f0cbd3ec | bellard | * If resending a FIN, be sure not to use a new sequence number.
|
411 | f0cbd3ec | bellard | */
|
412 | f0cbd3ec | bellard | if (flags & TH_FIN && tp->t_flags & TF_SENTFIN &&
|
413 | f0cbd3ec | bellard | tp->snd_nxt == tp->snd_max) |
414 | f0cbd3ec | bellard | tp->snd_nxt--; |
415 | f0cbd3ec | bellard | /*
|
416 | f0cbd3ec | bellard | * If we are doing retransmissions, then snd_nxt will
|
417 | f0cbd3ec | bellard | * not reflect the first unsent octet. For ACK only
|
418 | f0cbd3ec | bellard | * packets, we do not want the sequence number of the
|
419 | f0cbd3ec | bellard | * retransmitted packet, we want the sequence number
|
420 | f0cbd3ec | bellard | * of the next unsent octet. So, if there is no data
|
421 | f0cbd3ec | bellard | * (and no SYN or FIN), use snd_max instead of snd_nxt
|
422 | f0cbd3ec | bellard | * when filling in ti_seq. But if we are in persist
|
423 | f0cbd3ec | bellard | * state, snd_max might reflect one byte beyond the
|
424 | f0cbd3ec | bellard | * right edge of the window, so use snd_nxt in that
|
425 | f0cbd3ec | bellard | * case, since we know we aren't doing a retransmission.
|
426 | f0cbd3ec | bellard | * (retransmit and persist are mutually exclusive...)
|
427 | f0cbd3ec | bellard | */
|
428 | f0cbd3ec | bellard | if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST])
|
429 | f0cbd3ec | bellard | ti->ti_seq = htonl(tp->snd_nxt); |
430 | f0cbd3ec | bellard | else
|
431 | f0cbd3ec | bellard | ti->ti_seq = htonl(tp->snd_max); |
432 | f0cbd3ec | bellard | ti->ti_ack = htonl(tp->rcv_nxt); |
433 | f0cbd3ec | bellard | if (optlen) {
|
434 | f0cbd3ec | bellard | memcpy((caddr_t)(ti + 1), (caddr_t)opt, optlen);
|
435 | f0cbd3ec | bellard | ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; |
436 | f0cbd3ec | bellard | } |
437 | f0cbd3ec | bellard | ti->ti_flags = flags; |
438 | f0cbd3ec | bellard | /*
|
439 | f0cbd3ec | bellard | * Calculate receive window. Don't shrink window,
|
440 | f0cbd3ec | bellard | * but avoid silly window syndrome.
|
441 | f0cbd3ec | bellard | */
|
442 | f0cbd3ec | bellard | if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg) |
443 | f0cbd3ec | bellard | win = 0;
|
444 | f0cbd3ec | bellard | if (win > (long)TCP_MAXWIN << tp->rcv_scale) |
445 | f0cbd3ec | bellard | win = (long)TCP_MAXWIN << tp->rcv_scale;
|
446 | f0cbd3ec | bellard | if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) |
447 | f0cbd3ec | bellard | win = (long)(tp->rcv_adv - tp->rcv_nxt);
|
448 | f0cbd3ec | bellard | ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale)); |
449 | f0cbd3ec | bellard | |
450 | f0cbd3ec | bellard | if (SEQ_GT(tp->snd_up, tp->snd_una)) {
|
451 | f0cbd3ec | bellard | ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq))); |
452 | f0cbd3ec | bellard | #ifdef notdef
|
453 | f0cbd3ec | bellard | if (SEQ_GT(tp->snd_up, tp->snd_nxt)) {
|
454 | f0cbd3ec | bellard | ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt)); |
455 | f0cbd3ec | bellard | #endif
|
456 | f0cbd3ec | bellard | ti->ti_flags |= TH_URG; |
457 | f0cbd3ec | bellard | } else
|
458 | f0cbd3ec | bellard | /*
|
459 | f0cbd3ec | bellard | * If no urgent pointer to send, then we pull
|
460 | f0cbd3ec | bellard | * the urgent pointer to the left edge of the send window
|
461 | f0cbd3ec | bellard | * so that it doesn't drift into the send window on sequence
|
462 | f0cbd3ec | bellard | * number wraparound.
|
463 | f0cbd3ec | bellard | */
|
464 | f0cbd3ec | bellard | tp->snd_up = tp->snd_una; /* drag it along */
|
465 | f0cbd3ec | bellard | |
466 | f0cbd3ec | bellard | /*
|
467 | f0cbd3ec | bellard | * Put TCP length in extended header, and then
|
468 | f0cbd3ec | bellard | * checksum extended header and data.
|
469 | f0cbd3ec | bellard | */
|
470 | f0cbd3ec | bellard | if (len + optlen)
|
471 | f0cbd3ec | bellard | ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + |
472 | f0cbd3ec | bellard | optlen + len)); |
473 | f0cbd3ec | bellard | ti->ti_sum = cksum(m, (int)(hdrlen + len));
|
474 | f0cbd3ec | bellard | |
475 | f0cbd3ec | bellard | /*
|
476 | f0cbd3ec | bellard | * In transmit state, time the transmission and arrange for
|
477 | f0cbd3ec | bellard | * the retransmit. In persist state, just set snd_max.
|
478 | f0cbd3ec | bellard | */
|
479 | f0cbd3ec | bellard | if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { |
480 | f0cbd3ec | bellard | tcp_seq startseq = tp->snd_nxt; |
481 | f0cbd3ec | bellard | |
482 | f0cbd3ec | bellard | /*
|
483 | f0cbd3ec | bellard | * Advance snd_nxt over sequence space of this segment.
|
484 | f0cbd3ec | bellard | */
|
485 | f0cbd3ec | bellard | if (flags & (TH_SYN|TH_FIN)) {
|
486 | f0cbd3ec | bellard | if (flags & TH_SYN)
|
487 | f0cbd3ec | bellard | tp->snd_nxt++; |
488 | f0cbd3ec | bellard | if (flags & TH_FIN) {
|
489 | f0cbd3ec | bellard | tp->snd_nxt++; |
490 | f0cbd3ec | bellard | tp->t_flags |= TF_SENTFIN; |
491 | f0cbd3ec | bellard | } |
492 | f0cbd3ec | bellard | } |
493 | f0cbd3ec | bellard | tp->snd_nxt += len; |
494 | f0cbd3ec | bellard | if (SEQ_GT(tp->snd_nxt, tp->snd_max)) {
|
495 | f0cbd3ec | bellard | tp->snd_max = tp->snd_nxt; |
496 | f0cbd3ec | bellard | /*
|
497 | f0cbd3ec | bellard | * Time this transmission if not a retransmission and
|
498 | f0cbd3ec | bellard | * not currently timing anything.
|
499 | f0cbd3ec | bellard | */
|
500 | f0cbd3ec | bellard | if (tp->t_rtt == 0) { |
501 | f0cbd3ec | bellard | tp->t_rtt = 1;
|
502 | f0cbd3ec | bellard | tp->t_rtseq = startseq; |
503 | f0cbd3ec | bellard | tcpstat.tcps_segstimed++; |
504 | f0cbd3ec | bellard | } |
505 | f0cbd3ec | bellard | } |
506 | f0cbd3ec | bellard | |
507 | f0cbd3ec | bellard | /*
|
508 | f0cbd3ec | bellard | * Set retransmit timer if not currently set,
|
509 | f0cbd3ec | bellard | * and not doing an ack or a keep-alive probe.
|
510 | f0cbd3ec | bellard | * Initial value for retransmit timer is smoothed
|
511 | f0cbd3ec | bellard | * round-trip time + 2 * round-trip time variance.
|
512 | f0cbd3ec | bellard | * Initialize shift counter which is used for backoff
|
513 | f0cbd3ec | bellard | * of retransmit time.
|
514 | f0cbd3ec | bellard | */
|
515 | f0cbd3ec | bellard | if (tp->t_timer[TCPT_REXMT] == 0 && |
516 | f0cbd3ec | bellard | tp->snd_nxt != tp->snd_una) { |
517 | f0cbd3ec | bellard | tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; |
518 | f0cbd3ec | bellard | if (tp->t_timer[TCPT_PERSIST]) {
|
519 | f0cbd3ec | bellard | tp->t_timer[TCPT_PERSIST] = 0;
|
520 | f0cbd3ec | bellard | tp->t_rxtshift = 0;
|
521 | f0cbd3ec | bellard | } |
522 | f0cbd3ec | bellard | } |
523 | f0cbd3ec | bellard | } else
|
524 | f0cbd3ec | bellard | if (SEQ_GT(tp->snd_nxt + len, tp->snd_max))
|
525 | f0cbd3ec | bellard | tp->snd_max = tp->snd_nxt + len; |
526 | f0cbd3ec | bellard | |
527 | f0cbd3ec | bellard | /*
|
528 | f0cbd3ec | bellard | * Fill in IP length and desired time to live and
|
529 | f0cbd3ec | bellard | * send to IP level. There should be a better way
|
530 | f0cbd3ec | bellard | * to handle ttl and tos; we could keep them in
|
531 | f0cbd3ec | bellard | * the template, but need a way to checksum without them.
|
532 | f0cbd3ec | bellard | */
|
533 | f0cbd3ec | bellard | m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */
|
534 | f0cbd3ec | bellard | |
535 | f0cbd3ec | bellard | { |
536 | f0cbd3ec | bellard | |
537 | f0cbd3ec | bellard | ((struct ip *)ti)->ip_len = m->m_len;
|
538 | f0cbd3ec | bellard | |
539 | f0cbd3ec | bellard | ((struct ip *)ti)->ip_ttl = ip_defttl;
|
540 | f0cbd3ec | bellard | ((struct ip *)ti)->ip_tos = so->so_iptos;
|
541 | f0cbd3ec | bellard | |
542 | f0cbd3ec | bellard | /* #if BSD >= 43 */
|
543 | f0cbd3ec | bellard | /* Don't do IP options... */
|
544 | f0cbd3ec | bellard | /* error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
|
545 | f0cbd3ec | bellard | * so->so_options & SO_DONTROUTE, 0);
|
546 | f0cbd3ec | bellard | */
|
547 | f0cbd3ec | bellard | error = ip_output(so, m); |
548 | f0cbd3ec | bellard | |
549 | f0cbd3ec | bellard | /* #else
|
550 | f0cbd3ec | bellard | * error = ip_output(m, (struct mbuf *)0, &tp->t_inpcb->inp_route,
|
551 | f0cbd3ec | bellard | * so->so_options & SO_DONTROUTE);
|
552 | f0cbd3ec | bellard | * #endif
|
553 | f0cbd3ec | bellard | */
|
554 | f0cbd3ec | bellard | } |
555 | f0cbd3ec | bellard | if (error) {
|
556 | f0cbd3ec | bellard | out:
|
557 | f0cbd3ec | bellard | /* if (error == ENOBUFS) {
|
558 | f0cbd3ec | bellard | * tcp_quench(tp->t_inpcb, 0);
|
559 | f0cbd3ec | bellard | * return (0);
|
560 | f0cbd3ec | bellard | * }
|
561 | f0cbd3ec | bellard | */
|
562 | f0cbd3ec | bellard | /* if ((error == EHOSTUNREACH || error == ENETDOWN)
|
563 | f0cbd3ec | bellard | * && TCPS_HAVERCVDSYN(tp->t_state)) {
|
564 | f0cbd3ec | bellard | * tp->t_softerror = error;
|
565 | f0cbd3ec | bellard | * return (0);
|
566 | f0cbd3ec | bellard | * }
|
567 | f0cbd3ec | bellard | */
|
568 | f0cbd3ec | bellard | return (error);
|
569 | f0cbd3ec | bellard | } |
570 | f0cbd3ec | bellard | tcpstat.tcps_sndtotal++; |
571 | f0cbd3ec | bellard | |
572 | f0cbd3ec | bellard | /*
|
573 | f0cbd3ec | bellard | * Data sent (as far as we can tell).
|
574 | f0cbd3ec | bellard | * If this advertises a larger window than any other segment,
|
575 | f0cbd3ec | bellard | * then remember the size of the advertised window.
|
576 | f0cbd3ec | bellard | * Any pending ACK has now been sent.
|
577 | f0cbd3ec | bellard | */
|
578 | f0cbd3ec | bellard | if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) |
579 | f0cbd3ec | bellard | tp->rcv_adv = tp->rcv_nxt + win; |
580 | f0cbd3ec | bellard | tp->last_ack_sent = tp->rcv_nxt; |
581 | f0cbd3ec | bellard | tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); |
582 | f0cbd3ec | bellard | if (sendalot)
|
583 | f0cbd3ec | bellard | goto again;
|
584 | f0cbd3ec | bellard | |
585 | f0cbd3ec | bellard | return (0); |
586 | f0cbd3ec | bellard | } |
587 | f0cbd3ec | bellard | |
588 | f0cbd3ec | bellard | void
|
589 | f0cbd3ec | bellard | tcp_setpersist(tp) |
590 | f0cbd3ec | bellard | register struct tcpcb *tp; |
591 | f0cbd3ec | bellard | { |
592 | f0cbd3ec | bellard | int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; |
593 | f0cbd3ec | bellard | |
594 | f0cbd3ec | bellard | /* if (tp->t_timer[TCPT_REXMT])
|
595 | f0cbd3ec | bellard | * panic("tcp_output REXMT");
|
596 | f0cbd3ec | bellard | */
|
597 | f0cbd3ec | bellard | /*
|
598 | f0cbd3ec | bellard | * Start/restart persistence timer.
|
599 | f0cbd3ec | bellard | */
|
600 | f0cbd3ec | bellard | TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], |
601 | f0cbd3ec | bellard | t * tcp_backoff[tp->t_rxtshift], |
602 | f0cbd3ec | bellard | TCPTV_PERSMIN, TCPTV_PERSMAX); |
603 | f0cbd3ec | bellard | if (tp->t_rxtshift < TCP_MAXRXTSHIFT)
|
604 | f0cbd3ec | bellard | tp->t_rxtshift++; |
605 | f0cbd3ec | bellard | } |