1c398230bSWarner Losh /*- 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 * 4. Neither the name of the University nor the names of its contributors 14df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 15df8bae1dSRodney W. Grimes * without specific prior written permission. 16df8bae1dSRodney W. Grimes * 17df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27df8bae1dSRodney W. Grimes * SUCH DAMAGE. 28df8bae1dSRodney W. Grimes * 29e79adb8eSGarrett Wollman * @(#)tcp_timer.c 8.2 (Berkeley) 5/24/95 30df8bae1dSRodney W. Grimes */ 31df8bae1dSRodney W. Grimes 324b421e2dSMike Silbersack #include <sys/cdefs.h> 334b421e2dSMike Silbersack __FBSDID("$FreeBSD$"); 344b421e2dSMike Silbersack 35825fd1e4SNavdeep Parhar #include "opt_inet.h" 36fb59c426SYoshinobu Inoue #include "opt_inet6.h" 370cc12cc5SJoerg Wunsch #include "opt_tcpdebug.h" 38883831c6SAdrian Chadd #include "opt_rss.h" 390cc12cc5SJoerg Wunsch 40df8bae1dSRodney W. Grimes #include <sys/param.h> 4198163b98SPoul-Henning Kamp #include <sys/kernel.h> 42c74af4faSBruce Evans #include <sys/lock.h> 4308517d53SMike Silbersack #include <sys/mbuf.h> 44c74af4faSBruce Evans #include <sys/mutex.h> 45c74af4faSBruce Evans #include <sys/protosw.h> 4687aedea4SKip Macy #include <sys/smp.h> 47df8bae1dSRodney W. Grimes #include <sys/socket.h> 48df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 49c74af4faSBruce Evans #include <sys/sysctl.h> 50c74af4faSBruce Evans #include <sys/systm.h> 51e79adb8eSGarrett Wollman 524b79449eSBjoern A. Zeeb #include <net/if.h> 53df8bae1dSRodney W. Grimes #include <net/route.h> 54530c0060SRobert Watson #include <net/vnet.h> 55883831c6SAdrian Chadd #include <net/netisr.h> 56df8bae1dSRodney W. Grimes 57dbc42409SLawrence Stewart #include <netinet/cc.h> 58df8bae1dSRodney W. Grimes #include <netinet/in.h> 59df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 60883831c6SAdrian Chadd #include <netinet/in_rss.h> 61c74af4faSBruce Evans #include <netinet/in_systm.h> 62fb59c426SYoshinobu Inoue #ifdef INET6 63fb59c426SYoshinobu Inoue #include <netinet6/in6_pcb.h> 64fb59c426SYoshinobu Inoue #endif 65df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 66df8bae1dSRodney W. Grimes #include <netinet/tcp_fsm.h> 67df8bae1dSRodney W. Grimes #include <netinet/tcp_timer.h> 68df8bae1dSRodney W. Grimes #include <netinet/tcp_var.h> 69df8bae1dSRodney W. Grimes #include <netinet/tcpip.h> 70af7a2999SDavid Greenman #ifdef TCPDEBUG 71af7a2999SDavid Greenman #include <netinet/tcp_debug.h> 72af7a2999SDavid Greenman #endif 73df8bae1dSRodney W. Grimes 749b8b58e0SJonathan Lemon int tcp_keepinit; 75ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, CTLTYPE_INT|CTLFLAG_RW, 7641698ebfSTom Rhodes &tcp_keepinit, 0, sysctl_msec_to_ticks, "I", "time to establish connection"); 777b40aa32SPaul Traina 789b8b58e0SJonathan Lemon int tcp_keepidle; 79ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, CTLTYPE_INT|CTLFLAG_RW, 8041698ebfSTom Rhodes &tcp_keepidle, 0, sysctl_msec_to_ticks, "I", "time before keepalive probes begin"); 8198163b98SPoul-Henning Kamp 829b8b58e0SJonathan Lemon int tcp_keepintvl; 83ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, CTLTYPE_INT|CTLFLAG_RW, 8441698ebfSTom Rhodes &tcp_keepintvl, 0, sysctl_msec_to_ticks, "I", "time between keepalive probes"); 8598163b98SPoul-Henning Kamp 869b8b58e0SJonathan Lemon int tcp_delacktime; 876489fe65SAndre Oppermann SYSCTL_PROC(_net_inet_tcp, TCPCTL_DELACKTIME, delacktime, CTLTYPE_INT|CTLFLAG_RW, 886489fe65SAndre Oppermann &tcp_delacktime, 0, sysctl_msec_to_ticks, "I", 89ccb4d0c6SJonathan Lemon "Time before a delayed ACK is sent"); 909b8b58e0SJonathan Lemon 919b8b58e0SJonathan Lemon int tcp_msl; 92ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl, CTLTYPE_INT|CTLFLAG_RW, 93ccb4d0c6SJonathan Lemon &tcp_msl, 0, sysctl_msec_to_ticks, "I", "Maximum segment lifetime"); 949b8b58e0SJonathan Lemon 95701bec5aSMatthew Dillon int tcp_rexmit_min; 96701bec5aSMatthew Dillon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_min, CTLTYPE_INT|CTLFLAG_RW, 976489fe65SAndre Oppermann &tcp_rexmit_min, 0, sysctl_msec_to_ticks, "I", 986489fe65SAndre Oppermann "Minimum Retransmission Timeout"); 99701bec5aSMatthew Dillon 100701bec5aSMatthew Dillon int tcp_rexmit_slop; 101701bec5aSMatthew Dillon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_slop, CTLTYPE_INT|CTLFLAG_RW, 1026489fe65SAndre Oppermann &tcp_rexmit_slop, 0, sysctl_msec_to_ticks, "I", 1036489fe65SAndre Oppermann "Retransmission Timer Slop"); 104701bec5aSMatthew Dillon 105c39a614eSRobert Watson static int always_keepalive = 1; 1063d177f46SBill Fumerola SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW, 1073d177f46SBill Fumerola &always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections"); 10834be9bf3SPoul-Henning Kamp 1097c72af87SMohan Srinivasan int tcp_fast_finwait2_recycle = 0; 1107c72af87SMohan Srinivasan SYSCTL_INT(_net_inet_tcp, OID_AUTO, fast_finwait2_recycle, CTLFLAG_RW, 1116489fe65SAndre Oppermann &tcp_fast_finwait2_recycle, 0, 1126489fe65SAndre Oppermann "Recycle closed FIN_WAIT_2 connections faster"); 1137c72af87SMohan Srinivasan 1147c72af87SMohan Srinivasan int tcp_finwait2_timeout; 1157c72af87SMohan Srinivasan SYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, CTLTYPE_INT|CTLFLAG_RW, 1166489fe65SAndre Oppermann &tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", "FIN-WAIT2 timeout"); 1177c72af87SMohan Srinivasan 1189077f387SGleb Smirnoff int tcp_keepcnt = TCPTV_KEEPCNT; 1199077f387SGleb Smirnoff SYSCTL_INT(_net_inet_tcp, OID_AUTO, keepcnt, CTLFLAG_RW, &tcp_keepcnt, 0, 1209077f387SGleb Smirnoff "Number of keepalive probes to send"); 1217c72af87SMohan Srinivasan 1220312fbe9SPoul-Henning Kamp /* max idle probes */ 1239b8b58e0SJonathan Lemon int tcp_maxpersistidle; 124e79adb8eSGarrett Wollman 1256c0ef895SJohn Baldwin static int tcp_rexmit_drop_options = 0; 1266c0ef895SJohn Baldwin SYSCTL_INT(_net_inet_tcp, OID_AUTO, rexmit_drop_options, CTLFLAG_RW, 1276c0ef895SJohn Baldwin &tcp_rexmit_drop_options, 0, 1286c0ef895SJohn Baldwin "Drop TCP options from 3rd and later retransmitted SYN"); 1296c0ef895SJohn Baldwin 130*8f7e75cbSAdrian Chadd #ifdef RSS 131*8f7e75cbSAdrian Chadd static int per_cpu_timers = 1; 132*8f7e75cbSAdrian Chadd #else 13387aedea4SKip Macy static int per_cpu_timers = 0; 134*8f7e75cbSAdrian Chadd #endif 13587aedea4SKip Macy SYSCTL_INT(_net_inet_tcp, OID_AUTO, per_cpu_timers, CTLFLAG_RW, 13687aedea4SKip Macy &per_cpu_timers , 0, "run tcp timers on all cpus"); 13787aedea4SKip Macy 138883831c6SAdrian Chadd #if 0 13987aedea4SKip Macy #define INP_CPU(inp) (per_cpu_timers ? (!CPU_ABSENT(((inp)->inp_flowid % (mp_maxid+1))) ? \ 14087aedea4SKip Macy ((inp)->inp_flowid % (mp_maxid+1)) : curcpu) : 0) 141883831c6SAdrian Chadd #endif 142883831c6SAdrian Chadd 143883831c6SAdrian Chadd /* 144883831c6SAdrian Chadd * Map the given inp to a CPU id. 145883831c6SAdrian Chadd * 146883831c6SAdrian Chadd * This queries RSS if it's compiled in, else it defaults to the current 147883831c6SAdrian Chadd * CPU ID. 148883831c6SAdrian Chadd */ 149883831c6SAdrian Chadd static inline int 150883831c6SAdrian Chadd inp_to_cpuid(struct inpcb *inp) 151883831c6SAdrian Chadd { 152883831c6SAdrian Chadd u_int cpuid; 153883831c6SAdrian Chadd 154883831c6SAdrian Chadd #ifdef RSS 155883831c6SAdrian Chadd if (per_cpu_timers) { 156883831c6SAdrian Chadd cpuid = rss_hash2cpuid(inp->inp_flowid, inp->inp_flowtype); 157883831c6SAdrian Chadd if (cpuid == NETISR_CPUID_NONE) 158883831c6SAdrian Chadd return (curcpu); /* XXX */ 159883831c6SAdrian Chadd else 160883831c6SAdrian Chadd return (cpuid); 161883831c6SAdrian Chadd } 162883831c6SAdrian Chadd #else 163883831c6SAdrian Chadd /* Legacy, pre-RSS behaviour */ 164883831c6SAdrian Chadd if (per_cpu_timers) { 165883831c6SAdrian Chadd /* 166883831c6SAdrian Chadd * We don't have a flowid -> cpuid mapping, so cheat and 167883831c6SAdrian Chadd * just map unknown cpuids to curcpu. Not the best, but 168883831c6SAdrian Chadd * apparently better than defaulting to swi 0. 169883831c6SAdrian Chadd */ 170883831c6SAdrian Chadd cpuid = inp->inp_flowid % (mp_maxid + 1); 171883831c6SAdrian Chadd if (! CPU_ABSENT(cpuid)) 172883831c6SAdrian Chadd return (cpuid); 173883831c6SAdrian Chadd return (curcpu); 174883831c6SAdrian Chadd } 175883831c6SAdrian Chadd #endif 176883831c6SAdrian Chadd /* Default for RSS and non-RSS - cpuid 0 */ 177883831c6SAdrian Chadd else { 178883831c6SAdrian Chadd return (0); 179883831c6SAdrian Chadd } 180883831c6SAdrian Chadd } 18187aedea4SKip Macy 182df8bae1dSRodney W. Grimes /* 183df8bae1dSRodney W. Grimes * Tcp protocol timeout routine called every 500 ms. 1849b8b58e0SJonathan Lemon * Updates timestamps used for TCP 185df8bae1dSRodney W. Grimes * causes finite state machine actions if timers expire. 186df8bae1dSRodney W. Grimes */ 187df8bae1dSRodney W. Grimes void 188e2f2059fSMike Silbersack tcp_slowtimo(void) 189df8bae1dSRodney W. Grimes { 1908b615593SMarko Zec VNET_ITERATOR_DECL(vnet_iter); 19115bd2b43SDavid Greenman 1925ee847d3SRobert Watson VNET_LIST_RLOCK_NOSLEEP(); 1938b615593SMarko Zec VNET_FOREACH(vnet_iter) { 1948b615593SMarko Zec CURVNET_SET(vnet_iter); 19566eefb1eSJohn Baldwin tcp_tw_2msl_scan(); 1968b615593SMarko Zec CURVNET_RESTORE(); 1978b615593SMarko Zec } 1985ee847d3SRobert Watson VNET_LIST_RUNLOCK_NOSLEEP(); 199df8bae1dSRodney W. Grimes } 200df8bae1dSRodney W. Grimes 2017d42e30cSJonathan Lemon int tcp_syn_backoff[TCP_MAXRXTSHIFT + 1] = 2027d42e30cSJonathan Lemon { 1, 1, 1, 1, 1, 2, 4, 8, 16, 32, 64, 64, 64 }; 2037d42e30cSJonathan Lemon 204df8bae1dSRodney W. Grimes int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 205f058535dSJeffrey Hsu { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 512, 512, 512 }; 206df8bae1dSRodney W. Grimes 207f058535dSJeffrey Hsu static int tcp_totbackoff = 2559; /* sum of tcp_backoff[] */ 208e79adb8eSGarrett Wollman 209623dce13SRobert Watson static int tcp_timer_race; 210623dce13SRobert Watson SYSCTL_INT(_net_inet_tcp, OID_AUTO, timer_race, CTLFLAG_RD, &tcp_timer_race, 211623dce13SRobert Watson 0, "Count of t_inpcb races on tcp_discardcb"); 212623dce13SRobert Watson 213df8bae1dSRodney W. Grimes /* 214df8bae1dSRodney W. Grimes * TCP timer processing. 215df8bae1dSRodney W. Grimes */ 21685d94372SRobert Watson 21785d94372SRobert Watson void 21885d94372SRobert Watson tcp_timer_delack(void *xtp) 219df8bae1dSRodney W. Grimes { 22085d94372SRobert Watson struct tcpcb *tp = xtp; 22185d94372SRobert Watson struct inpcb *inp; 2228b615593SMarko Zec CURVNET_SET(tp->t_vnet); 22385d94372SRobert Watson 22485d94372SRobert Watson inp = tp->t_inpcb; 22585d94372SRobert Watson /* 22685d94372SRobert Watson * XXXRW: While this assert is in fact correct, bugs in the tcpcb 22785d94372SRobert Watson * tear-down mean we need it as a work-around for races between 22885d94372SRobert Watson * timers and tcp_discardcb(). 22985d94372SRobert Watson * 23085d94372SRobert Watson * KASSERT(inp != NULL, ("tcp_timer_delack: inp == NULL")); 23185d94372SRobert Watson */ 23285d94372SRobert Watson if (inp == NULL) { 23385d94372SRobert Watson tcp_timer_race++; 2348b615593SMarko Zec CURVNET_RESTORE(); 23585d94372SRobert Watson return; 23685d94372SRobert Watson } 2378501a69cSRobert Watson INP_WLOCK(inp); 238655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_delack) || 239655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_delack)) { 2408501a69cSRobert Watson INP_WUNLOCK(inp); 2418b615593SMarko Zec CURVNET_RESTORE(); 24285d94372SRobert Watson return; 24385d94372SRobert Watson } 244e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_delack); 245655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 246655f934bSMikolaj Golub INP_WUNLOCK(inp); 247655f934bSMikolaj Golub CURVNET_RESTORE(); 248655f934bSMikolaj Golub return; 249655f934bSMikolaj Golub } 250df8bae1dSRodney W. Grimes 2519b8b58e0SJonathan Lemon tp->t_flags |= TF_ACKNOW; 25278b50714SRobert Watson TCPSTAT_INC(tcps_delack); 2539b8b58e0SJonathan Lemon (void) tcp_output(tp); 2548501a69cSRobert Watson INP_WUNLOCK(inp); 2558b615593SMarko Zec CURVNET_RESTORE(); 2569b8b58e0SJonathan Lemon } 2579b8b58e0SJonathan Lemon 25885d94372SRobert Watson void 25985d94372SRobert Watson tcp_timer_2msl(void *xtp) 2609b8b58e0SJonathan Lemon { 26185d94372SRobert Watson struct tcpcb *tp = xtp; 26285d94372SRobert Watson struct inpcb *inp; 2638b615593SMarko Zec CURVNET_SET(tp->t_vnet); 2649b8b58e0SJonathan Lemon #ifdef TCPDEBUG 2659b8b58e0SJonathan Lemon int ostate; 2669b8b58e0SJonathan Lemon 2679b8b58e0SJonathan Lemon ostate = tp->t_state; 2689b8b58e0SJonathan Lemon #endif 269623dce13SRobert Watson /* 27085d94372SRobert Watson * XXXRW: Does this actually happen? 27185d94372SRobert Watson */ 272603724d3SBjoern A. Zeeb INP_INFO_WLOCK(&V_tcbinfo); 27385d94372SRobert Watson inp = tp->t_inpcb; 27485d94372SRobert Watson /* 27585d94372SRobert Watson * XXXRW: While this assert is in fact correct, bugs in the tcpcb 27685d94372SRobert Watson * tear-down mean we need it as a work-around for races between 27785d94372SRobert Watson * timers and tcp_discardcb(). 27885d94372SRobert Watson * 27985d94372SRobert Watson * KASSERT(inp != NULL, ("tcp_timer_2msl: inp == NULL")); 28085d94372SRobert Watson */ 28185d94372SRobert Watson if (inp == NULL) { 28285d94372SRobert Watson tcp_timer_race++; 283603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_tcbinfo); 2848b615593SMarko Zec CURVNET_RESTORE(); 28585d94372SRobert Watson return; 28685d94372SRobert Watson } 2878501a69cSRobert Watson INP_WLOCK(inp); 28885d94372SRobert Watson tcp_free_sackholes(tp); 289655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_2msl) || 290e2f2059fSMike Silbersack !callout_active(&tp->t_timers->tt_2msl)) { 2918501a69cSRobert Watson INP_WUNLOCK(tp->t_inpcb); 292603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_tcbinfo); 2938b615593SMarko Zec CURVNET_RESTORE(); 29485d94372SRobert Watson return; 29585d94372SRobert Watson } 296e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_2msl); 297655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 298655f934bSMikolaj Golub INP_WUNLOCK(inp); 299655f934bSMikolaj Golub INP_INFO_WUNLOCK(&V_tcbinfo); 300655f934bSMikolaj Golub CURVNET_RESTORE(); 301655f934bSMikolaj Golub return; 302655f934bSMikolaj Golub } 30385d94372SRobert Watson /* 304df8bae1dSRodney W. Grimes * 2 MSL timeout in shutdown went off. If we're closed but 305df8bae1dSRodney W. Grimes * still waiting for peer to close and connection has been idle 306df8bae1dSRodney W. Grimes * too long, or if 2MSL time is up from TIME_WAIT, delete connection 307df8bae1dSRodney W. Grimes * control block. Otherwise, check again in a bit. 3087c72af87SMohan Srinivasan * 3097c72af87SMohan Srinivasan * If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, 3107c72af87SMohan Srinivasan * there's no point in hanging onto FIN_WAIT_2 socket. Just close it. 3117c72af87SMohan Srinivasan * Ignore fact that there were recent incoming segments. 312df8bae1dSRodney W. Grimes */ 3137c72af87SMohan Srinivasan if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && 31485d94372SRobert Watson tp->t_inpcb && tp->t_inpcb->inp_socket && 3157c72af87SMohan Srinivasan (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { 31678b50714SRobert Watson TCPSTAT_INC(tcps_finwait2_drops); 31785d94372SRobert Watson tp = tcp_close(tp); 3187c72af87SMohan Srinivasan } else { 319df8bae1dSRodney W. Grimes if (tp->t_state != TCPS_TIME_WAIT && 3209077f387SGleb Smirnoff ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) 3219077f387SGleb Smirnoff callout_reset_on(&tp->t_timers->tt_2msl, 322883831c6SAdrian Chadd TP_KEEPINTVL(tp), tcp_timer_2msl, tp, 323883831c6SAdrian Chadd inp_to_cpuid(inp)); 324df8bae1dSRodney W. Grimes else 32585d94372SRobert Watson tp = tcp_close(tp); 3267c72af87SMohan Srinivasan } 327df8bae1dSRodney W. Grimes 3289b8b58e0SJonathan Lemon #ifdef TCPDEBUG 329586b4a0eSKonstantin Belousov if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 330fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 3319b8b58e0SJonathan Lemon PRU_SLOWTIMO); 3329b8b58e0SJonathan Lemon #endif 33385d94372SRobert Watson if (tp != NULL) 3348501a69cSRobert Watson INP_WUNLOCK(inp); 335603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_tcbinfo); 3368b615593SMarko Zec CURVNET_RESTORE(); 3379b8b58e0SJonathan Lemon } 3389b8b58e0SJonathan Lemon 33985d94372SRobert Watson void 34085d94372SRobert Watson tcp_timer_keep(void *xtp) 3419b8b58e0SJonathan Lemon { 34285d94372SRobert Watson struct tcpcb *tp = xtp; 34308517d53SMike Silbersack struct tcptemp *t_template; 34485d94372SRobert Watson struct inpcb *inp; 3458b615593SMarko Zec CURVNET_SET(tp->t_vnet); 3469b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3479b8b58e0SJonathan Lemon int ostate; 3489b8b58e0SJonathan Lemon 3499b8b58e0SJonathan Lemon ostate = tp->t_state; 3509b8b58e0SJonathan Lemon #endif 351603724d3SBjoern A. Zeeb INP_INFO_WLOCK(&V_tcbinfo); 35285d94372SRobert Watson inp = tp->t_inpcb; 35385d94372SRobert Watson /* 35485d94372SRobert Watson * XXXRW: While this assert is in fact correct, bugs in the tcpcb 35585d94372SRobert Watson * tear-down mean we need it as a work-around for races between 35685d94372SRobert Watson * timers and tcp_discardcb(). 35785d94372SRobert Watson * 35885d94372SRobert Watson * KASSERT(inp != NULL, ("tcp_timer_keep: inp == NULL")); 35985d94372SRobert Watson */ 36085d94372SRobert Watson if (inp == NULL) { 36185d94372SRobert Watson tcp_timer_race++; 362603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_tcbinfo); 3638b615593SMarko Zec CURVNET_RESTORE(); 36485d94372SRobert Watson return; 36585d94372SRobert Watson } 3668501a69cSRobert Watson INP_WLOCK(inp); 367655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_keep) || 368655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_keep)) { 3698501a69cSRobert Watson INP_WUNLOCK(inp); 370603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_tcbinfo); 3718b615593SMarko Zec CURVNET_RESTORE(); 37285d94372SRobert Watson return; 37385d94372SRobert Watson } 374e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_keep); 375655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 376655f934bSMikolaj Golub INP_WUNLOCK(inp); 377655f934bSMikolaj Golub INP_INFO_WUNLOCK(&V_tcbinfo); 378655f934bSMikolaj Golub CURVNET_RESTORE(); 379655f934bSMikolaj Golub return; 380655f934bSMikolaj Golub } 3819b8b58e0SJonathan Lemon /* 3829b8b58e0SJonathan Lemon * Keep-alive timer went off; send something 3839b8b58e0SJonathan Lemon * or drop connection if idle for too long. 3849b8b58e0SJonathan Lemon */ 38578b50714SRobert Watson TCPSTAT_INC(tcps_keeptimeo); 3869b8b58e0SJonathan Lemon if (tp->t_state < TCPS_ESTABLISHED) 3879b8b58e0SJonathan Lemon goto dropit; 3882a074620SSam Leffler if ((always_keepalive || inp->inp_socket->so_options & SO_KEEPALIVE) && 3899b8b58e0SJonathan Lemon tp->t_state <= TCPS_CLOSING) { 3909077f387SGleb Smirnoff if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp)) 3919b8b58e0SJonathan Lemon goto dropit; 3929b8b58e0SJonathan Lemon /* 3939b8b58e0SJonathan Lemon * Send a packet designed to force a response 3949b8b58e0SJonathan Lemon * if the peer is up and reachable: 3959b8b58e0SJonathan Lemon * either an ACK if the connection is still alive, 3969b8b58e0SJonathan Lemon * or an RST if the peer has closed the connection 3979b8b58e0SJonathan Lemon * due to timeout or reboot. 3989b8b58e0SJonathan Lemon * Using sequence number tp->snd_una-1 3999b8b58e0SJonathan Lemon * causes the transmitted zero-length segment 4009b8b58e0SJonathan Lemon * to lie outside the receive window; 4019b8b58e0SJonathan Lemon * by the protocol spec, this requires the 4029b8b58e0SJonathan Lemon * correspondent TCP to respond. 4039b8b58e0SJonathan Lemon */ 40478b50714SRobert Watson TCPSTAT_INC(tcps_keepprobe); 40579909384SJonathan Lemon t_template = tcpip_maketemplate(inp); 40608517d53SMike Silbersack if (t_template) { 40708517d53SMike Silbersack tcp_respond(tp, t_template->tt_ipgen, 40808517d53SMike Silbersack &t_template->tt_t, (struct mbuf *)NULL, 4099b8b58e0SJonathan Lemon tp->rcv_nxt, tp->snd_una - 1, 0); 41053640b0eSRobert Watson free(t_template, M_TEMP); 41108517d53SMike Silbersack } 4129077f387SGleb Smirnoff callout_reset_on(&tp->t_timers->tt_keep, TP_KEEPINTVL(tp), 413883831c6SAdrian Chadd tcp_timer_keep, tp, inp_to_cpuid(inp)); 4144cc20ab1SSeigo Tanimura } else 4159077f387SGleb Smirnoff callout_reset_on(&tp->t_timers->tt_keep, TP_KEEPIDLE(tp), 416883831c6SAdrian Chadd tcp_timer_keep, tp, inp_to_cpuid(inp)); 4179b8b58e0SJonathan Lemon 4189b8b58e0SJonathan Lemon #ifdef TCPDEBUG 4192a074620SSam Leffler if (inp->inp_socket->so_options & SO_DEBUG) 420fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 4219b8b58e0SJonathan Lemon PRU_SLOWTIMO); 4229b8b58e0SJonathan Lemon #endif 4238501a69cSRobert Watson INP_WUNLOCK(inp); 424603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_tcbinfo); 4258b615593SMarko Zec CURVNET_RESTORE(); 42685d94372SRobert Watson return; 4279b8b58e0SJonathan Lemon 4289b8b58e0SJonathan Lemon dropit: 42978b50714SRobert Watson TCPSTAT_INC(tcps_keepdrops); 43085d94372SRobert Watson tp = tcp_drop(tp, ETIMEDOUT); 43185d94372SRobert Watson 43285d94372SRobert Watson #ifdef TCPDEBUG 43385d94372SRobert Watson if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 43485d94372SRobert Watson tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 43585d94372SRobert Watson PRU_SLOWTIMO); 43685d94372SRobert Watson #endif 43785d94372SRobert Watson if (tp != NULL) 4388501a69cSRobert Watson INP_WUNLOCK(tp->t_inpcb); 439603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_tcbinfo); 4408b615593SMarko Zec CURVNET_RESTORE(); 4419b8b58e0SJonathan Lemon } 4429b8b58e0SJonathan Lemon 44385d94372SRobert Watson void 44485d94372SRobert Watson tcp_timer_persist(void *xtp) 4459b8b58e0SJonathan Lemon { 44685d94372SRobert Watson struct tcpcb *tp = xtp; 44785d94372SRobert Watson struct inpcb *inp; 4488b615593SMarko Zec CURVNET_SET(tp->t_vnet); 4499b8b58e0SJonathan Lemon #ifdef TCPDEBUG 4509b8b58e0SJonathan Lemon int ostate; 4519b8b58e0SJonathan Lemon 4529b8b58e0SJonathan Lemon ostate = tp->t_state; 4539b8b58e0SJonathan Lemon #endif 454603724d3SBjoern A. Zeeb INP_INFO_WLOCK(&V_tcbinfo); 45585d94372SRobert Watson inp = tp->t_inpcb; 45685d94372SRobert Watson /* 45785d94372SRobert Watson * XXXRW: While this assert is in fact correct, bugs in the tcpcb 45885d94372SRobert Watson * tear-down mean we need it as a work-around for races between 45985d94372SRobert Watson * timers and tcp_discardcb(). 46085d94372SRobert Watson * 46185d94372SRobert Watson * KASSERT(inp != NULL, ("tcp_timer_persist: inp == NULL")); 46285d94372SRobert Watson */ 46385d94372SRobert Watson if (inp == NULL) { 46485d94372SRobert Watson tcp_timer_race++; 465603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_tcbinfo); 4668b615593SMarko Zec CURVNET_RESTORE(); 46785d94372SRobert Watson return; 46885d94372SRobert Watson } 4698501a69cSRobert Watson INP_WLOCK(inp); 470655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_persist) || 471655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_persist)) { 4728501a69cSRobert Watson INP_WUNLOCK(inp); 473603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_tcbinfo); 4748b615593SMarko Zec CURVNET_RESTORE(); 47585d94372SRobert Watson return; 47685d94372SRobert Watson } 477e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_persist); 478655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 479655f934bSMikolaj Golub INP_WUNLOCK(inp); 480655f934bSMikolaj Golub INP_INFO_WUNLOCK(&V_tcbinfo); 481655f934bSMikolaj Golub CURVNET_RESTORE(); 482655f934bSMikolaj Golub return; 483655f934bSMikolaj Golub } 4849b8b58e0SJonathan Lemon /* 4859b8b58e0SJonathan Lemon * Persistance timer into zero window. 4869b8b58e0SJonathan Lemon * Force a byte to be output, if possible. 4879b8b58e0SJonathan Lemon */ 48878b50714SRobert Watson TCPSTAT_INC(tcps_persisttimeo); 4899b8b58e0SJonathan Lemon /* 4909b8b58e0SJonathan Lemon * Hack: if the peer is dead/unreachable, we do not 4919b8b58e0SJonathan Lemon * time out if the window is closed. After a full 4929b8b58e0SJonathan Lemon * backoff, drop the connection if the idle time 4939b8b58e0SJonathan Lemon * (no responses to probes) reaches the maximum 4949b8b58e0SJonathan Lemon * backoff that we would use if retransmitting. 4959b8b58e0SJonathan Lemon */ 4969b8b58e0SJonathan Lemon if (tp->t_rxtshift == TCP_MAXRXTSHIFT && 4976b0c5521SJohn Baldwin (ticks - tp->t_rcvtime >= tcp_maxpersistidle || 4986b0c5521SJohn Baldwin ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { 49978b50714SRobert Watson TCPSTAT_INC(tcps_persistdrop); 50085d94372SRobert Watson tp = tcp_drop(tp, ETIMEDOUT); 50185d94372SRobert Watson goto out; 5029b8b58e0SJonathan Lemon } 503322181c9SAndre Oppermann /* 504322181c9SAndre Oppermann * If the user has closed the socket then drop a persisting 505322181c9SAndre Oppermann * connection after a much reduced timeout. 506322181c9SAndre Oppermann */ 507322181c9SAndre Oppermann if (tp->t_state > TCPS_CLOSE_WAIT && 508322181c9SAndre Oppermann (ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) { 509322181c9SAndre Oppermann TCPSTAT_INC(tcps_persistdrop); 510322181c9SAndre Oppermann tp = tcp_drop(tp, ETIMEDOUT); 511322181c9SAndre Oppermann goto out; 512322181c9SAndre Oppermann } 5139b8b58e0SJonathan Lemon tcp_setpersist(tp); 5142cdbfa66SPaul Saab tp->t_flags |= TF_FORCEDATA; 5159b8b58e0SJonathan Lemon (void) tcp_output(tp); 5162cdbfa66SPaul Saab tp->t_flags &= ~TF_FORCEDATA; 5179b8b58e0SJonathan Lemon 51885d94372SRobert Watson out: 5199b8b58e0SJonathan Lemon #ifdef TCPDEBUG 520ffb761f6SGleb Smirnoff if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 521ffb761f6SGleb Smirnoff tcp_trace(TA_USER, ostate, tp, NULL, NULL, PRU_SLOWTIMO); 5229b8b58e0SJonathan Lemon #endif 52385d94372SRobert Watson if (tp != NULL) 5248501a69cSRobert Watson INP_WUNLOCK(inp); 525603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_tcbinfo); 5268b615593SMarko Zec CURVNET_RESTORE(); 5279b8b58e0SJonathan Lemon } 5289b8b58e0SJonathan Lemon 52985d94372SRobert Watson void 53085d94372SRobert Watson tcp_timer_rexmt(void * xtp) 5319b8b58e0SJonathan Lemon { 53285d94372SRobert Watson struct tcpcb *tp = xtp; 5338b615593SMarko Zec CURVNET_SET(tp->t_vnet); 5349b8b58e0SJonathan Lemon int rexmt; 53585d94372SRobert Watson int headlocked; 53685d94372SRobert Watson struct inpcb *inp; 5379b8b58e0SJonathan Lemon #ifdef TCPDEBUG 5389b8b58e0SJonathan Lemon int ostate; 5399b8b58e0SJonathan Lemon 5409b8b58e0SJonathan Lemon ostate = tp->t_state; 5419b8b58e0SJonathan Lemon #endif 54287aedea4SKip Macy INP_INFO_RLOCK(&V_tcbinfo); 54385d94372SRobert Watson inp = tp->t_inpcb; 54485d94372SRobert Watson /* 54585d94372SRobert Watson * XXXRW: While this assert is in fact correct, bugs in the tcpcb 54685d94372SRobert Watson * tear-down mean we need it as a work-around for races between 54785d94372SRobert Watson * timers and tcp_discardcb(). 54885d94372SRobert Watson * 54985d94372SRobert Watson * KASSERT(inp != NULL, ("tcp_timer_rexmt: inp == NULL")); 55085d94372SRobert Watson */ 55185d94372SRobert Watson if (inp == NULL) { 55285d94372SRobert Watson tcp_timer_race++; 55387aedea4SKip Macy INP_INFO_RUNLOCK(&V_tcbinfo); 5548b615593SMarko Zec CURVNET_RESTORE(); 55585d94372SRobert Watson return; 55685d94372SRobert Watson } 5578501a69cSRobert Watson INP_WLOCK(inp); 558655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_rexmt) || 559655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_rexmt)) { 5608501a69cSRobert Watson INP_WUNLOCK(inp); 56187aedea4SKip Macy INP_INFO_RUNLOCK(&V_tcbinfo); 5628b615593SMarko Zec CURVNET_RESTORE(); 56385d94372SRobert Watson return; 56485d94372SRobert Watson } 565e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_rexmt); 566655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 567655f934bSMikolaj Golub INP_WUNLOCK(inp); 568655f934bSMikolaj Golub INP_INFO_RUNLOCK(&V_tcbinfo); 569655f934bSMikolaj Golub CURVNET_RESTORE(); 570655f934bSMikolaj Golub return; 571655f934bSMikolaj Golub } 5726d90faf3SPaul Saab tcp_free_sackholes(tp); 573df8bae1dSRodney W. Grimes /* 574df8bae1dSRodney W. Grimes * Retransmission timer went off. Message has not 575df8bae1dSRodney W. Grimes * been acked within retransmit interval. Back off 576df8bae1dSRodney W. Grimes * to a longer retransmit interval and retransmit one segment. 577df8bae1dSRodney W. Grimes */ 578df8bae1dSRodney W. Grimes if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 579df8bae1dSRodney W. Grimes tp->t_rxtshift = TCP_MAXRXTSHIFT; 58078b50714SRobert Watson TCPSTAT_INC(tcps_timeoutdrop); 58187aedea4SKip Macy in_pcbref(inp); 58287aedea4SKip Macy INP_INFO_RUNLOCK(&V_tcbinfo); 58387aedea4SKip Macy INP_WUNLOCK(inp); 58487aedea4SKip Macy INP_INFO_WLOCK(&V_tcbinfo); 58587aedea4SKip Macy INP_WLOCK(inp); 586fa046d87SRobert Watson if (in_pcbrele_wlocked(inp)) { 58787aedea4SKip Macy INP_INFO_WUNLOCK(&V_tcbinfo); 58887aedea4SKip Macy CURVNET_RESTORE(); 58987aedea4SKip Macy return; 59087aedea4SKip Macy } 591aa4b09c5SNavdeep Parhar if (inp->inp_flags & INP_DROPPED) { 592aa4b09c5SNavdeep Parhar INP_WUNLOCK(inp); 593aa4b09c5SNavdeep Parhar INP_INFO_WUNLOCK(&V_tcbinfo); 594aa4b09c5SNavdeep Parhar CURVNET_RESTORE(); 595aa4b09c5SNavdeep Parhar return; 596aa4b09c5SNavdeep Parhar } 597aa4b09c5SNavdeep Parhar 59885d94372SRobert Watson tp = tcp_drop(tp, tp->t_softerror ? 59985d94372SRobert Watson tp->t_softerror : ETIMEDOUT); 60087aedea4SKip Macy headlocked = 1; 60185d94372SRobert Watson goto out; 6029b8b58e0SJonathan Lemon } 60387aedea4SKip Macy INP_INFO_RUNLOCK(&V_tcbinfo); 60485d94372SRobert Watson headlocked = 0; 605cf8f04f4SAndre Oppermann if (tp->t_state == TCPS_SYN_SENT) { 606cf8f04f4SAndre Oppermann /* 607cf8f04f4SAndre Oppermann * If the SYN was retransmitted, indicate CWND to be 608cf8f04f4SAndre Oppermann * limited to 1 segment in cc_conn_init(). 609cf8f04f4SAndre Oppermann */ 610cf8f04f4SAndre Oppermann tp->snd_cwnd = 1; 611cf8f04f4SAndre Oppermann } else if (tp->t_rxtshift == 1) { 6129b8b58e0SJonathan Lemon /* 6139b8b58e0SJonathan Lemon * first retransmit; record ssthresh and cwnd so they can 6149b8b58e0SJonathan Lemon * be recovered if this turns out to be a "bad" retransmit. 6159b8b58e0SJonathan Lemon * A retransmit is considered "bad" if an ACK for this 6169b8b58e0SJonathan Lemon * segment is received within RTT/2 interval; the assumption 6179b8b58e0SJonathan Lemon * here is that the ACK was already in flight. See 6189b8b58e0SJonathan Lemon * "On Estimating End-to-End Network Path Properties" by 6199b8b58e0SJonathan Lemon * Allman and Paxson for more details. 6209b8b58e0SJonathan Lemon */ 6219b8b58e0SJonathan Lemon tp->snd_cwnd_prev = tp->snd_cwnd; 6229b8b58e0SJonathan Lemon tp->snd_ssthresh_prev = tp->snd_ssthresh; 6239d11646dSJeffrey Hsu tp->snd_recover_prev = tp->snd_recover; 624dbc42409SLawrence Stewart if (IN_FASTRECOVERY(tp->t_flags)) 6259d11646dSJeffrey Hsu tp->t_flags |= TF_WASFRECOVERY; 6269d11646dSJeffrey Hsu else 6279d11646dSJeffrey Hsu tp->t_flags &= ~TF_WASFRECOVERY; 628dbc42409SLawrence Stewart if (IN_CONGRECOVERY(tp->t_flags)) 629dbc42409SLawrence Stewart tp->t_flags |= TF_WASCRECOVERY; 630dbc42409SLawrence Stewart else 631dbc42409SLawrence Stewart tp->t_flags &= ~TF_WASCRECOVERY; 6329b8b58e0SJonathan Lemon tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); 633672dc4aeSJohn Baldwin tp->t_flags |= TF_PREVVALID; 634672dc4aeSJohn Baldwin } else 635672dc4aeSJohn Baldwin tp->t_flags &= ~TF_PREVVALID; 63678b50714SRobert Watson TCPSTAT_INC(tcps_rexmttimeo); 6377d42e30cSJonathan Lemon if (tp->t_state == TCPS_SYN_SENT) 638f4748ef5SAndre Oppermann rexmt = TCPTV_RTOBASE * tcp_syn_backoff[tp->t_rxtshift]; 6397d42e30cSJonathan Lemon else 640df8bae1dSRodney W. Grimes rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; 641df8bae1dSRodney W. Grimes TCPT_RANGESET(tp->t_rxtcur, rexmt, 642df8bae1dSRodney W. Grimes tp->t_rttmin, TCPTV_REXMTMAX); 643df8bae1dSRodney W. Grimes /* 64477339e1cSAndre Oppermann * Disable RFC1323 and SACK if we haven't got any response to 6457ceb7783SJesper Skriver * our third SYN to work-around some broken terminal servers 6467ceb7783SJesper Skriver * (most of which have hopefully been retired) that have bad VJ 6477ceb7783SJesper Skriver * header compression code which trashes TCP segments containing 6487ceb7783SJesper Skriver * unknown-to-them TCP options. 6497ceb7783SJesper Skriver */ 6506c0ef895SJohn Baldwin if (tcp_rexmit_drop_options && (tp->t_state == TCPS_SYN_SENT) && 6516c0ef895SJohn Baldwin (tp->t_rxtshift == 3)) 652c4ab59c1SAndre Oppermann tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_SACK_PERMIT); 6537ceb7783SJesper Skriver /* 65497d8d152SAndre Oppermann * If we backed off this far, our srtt estimate is probably bogus. 65597d8d152SAndre Oppermann * Clobber it so we'll take the next rtt measurement as our srtt; 656df8bae1dSRodney W. Grimes * move the current srtt into rttvar to keep the current 657df8bae1dSRodney W. Grimes * retransmit times until then. 658df8bae1dSRodney W. Grimes */ 659df8bae1dSRodney W. Grimes if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { 660fb59c426SYoshinobu Inoue #ifdef INET6 661fb59c426SYoshinobu Inoue if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) 662fb59c426SYoshinobu Inoue in6_losing(tp->t_inpcb); 663fb59c426SYoshinobu Inoue #endif 664df8bae1dSRodney W. Grimes tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); 665df8bae1dSRodney W. Grimes tp->t_srtt = 0; 666df8bae1dSRodney W. Grimes } 667df8bae1dSRodney W. Grimes tp->snd_nxt = tp->snd_una; 6689d11646dSJeffrey Hsu tp->snd_recover = tp->snd_max; 66946f58482SJonathan Lemon /* 67074b48c1dSAndras Olah * Force a segment to be sent. 67174b48c1dSAndras Olah */ 67274b48c1dSAndras Olah tp->t_flags |= TF_ACKNOW; 67374b48c1dSAndras Olah /* 674df8bae1dSRodney W. Grimes * If timing a segment in this window, stop the timer. 675df8bae1dSRodney W. Grimes */ 6769b8b58e0SJonathan Lemon tp->t_rtttime = 0; 677dbc42409SLawrence Stewart 678b5af1b88SLawrence Stewart cc_cong_signal(tp, NULL, CC_RTO); 679dbc42409SLawrence Stewart 680df8bae1dSRodney W. Grimes (void) tcp_output(tp); 681df8bae1dSRodney W. Grimes 68285d94372SRobert Watson out: 6839b8b58e0SJonathan Lemon #ifdef TCPDEBUG 6841c53f806SRobert Watson if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 685fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 6869b8b58e0SJonathan Lemon PRU_SLOWTIMO); 687df8bae1dSRodney W. Grimes #endif 68885d94372SRobert Watson if (tp != NULL) 6898501a69cSRobert Watson INP_WUNLOCK(inp); 69085d94372SRobert Watson if (headlocked) 691603724d3SBjoern A. Zeeb INP_INFO_WUNLOCK(&V_tcbinfo); 6928b615593SMarko Zec CURVNET_RESTORE(); 69385d94372SRobert Watson } 69485d94372SRobert Watson 69585d94372SRobert Watson void 69685d94372SRobert Watson tcp_timer_activate(struct tcpcb *tp, int timer_type, u_int delta) 69785d94372SRobert Watson { 69885d94372SRobert Watson struct callout *t_callout; 69985d94372SRobert Watson void *f_callout; 70087aedea4SKip Macy struct inpcb *inp = tp->t_inpcb; 701883831c6SAdrian Chadd int cpu = inp_to_cpuid(inp); 70285d94372SRobert Watson 70309fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD 70409fe6320SNavdeep Parhar if (tp->t_flags & TF_TOE) 70509fe6320SNavdeep Parhar return; 70609fe6320SNavdeep Parhar #endif 70709fe6320SNavdeep Parhar 70885d94372SRobert Watson switch (timer_type) { 70985d94372SRobert Watson case TT_DELACK: 710e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 71185d94372SRobert Watson f_callout = tcp_timer_delack; 71285d94372SRobert Watson break; 71385d94372SRobert Watson case TT_REXMT: 714e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 71585d94372SRobert Watson f_callout = tcp_timer_rexmt; 71685d94372SRobert Watson break; 71785d94372SRobert Watson case TT_PERSIST: 718e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 71985d94372SRobert Watson f_callout = tcp_timer_persist; 72085d94372SRobert Watson break; 72185d94372SRobert Watson case TT_KEEP: 722e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 72385d94372SRobert Watson f_callout = tcp_timer_keep; 72485d94372SRobert Watson break; 72585d94372SRobert Watson case TT_2MSL: 726e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 72785d94372SRobert Watson f_callout = tcp_timer_2msl; 72885d94372SRobert Watson break; 72985d94372SRobert Watson default: 73085d94372SRobert Watson panic("bad timer_type"); 73185d94372SRobert Watson } 73285d94372SRobert Watson if (delta == 0) { 73385d94372SRobert Watson callout_stop(t_callout); 73485d94372SRobert Watson } else { 73587aedea4SKip Macy callout_reset_on(t_callout, delta, f_callout, tp, cpu); 73685d94372SRobert Watson } 73785d94372SRobert Watson } 73885d94372SRobert Watson 73985d94372SRobert Watson int 74085d94372SRobert Watson tcp_timer_active(struct tcpcb *tp, int timer_type) 74185d94372SRobert Watson { 74285d94372SRobert Watson struct callout *t_callout; 74385d94372SRobert Watson 74485d94372SRobert Watson switch (timer_type) { 74585d94372SRobert Watson case TT_DELACK: 746e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 74785d94372SRobert Watson break; 74885d94372SRobert Watson case TT_REXMT: 749e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 75085d94372SRobert Watson break; 75185d94372SRobert Watson case TT_PERSIST: 752e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 75385d94372SRobert Watson break; 75485d94372SRobert Watson case TT_KEEP: 755e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 75685d94372SRobert Watson break; 75785d94372SRobert Watson case TT_2MSL: 758e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 75985d94372SRobert Watson break; 76085d94372SRobert Watson default: 76185d94372SRobert Watson panic("bad timer_type"); 76285d94372SRobert Watson } 76385d94372SRobert Watson return callout_active(t_callout); 764df8bae1dSRodney W. Grimes } 765b8614722SMike Silbersack 766b8614722SMike Silbersack #define ticks_to_msecs(t) (1000*(t) / hz) 767b8614722SMike Silbersack 768b8614722SMike Silbersack void 7695b999a6bSDavide Italiano tcp_timer_to_xtimer(struct tcpcb *tp, struct tcp_timer *timer, 7705b999a6bSDavide Italiano struct xtcp_timer *xtimer) 771b8614722SMike Silbersack { 7725b999a6bSDavide Italiano sbintime_t now; 7735b999a6bSDavide Italiano 7745b999a6bSDavide Italiano bzero(xtimer, sizeof(*xtimer)); 775b8614722SMike Silbersack if (timer == NULL) 776b8614722SMike Silbersack return; 7775b999a6bSDavide Italiano now = getsbinuptime(); 778b8614722SMike Silbersack if (callout_active(&timer->tt_delack)) 7795b999a6bSDavide Italiano xtimer->tt_delack = (timer->tt_delack.c_time - now) / SBT_1MS; 780b8614722SMike Silbersack if (callout_active(&timer->tt_rexmt)) 7815b999a6bSDavide Italiano xtimer->tt_rexmt = (timer->tt_rexmt.c_time - now) / SBT_1MS; 782b8614722SMike Silbersack if (callout_active(&timer->tt_persist)) 7835b999a6bSDavide Italiano xtimer->tt_persist = (timer->tt_persist.c_time - now) / SBT_1MS; 784b8614722SMike Silbersack if (callout_active(&timer->tt_keep)) 7855b999a6bSDavide Italiano xtimer->tt_keep = (timer->tt_keep.c_time - now) / SBT_1MS; 786b8614722SMike Silbersack if (callout_active(&timer->tt_2msl)) 7875b999a6bSDavide Italiano xtimer->tt_2msl = (timer->tt_2msl.c_time - now) / SBT_1MS; 788b8614722SMike Silbersack xtimer->t_rcvtime = ticks_to_msecs(ticks - tp->t_rcvtime); 789b8614722SMike Silbersack } 790