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