ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/slirp/tcp_timer.c
Revision: 1.1
Committed: 2005-05-13T09:00:59Z (19 years, 6 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
CVS Tags: nigel-build-19, nigel-build-17
Log Message:
slirp user mode network emulation code from qemu

File Contents

# User Rev Content
1 gbeauche 1.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     int tcp_keepidle = TCPTV_KEEP_IDLE;
40     int tcp_keepintvl = TCPTV_KEEPINTVL;
41     int tcp_maxidle;
42     int so_options = DO_KEEPALIVE;
43    
44     struct tcpstat tcpstat; /* tcp statistics */
45     u_int32_t tcp_now; /* for RFC 1323 timestamps */
46    
47     /*
48     * Fast timeout routine for processing delayed acks
49     */
50     void
51     tcp_fasttimo()
52     {
53     register struct socket *so;
54     register struct tcpcb *tp;
55    
56     DEBUG_CALL("tcp_fasttimo");
57    
58     so = tcb.so_next;
59     if (so)
60     for (; so != &tcb; so = so->so_next)
61     if ((tp = (struct tcpcb *)so->so_tcpcb) &&
62     (tp->t_flags & TF_DELACK)) {
63     tp->t_flags &= ~TF_DELACK;
64     tp->t_flags |= TF_ACKNOW;
65     tcpstat.tcps_delack++;
66     (void) tcp_output(tp);
67     }
68     }
69    
70     /*
71     * Tcp protocol timeout routine called every 500 ms.
72     * Updates the timers in all active tcb's and
73     * causes finite state machine actions if timers expire.
74     */
75     void
76     tcp_slowtimo()
77     {
78     register struct socket *ip, *ipnxt;
79     register struct tcpcb *tp;
80     register int i;
81    
82     DEBUG_CALL("tcp_slowtimo");
83    
84     tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl;
85     /*
86     * Search through tcb's and update active timers.
87     */
88     ip = tcb.so_next;
89     if (ip == 0)
90     return;
91     for (; ip != &tcb; ip = ipnxt) {
92     ipnxt = ip->so_next;
93     tp = sototcpcb(ip);
94     if (tp == 0)
95     continue;
96     for (i = 0; i < TCPT_NTIMERS; i++) {
97     if (tp->t_timer[i] && --tp->t_timer[i] == 0) {
98     tcp_timers(tp,i);
99     if (ipnxt->so_prev != ip)
100     goto tpgone;
101     }
102     }
103     tp->t_idle++;
104     if (tp->t_rtt)
105     tp->t_rtt++;
106     tpgone:
107     ;
108     }
109     tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */
110     #ifdef TCP_COMPAT_42
111     if ((int)tcp_iss < 0)
112     tcp_iss = 0; /* XXX */
113     #endif
114     tcp_now++; /* for timestamps */
115     }
116    
117     /*
118     * Cancel all timers for TCP tp.
119     */
120     void
121     tcp_canceltimers(tp)
122     struct tcpcb *tp;
123     {
124     register int i;
125    
126     for (i = 0; i < TCPT_NTIMERS; i++)
127     tp->t_timer[i] = 0;
128     }
129    
130     int tcp_backoff[TCP_MAXRXTSHIFT + 1] =
131     { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
132    
133     /*
134     * TCP timer processing.
135     */
136     struct tcpcb *
137     tcp_timers(tp, timer)
138     register struct tcpcb *tp;
139     int timer;
140     {
141     register int rexmt;
142    
143     DEBUG_CALL("tcp_timers");
144    
145     switch (timer) {
146    
147     /*
148     * 2 MSL timeout in shutdown went off. If we're closed but
149     * still waiting for peer to close and connection has been idle
150     * too long, or if 2MSL time is up from TIME_WAIT, delete connection
151     * control block. Otherwise, check again in a bit.
152     */
153     case TCPT_2MSL:
154     if (tp->t_state != TCPS_TIME_WAIT &&
155     tp->t_idle <= tcp_maxidle)
156     tp->t_timer[TCPT_2MSL] = tcp_keepintvl;
157     else
158     tp = tcp_close(tp);
159     break;
160    
161     /*
162     * Retransmission timer went off. Message has not
163     * been acked within retransmit interval. Back off
164     * to a longer retransmit interval and retransmit one segment.
165     */
166     case TCPT_REXMT:
167    
168     /*
169     * XXXXX If a packet has timed out, then remove all the queued
170     * packets for that session.
171     */
172    
173     if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
174     /*
175     * This is a hack to suit our terminal server here at the uni of canberra
176     * since they have trouble with zeroes... It usually lets them through
177     * unharmed, but under some conditions, it'll eat the zeros. If we
178     * keep retransmitting it, it'll keep eating the zeroes, so we keep
179     * retransmitting, and eventually the connection dies...
180     * (this only happens on incoming data)
181     *
182     * So, if we were gonna drop the connection from too many retransmits,
183     * don't... instead halve the t_maxseg, which might break up the NULLs and
184     * let them through
185     *
186     * *sigh*
187     */
188    
189     tp->t_maxseg >>= 1;
190     if (tp->t_maxseg < 32) {
191     /*
192     * We tried our best, now the connection must die!
193     */
194     tp->t_rxtshift = TCP_MAXRXTSHIFT;
195     tcpstat.tcps_timeoutdrop++;
196     tp = tcp_drop(tp, tp->t_softerror);
197     /* tp->t_softerror : ETIMEDOUT); */ /* XXX */
198     return (tp); /* XXX */
199     }
200    
201     /*
202     * Set rxtshift to 6, which is still at the maximum
203     * backoff time
204     */
205     tp->t_rxtshift = 6;
206     }
207     tcpstat.tcps_rexmttimeo++;
208     rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift];
209     TCPT_RANGESET(tp->t_rxtcur, rexmt,
210     (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */
211     tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
212     /*
213     * If losing, let the lower level know and try for
214     * a better route. Also, if we backed off this far,
215     * our srtt estimate is probably bogus. Clobber it
216     * so we'll take the next rtt measurement as our srtt;
217     * move the current srtt into rttvar to keep the current
218     * retransmit times until then.
219     */
220     if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
221     /* in_losing(tp->t_inpcb); */
222     tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
223     tp->t_srtt = 0;
224     }
225     tp->snd_nxt = tp->snd_una;
226     /*
227     * If timing a segment in this window, stop the timer.
228     */
229     tp->t_rtt = 0;
230     /*
231     * Close the congestion window down to one segment
232     * (we'll open it by one segment for each ack we get).
233     * Since we probably have a window's worth of unacked
234     * data accumulated, this "slow start" keeps us from
235     * dumping all that data as back-to-back packets (which
236     * might overwhelm an intermediate gateway).
237     *
238     * There are two phases to the opening: Initially we
239     * open by one mss on each ack. This makes the window
240     * size increase exponentially with time. If the
241     * window is larger than the path can handle, this
242     * exponential growth results in dropped packet(s)
243     * almost immediately. To get more time between
244     * drops but still "push" the network to take advantage
245     * of improving conditions, we switch from exponential
246     * to linear window opening at some threshold size.
247     * For a threshold, we use half the current window
248     * size, truncated to a multiple of the mss.
249     *
250     * (the minimum cwnd that will give us exponential
251     * growth is 2 mss. We don't allow the threshold
252     * to go below this.)
253     */
254     {
255     u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;
256     if (win < 2)
257     win = 2;
258     tp->snd_cwnd = tp->t_maxseg;
259     tp->snd_ssthresh = win * tp->t_maxseg;
260     tp->t_dupacks = 0;
261     }
262     (void) tcp_output(tp);
263     break;
264    
265     /*
266     * Persistence timer into zero window.
267     * Force a byte to be output, if possible.
268     */
269     case TCPT_PERSIST:
270     tcpstat.tcps_persisttimeo++;
271     tcp_setpersist(tp);
272     tp->t_force = 1;
273     (void) tcp_output(tp);
274     tp->t_force = 0;
275     break;
276    
277     /*
278     * Keep-alive timer went off; send something
279     * or drop connection if idle for too long.
280     */
281     case TCPT_KEEP:
282     tcpstat.tcps_keeptimeo++;
283     if (tp->t_state < TCPS_ESTABLISHED)
284     goto dropit;
285    
286     /* if (tp->t_socket->so_options & SO_KEEPALIVE && */
287     if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) {
288     if (tp->t_idle >= tcp_keepidle + tcp_maxidle)
289     goto dropit;
290     /*
291     * Send a packet designed to force a response
292     * if the peer is up and reachable:
293     * either an ACK if the connection is still alive,
294     * or an RST if the peer has closed the connection
295     * due to timeout or reboot.
296     * Using sequence number tp->snd_una-1
297     * causes the transmitted zero-length segment
298     * to lie outside the receive window;
299     * by the protocol spec, this requires the
300     * correspondent TCP to respond.
301     */
302     tcpstat.tcps_keepprobe++;
303     #ifdef TCP_COMPAT_42
304     /*
305     * The keepalive packet must have nonzero length
306     * to get a 4.2 host to respond.
307     */
308     tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
309     tp->rcv_nxt - 1, tp->snd_una - 1, 0);
310     #else
311     tcp_respond(tp, &tp->t_template, (struct mbuf *)NULL,
312     tp->rcv_nxt, tp->snd_una - 1, 0);
313     #endif
314     tp->t_timer[TCPT_KEEP] = tcp_keepintvl;
315     } else
316     tp->t_timer[TCPT_KEEP] = tcp_keepidle;
317     break;
318    
319     dropit:
320     tcpstat.tcps_keepdrops++;
321     tp = tcp_drop(tp, 0); /* ETIMEDOUT); */
322     break;
323     }
324    
325     return (tp);
326     }