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