VirtualBox

source: vbox/trunk/src/VBox/Devices/Network/slirp/tcp_timer.c@ 1033

Last change on this file since 1033 was 1033, checked in by vboxsync, 18 years ago

Big change to make slirp fully instantiatable (replace all global
variables with local ones, passing a reference to the state/config
structure to all places which are interested). You can now have as many
cards in the guest configured for NAT networking as you want.

  • Property svn:eol-style set to native
File size: 10.5 KB
Line 
1/*
2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93
34 * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp
35 */
36
37#include <slirp.h>
38
39#ifndef VBOX
40int tcp_keepidle = TCPTV_KEEP_IDLE;
41int tcp_keepintvl = TCPTV_KEEPINTVL;
42int tcp_maxidle;
43int so_options = DO_KEEPALIVE;
44
45struct tcpstat tcpstat; /* tcp statistics */
46u_int32_t tcp_now; /* for RFC 1323 timestamps */
47#endif /* !VBOX */
48
49/*
50 * Fast timeout routine for processing delayed acks
51 */
52void
53#ifdef VBOX
54tcp_fasttimo(PNATState pData)
55#else /* !VBOX */
56tcp_fasttimo()
57#endif /* !VBOX */
58{
59 register struct socket *so;
60 register struct tcpcb *tp;
61
62 DEBUG_CALL("tcp_fasttimo");
63
64 so = tcb.so_next;
65 if (so)
66 for (; so != &tcb; so = so->so_next)
67 if ((tp = (struct tcpcb *)so->so_tcpcb) &&
68 (tp->t_flags & TF_DELACK)) {
69 tp->t_flags &= ~TF_DELACK;
70 tp->t_flags |= TF_ACKNOW;
71 tcpstat.tcps_delack++;
72#ifdef VBOX
73 (void) tcp_output(pData, tp);
74#else /*! VBOX */
75 (void) tcp_output(tp);
76#endif /* !VBOX */
77 }
78}
79
80/*
81 * Tcp protocol timeout routine called every 500 ms.
82 * Updates the timers in all active tcb's and
83 * causes finite state machine actions if timers expire.
84 */
85void
86#ifdef VBOX
87tcp_slowtimo(PNATState pData)
88#else /* !VBOX */
89tcp_slowtimo()
90#endif /* !VBOX */
91{
92 register struct socket *ip, *ipnxt;
93 register struct tcpcb *tp;
94 register int i;
95
96 DEBUG_CALL("tcp_slowtimo");
97
98#ifndef VBOX
99 tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl;
100#endif /* !VBOX */
101 /*
102 * Search through tcb's and update active timers.
103 */
104 ip = tcb.so_next;
105 if (ip == 0)
106 return;
107 for (; ip != &tcb; ip = ipnxt) {
108 ipnxt = ip->so_next;
109 tp = sototcpcb(ip);
110 if (tp == 0)
111 continue;
112 for (i = 0; i < TCPT_NTIMERS; i++) {
113 if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
114#ifdef VBOX
115 tcp_timers(pData, tp,i);
116#else /* !VBOX */
117 tcp_timers(tp,i);
118#endif /* !VBOX */
119 if (ipnxt->so_prev != ip)
120 goto tpgone;
121 }
122 }
123 tp->t_idle++;
124 if (tp->t_rtt)
125 tp->t_rtt++;
126tpgone:
127 ;
128 }
129 tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */
130#ifdef TCP_COMPAT_42
131 if ((int)tcp_iss < 0)
132 tcp_iss = 0; /* XXX */
133#endif
134 tcp_now++; /* for timestamps */
135}
136
137/*
138 * Cancel all timers for TCP tp.
139 */
140void
141tcp_canceltimers(tp)
142 struct tcpcb *tp;
143{
144 register int i;
145
146 for (i = 0; i < TCPT_NTIMERS; i++)
147 tp->t_timer[i] = 0;
148}
149
150#ifdef VBOX
151const int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
152#else /* !VBOX */
153int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
154#endif /* !VBOX */
155 { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
156
157/*
158 * TCP timer processing.
159 */
160struct tcpcb *
161#ifdef VBOX
162tcp_timers(PNATState pData, register struct tcpcb *tp, int timer)
163#else /* !VBOX */
164tcp_timers(tp, timer)
165 register struct tcpcb *tp;
166 int timer;
167#endif /* !VBOX */
168{
169 register int rexmt;
170
171 DEBUG_CALL("tcp_timers");
172
173 switch (timer) {
174
175 /*
176 * 2 MSL timeout in shutdown went off. If we're closed but
177 * still waiting for peer to close and connection has been idle
178 * too long, or if 2MSL time is up from TIME_WAIT, delete connection
179 * control block. Otherwise, check again in a bit.
180 */
181 case TCPT_2MSL:
182 if (tp->t_state != TCPS_TIME_WAIT &&
183 tp->t_idle <= tcp_maxidle)
184 tp->t_timer[TCPT_2MSL] = tcp_keepintvl;
185 else
186#ifdef VBOX
187 tp = tcp_close(pData, tp);
188#else /* !VBOX */
189 tp = tcp_close(tp);
190#endif /* !VBOX */
191 break;
192
193 /*
194 * Retransmission timer went off. Message has not
195 * been acked within retransmit interval. Back off
196 * to a longer retransmit interval and retransmit one segment.
197 */
198 case TCPT_REXMT:
199
200 /*
201 * XXXXX If a packet has timed out, then remove all the queued
202 * packets for that session.
203 */
204
205 if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
206 /*
207 * This is a hack to suit our terminal server here at the uni of canberra
208 * since they have trouble with zeroes... It usually lets them through
209 * unharmed, but under some conditions, it'll eat the zeros. If we
210 * keep retransmitting it, it'll keep eating the zeroes, so we keep
211 * retransmitting, and eventually the connection dies...
212 * (this only happens on incoming data)
213 *
214 * So, if we were gonna drop the connection from too many retransmits,
215 * don't... instead halve the t_maxseg, which might break up the NULLs and
216 * let them through
217 *
218 * *sigh*
219 */
220
221 tp->t_maxseg >>= 1;
222 if (tp->t_maxseg < 32) {
223 /*
224 * We tried our best, now the connection must die!
225 */
226 tp->t_rxtshift = TCP_MAXRXTSHIFT;
227 tcpstat.tcps_timeoutdrop++;
228#ifdef VBOX
229 tp = tcp_drop(pData, tp, tp->t_softerror);
230#else /* !VBOX */
231 tp = tcp_drop(tp, tp->t_softerror);
232#endif /* !VBOX */
233 /* tp->t_softerror : ETIMEDOUT); */ /* XXX */
234 return (tp); /* XXX */
235 }
236
237 /*
238 * Set rxtshift to 6, which is still at the maximum
239 * backoff time
240 */
241 tp->t_rxtshift = 6;
242 }
243 tcpstat.tcps_rexmttimeo++;
244 rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
245 TCPT_RANGESET(tp->t_rxtcur, rexmt,
246 (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
247 tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
248 /*
249 * If losing, let the lower level know and try for
250 * a better route. Also, if we backed off this far,
251 * our srtt estimate is probably bogus. Clobber it
252 * so we'll take the next rtt measurement as our srtt;
253 * move the current srtt into rttvar to keep the current
254 * retransmit times until then.
255 */
256 if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
257/* in_losing(tp->t_inpcb); */
258 tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
259 tp->t_srtt = 0;
260 }
261 tp->snd_nxt = tp->snd_una;
262 /*
263 * If timing a segment in this window, stop the timer.
264 */
265 tp->t_rtt = 0;
266 /*
267 * Close the congestion window down to one segment
268 * (we'll open it by one segment for each ack we get).
269 * Since we probably have a window's worth of unacked
270 * data accumulated, this "slow start" keeps us from
271 * dumping all that data as back-to-back packets (which
272 * might overwhelm an intermediate gateway).
273 *
274 * There are two phases to the opening: Initially we
275 * open by one mss on each ack. This makes the window
276 * size increase exponentially with time. If the
277 * window is larger than the path can handle, this
278 * exponential growth results in dropped packet(s)
279 * almost immediately. To get more time between
280 * drops but still "push" the network to take advantage
281 * of improving conditions, we switch from exponential
282 * to linear window opening at some threshold size.
283 * For a threshold, we use half the current window
284 * size, truncated to a multiple of the mss.
285 *
286 * (the minimum cwnd that will give us exponential
287 * growth is 2 mss. We don't allow the threshold
288 * to go below this.)
289 */
290 {
291 u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
292 if (win < 2)
293 win = 2;
294 tp->snd_cwnd = tp->t_maxseg;
295 tp->snd_ssthresh = win * tp->t_maxseg;
296 tp->t_dupacks = 0;
297 }
298#ifdef VBOX
299 (void) tcp_output(pData, tp);
300#else /* !VBOX */
301 (void) tcp_output(tp);
302#endif /* !VBOX */
303 break;
304
305 /*
306 * Persistence timer into zero window.
307 * Force a byte to be output, if possible.
308 */
309 case TCPT_PERSIST:
310 tcpstat.tcps_persisttimeo++;
311 tcp_setpersist(tp);
312 tp->t_force = 1;
313#ifdef VBOX
314 (void) tcp_output(pData, tp);
315#else /* !VBOX */
316 (void) tcp_output(tp);
317#endif /* !VBOX */
318 tp->t_force = 0;
319 break;
320
321 /*
322 * Keep-alive timer went off; send something
323 * or drop connection if idle for too long.
324 */
325 case TCPT_KEEP:
326 tcpstat.tcps_keeptimeo++;
327 if (tp->t_state < TCPS_ESTABLISHED)
328 goto dropit;
329
330/* if (tp->t_socket->so_options & SO_KEEPALIVE && */
331 if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) {
332 if (tp->t_idle >= tcp_keepidle + tcp_maxidle)
333 goto dropit;
334 /*
335 * Send a packet designed to force a response
336 * if the peer is up and reachable:
337 * either an ACK if the connection is still alive,
338 * or an RST if the peer has closed the connection
339 * due to timeout or reboot.
340 * Using sequence number tp->snd_una-1
341 * causes the transmitted zero-length segment
342 * to lie outside the receive window;
343 * by the protocol spec, this requires the
344 * correspondent TCP to respond.
345 */
346 tcpstat.tcps_keepprobe++;
347#ifdef TCP_COMPAT_42
348 /*
349 * The keepalive packet must have nonzero length
350 * to get a 4.2 host to respond.
351 */
352 tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
353 tp->rcv_nxt - 1, tp->snd_una - 1, 0);
354#else
355#ifdef VBOX
356 tcp_respond(pData, tp, &tp->t_template, (struct mbuf *)NULL,
357 tp->rcv_nxt, tp->snd_una - 1, 0);
358#else /* !VBOX */
359 tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
360 tp->rcv_nxt, tp->snd_una - 1, 0);
361#endif /* !VBOX */
362#endif
363 tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
364 } else
365 tp->t_timer[TCPT_KEEP] = tcp_keepidle;
366 break;
367
368 dropit:
369 tcpstat.tcps_keepdrops++;
370#ifdef VBOX
371 tp = tcp_drop(pData, tp, 0); /* ETIMEDOUT); */
372#else /* !VBOX */
373 tp = tcp_drop(tp, 0); /* ETIMEDOUT); */
374#endif /* !VBOX */
375 break;
376 }
377
378 return (tp);
379}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette