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" 38fb59c426SYoshinobu Inoue #include "opt_inet6.h" 390cc12cc5SJoerg Wunsch #include "opt_tcpdebug.h" 400cc12cc5SJoerg Wunsch 41df8bae1dSRodney W. Grimes #include <sys/param.h> 424cc20ab1SSeigo Tanimura #include <sys/systm.h> 4398163b98SPoul-Henning Kamp #include <sys/kernel.h> 4408517d53SMike Silbersack #include <sys/mbuf.h> 454cc20ab1SSeigo Tanimura #include <sys/sysctl.h> 46df8bae1dSRodney W. Grimes #include <sys/socket.h> 47df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 484cc20ab1SSeigo Tanimura #include <sys/protosw.h> 49df8bae1dSRodney W. Grimes 50e79adb8eSGarrett Wollman #include <machine/cpu.h> /* before tcp_seq.h, for tcp_random18() */ 51e79adb8eSGarrett Wollman 52df8bae1dSRodney W. Grimes #include <net/route.h> 53df8bae1dSRodney W. Grimes 54df8bae1dSRodney W. Grimes #include <netinet/in.h> 55df8bae1dSRodney W. Grimes #include <netinet/in_systm.h> 56df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 57fb59c426SYoshinobu Inoue #ifdef INET6 58fb59c426SYoshinobu Inoue #include <netinet6/in6_pcb.h> 59fb59c426SYoshinobu Inoue #endif 60df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 61df8bae1dSRodney W. Grimes #include <netinet/tcp.h> 62df8bae1dSRodney W. Grimes #include <netinet/tcp_fsm.h> 63df8bae1dSRodney W. Grimes #include <netinet/tcp_seq.h> 64df8bae1dSRodney W. Grimes #include <netinet/tcp_timer.h> 65df8bae1dSRodney W. Grimes #include <netinet/tcp_var.h> 66df8bae1dSRodney W. Grimes #include <netinet/tcpip.h> 67af7a2999SDavid Greenman #ifdef TCPDEBUG 68af7a2999SDavid Greenman #include <netinet/tcp_debug.h> 69af7a2999SDavid Greenman #endif 70df8bae1dSRodney W. Grimes 71ccb4d0c6SJonathan Lemon static int 7282d9ae4eSPoul-Henning Kamp sysctl_msec_to_ticks(SYSCTL_HANDLER_ARGS) 73ccb4d0c6SJonathan Lemon { 74ccb4d0c6SJonathan Lemon int error, s, tt; 75ccb4d0c6SJonathan Lemon 76ccb4d0c6SJonathan Lemon tt = *(int *)oidp->oid_arg1; 77ccb4d0c6SJonathan Lemon s = tt * 1000 / hz; 78ccb4d0c6SJonathan Lemon 799fc2bcf6SJonathan Lemon error = sysctl_handle_int(oidp, &s, 0, req); 80ccb4d0c6SJonathan Lemon if (error || !req->newptr) 81ccb4d0c6SJonathan Lemon return (error); 82ccb4d0c6SJonathan Lemon 83ccb4d0c6SJonathan Lemon tt = s * hz / 1000; 849fc2bcf6SJonathan Lemon if (tt < 1) 859fc2bcf6SJonathan Lemon return (EINVAL); 86ccb4d0c6SJonathan Lemon 87ccb4d0c6SJonathan Lemon *(int *)oidp->oid_arg1 = tt; 88ccb4d0c6SJonathan Lemon return (0); 89ccb4d0c6SJonathan Lemon } 90ccb4d0c6SJonathan Lemon 919b8b58e0SJonathan Lemon int tcp_keepinit; 92ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, CTLTYPE_INT|CTLFLAG_RW, 93ccb4d0c6SJonathan Lemon &tcp_keepinit, 0, sysctl_msec_to_ticks, "I", ""); 947b40aa32SPaul Traina 959b8b58e0SJonathan Lemon int tcp_keepidle; 96ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, CTLTYPE_INT|CTLFLAG_RW, 97ccb4d0c6SJonathan Lemon &tcp_keepidle, 0, sysctl_msec_to_ticks, "I", ""); 9898163b98SPoul-Henning Kamp 999b8b58e0SJonathan Lemon int tcp_keepintvl; 100ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, CTLTYPE_INT|CTLFLAG_RW, 101ccb4d0c6SJonathan Lemon &tcp_keepintvl, 0, sysctl_msec_to_ticks, "I", ""); 10298163b98SPoul-Henning Kamp 1039b8b58e0SJonathan Lemon int tcp_delacktime; 104ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_DELACKTIME, delacktime, 105ccb4d0c6SJonathan Lemon CTLTYPE_INT|CTLFLAG_RW, &tcp_delacktime, 0, sysctl_msec_to_ticks, "I", 106ccb4d0c6SJonathan Lemon "Time before a delayed ACK is sent"); 1079b8b58e0SJonathan Lemon 1089b8b58e0SJonathan Lemon int tcp_msl; 109ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl, CTLTYPE_INT|CTLFLAG_RW, 110ccb4d0c6SJonathan Lemon &tcp_msl, 0, sysctl_msec_to_ticks, "I", "Maximum segment lifetime"); 1119b8b58e0SJonathan Lemon 112701bec5aSMatthew Dillon int tcp_rexmit_min; 113701bec5aSMatthew Dillon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_min, CTLTYPE_INT|CTLFLAG_RW, 114701bec5aSMatthew Dillon &tcp_rexmit_min, 0, sysctl_msec_to_ticks, "I", "Minimum Retransmission Timeout"); 115701bec5aSMatthew Dillon 116701bec5aSMatthew Dillon int tcp_rexmit_slop; 117701bec5aSMatthew Dillon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_slop, CTLTYPE_INT|CTLFLAG_RW, 118701bec5aSMatthew Dillon &tcp_rexmit_slop, 0, sysctl_msec_to_ticks, "I", "Retransmission Timer Slop"); 119701bec5aSMatthew Dillon 120c39a614eSRobert Watson static int always_keepalive = 1; 1213d177f46SBill Fumerola SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW, 1223d177f46SBill Fumerola &always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections"); 12334be9bf3SPoul-Henning Kamp 1240312fbe9SPoul-Henning Kamp static int tcp_keepcnt = TCPTV_KEEPCNT; 1250312fbe9SPoul-Henning Kamp /* max idle probes */ 1269b8b58e0SJonathan Lemon int tcp_maxpersistidle; 1270312fbe9SPoul-Henning Kamp /* max idle time in persist */ 128df8bae1dSRodney W. Grimes int tcp_maxidle; 129e79adb8eSGarrett Wollman 130df8bae1dSRodney W. Grimes /* 131df8bae1dSRodney W. Grimes * Tcp protocol timeout routine called every 500 ms. 1329b8b58e0SJonathan Lemon * Updates timestamps used for TCP 133df8bae1dSRodney W. Grimes * causes finite state machine actions if timers expire. 134df8bae1dSRodney W. Grimes */ 135df8bae1dSRodney W. Grimes void 136df8bae1dSRodney W. Grimes tcp_slowtimo() 137df8bae1dSRodney W. Grimes { 13815bd2b43SDavid Greenman int s; 13915bd2b43SDavid Greenman 14015bd2b43SDavid Greenman s = splnet(); 141df8bae1dSRodney W. Grimes 142e79adb8eSGarrett Wollman tcp_maxidle = tcp_keepcnt * tcp_keepintvl; 14315bd2b43SDavid Greenman 144df8bae1dSRodney W. Grimes splx(s); 145df8bae1dSRodney W. Grimes } 146df8bae1dSRodney W. Grimes 147df8bae1dSRodney W. Grimes /* 148df8bae1dSRodney W. Grimes * Cancel all timers for TCP tp. 149df8bae1dSRodney W. Grimes */ 150df8bae1dSRodney W. Grimes void 151df8bae1dSRodney W. Grimes tcp_canceltimers(tp) 152df8bae1dSRodney W. Grimes struct tcpcb *tp; 153df8bae1dSRodney W. Grimes { 1549b8b58e0SJonathan Lemon callout_stop(tp->tt_2msl); 1559b8b58e0SJonathan Lemon callout_stop(tp->tt_persist); 1569b8b58e0SJonathan Lemon callout_stop(tp->tt_keep); 1579b8b58e0SJonathan Lemon callout_stop(tp->tt_rexmt); 158df8bae1dSRodney W. Grimes } 159df8bae1dSRodney W. Grimes 1607d42e30cSJonathan Lemon int tcp_syn_backoff[TCP_MAXRXTSHIFT + 1] = 1617d42e30cSJonathan Lemon { 1, 1, 1, 1, 1, 2, 4, 8, 16, 32, 64, 64, 64 }; 1627d42e30cSJonathan Lemon 163df8bae1dSRodney W. Grimes int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 164df8bae1dSRodney W. Grimes { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; 165df8bae1dSRodney W. Grimes 1660312fbe9SPoul-Henning Kamp static int tcp_totbackoff = 511; /* sum of tcp_backoff[] */ 167e79adb8eSGarrett Wollman 168df8bae1dSRodney W. Grimes /* 169df8bae1dSRodney W. Grimes * TCP timer processing. 170df8bae1dSRodney W. Grimes */ 171f76fcf6dSJeffrey Hsu 1729b8b58e0SJonathan Lemon void 1739b8b58e0SJonathan Lemon tcp_timer_delack(xtp) 1749b8b58e0SJonathan Lemon void *xtp; 175df8bae1dSRodney W. Grimes { 1769b8b58e0SJonathan Lemon struct tcpcb *tp = xtp; 1779b8b58e0SJonathan Lemon int s; 178f76fcf6dSJeffrey Hsu struct inpcb *inp; 179df8bae1dSRodney W. Grimes 1809b8b58e0SJonathan Lemon s = splnet(); 181f76fcf6dSJeffrey Hsu INP_INFO_RLOCK(&tcbinfo); 182f76fcf6dSJeffrey Hsu inp = tp->t_inpcb; 183f76fcf6dSJeffrey Hsu INP_LOCK(inp); 184f76fcf6dSJeffrey Hsu INP_INFO_RUNLOCK(&tcbinfo); 185af1270f8SJonathan Lemon if (callout_pending(tp->tt_delack) || !callout_active(tp->tt_delack)) { 186f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 1879b8b58e0SJonathan Lemon splx(s); 1889b8b58e0SJonathan Lemon return; 1899b8b58e0SJonathan Lemon } 1909b8b58e0SJonathan Lemon callout_deactivate(tp->tt_delack); 191df8bae1dSRodney W. Grimes 1929b8b58e0SJonathan Lemon tp->t_flags |= TF_ACKNOW; 1939b8b58e0SJonathan Lemon tcpstat.tcps_delack++; 1949b8b58e0SJonathan Lemon (void) tcp_output(tp); 195f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 1969b8b58e0SJonathan Lemon splx(s); 1979b8b58e0SJonathan Lemon } 1989b8b58e0SJonathan Lemon 1999b8b58e0SJonathan Lemon void 2009b8b58e0SJonathan Lemon tcp_timer_2msl(xtp) 2019b8b58e0SJonathan Lemon void *xtp; 2029b8b58e0SJonathan Lemon { 2039b8b58e0SJonathan Lemon struct tcpcb *tp = xtp; 2049b8b58e0SJonathan Lemon int s; 205f76fcf6dSJeffrey Hsu struct inpcb *inp; 2069b8b58e0SJonathan Lemon #ifdef TCPDEBUG 2079b8b58e0SJonathan Lemon int ostate; 2089b8b58e0SJonathan Lemon 2099b8b58e0SJonathan Lemon ostate = tp->t_state; 2109b8b58e0SJonathan Lemon #endif 2119b8b58e0SJonathan Lemon s = splnet(); 212f76fcf6dSJeffrey Hsu INP_INFO_WLOCK(&tcbinfo); 213f76fcf6dSJeffrey Hsu inp = tp->t_inpcb; 214f76fcf6dSJeffrey Hsu INP_LOCK(inp); 215af1270f8SJonathan Lemon if (callout_pending(tp->tt_2msl) || !callout_active(tp->tt_2msl)) { 216f76fcf6dSJeffrey Hsu INP_UNLOCK(tp->t_inpcb); 217f76fcf6dSJeffrey Hsu INP_INFO_WUNLOCK(&tcbinfo); 2189b8b58e0SJonathan Lemon splx(s); 2199b8b58e0SJonathan Lemon return; 2209b8b58e0SJonathan Lemon } 2219b8b58e0SJonathan Lemon callout_deactivate(tp->tt_2msl); 222df8bae1dSRodney W. Grimes /* 223df8bae1dSRodney W. Grimes * 2 MSL timeout in shutdown went off. If we're closed but 224df8bae1dSRodney W. Grimes * still waiting for peer to close and connection has been idle 225df8bae1dSRodney W. Grimes * too long, or if 2MSL time is up from TIME_WAIT, delete connection 226df8bae1dSRodney W. Grimes * control block. Otherwise, check again in a bit. 227df8bae1dSRodney W. Grimes */ 228df8bae1dSRodney W. Grimes if (tp->t_state != TCPS_TIME_WAIT && 2299b8b58e0SJonathan Lemon (ticks - tp->t_rcvtime) <= tcp_maxidle) 2309b8b58e0SJonathan Lemon callout_reset(tp->tt_2msl, tcp_keepintvl, 2319b8b58e0SJonathan Lemon tcp_timer_2msl, tp); 232df8bae1dSRodney W. Grimes else 233df8bae1dSRodney W. Grimes tp = tcp_close(tp); 234df8bae1dSRodney W. Grimes 2359b8b58e0SJonathan Lemon #ifdef TCPDEBUG 2364cc20ab1SSeigo Tanimura if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 237fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 2389b8b58e0SJonathan Lemon PRU_SLOWTIMO); 2399b8b58e0SJonathan Lemon #endif 240f76fcf6dSJeffrey Hsu if (tp) 241f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 242f76fcf6dSJeffrey Hsu INP_INFO_WUNLOCK(&tcbinfo); 2439b8b58e0SJonathan Lemon splx(s); 2449b8b58e0SJonathan Lemon } 2459b8b58e0SJonathan Lemon 2469b8b58e0SJonathan Lemon void 2479b8b58e0SJonathan Lemon tcp_timer_keep(xtp) 2489b8b58e0SJonathan Lemon void *xtp; 2499b8b58e0SJonathan Lemon { 2509b8b58e0SJonathan Lemon struct tcpcb *tp = xtp; 25108517d53SMike Silbersack struct tcptemp *t_template; 2529b8b58e0SJonathan Lemon int s; 253f76fcf6dSJeffrey Hsu struct inpcb *inp; 2549b8b58e0SJonathan Lemon #ifdef TCPDEBUG 2559b8b58e0SJonathan Lemon int ostate; 2569b8b58e0SJonathan Lemon 2579b8b58e0SJonathan Lemon ostate = tp->t_state; 2589b8b58e0SJonathan Lemon #endif 2599b8b58e0SJonathan Lemon s = splnet(); 260f76fcf6dSJeffrey Hsu INP_INFO_WLOCK(&tcbinfo); 261f76fcf6dSJeffrey Hsu inp = tp->t_inpcb; 262f76fcf6dSJeffrey Hsu INP_LOCK(inp); 263af1270f8SJonathan Lemon if (callout_pending(tp->tt_keep) || !callout_active(tp->tt_keep)) { 264f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 265f76fcf6dSJeffrey Hsu INP_INFO_WUNLOCK(&tcbinfo); 2669b8b58e0SJonathan Lemon splx(s); 2679b8b58e0SJonathan Lemon return; 2689b8b58e0SJonathan Lemon } 2699b8b58e0SJonathan Lemon callout_deactivate(tp->tt_keep); 2709b8b58e0SJonathan Lemon /* 2719b8b58e0SJonathan Lemon * Keep-alive timer went off; send something 2729b8b58e0SJonathan Lemon * or drop connection if idle for too long. 2739b8b58e0SJonathan Lemon */ 2749b8b58e0SJonathan Lemon tcpstat.tcps_keeptimeo++; 2759b8b58e0SJonathan Lemon if (tp->t_state < TCPS_ESTABLISHED) 2769b8b58e0SJonathan Lemon goto dropit; 2779b8b58e0SJonathan Lemon if ((always_keepalive || 2789b8b58e0SJonathan Lemon tp->t_inpcb->inp_socket->so_options & SO_KEEPALIVE) && 2799b8b58e0SJonathan Lemon tp->t_state <= TCPS_CLOSING) { 2809b8b58e0SJonathan Lemon if ((ticks - tp->t_rcvtime) >= tcp_keepidle + tcp_maxidle) 2819b8b58e0SJonathan Lemon goto dropit; 2829b8b58e0SJonathan Lemon /* 2839b8b58e0SJonathan Lemon * Send a packet designed to force a response 2849b8b58e0SJonathan Lemon * if the peer is up and reachable: 2859b8b58e0SJonathan Lemon * either an ACK if the connection is still alive, 2869b8b58e0SJonathan Lemon * or an RST if the peer has closed the connection 2879b8b58e0SJonathan Lemon * due to timeout or reboot. 2889b8b58e0SJonathan Lemon * Using sequence number tp->snd_una-1 2899b8b58e0SJonathan Lemon * causes the transmitted zero-length segment 2909b8b58e0SJonathan Lemon * to lie outside the receive window; 2919b8b58e0SJonathan Lemon * by the protocol spec, this requires the 2929b8b58e0SJonathan Lemon * correspondent TCP to respond. 2939b8b58e0SJonathan Lemon */ 2949b8b58e0SJonathan Lemon tcpstat.tcps_keepprobe++; 29508517d53SMike Silbersack t_template = tcp_maketemplate(tp); 29608517d53SMike Silbersack if (t_template) { 29708517d53SMike Silbersack tcp_respond(tp, t_template->tt_ipgen, 29808517d53SMike Silbersack &t_template->tt_t, (struct mbuf *)NULL, 2999b8b58e0SJonathan Lemon tp->rcv_nxt, tp->snd_una - 1, 0); 30008517d53SMike Silbersack (void) m_free(dtom(t_template)); 30108517d53SMike Silbersack } 3029b8b58e0SJonathan Lemon callout_reset(tp->tt_keep, tcp_keepintvl, tcp_timer_keep, tp); 3034cc20ab1SSeigo Tanimura } else 3049b8b58e0SJonathan Lemon callout_reset(tp->tt_keep, tcp_keepidle, tcp_timer_keep, tp); 3059b8b58e0SJonathan Lemon 3069b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3074cc20ab1SSeigo Tanimura if (tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 308fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 3099b8b58e0SJonathan Lemon PRU_SLOWTIMO); 3109b8b58e0SJonathan Lemon #endif 311f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 312f76fcf6dSJeffrey Hsu INP_INFO_WUNLOCK(&tcbinfo); 3139b8b58e0SJonathan Lemon splx(s); 3149b8b58e0SJonathan Lemon return; 3159b8b58e0SJonathan Lemon 3169b8b58e0SJonathan Lemon dropit: 3179b8b58e0SJonathan Lemon tcpstat.tcps_keepdrops++; 3189b8b58e0SJonathan Lemon tp = tcp_drop(tp, ETIMEDOUT); 3199b8b58e0SJonathan Lemon 3209b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3214cc20ab1SSeigo Tanimura if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 322fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 3239b8b58e0SJonathan Lemon PRU_SLOWTIMO); 3249b8b58e0SJonathan Lemon #endif 325f76fcf6dSJeffrey Hsu if (tp) 326f76fcf6dSJeffrey Hsu INP_UNLOCK(tp->t_inpcb); 327f76fcf6dSJeffrey Hsu INP_INFO_WUNLOCK(&tcbinfo); 3289b8b58e0SJonathan Lemon splx(s); 3299b8b58e0SJonathan Lemon } 3309b8b58e0SJonathan Lemon 3319b8b58e0SJonathan Lemon void 3329b8b58e0SJonathan Lemon tcp_timer_persist(xtp) 3339b8b58e0SJonathan Lemon void *xtp; 3349b8b58e0SJonathan Lemon { 3359b8b58e0SJonathan Lemon struct tcpcb *tp = xtp; 3369b8b58e0SJonathan Lemon int s; 337f76fcf6dSJeffrey Hsu struct inpcb *inp; 3389b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3399b8b58e0SJonathan Lemon int ostate; 3409b8b58e0SJonathan Lemon 3419b8b58e0SJonathan Lemon ostate = tp->t_state; 3429b8b58e0SJonathan Lemon #endif 3439b8b58e0SJonathan Lemon s = splnet(); 344f76fcf6dSJeffrey Hsu INP_INFO_WLOCK(&tcbinfo); 345f76fcf6dSJeffrey Hsu inp = tp->t_inpcb; 346f76fcf6dSJeffrey Hsu INP_LOCK(inp); 347af1270f8SJonathan Lemon if (callout_pending(tp->tt_persist) || !callout_active(tp->tt_persist)){ 348f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 349f76fcf6dSJeffrey Hsu INP_INFO_WUNLOCK(&tcbinfo); 3509b8b58e0SJonathan Lemon splx(s); 3519b8b58e0SJonathan Lemon return; 3529b8b58e0SJonathan Lemon } 3539b8b58e0SJonathan Lemon callout_deactivate(tp->tt_persist); 3549b8b58e0SJonathan Lemon /* 3559b8b58e0SJonathan Lemon * Persistance timer into zero window. 3569b8b58e0SJonathan Lemon * Force a byte to be output, if possible. 3579b8b58e0SJonathan Lemon */ 3589b8b58e0SJonathan Lemon tcpstat.tcps_persisttimeo++; 3599b8b58e0SJonathan Lemon /* 3609b8b58e0SJonathan Lemon * Hack: if the peer is dead/unreachable, we do not 3619b8b58e0SJonathan Lemon * time out if the window is closed. After a full 3629b8b58e0SJonathan Lemon * backoff, drop the connection if the idle time 3639b8b58e0SJonathan Lemon * (no responses to probes) reaches the maximum 3649b8b58e0SJonathan Lemon * backoff that we would use if retransmitting. 3659b8b58e0SJonathan Lemon */ 3669b8b58e0SJonathan Lemon if (tp->t_rxtshift == TCP_MAXRXTSHIFT && 3679b8b58e0SJonathan Lemon ((ticks - tp->t_rcvtime) >= tcp_maxpersistidle || 3689b8b58e0SJonathan Lemon (ticks - tp->t_rcvtime) >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { 3699b8b58e0SJonathan Lemon tcpstat.tcps_persistdrop++; 3709b8b58e0SJonathan Lemon tp = tcp_drop(tp, ETIMEDOUT); 3719b8b58e0SJonathan Lemon goto out; 3729b8b58e0SJonathan Lemon } 3739b8b58e0SJonathan Lemon tcp_setpersist(tp); 3749b8b58e0SJonathan Lemon tp->t_force = 1; 3759b8b58e0SJonathan Lemon (void) tcp_output(tp); 3769b8b58e0SJonathan Lemon tp->t_force = 0; 3779b8b58e0SJonathan Lemon 3789b8b58e0SJonathan Lemon out: 3799b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3804cc20ab1SSeigo Tanimura if (tp && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 381fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 3829b8b58e0SJonathan Lemon PRU_SLOWTIMO); 3839b8b58e0SJonathan Lemon #endif 384f76fcf6dSJeffrey Hsu if (tp) 385f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 386f76fcf6dSJeffrey Hsu INP_INFO_WUNLOCK(&tcbinfo); 3879b8b58e0SJonathan Lemon splx(s); 3889b8b58e0SJonathan Lemon } 3899b8b58e0SJonathan Lemon 3909b8b58e0SJonathan Lemon void 3919b8b58e0SJonathan Lemon tcp_timer_rexmt(xtp) 3929b8b58e0SJonathan Lemon void *xtp; 3939b8b58e0SJonathan Lemon { 3949b8b58e0SJonathan Lemon struct tcpcb *tp = xtp; 3959b8b58e0SJonathan Lemon int s; 3969b8b58e0SJonathan Lemon int rexmt; 397f76fcf6dSJeffrey Hsu int headlocked; 398f76fcf6dSJeffrey Hsu struct inpcb *inp; 3999b8b58e0SJonathan Lemon #ifdef TCPDEBUG 4009b8b58e0SJonathan Lemon int ostate; 4019b8b58e0SJonathan Lemon 4029b8b58e0SJonathan Lemon ostate = tp->t_state; 4039b8b58e0SJonathan Lemon #endif 4049b8b58e0SJonathan Lemon s = splnet(); 405f76fcf6dSJeffrey Hsu INP_INFO_WLOCK(&tcbinfo); 406f76fcf6dSJeffrey Hsu headlocked = 1; 407f76fcf6dSJeffrey Hsu inp = tp->t_inpcb; 408f76fcf6dSJeffrey Hsu INP_LOCK(inp); 409af1270f8SJonathan Lemon if (callout_pending(tp->tt_rexmt) || !callout_active(tp->tt_rexmt)) { 410f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 411f76fcf6dSJeffrey Hsu INP_INFO_WUNLOCK(&tcbinfo); 4129b8b58e0SJonathan Lemon splx(s); 4139b8b58e0SJonathan Lemon return; 4149b8b58e0SJonathan Lemon } 4159b8b58e0SJonathan Lemon callout_deactivate(tp->tt_rexmt); 416df8bae1dSRodney W. Grimes /* 417df8bae1dSRodney W. Grimes * Retransmission timer went off. Message has not 418df8bae1dSRodney W. Grimes * been acked within retransmit interval. Back off 419df8bae1dSRodney W. Grimes * to a longer retransmit interval and retransmit one segment. 420df8bae1dSRodney W. Grimes */ 421df8bae1dSRodney W. Grimes if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 422df8bae1dSRodney W. Grimes tp->t_rxtshift = TCP_MAXRXTSHIFT; 423df8bae1dSRodney W. Grimes tcpstat.tcps_timeoutdrop++; 424df8bae1dSRodney W. Grimes tp = tcp_drop(tp, tp->t_softerror ? 425df8bae1dSRodney W. Grimes tp->t_softerror : ETIMEDOUT); 4269b8b58e0SJonathan Lemon goto out; 4279b8b58e0SJonathan Lemon } 428f76fcf6dSJeffrey Hsu INP_INFO_WUNLOCK(&tcbinfo); 429f76fcf6dSJeffrey Hsu headlocked = 0; 4309b8b58e0SJonathan Lemon if (tp->t_rxtshift == 1) { 4319b8b58e0SJonathan Lemon /* 4329b8b58e0SJonathan Lemon * first retransmit; record ssthresh and cwnd so they can 4339b8b58e0SJonathan Lemon * be recovered if this turns out to be a "bad" retransmit. 4349b8b58e0SJonathan Lemon * A retransmit is considered "bad" if an ACK for this 4359b8b58e0SJonathan Lemon * segment is received within RTT/2 interval; the assumption 4369b8b58e0SJonathan Lemon * here is that the ACK was already in flight. See 4379b8b58e0SJonathan Lemon * "On Estimating End-to-End Network Path Properties" by 4389b8b58e0SJonathan Lemon * Allman and Paxson for more details. 4399b8b58e0SJonathan Lemon */ 4409b8b58e0SJonathan Lemon tp->snd_cwnd_prev = tp->snd_cwnd; 4419b8b58e0SJonathan Lemon tp->snd_ssthresh_prev = tp->snd_ssthresh; 4429b8b58e0SJonathan Lemon tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); 443df8bae1dSRodney W. Grimes } 444df8bae1dSRodney W. Grimes tcpstat.tcps_rexmttimeo++; 4457d42e30cSJonathan Lemon if (tp->t_state == TCPS_SYN_SENT) 4467d42e30cSJonathan Lemon rexmt = TCP_REXMTVAL(tp) * tcp_syn_backoff[tp->t_rxtshift]; 4477d42e30cSJonathan Lemon else 448df8bae1dSRodney W. Grimes rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; 449df8bae1dSRodney W. Grimes TCPT_RANGESET(tp->t_rxtcur, rexmt, 450df8bae1dSRodney W. Grimes tp->t_rttmin, TCPTV_REXMTMAX); 451df8bae1dSRodney W. Grimes /* 4527ceb7783SJesper Skriver * Disable rfc1323 and rfc1644 if we havn't got any response to 4537ceb7783SJesper Skriver * our third SYN to work-around some broken terminal servers 4547ceb7783SJesper Skriver * (most of which have hopefully been retired) that have bad VJ 4557ceb7783SJesper Skriver * header compression code which trashes TCP segments containing 4567ceb7783SJesper Skriver * unknown-to-them TCP options. 4577ceb7783SJesper Skriver */ 4587ceb7783SJesper Skriver if ((tp->t_state == TCPS_SYN_SENT) && (tp->t_rxtshift == 3)) 4597ceb7783SJesper Skriver tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_REQ_CC); 4607ceb7783SJesper Skriver /* 461df8bae1dSRodney W. Grimes * If losing, let the lower level know and try for 462df8bae1dSRodney W. Grimes * a better route. Also, if we backed off this far, 463df8bae1dSRodney W. Grimes * our srtt estimate is probably bogus. Clobber it 464df8bae1dSRodney W. Grimes * so we'll take the next rtt measurement as our srtt; 465df8bae1dSRodney W. Grimes * move the current srtt into rttvar to keep the current 466df8bae1dSRodney W. Grimes * retransmit times until then. 467df8bae1dSRodney W. Grimes */ 468df8bae1dSRodney W. Grimes if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { 469fb59c426SYoshinobu Inoue #ifdef INET6 470fb59c426SYoshinobu Inoue if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) 471fb59c426SYoshinobu Inoue in6_losing(tp->t_inpcb); 472fb59c426SYoshinobu Inoue else 473fb59c426SYoshinobu Inoue #endif 474df8bae1dSRodney W. Grimes in_losing(tp->t_inpcb); 475df8bae1dSRodney W. Grimes tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); 476df8bae1dSRodney W. Grimes tp->t_srtt = 0; 477df8bae1dSRodney W. Grimes } 478df8bae1dSRodney W. Grimes tp->snd_nxt = tp->snd_una; 479a0292f23SGarrett Wollman /* 48046f58482SJonathan Lemon * Note: We overload snd_recover to function also as the 48146f58482SJonathan Lemon * snd_last variable described in RFC 2582 48246f58482SJonathan Lemon */ 48346f58482SJonathan Lemon tp->snd_recover = tp->snd_max; 48446f58482SJonathan Lemon /* 48574b48c1dSAndras Olah * Force a segment to be sent. 48674b48c1dSAndras Olah */ 48774b48c1dSAndras Olah tp->t_flags |= TF_ACKNOW; 48874b48c1dSAndras Olah /* 489df8bae1dSRodney W. Grimes * If timing a segment in this window, stop the timer. 490df8bae1dSRodney W. Grimes */ 4919b8b58e0SJonathan Lemon tp->t_rtttime = 0; 492df8bae1dSRodney W. Grimes /* 493df8bae1dSRodney W. Grimes * Close the congestion window down to one segment 494df8bae1dSRodney W. Grimes * (we'll open it by one segment for each ack we get). 495df8bae1dSRodney W. Grimes * Since we probably have a window's worth of unacked 496df8bae1dSRodney W. Grimes * data accumulated, this "slow start" keeps us from 497df8bae1dSRodney W. Grimes * dumping all that data as back-to-back packets (which 498df8bae1dSRodney W. Grimes * might overwhelm an intermediate gateway). 499df8bae1dSRodney W. Grimes * 500df8bae1dSRodney W. Grimes * There are two phases to the opening: Initially we 501df8bae1dSRodney W. Grimes * open by one mss on each ack. This makes the window 502df8bae1dSRodney W. Grimes * size increase exponentially with time. If the 503df8bae1dSRodney W. Grimes * window is larger than the path can handle, this 504df8bae1dSRodney W. Grimes * exponential growth results in dropped packet(s) 505df8bae1dSRodney W. Grimes * almost immediately. To get more time between 506df8bae1dSRodney W. Grimes * drops but still "push" the network to take advantage 507df8bae1dSRodney W. Grimes * of improving conditions, we switch from exponential 508df8bae1dSRodney W. Grimes * to linear window opening at some threshhold size. 509df8bae1dSRodney W. Grimes * For a threshhold, we use half the current window 510df8bae1dSRodney W. Grimes * size, truncated to a multiple of the mss. 511df8bae1dSRodney W. Grimes * 512df8bae1dSRodney W. Grimes * (the minimum cwnd that will give us exponential 513df8bae1dSRodney W. Grimes * growth is 2 mss. We don't allow the threshhold 514df8bae1dSRodney W. Grimes * to go below this.) 515df8bae1dSRodney W. Grimes */ 516df8bae1dSRodney W. Grimes { 517df8bae1dSRodney W. Grimes u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; 518df8bae1dSRodney W. Grimes if (win < 2) 519df8bae1dSRodney W. Grimes win = 2; 520df8bae1dSRodney W. Grimes tp->snd_cwnd = tp->t_maxseg; 521df8bae1dSRodney W. Grimes tp->snd_ssthresh = win * tp->t_maxseg; 522df8bae1dSRodney W. Grimes tp->t_dupacks = 0; 523df8bae1dSRodney W. Grimes } 524df8bae1dSRodney W. Grimes (void) tcp_output(tp); 525df8bae1dSRodney W. Grimes 5269b8b58e0SJonathan Lemon out: 5279b8b58e0SJonathan Lemon #ifdef TCPDEBUG 5284cc20ab1SSeigo Tanimura if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 529fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 5309b8b58e0SJonathan Lemon PRU_SLOWTIMO); 531df8bae1dSRodney W. Grimes #endif 532f76fcf6dSJeffrey Hsu if (tp) 533f76fcf6dSJeffrey Hsu INP_UNLOCK(inp); 534f76fcf6dSJeffrey Hsu if (headlocked) 535f76fcf6dSJeffrey Hsu INP_INFO_WUNLOCK(&tcbinfo); 5369b8b58e0SJonathan Lemon splx(s); 537df8bae1dSRodney W. Grimes } 538