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