1df8bae1dSRodney W. Grimes /* 2e79adb8eSGarrett Wollman * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33e79adb8eSGarrett Wollman * @(#)tcp_timer.c 8.2 (Berkeley) 5/24/95 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 3792252381SEivind Eklund #include "opt_compat.h" 380cc12cc5SJoerg Wunsch #include "opt_tcpdebug.h" 390cc12cc5SJoerg Wunsch 40df8bae1dSRodney W. Grimes #include <sys/param.h> 41df8bae1dSRodney W. Grimes #include <sys/systm.h> 4298163b98SPoul-Henning Kamp #include <sys/kernel.h> 4398163b98SPoul-Henning Kamp #include <sys/sysctl.h> 44df8bae1dSRodney W. Grimes #include <sys/socket.h> 45df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 46df8bae1dSRodney W. Grimes #include <sys/protosw.h> 47df8bae1dSRodney W. Grimes 48e79adb8eSGarrett Wollman #include <machine/cpu.h> /* before tcp_seq.h, for tcp_random18() */ 49e79adb8eSGarrett Wollman 50df8bae1dSRodney W. Grimes #include <net/route.h> 51df8bae1dSRodney W. Grimes 52df8bae1dSRodney W. Grimes #include <netinet/in.h> 53df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 54df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 55df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 56df8bae1dSRodney W. Grimes #include <netinet/tcp.h> 57df8bae1dSRodney W. Grimes #include <netinet/tcp_fsm.h> 58df8bae1dSRodney W. Grimes #include <netinet/tcp_seq.h> 59df8bae1dSRodney W. Grimes #include <netinet/tcp_timer.h> 60df8bae1dSRodney W. Grimes #include <netinet/tcp_var.h> 61df8bae1dSRodney W. Grimes #include <netinet/tcpip.h> 62af7a2999SDavid Greenman #ifdef TCPDEBUG 63af7a2999SDavid Greenman #include <netinet/tcp_debug.h> 64af7a2999SDavid Greenman #endif 65df8bae1dSRodney W. Grimes 669b8b58e0SJonathan Lemon int tcp_keepinit; 677b40aa32SPaul Traina SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, 687b40aa32SPaul Traina CTLFLAG_RW, &tcp_keepinit , 0, ""); 697b40aa32SPaul Traina 709b8b58e0SJonathan Lemon int tcp_keepidle; 7198163b98SPoul-Henning Kamp SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, 7298163b98SPoul-Henning Kamp CTLFLAG_RW, &tcp_keepidle , 0, ""); 7398163b98SPoul-Henning Kamp 749b8b58e0SJonathan Lemon int tcp_keepintvl; 7598163b98SPoul-Henning Kamp SYSCTL_INT(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, 7698163b98SPoul-Henning Kamp CTLFLAG_RW, &tcp_keepintvl , 0, ""); 7798163b98SPoul-Henning Kamp 789b8b58e0SJonathan Lemon int tcp_delacktime; 799b8b58e0SJonathan Lemon SYSCTL_INT(_net_inet_tcp, TCPCTL_DELACKTIME, delacktime, CTLFLAG_RW, 809b8b58e0SJonathan Lemon &tcp_delacktime, 0, "Time before a delayed ACK is sent"); 819b8b58e0SJonathan Lemon 829b8b58e0SJonathan Lemon int tcp_msl; 839b8b58e0SJonathan Lemon SYSCTL_INT(_net_inet_tcp, OID_AUTO, msl, CTLFLAG_RW, 849b8b58e0SJonathan Lemon &tcp_msl, 0, "Maximum segment lifetime"); 859b8b58e0SJonathan Lemon 8634be9bf3SPoul-Henning Kamp static int always_keepalive = 0; 873d177f46SBill Fumerola SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW, 883d177f46SBill Fumerola &always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections"); 8934be9bf3SPoul-Henning Kamp 900312fbe9SPoul-Henning Kamp static int tcp_keepcnt = TCPTV_KEEPCNT; 910312fbe9SPoul-Henning Kamp /* max idle probes */ 929b8b58e0SJonathan Lemon int tcp_maxpersistidle; 930312fbe9SPoul-Henning Kamp /* max idle time in persist */ 94df8bae1dSRodney W. Grimes int tcp_maxidle; 95e79adb8eSGarrett Wollman 96df8bae1dSRodney W. Grimes /* 97df8bae1dSRodney W. Grimes * Tcp protocol timeout routine called every 500 ms. 989b8b58e0SJonathan Lemon * Updates timestamps used for TCP 99df8bae1dSRodney W. Grimes * causes finite state machine actions if timers expire. 100df8bae1dSRodney W. Grimes */ 101df8bae1dSRodney W. Grimes void 102df8bae1dSRodney W. Grimes tcp_slowtimo() 103df8bae1dSRodney W. Grimes { 10415bd2b43SDavid Greenman int s; 10515bd2b43SDavid Greenman 10615bd2b43SDavid Greenman s = splnet(); 107df8bae1dSRodney W. Grimes 108e79adb8eSGarrett Wollman tcp_maxidle = tcp_keepcnt * tcp_keepintvl; 10915bd2b43SDavid Greenman 110df8bae1dSRodney W. Grimes tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ 111df8bae1dSRodney W. Grimes #ifdef TCP_COMPAT_42 112df8bae1dSRodney W. Grimes if ((int)tcp_iss < 0) 113e79adb8eSGarrett Wollman tcp_iss = TCP_ISSINCR; /* XXX */ 114df8bae1dSRodney W. Grimes #endif 115df8bae1dSRodney W. Grimes splx(s); 116df8bae1dSRodney W. Grimes } 117df8bae1dSRodney W. Grimes 118df8bae1dSRodney W. Grimes /* 119df8bae1dSRodney W. Grimes * Cancel all timers for TCP tp. 120df8bae1dSRodney W. Grimes */ 121df8bae1dSRodney W. Grimes void 122df8bae1dSRodney W. Grimes tcp_canceltimers(tp) 123df8bae1dSRodney W. Grimes struct tcpcb *tp; 124df8bae1dSRodney W. Grimes { 1259b8b58e0SJonathan Lemon callout_stop(tp->tt_2msl); 1269b8b58e0SJonathan Lemon callout_stop(tp->tt_persist); 1279b8b58e0SJonathan Lemon callout_stop(tp->tt_keep); 1289b8b58e0SJonathan Lemon callout_stop(tp->tt_rexmt); 129df8bae1dSRodney W. Grimes } 130df8bae1dSRodney W. Grimes 131df8bae1dSRodney W. Grimes int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 132df8bae1dSRodney W. Grimes { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 133df8bae1dSRodney W. Grimes 1340312fbe9SPoul-Henning Kamp static int tcp_totbackoff = 511; /* sum of tcp_backoff[] */ 135e79adb8eSGarrett Wollman 136df8bae1dSRodney W. Grimes /* 137df8bae1dSRodney W. Grimes * TCP timer processing. 138df8bae1dSRodney W. Grimes */ 1399b8b58e0SJonathan Lemon void 1409b8b58e0SJonathan Lemon tcp_timer_delack(xtp) 1419b8b58e0SJonathan Lemon void *xtp; 142df8bae1dSRodney W. Grimes { 1439b8b58e0SJonathan Lemon struct tcpcb *tp = xtp; 1449b8b58e0SJonathan Lemon int s; 145df8bae1dSRodney W. Grimes 1469b8b58e0SJonathan Lemon s = splnet(); 1479b8b58e0SJonathan Lemon if (callout_pending(tp->tt_delack)) { 1489b8b58e0SJonathan Lemon splx(s); 1499b8b58e0SJonathan Lemon return; 1509b8b58e0SJonathan Lemon } 1519b8b58e0SJonathan Lemon callout_deactivate(tp->tt_delack); 152df8bae1dSRodney W. Grimes 1539b8b58e0SJonathan Lemon tp->t_flags |= TF_ACKNOW; 1549b8b58e0SJonathan Lemon tcpstat.tcps_delack++; 1559b8b58e0SJonathan Lemon (void) tcp_output(tp); 1569b8b58e0SJonathan Lemon splx(s); 1579b8b58e0SJonathan Lemon } 1589b8b58e0SJonathan Lemon 1599b8b58e0SJonathan Lemon void 1609b8b58e0SJonathan Lemon tcp_timer_2msl(xtp) 1619b8b58e0SJonathan Lemon void *xtp; 1629b8b58e0SJonathan Lemon { 1639b8b58e0SJonathan Lemon struct tcpcb *tp = xtp; 1649b8b58e0SJonathan Lemon int s; 1659b8b58e0SJonathan Lemon #ifdef TCPDEBUG 1669b8b58e0SJonathan Lemon int ostate; 1679b8b58e0SJonathan Lemon 1689b8b58e0SJonathan Lemon ostate = tp->t_state; 1699b8b58e0SJonathan Lemon #endif 1709b8b58e0SJonathan Lemon s = splnet(); 1719b8b58e0SJonathan Lemon if (callout_pending(tp->tt_2msl)) { 1729b8b58e0SJonathan Lemon splx(s); 1739b8b58e0SJonathan Lemon return; 1749b8b58e0SJonathan Lemon } 1759b8b58e0SJonathan Lemon callout_deactivate(tp->tt_2msl); 176df8bae1dSRodney W. Grimes /* 177df8bae1dSRodney W. Grimes * 2 MSL timeout in shutdown went off. If we're closed but 178df8bae1dSRodney W. Grimes * still waiting for peer to close and connection has been idle 179df8bae1dSRodney W. Grimes * too long, or if 2MSL time is up from TIME_WAIT, delete connection 180df8bae1dSRodney W. Grimes * control block. Otherwise, check again in a bit. 181df8bae1dSRodney W. Grimes */ 182df8bae1dSRodney W. Grimes if (tp->t_state != TCPS_TIME_WAIT && 1839b8b58e0SJonathan Lemon (ticks - tp->t_rcvtime) <= tcp_maxidle) 1849b8b58e0SJonathan Lemon callout_reset(tp->tt_2msl, tcp_keepintvl, 1859b8b58e0SJonathan Lemon tcp_timer_2msl, tp); 186df8bae1dSRodney W. Grimes else 187df8bae1dSRodney W. Grimes tp = tcp_close(tp); 188df8bae1dSRodney W. Grimes 1899b8b58e0SJonathan Lemon #ifdef TCPDEBUG 1909b8b58e0SJonathan Lemon if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 1919b8b58e0SJonathan Lemon tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, 1929b8b58e0SJonathan Lemon PRU_SLOWTIMO); 1939b8b58e0SJonathan Lemon #endif 1949b8b58e0SJonathan Lemon splx(s); 1959b8b58e0SJonathan Lemon } 1969b8b58e0SJonathan Lemon 1979b8b58e0SJonathan Lemon void 1989b8b58e0SJonathan Lemon tcp_timer_keep(xtp) 1999b8b58e0SJonathan Lemon void *xtp; 2009b8b58e0SJonathan Lemon { 2019b8b58e0SJonathan Lemon struct tcpcb *tp = xtp; 2029b8b58e0SJonathan Lemon int s; 2039b8b58e0SJonathan Lemon #ifdef TCPDEBUG 2049b8b58e0SJonathan Lemon int ostate; 2059b8b58e0SJonathan Lemon 2069b8b58e0SJonathan Lemon ostate = tp->t_state; 2079b8b58e0SJonathan Lemon #endif 2089b8b58e0SJonathan Lemon s = splnet(); 2099b8b58e0SJonathan Lemon if (callout_pending(tp->tt_keep)) { 2109b8b58e0SJonathan Lemon splx(s); 2119b8b58e0SJonathan Lemon return; 2129b8b58e0SJonathan Lemon } 2139b8b58e0SJonathan Lemon callout_deactivate(tp->tt_keep); 2149b8b58e0SJonathan Lemon /* 2159b8b58e0SJonathan Lemon * Keep-alive timer went off; send something 2169b8b58e0SJonathan Lemon * or drop connection if idle for too long. 2179b8b58e0SJonathan Lemon */ 2189b8b58e0SJonathan Lemon tcpstat.tcps_keeptimeo++; 2199b8b58e0SJonathan Lemon if (tp->t_state < TCPS_ESTABLISHED) 2209b8b58e0SJonathan Lemon goto dropit; 2219b8b58e0SJonathan Lemon if ((always_keepalive || 2229b8b58e0SJonathan Lemon tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) && 2239b8b58e0SJonathan Lemon tp->t_state <= TCPS_CLOSING) { 2249b8b58e0SJonathan Lemon if ((ticks - tp->t_rcvtime) >= tcp_keepidle + tcp_maxidle) 2259b8b58e0SJonathan Lemon goto dropit; 2269b8b58e0SJonathan Lemon /* 2279b8b58e0SJonathan Lemon * Send a packet designed to force a response 2289b8b58e0SJonathan Lemon * if the peer is up and reachable: 2299b8b58e0SJonathan Lemon * either an ACK if the connection is still alive, 2309b8b58e0SJonathan Lemon * or an RST if the peer has closed the connection 2319b8b58e0SJonathan Lemon * due to timeout or reboot. 2329b8b58e0SJonathan Lemon * Using sequence number tp->snd_una-1 2339b8b58e0SJonathan Lemon * causes the transmitted zero-length segment 2349b8b58e0SJonathan Lemon * to lie outside the receive window; 2359b8b58e0SJonathan Lemon * by the protocol spec, this requires the 2369b8b58e0SJonathan Lemon * correspondent TCP to respond. 2379b8b58e0SJonathan Lemon */ 2389b8b58e0SJonathan Lemon tcpstat.tcps_keepprobe++; 2399b8b58e0SJonathan Lemon #ifdef TCP_COMPAT_42 2409b8b58e0SJonathan Lemon /* 2419b8b58e0SJonathan Lemon * The keepalive packet must have nonzero length 2429b8b58e0SJonathan Lemon * to get a 4.2 host to respond. 2439b8b58e0SJonathan Lemon */ 2449b8b58e0SJonathan Lemon tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, 2459b8b58e0SJonathan Lemon tp->rcv_nxt - 1, tp->snd_una - 1, 0); 2469b8b58e0SJonathan Lemon #else 2479b8b58e0SJonathan Lemon tcp_respond(tp, tp->t_template, (struct mbuf *)NULL, 2489b8b58e0SJonathan Lemon tp->rcv_nxt, tp->snd_una - 1, 0); 2499b8b58e0SJonathan Lemon #endif 2509b8b58e0SJonathan Lemon callout_reset(tp->tt_keep, tcp_keepintvl, tcp_timer_keep, tp); 2519b8b58e0SJonathan Lemon } else 2529b8b58e0SJonathan Lemon callout_reset(tp->tt_keep, tcp_keepidle, tcp_timer_keep, tp); 2539b8b58e0SJonathan Lemon 2549b8b58e0SJonathan Lemon #ifdef TCPDEBUG 2559b8b58e0SJonathan Lemon if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 2569b8b58e0SJonathan Lemon tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, 2579b8b58e0SJonathan Lemon PRU_SLOWTIMO); 2589b8b58e0SJonathan Lemon #endif 2599b8b58e0SJonathan Lemon splx(s); 2609b8b58e0SJonathan Lemon return; 2619b8b58e0SJonathan Lemon 2629b8b58e0SJonathan Lemon dropit: 2639b8b58e0SJonathan Lemon tcpstat.tcps_keepdrops++; 2649b8b58e0SJonathan Lemon tp = tcp_drop(tp, ETIMEDOUT); 2659b8b58e0SJonathan Lemon 2669b8b58e0SJonathan Lemon #ifdef TCPDEBUG 2679b8b58e0SJonathan Lemon if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 2689b8b58e0SJonathan Lemon tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, 2699b8b58e0SJonathan Lemon PRU_SLOWTIMO); 2709b8b58e0SJonathan Lemon #endif 2719b8b58e0SJonathan Lemon splx(s); 2729b8b58e0SJonathan Lemon } 2739b8b58e0SJonathan Lemon 2749b8b58e0SJonathan Lemon void 2759b8b58e0SJonathan Lemon tcp_timer_persist(xtp) 2769b8b58e0SJonathan Lemon void *xtp; 2779b8b58e0SJonathan Lemon { 2789b8b58e0SJonathan Lemon struct tcpcb *tp = xtp; 2799b8b58e0SJonathan Lemon int s; 2809b8b58e0SJonathan Lemon #ifdef TCPDEBUG 2819b8b58e0SJonathan Lemon int ostate; 2829b8b58e0SJonathan Lemon 2839b8b58e0SJonathan Lemon ostate = tp->t_state; 2849b8b58e0SJonathan Lemon #endif 2859b8b58e0SJonathan Lemon s = splnet(); 2869b8b58e0SJonathan Lemon if (callout_pending(tp->tt_persist)) { 2879b8b58e0SJonathan Lemon splx(s); 2889b8b58e0SJonathan Lemon return; 2899b8b58e0SJonathan Lemon } 2909b8b58e0SJonathan Lemon callout_deactivate(tp->tt_persist); 2919b8b58e0SJonathan Lemon /* 2929b8b58e0SJonathan Lemon * Persistance timer into zero window. 2939b8b58e0SJonathan Lemon * Force a byte to be output, if possible. 2949b8b58e0SJonathan Lemon */ 2959b8b58e0SJonathan Lemon tcpstat.tcps_persisttimeo++; 2969b8b58e0SJonathan Lemon /* 2979b8b58e0SJonathan Lemon * Hack: if the peer is dead/unreachable, we do not 2989b8b58e0SJonathan Lemon * time out if the window is closed. After a full 2999b8b58e0SJonathan Lemon * backoff, drop the connection if the idle time 3009b8b58e0SJonathan Lemon * (no responses to probes) reaches the maximum 3019b8b58e0SJonathan Lemon * backoff that we would use if retransmitting. 3029b8b58e0SJonathan Lemon */ 3039b8b58e0SJonathan Lemon if (tp->t_rxtshift == TCP_MAXRXTSHIFT && 3049b8b58e0SJonathan Lemon ((ticks - tp->t_rcvtime) >= tcp_maxpersistidle || 3059b8b58e0SJonathan Lemon (ticks - tp->t_rcvtime) >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { 3069b8b58e0SJonathan Lemon tcpstat.tcps_persistdrop++; 3079b8b58e0SJonathan Lemon tp = tcp_drop(tp, ETIMEDOUT); 3089b8b58e0SJonathan Lemon goto out; 3099b8b58e0SJonathan Lemon } 3109b8b58e0SJonathan Lemon tcp_setpersist(tp); 3119b8b58e0SJonathan Lemon tp->t_force = 1; 3129b8b58e0SJonathan Lemon (void) tcp_output(tp); 3139b8b58e0SJonathan Lemon tp->t_force = 0; 3149b8b58e0SJonathan Lemon 3159b8b58e0SJonathan Lemon out: 3169b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3179b8b58e0SJonathan Lemon if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 3189b8b58e0SJonathan Lemon tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, 3199b8b58e0SJonathan Lemon PRU_SLOWTIMO); 3209b8b58e0SJonathan Lemon #endif 3219b8b58e0SJonathan Lemon splx(s); 3229b8b58e0SJonathan Lemon } 3239b8b58e0SJonathan Lemon 3249b8b58e0SJonathan Lemon void 3259b8b58e0SJonathan Lemon tcp_timer_rexmt(xtp) 3269b8b58e0SJonathan Lemon void *xtp; 3279b8b58e0SJonathan Lemon { 3289b8b58e0SJonathan Lemon struct tcpcb *tp = xtp; 3299b8b58e0SJonathan Lemon int s; 3309b8b58e0SJonathan Lemon int rexmt; 3319b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3329b8b58e0SJonathan Lemon int ostate; 3339b8b58e0SJonathan Lemon 3349b8b58e0SJonathan Lemon ostate = tp->t_state; 3359b8b58e0SJonathan Lemon #endif 3369b8b58e0SJonathan Lemon s = splnet(); 3379b8b58e0SJonathan Lemon if (callout_pending(tp->tt_rexmt)) { 3389b8b58e0SJonathan Lemon splx(s); 3399b8b58e0SJonathan Lemon return; 3409b8b58e0SJonathan Lemon } 3419b8b58e0SJonathan Lemon callout_deactivate(tp->tt_rexmt); 342df8bae1dSRodney W. Grimes /* 343df8bae1dSRodney W. Grimes * Retransmission timer went off. Message has not 344df8bae1dSRodney W. Grimes * been acked within retransmit interval. Back off 345df8bae1dSRodney W. Grimes * to a longer retransmit interval and retransmit one segment. 346df8bae1dSRodney W. Grimes */ 347df8bae1dSRodney W. Grimes if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 348df8bae1dSRodney W. Grimes tp->t_rxtshift = TCP_MAXRXTSHIFT; 349df8bae1dSRodney W. Grimes tcpstat.tcps_timeoutdrop++; 350df8bae1dSRodney W. Grimes tp = tcp_drop(tp, tp->t_softerror ? 351df8bae1dSRodney W. Grimes tp->t_softerror : ETIMEDOUT); 3529b8b58e0SJonathan Lemon goto out; 3539b8b58e0SJonathan Lemon } 3549b8b58e0SJonathan Lemon if (tp->t_rxtshift == 1) { 3559b8b58e0SJonathan Lemon /* 3569b8b58e0SJonathan Lemon * first retransmit; record ssthresh and cwnd so they can 3579b8b58e0SJonathan Lemon * be recovered if this turns out to be a "bad" retransmit. 3589b8b58e0SJonathan Lemon * A retransmit is considered "bad" if an ACK for this 3599b8b58e0SJonathan Lemon * segment is received within RTT/2 interval; the assumption 3609b8b58e0SJonathan Lemon * here is that the ACK was already in flight. See 3619b8b58e0SJonathan Lemon * "On Estimating End-to-End Network Path Properties" by 3629b8b58e0SJonathan Lemon * Allman and Paxson for more details. 3639b8b58e0SJonathan Lemon */ 3649b8b58e0SJonathan Lemon tp->snd_cwnd_prev = tp->snd_cwnd; 3659b8b58e0SJonathan Lemon tp->snd_ssthresh_prev = tp->snd_ssthresh; 3669b8b58e0SJonathan Lemon tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); 367df8bae1dSRodney W. Grimes } 368df8bae1dSRodney W. Grimes tcpstat.tcps_rexmttimeo++; 369df8bae1dSRodney W. Grimes rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; 370df8bae1dSRodney W. Grimes TCPT_RANGESET(tp->t_rxtcur, rexmt, 371df8bae1dSRodney W. Grimes tp->t_rttmin, TCPTV_REXMTMAX); 372df8bae1dSRodney W. Grimes /* 373df8bae1dSRodney W. Grimes * If losing, let the lower level know and try for 374df8bae1dSRodney W. Grimes * a better route. Also, if we backed off this far, 375df8bae1dSRodney W. Grimes * our srtt estimate is probably bogus. Clobber it 376df8bae1dSRodney W. Grimes * so we'll take the next rtt measurement as our srtt; 377df8bae1dSRodney W. Grimes * move the current srtt into rttvar to keep the current 378df8bae1dSRodney W. Grimes * retransmit times until then. 379df8bae1dSRodney W. Grimes */ 380df8bae1dSRodney W. Grimes if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { 381df8bae1dSRodney W. Grimes in_losing(tp->t_inpcb); 382df8bae1dSRodney W. Grimes tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); 383df8bae1dSRodney W. Grimes tp->t_srtt = 0; 384df8bae1dSRodney W. Grimes } 385df8bae1dSRodney W. Grimes tp->snd_nxt = tp->snd_una; 386a0292f23SGarrett Wollman /* 38774b48c1dSAndras Olah * Force a segment to be sent. 38874b48c1dSAndras Olah */ 38974b48c1dSAndras Olah tp->t_flags |= TF_ACKNOW; 39074b48c1dSAndras Olah /* 391df8bae1dSRodney W. Grimes * If timing a segment in this window, stop the timer. 392df8bae1dSRodney W. Grimes */ 3939b8b58e0SJonathan Lemon tp->t_rtttime = 0; 394df8bae1dSRodney W. Grimes /* 395df8bae1dSRodney W. Grimes * Close the congestion window down to one segment 396df8bae1dSRodney W. Grimes * (we'll open it by one segment for each ack we get). 397df8bae1dSRodney W. Grimes * Since we probably have a window's worth of unacked 398df8bae1dSRodney W. Grimes * data accumulated, this "slow start" keeps us from 399df8bae1dSRodney W. Grimes * dumping all that data as back-to-back packets (which 400df8bae1dSRodney W. Grimes * might overwhelm an intermediate gateway). 401df8bae1dSRodney W. Grimes * 402df8bae1dSRodney W. Grimes * There are two phases to the opening: Initially we 403df8bae1dSRodney W. Grimes * open by one mss on each ack. This makes the window 404df8bae1dSRodney W. Grimes * size increase exponentially with time. If the 405df8bae1dSRodney W. Grimes * window is larger than the path can handle, this 406df8bae1dSRodney W. Grimes * exponential growth results in dropped packet(s) 407df8bae1dSRodney W. Grimes * almost immediately. To get more time between 408df8bae1dSRodney W. Grimes * drops but still "push" the network to take advantage 409df8bae1dSRodney W. Grimes * of improving conditions, we switch from exponential 410df8bae1dSRodney W. Grimes * to linear window opening at some threshhold size. 411df8bae1dSRodney W. Grimes * For a threshhold, we use half the current window 412df8bae1dSRodney W. Grimes * size, truncated to a multiple of the mss. 413df8bae1dSRodney W. Grimes * 414df8bae1dSRodney W. Grimes * (the minimum cwnd that will give us exponential 415df8bae1dSRodney W. Grimes * growth is 2 mss. We don't allow the threshhold 416df8bae1dSRodney W. Grimes * to go below this.) 417df8bae1dSRodney W. Grimes */ 418df8bae1dSRodney W. Grimes { 419df8bae1dSRodney W. Grimes u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; 420df8bae1dSRodney W. Grimes if (win < 2) 421df8bae1dSRodney W. Grimes win = 2; 422df8bae1dSRodney W. Grimes tp->snd_cwnd = tp->t_maxseg; 423df8bae1dSRodney W. Grimes tp->snd_ssthresh = win * tp->t_maxseg; 424df8bae1dSRodney W. Grimes tp->t_dupacks = 0; 425df8bae1dSRodney W. Grimes } 426df8bae1dSRodney W. Grimes (void) tcp_output(tp); 427df8bae1dSRodney W. Grimes 4289b8b58e0SJonathan Lemon out: 4299b8b58e0SJonathan Lemon #ifdef TCPDEBUG 4309b8b58e0SJonathan Lemon if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 4319b8b58e0SJonathan Lemon tcp_trace(TA_USER, ostate, tp, (struct tcpiphdr *)0, 4329b8b58e0SJonathan Lemon PRU_SLOWTIMO); 433df8bae1dSRodney W. Grimes #endif 4349b8b58e0SJonathan Lemon splx(s); 435df8bae1dSRodney W. Grimes } 436