|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * ! 26: * Redistribution and use in source and binary forms, with or without ! 27: * modification, are permitted provided that the following conditions ! 28: * are met: ! 29: * 1. Redistributions of source code must retain the above copyright ! 30: * notice, this list of conditions and the following disclaimer. ! 31: * 2. Redistributions in binary form must reproduce the above copyright ! 32: * notice, this list of conditions and the following disclaimer in the ! 33: * documentation and/or other materials provided with the distribution. ! 34: * 3. All advertising materials mentioning features or use of this software ! 35: * must display the following acknowledgement: ! 36: * This product includes software developed by the University of ! 37: * California, Berkeley and its contributors. ! 38: * 4. Neither the name of the University nor the names of its contributors ! 39: * may be used to endorse or promote products derived from this software ! 40: * without specific prior written permission. ! 41: * ! 42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 52: * SUCH DAMAGE. ! 53: * ! 54: * @(#)tcp_timer.c 8.2 (Berkeley) 5/24/95 ! 55: */ ! 56: ! 57: #if ISFB31 ! 58: #include "opt_compat.h" ! 59: #include "opt_tcpdebug.h" ! 60: #endif ! 61: ! 62: #include <sys/param.h> ! 63: #include <sys/systm.h> ! 64: #include <sys/kernel.h> ! 65: #include <sys/sysctl.h> ! 66: #include <sys/socket.h> ! 67: #include <sys/socketvar.h> ! 68: #include <sys/protosw.h> ! 69: ! 70: #include <kern/cpu_number.h> /* before tcp_seq.h, for tcp_random18() */ ! 71: ! 72: #include <net/route.h> ! 73: ! 74: #include <netinet/in.h> ! 75: #include <netinet/in_systm.h> ! 76: #include <netinet/in_pcb.h> ! 77: #include <netinet/ip_var.h> ! 78: #include <netinet/tcp.h> ! 79: #include <netinet/tcp_fsm.h> ! 80: #include <netinet/tcp_seq.h> ! 81: #include <netinet/tcp_timer.h> ! 82: #include <netinet/tcp_var.h> ! 83: #include <netinet/tcpip.h> ! 84: #if TCPDEBUG ! 85: #include <netinet/tcp_debug.h> ! 86: #endif ! 87: ! 88: int tcp_keepinit = TCPTV_KEEP_INIT; ! 89: SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, ! 90: CTLFLAG_RW, &tcp_keepinit , 0, ""); ! 91: ! 92: int tcp_keepidle = TCPTV_KEEP_IDLE; ! 93: SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, ! 94: CTLFLAG_RW, &tcp_keepidle , 0, ""); ! 95: ! 96: static int tcp_keepintvl = TCPTV_KEEPINTVL; ! 97: SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, ! 98: CTLFLAG_RW, &tcp_keepintvl , 0, ""); ! 99: ! 100: static int always_keepalive = 0; ! 101: SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, ! 102: CTLFLAG_RW, &always_keepalive , 0, ""); ! 103: ! 104: static int tcp_keepcnt = TCPTV_KEEPCNT; ! 105: /* max idle probes */ ! 106: static int tcp_maxpersistidle = TCPTV_KEEP_IDLE; ! 107: /* max idle time in persist */ ! 108: int tcp_maxidle; ! 109: ! 110: /* ! 111: * Fast timeout routine for processing delayed acks ! 112: */ ! 113: void ! 114: tcp_fasttimo() ! 115: { ! 116: register struct inpcb *inp; ! 117: register struct tcpcb *tp; ! 118: int s; ! 119: ! 120: if (tcp_delack_enabled) { ! 121: s = splnet(); ! 122: for (inp = tcb.lh_first; inp != NULL; inp = inp->inp_list.le_next) { ! 123: if ((tp = (struct tcpcb *)inp->inp_ppcb) && ! 124: (tp->t_flags & TF_DELACK)) { ! 125: tp->t_flags &= ~TF_DELACK; ! 126: tp->t_flags |= TF_ACKNOW; ! 127: tcpstat.tcps_delack++; ! 128: (void) tcp_output(tp); ! 129: } ! 130: } ! 131: splx(s); ! 132: } ! 133: } ! 134: ! 135: /* ! 136: * Tcp protocol timeout routine called every 500 ms. ! 137: * Updates the timers in all active tcb's and ! 138: * causes finite state machine actions if timers expire. ! 139: */ ! 140: void ! 141: tcp_slowtimo() ! 142: { ! 143: register struct inpcb *ip, *ipnxt; ! 144: register struct tcpcb *tp; ! 145: register int i; ! 146: int s; ! 147: #if TCPDEBUG ! 148: int ostate; ! 149: #endif ! 150: ! 151: s = splnet(); ! 152: ! 153: tcp_maxidle = tcp_keepcnt * tcp_keepintvl; ! 154: ! 155: ip = tcb.lh_first; ! 156: if (ip == NULL) { ! 157: splx(s); ! 158: return; ! 159: } ! 160: /* ! 161: * Search through tcb's and update active timers. ! 162: */ ! 163: for (; ip != NULL; ip = ipnxt) { ! 164: ipnxt = ip->inp_list.le_next; ! 165: tp = intotcpcb(ip); ! 166: if (tp == 0 || tp->t_state == TCPS_LISTEN) ! 167: continue; ! 168: for (i = 0; i < TCPT_NTIMERS; i++) { ! 169: if (tp->t_timer[i] && --tp->t_timer[i] == 0) { ! 170: #if TCPDEBUG ! 171: ostate = tp->t_state; ! 172: #endif ! 173: tp = tcp_timers(tp, i); ! 174: if (tp == NULL) ! 175: goto tpgone; ! 176: #if TCPDEBUG ! 177: if (tp->t_inpcb->inp_socket->so_options ! 178: & SO_DEBUG) ! 179: tcp_trace(TA_USER, ostate, tp, ! 180: (struct tcpiphdr *)0, ! 181: PRU_SLOWTIMO); ! 182: #endif ! 183: } ! 184: } ! 185: tp->t_idle++; ! 186: tp->t_duration++; ! 187: if (tp->t_rtt) ! 188: tp->t_rtt++; ! 189: tpgone: ! 190: ; ! 191: } ! 192: tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ ! 193: #if TCP_COMPAT_42 ! 194: if ((int)tcp_iss < 0) ! 195: tcp_iss = TCP_ISSINCR; /* XXX */ ! 196: #endif ! 197: tcp_now++; /* for timestamps */ ! 198: splx(s); ! 199: } ! 200: ! 201: /* ! 202: * Cancel all timers for TCP tp. ! 203: */ ! 204: void ! 205: tcp_canceltimers(tp) ! 206: struct tcpcb *tp; ! 207: { ! 208: register int i; ! 209: ! 210: for (i = 0; i < TCPT_NTIMERS; i++) ! 211: tp->t_timer[i] = 0; ! 212: } ! 213: ! 214: int tcp_backoff[TCP_MAXRXTSHIFT + 1] = ! 215: { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; ! 216: ! 217: static int tcp_totbackoff = 511; /* sum of tcp_backoff[] */ ! 218: ! 219: /* ! 220: * TCP timer processing. ! 221: */ ! 222: struct tcpcb * ! 223: tcp_timers(tp, timer) ! 224: register struct tcpcb *tp; ! 225: int timer; ! 226: { ! 227: register int rexmt; ! 228: struct socket *so_tmp; ! 229: ! 230: switch (timer) { ! 231: ! 232: /* ! 233: * 2 MSL timeout in shutdown went off. If we're closed but ! 234: * still waiting for peer to close and connection has been idle ! 235: * too long, or if 2MSL time is up from TIME_WAIT, delete connection ! 236: * control block. Otherwise, check again in a bit. ! 237: */ ! 238: case TCPT_2MSL: ! 239: if (tp->t_state != TCPS_TIME_WAIT && ! 240: tp->t_idle <= tcp_maxidle) ! 241: tp->t_timer[TCPT_2MSL] = tcp_keepintvl; ! 242: else ! 243: tp = tcp_close(tp); ! 244: break; ! 245: ! 246: /* ! 247: * Retransmission timer went off. Message has not ! 248: * been acked within retransmit interval. Back off ! 249: * to a longer retransmit interval and retransmit one segment. ! 250: */ ! 251: case TCPT_REXMT: ! 252: if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { ! 253: tp->t_rxtshift = TCP_MAXRXTSHIFT; ! 254: tcpstat.tcps_timeoutdrop++; ! 255: so_tmp = tp->t_inpcb->inp_socket; ! 256: tp = tcp_drop(tp, tp->t_softerror ? ! 257: tp->t_softerror : ETIMEDOUT); ! 258: postevent(so_tmp, 0, EV_TIMEOUT); ! 259: break; ! 260: } ! 261: tcpstat.tcps_rexmttimeo++; ! 262: rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; ! 263: TCPT_RANGESET(tp->t_rxtcur, rexmt, ! 264: tp->t_rttmin, TCPTV_REXMTMAX); ! 265: tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; ! 266: /* ! 267: * If losing, let the lower level know and try for ! 268: * a better route. Also, if we backed off this far, ! 269: * our srtt estimate is probably bogus. Clobber it ! 270: * so we'll take the next rtt measurement as our srtt; ! 271: * move the current srtt into rttvar to keep the current ! 272: * retransmit times until then. ! 273: */ ! 274: if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { ! 275: in_losing(tp->t_inpcb); ! 276: tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); ! 277: tp->t_srtt = 0; ! 278: } ! 279: tp->snd_nxt = tp->snd_una; ! 280: /* ! 281: * Force a segment to be sent. ! 282: */ ! 283: tp->t_flags |= TF_ACKNOW; ! 284: /* ! 285: * If timing a segment in this window, stop the timer. ! 286: */ ! 287: tp->t_rtt = 0; ! 288: /* ! 289: * Close the congestion window down to one segment ! 290: * (we'll open it by one segment for each ack we get). ! 291: * Since we probably have a window's worth of unacked ! 292: * data accumulated, this "slow start" keeps us from ! 293: * dumping all that data as back-to-back packets (which ! 294: * might overwhelm an intermediate gateway). ! 295: * ! 296: * There are two phases to the opening: Initially we ! 297: * open by one mss on each ack. This makes the window ! 298: * size increase exponentially with time. If the ! 299: * window is larger than the path can handle, this ! 300: * exponential growth results in dropped packet(s) ! 301: * almost immediately. To get more time between ! 302: * drops but still "push" the network to take advantage ! 303: * of improving conditions, we switch from exponential ! 304: * to linear window opening at some threshhold size. ! 305: * For a threshhold, we use half the current window ! 306: * size, truncated to a multiple of the mss. ! 307: * ! 308: * (the minimum cwnd that will give us exponential ! 309: * growth is 2 mss. We don't allow the threshhold ! 310: * to go below this.) ! 311: */ ! 312: { ! 313: u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; ! 314: if (win < 2) ! 315: win = 2; ! 316: tp->snd_cwnd = tp->t_maxseg; ! 317: tp->snd_ssthresh = win * tp->t_maxseg; ! 318: tp->t_dupacks = 0; ! 319: } ! 320: (void) tcp_output(tp); ! 321: break; ! 322: ! 323: /* ! 324: * Persistance timer into zero window. ! 325: * Force a byte to be output, if possible. ! 326: */ ! 327: case TCPT_PERSIST: ! 328: tcpstat.tcps_persisttimeo++; ! 329: /* ! 330: * Hack: if the peer is dead/unreachable, we do not ! 331: * time out if the window is closed. After a full ! 332: * backoff, drop the connection if the idle time ! 333: * (no responses to probes) reaches the maximum ! 334: * backoff that we would use if retransmitting. ! 335: */ ! 336: if (tp->t_rxtshift == TCP_MAXRXTSHIFT && ! 337: (tp->t_idle >= tcp_maxpersistidle || ! 338: tp->t_idle >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { ! 339: tcpstat.tcps_persistdrop++; ! 340: so_tmp = tp->t_inpcb->inp_socket; ! 341: tp = tcp_drop(tp, ETIMEDOUT); ! 342: postevent(so_tmp, 0, EV_TIMEOUT); ! 343: break; ! 344: } ! 345: tcp_setpersist(tp); ! 346: tp->t_force = 1; ! 347: (void) tcp_output(tp); ! 348: tp->t_force = 0; ! 349: break; ! 350: ! 351: /* ! 352: * Keep-alive timer went off; send something ! 353: * or drop connection if idle for too long. ! 354: */ ! 355: case TCPT_KEEP: ! 356: tcpstat.tcps_keeptimeo++; ! 357: if (tp->t_state < TCPS_ESTABLISHED) ! 358: goto dropit; ! 359: if ((always_keepalive || ! 360: tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) && ! 361: tp->t_state <= TCPS_CLOSING) { ! 362: if (tp->t_idle >= tcp_keepidle + tcp_maxidle) ! 363: goto dropit; ! 364: /* ! 365: * Send a packet designed to force a response ! 366: * if the peer is up and reachable: ! 367: * either an ACK if the connection is still alive, ! 368: * or an RST if the peer has closed the connection ! 369: * due to timeout or reboot. ! 370: * Using sequence number tp->snd_una-1 ! 371: * causes the transmitted zero-length segment ! 372: * to lie outside the receive window; ! 373: * by the protocol spec, this requires the ! 374: * correspondent TCP to respond. ! 375: */ ! 376: tcpstat.tcps_keepprobe++; ! 377: #if TCP_COMPAT_42 ! 378: /* ! 379: * The keepalive packet must have nonzero length ! 380: * to get a 4.2 host to respond. ! 381: */ ! 382: tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, ! 383: tp->rcv_nxt - 1, tp->snd_una - 1, 0); ! 384: #else ! 385: tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, ! 386: tp->rcv_nxt, tp->snd_una - 1, 0); ! 387: #endif ! 388: tp->t_timer[TCPT_KEEP] = tcp_keepintvl; ! 389: } else ! 390: tp->t_timer[TCPT_KEEP] = tcp_keepidle; ! 391: break; ! 392: dropit: ! 393: tcpstat.tcps_keepdrops++; ! 394: so_tmp = tp->t_inpcb->inp_socket; ! 395: tp = tcp_drop(tp, ETIMEDOUT); ! 396: postevent(so_tmp, 0, EV_TIMEOUT); ! 397: break; ! 398: } ! 399: return (tp); ! 400: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.