1c398230bSWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4e79adb8eSGarrett Wollman * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 8df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 9df8bae1dSRodney W. Grimes * are met: 10df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 12df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 14df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 16df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 17df8bae1dSRodney W. Grimes * without specific prior written permission. 18df8bae1dSRodney W. Grimes * 19df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29df8bae1dSRodney W. Grimes * SUCH DAMAGE. 30df8bae1dSRodney W. Grimes * 31e79adb8eSGarrett Wollman * @(#)tcp_timer.c 8.2 (Berkeley) 5/24/95 32df8bae1dSRodney W. Grimes */ 33df8bae1dSRodney W. Grimes 344b421e2dSMike Silbersack #include <sys/cdefs.h> 354b421e2dSMike Silbersack __FBSDID("$FreeBSD$"); 364b421e2dSMike Silbersack 37825fd1e4SNavdeep Parhar #include "opt_inet.h" 38fb59c426SYoshinobu Inoue #include "opt_inet6.h" 390cc12cc5SJoerg Wunsch #include "opt_tcpdebug.h" 40883831c6SAdrian Chadd #include "opt_rss.h" 410cc12cc5SJoerg Wunsch 42df8bae1dSRodney W. Grimes #include <sys/param.h> 4398163b98SPoul-Henning Kamp #include <sys/kernel.h> 44c74af4faSBruce Evans #include <sys/lock.h> 4508517d53SMike Silbersack #include <sys/mbuf.h> 46c74af4faSBruce Evans #include <sys/mutex.h> 47c74af4faSBruce Evans #include <sys/protosw.h> 4887aedea4SKip Macy #include <sys/smp.h> 49df8bae1dSRodney W. Grimes #include <sys/socket.h> 50df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 51c74af4faSBruce Evans #include <sys/sysctl.h> 52c74af4faSBruce Evans #include <sys/systm.h> 53e79adb8eSGarrett Wollman 544b79449eSBjoern A. Zeeb #include <net/if.h> 55df8bae1dSRodney W. Grimes #include <net/route.h> 56b2bdc62aSAdrian Chadd #include <net/rss_config.h> 57530c0060SRobert Watson #include <net/vnet.h> 58883831c6SAdrian Chadd #include <net/netisr.h> 59df8bae1dSRodney W. Grimes 60df8bae1dSRodney W. Grimes #include <netinet/in.h> 615d06879aSGeorge V. Neville-Neil #include <netinet/in_kdtrace.h> 62df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 63883831c6SAdrian Chadd #include <netinet/in_rss.h> 64c74af4faSBruce Evans #include <netinet/in_systm.h> 65fb59c426SYoshinobu Inoue #ifdef INET6 66fb59c426SYoshinobu Inoue #include <netinet6/in6_pcb.h> 67fb59c426SYoshinobu Inoue #endif 68df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 692de3e790SGleb Smirnoff #include <netinet/tcp.h> 70df8bae1dSRodney W. Grimes #include <netinet/tcp_fsm.h> 712529f56eSJonathan T. Looney #include <netinet/tcp_log_buf.h> 72df8bae1dSRodney W. Grimes #include <netinet/tcp_timer.h> 73df8bae1dSRodney W. Grimes #include <netinet/tcp_var.h> 7489e560f4SRandall Stewart #include <netinet/tcp_seq.h> 754644fda3SGleb Smirnoff #include <netinet/cc/cc.h> 76f6f6703fSSean Bruno #ifdef INET6 77f6f6703fSSean Bruno #include <netinet6/tcp6_var.h> 78f6f6703fSSean Bruno #endif 79df8bae1dSRodney W. Grimes #include <netinet/tcpip.h> 80af7a2999SDavid Greenman #include <netinet/tcp_debug.h> 81df8bae1dSRodney W. Grimes 820645c604SHiren Panchasara int tcp_persmin; 837029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, persmin, 847029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 857029da5cSPawel Biernacki &tcp_persmin, 0, sysctl_msec_to_ticks, "I", 867029da5cSPawel Biernacki "minimum persistence interval"); 870645c604SHiren Panchasara 880645c604SHiren Panchasara int tcp_persmax; 897029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, persmax, 907029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 917029da5cSPawel Biernacki &tcp_persmax, 0, sysctl_msec_to_ticks, "I", 927029da5cSPawel Biernacki "maximum persistence interval"); 930645c604SHiren Panchasara 949b8b58e0SJonathan Lemon int tcp_keepinit; 957029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, 967029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 977029da5cSPawel Biernacki &tcp_keepinit, 0, sysctl_msec_to_ticks, "I", 987029da5cSPawel Biernacki "time to establish connection"); 997b40aa32SPaul Traina 1009b8b58e0SJonathan Lemon int tcp_keepidle; 1017029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, 1027029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1037029da5cSPawel Biernacki &tcp_keepidle, 0, sysctl_msec_to_ticks, "I", 1047029da5cSPawel Biernacki "time before keepalive probes begin"); 10598163b98SPoul-Henning Kamp 1069b8b58e0SJonathan Lemon int tcp_keepintvl; 1077029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, 1087029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1097029da5cSPawel Biernacki &tcp_keepintvl, 0, sysctl_msec_to_ticks, "I", 1107029da5cSPawel Biernacki "time between keepalive probes"); 11198163b98SPoul-Henning Kamp 1129b8b58e0SJonathan Lemon int tcp_delacktime; 1137029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, TCPCTL_DELACKTIME, delacktime, 1147029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1156489fe65SAndre Oppermann &tcp_delacktime, 0, sysctl_msec_to_ticks, "I", 116ccb4d0c6SJonathan Lemon "Time before a delayed ACK is sent"); 1179b8b58e0SJonathan Lemon 118c2c8e360SAlexander V. Chernikov VNET_DEFINE(int, tcp_msl); 1197029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl, 120c2c8e360SAlexander V. Chernikov CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_VNET, 121c2c8e360SAlexander V. Chernikov &VNET_NAME(tcp_msl), 0, sysctl_msec_to_ticks, "I", 1227029da5cSPawel Biernacki "Maximum segment lifetime"); 1239b8b58e0SJonathan Lemon 1240999766dSMichael Tuexen int tcp_rexmit_initial; 1257029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_initial, 1267029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1270999766dSMichael Tuexen &tcp_rexmit_initial, 0, sysctl_msec_to_ticks, "I", 1280999766dSMichael Tuexen "Initial Retransmission Timeout"); 1290999766dSMichael Tuexen 130701bec5aSMatthew Dillon int tcp_rexmit_min; 1317029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_min, 1327029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1336489fe65SAndre Oppermann &tcp_rexmit_min, 0, sysctl_msec_to_ticks, "I", 1346489fe65SAndre Oppermann "Minimum Retransmission Timeout"); 135701bec5aSMatthew Dillon 136701bec5aSMatthew Dillon int tcp_rexmit_slop; 1377029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_slop, 1387029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1396489fe65SAndre Oppermann &tcp_rexmit_slop, 0, sysctl_msec_to_ticks, "I", 1406489fe65SAndre Oppermann "Retransmission Timer Slop"); 141701bec5aSMatthew Dillon 142334fc582SBjoern A. Zeeb VNET_DEFINE(int, tcp_always_keepalive) = 1; 143334fc582SBjoern A. Zeeb SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_VNET|CTLFLAG_RW, 144334fc582SBjoern A. Zeeb &VNET_NAME(tcp_always_keepalive) , 0, 145334fc582SBjoern A. Zeeb "Assume SO_KEEPALIVE on all TCP connections"); 14634be9bf3SPoul-Henning Kamp 1477c72af87SMohan Srinivasan int tcp_fast_finwait2_recycle = 0; 1487c72af87SMohan Srinivasan SYSCTL_INT(_net_inet_tcp, OID_AUTO, fast_finwait2_recycle, CTLFLAG_RW, 1496489fe65SAndre Oppermann &tcp_fast_finwait2_recycle, 0, 1506489fe65SAndre Oppermann "Recycle closed FIN_WAIT_2 connections faster"); 1517c72af87SMohan Srinivasan 1527c72af87SMohan Srinivasan int tcp_finwait2_timeout; 1537029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, 1547029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1557029da5cSPawel Biernacki &tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", 1567029da5cSPawel Biernacki "FIN-WAIT2 timeout"); 1577c72af87SMohan Srinivasan 1589077f387SGleb Smirnoff int tcp_keepcnt = TCPTV_KEEPCNT; 1599077f387SGleb Smirnoff SYSCTL_INT(_net_inet_tcp, OID_AUTO, keepcnt, CTLFLAG_RW, &tcp_keepcnt, 0, 1609077f387SGleb Smirnoff "Number of keepalive probes to send"); 1617c72af87SMohan Srinivasan 1620312fbe9SPoul-Henning Kamp /* max idle probes */ 1639b8b58e0SJonathan Lemon int tcp_maxpersistidle; 164e79adb8eSGarrett Wollman 16589e560f4SRandall Stewart int tcp_rexmit_drop_options = 0; 1666c0ef895SJohn Baldwin SYSCTL_INT(_net_inet_tcp, OID_AUTO, rexmit_drop_options, CTLFLAG_RW, 1676c0ef895SJohn Baldwin &tcp_rexmit_drop_options, 0, 1686c0ef895SJohn Baldwin "Drop TCP options from 3rd and later retransmitted SYN"); 1696c0ef895SJohn Baldwin 17008af8aacSRandall Stewart int tcp_maxunacktime = TCPTV_MAXUNACKTIME; 17108af8aacSRandall Stewart SYSCTL_PROC(_net_inet_tcp, OID_AUTO, maxunacktime, 17208af8aacSRandall Stewart CTLTYPE_INT|CTLFLAG_RW | CTLFLAG_NEEDGIANT, 17308af8aacSRandall Stewart &tcp_maxunacktime, 0, sysctl_msec_to_ticks, "I", 17408af8aacSRandall Stewart "Maximum time (in ms) that a session can linger without making progress"); 17508af8aacSRandall Stewart 176e29c55e4SGleb Smirnoff VNET_DEFINE(int, tcp_pmtud_blackhole_detect); 177f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_detection, 178f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 179f6f6703fSSean Bruno &VNET_NAME(tcp_pmtud_blackhole_detect), 0, 180f6f6703fSSean Bruno "Path MTU Discovery Black Hole Detection Enabled"); 181f6f6703fSSean Bruno 182f6f6703fSSean Bruno #ifdef INET 183e29c55e4SGleb Smirnoff VNET_DEFINE(int, tcp_pmtud_blackhole_mss) = 1200; 184f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_mss, 185f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 186f6f6703fSSean Bruno &VNET_NAME(tcp_pmtud_blackhole_mss), 0, 187f6f6703fSSean Bruno "Path MTU Discovery Black Hole Detection lowered MSS"); 188f6f6703fSSean Bruno #endif 189f6f6703fSSean Bruno 190f6f6703fSSean Bruno #ifdef INET6 191e29c55e4SGleb Smirnoff VNET_DEFINE(int, tcp_v6pmtud_blackhole_mss) = 1220; 192f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, v6pmtud_blackhole_mss, 193f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 194f6f6703fSSean Bruno &VNET_NAME(tcp_v6pmtud_blackhole_mss), 0, 195f6f6703fSSean Bruno "Path MTU Discovery IPv6 Black Hole Detection lowered MSS"); 196f6f6703fSSean Bruno #endif 197f6f6703fSSean Bruno 1988f7e75cbSAdrian Chadd #ifdef RSS 1998f7e75cbSAdrian Chadd static int per_cpu_timers = 1; 2008f7e75cbSAdrian Chadd #else 20187aedea4SKip Macy static int per_cpu_timers = 0; 2028f7e75cbSAdrian Chadd #endif 20387aedea4SKip Macy SYSCTL_INT(_net_inet_tcp, OID_AUTO, per_cpu_timers, CTLFLAG_RW, 20487aedea4SKip Macy &per_cpu_timers , 0, "run tcp timers on all cpus"); 20587aedea4SKip Macy 206883831c6SAdrian Chadd /* 207883831c6SAdrian Chadd * Map the given inp to a CPU id. 208883831c6SAdrian Chadd * 209883831c6SAdrian Chadd * This queries RSS if it's compiled in, else it defaults to the current 210883831c6SAdrian Chadd * CPU ID. 211883831c6SAdrian Chadd */ 21289e560f4SRandall Stewart inline int 213883831c6SAdrian Chadd inp_to_cpuid(struct inpcb *inp) 214883831c6SAdrian Chadd { 215883831c6SAdrian Chadd u_int cpuid; 216883831c6SAdrian Chadd 217883831c6SAdrian Chadd if (per_cpu_timers) { 21847ded797SFranco Fichtner #ifdef RSS 219883831c6SAdrian Chadd cpuid = rss_hash2cpuid(inp->inp_flowid, inp->inp_flowtype); 220883831c6SAdrian Chadd if (cpuid == NETISR_CPUID_NONE) 221883831c6SAdrian Chadd return (curcpu); /* XXX */ 222883831c6SAdrian Chadd else 223883831c6SAdrian Chadd return (cpuid); 22447ded797SFranco Fichtner #endif 225883831c6SAdrian Chadd /* 226883831c6SAdrian Chadd * We don't have a flowid -> cpuid mapping, so cheat and 227883831c6SAdrian Chadd * just map unknown cpuids to curcpu. Not the best, but 228883831c6SAdrian Chadd * apparently better than defaulting to swi 0. 229883831c6SAdrian Chadd */ 230883831c6SAdrian Chadd cpuid = inp->inp_flowid % (mp_maxid + 1); 231883831c6SAdrian Chadd if (! CPU_ABSENT(cpuid)) 232883831c6SAdrian Chadd return (cpuid); 233883831c6SAdrian Chadd return (curcpu); 23447ded797SFranco Fichtner } else { 235883831c6SAdrian Chadd return (0); 236883831c6SAdrian Chadd } 237883831c6SAdrian Chadd } 23887aedea4SKip Macy 239df8bae1dSRodney W. Grimes int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 240f058535dSJeffrey Hsu { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 512, 512, 512 }; 241df8bae1dSRodney W. Grimes 24289e560f4SRandall Stewart int tcp_totbackoff = 2559; /* sum of tcp_backoff[] */ 243e79adb8eSGarrett Wollman 244df8bae1dSRodney W. Grimes /* 245df8bae1dSRodney W. Grimes * TCP timer processing. 246df8bae1dSRodney W. Grimes */ 24785d94372SRobert Watson 24885d94372SRobert Watson void 24985d94372SRobert Watson tcp_timer_delack(void *xtp) 250df8bae1dSRodney W. Grimes { 251109eb549SGleb Smirnoff struct epoch_tracker et; 25285d94372SRobert Watson struct tcpcb *tp = xtp; 253*9eb0e832SGleb Smirnoff #if defined(INVARIANTS) || defined(VIMAGE) 254*9eb0e832SGleb Smirnoff struct inpcb *inp = tptoinpcb(tp); 255*9eb0e832SGleb Smirnoff #endif 256*9eb0e832SGleb Smirnoff 2578b615593SMarko Zec CURVNET_SET(tp->t_vnet); 25885d94372SRobert Watson 2598501a69cSRobert Watson INP_WLOCK(inp); 260655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_delack) || 261655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_delack)) { 2628501a69cSRobert Watson INP_WUNLOCK(inp); 2638b615593SMarko Zec CURVNET_RESTORE(); 26485d94372SRobert Watson return; 26585d94372SRobert Watson } 266e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_delack); 267655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 268655f934bSMikolaj Golub INP_WUNLOCK(inp); 269655f934bSMikolaj Golub CURVNET_RESTORE(); 270655f934bSMikolaj Golub return; 271655f934bSMikolaj Golub } 2729b8b58e0SJonathan Lemon tp->t_flags |= TF_ACKNOW; 27378b50714SRobert Watson TCPSTAT_INC(tcps_delack); 274109eb549SGleb Smirnoff NET_EPOCH_ENTER(et); 275f64dc2abSGleb Smirnoff (void) tcp_output_unlock(tp); 276109eb549SGleb Smirnoff NET_EPOCH_EXIT(et); 2778b615593SMarko Zec CURVNET_RESTORE(); 2789b8b58e0SJonathan Lemon } 2799b8b58e0SJonathan Lemon 28077198a94SGleb Smirnoff /* 28177198a94SGleb Smirnoff * Call tcp_close() from a callout context. 28277198a94SGleb Smirnoff */ 28377198a94SGleb Smirnoff static void 28477198a94SGleb Smirnoff tcp_timer_close(struct tcpcb *tp) 285b07fef50SRandall Stewart { 28677198a94SGleb Smirnoff struct epoch_tracker et; 287*9eb0e832SGleb Smirnoff struct inpcb *inp = tptoinpcb(tp); 28877198a94SGleb Smirnoff 28977198a94SGleb Smirnoff INP_WLOCK_ASSERT(inp); 29077198a94SGleb Smirnoff 29177198a94SGleb Smirnoff NET_EPOCH_ENTER(et); 29277198a94SGleb Smirnoff tp = tcp_close(tp); 29377198a94SGleb Smirnoff NET_EPOCH_EXIT(et); 29477198a94SGleb Smirnoff if (tp != NULL) 29577198a94SGleb Smirnoff INP_WUNLOCK(inp); 29677198a94SGleb Smirnoff } 29777198a94SGleb Smirnoff 29877198a94SGleb Smirnoff /* 29977198a94SGleb Smirnoff * Call tcp_drop() from a callout context. 30077198a94SGleb Smirnoff */ 30177198a94SGleb Smirnoff static void 30277198a94SGleb Smirnoff tcp_timer_drop(struct tcpcb *tp) 30377198a94SGleb Smirnoff { 30477198a94SGleb Smirnoff struct epoch_tracker et; 305*9eb0e832SGleb Smirnoff struct inpcb *inp = tptoinpcb(tp); 30677198a94SGleb Smirnoff 30777198a94SGleb Smirnoff INP_WLOCK_ASSERT(inp); 30877198a94SGleb Smirnoff 30977198a94SGleb Smirnoff NET_EPOCH_ENTER(et); 31077198a94SGleb Smirnoff tp = tcp_drop(tp, ETIMEDOUT); 31177198a94SGleb Smirnoff NET_EPOCH_EXIT(et); 31277198a94SGleb Smirnoff if (tp != NULL) 313b07fef50SRandall Stewart INP_WUNLOCK(inp); 314b07fef50SRandall Stewart } 315b07fef50SRandall Stewart 31685d94372SRobert Watson void 31785d94372SRobert Watson tcp_timer_2msl(void *xtp) 3189b8b58e0SJonathan Lemon { 31985d94372SRobert Watson struct tcpcb *tp = xtp; 320*9eb0e832SGleb Smirnoff struct inpcb *inp = tptoinpcb(tp); 3218b615593SMarko Zec CURVNET_SET(tp->t_vnet); 3229b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3239b8b58e0SJonathan Lemon int ostate; 3249b8b58e0SJonathan Lemon 3259b8b58e0SJonathan Lemon ostate = tp->t_state; 3269b8b58e0SJonathan Lemon #endif 327*9eb0e832SGleb Smirnoff 3288501a69cSRobert Watson INP_WLOCK(inp); 329d1b07f36SRandall Stewart tcp_log_end_status(tp, TCP_EI_STATUS_2MSL); 33085d94372SRobert Watson tcp_free_sackholes(tp); 331655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_2msl) || 332e2f2059fSMike Silbersack !callout_active(&tp->t_timers->tt_2msl)) { 333*9eb0e832SGleb Smirnoff INP_WUNLOCK(inp); 3348b615593SMarko Zec CURVNET_RESTORE(); 33585d94372SRobert Watson return; 33685d94372SRobert Watson } 337e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_2msl); 33853af6903SGleb Smirnoff if (inp->inp_flags & INP_DROPPED) { 339655f934bSMikolaj Golub INP_WUNLOCK(inp); 340655f934bSMikolaj Golub CURVNET_RESTORE(); 341655f934bSMikolaj Golub return; 342655f934bSMikolaj Golub } 3435571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 3445571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 34585d94372SRobert Watson /* 346df8bae1dSRodney W. Grimes * 2 MSL timeout in shutdown went off. If we're closed but 347df8bae1dSRodney W. Grimes * still waiting for peer to close and connection has been idle 34831a7749dSJulien Charbon * too long delete connection control block. Otherwise, check 34931a7749dSJulien Charbon * again in a bit. 35031a7749dSJulien Charbon * 3517c72af87SMohan Srinivasan * If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, 3527c72af87SMohan Srinivasan * there's no point in hanging onto FIN_WAIT_2 socket. Just close it. 3537c72af87SMohan Srinivasan * Ignore fact that there were recent incoming segments. 354f71cb9f7SGleb Smirnoff * 355f71cb9f7SGleb Smirnoff * XXXGL: check if inp_socket shall always be !NULL here? 356df8bae1dSRodney W. Grimes */ 3570d744519SGleb Smirnoff if (tp->t_state == TCPS_TIME_WAIT) { 3580d744519SGleb Smirnoff tcp_timer_close(tp); 3590d744519SGleb Smirnoff CURVNET_RESTORE(); 3600d744519SGleb Smirnoff return; 3610d744519SGleb Smirnoff } else if (tp->t_state == TCPS_FIN_WAIT_2 && 362*9eb0e832SGleb Smirnoff tcp_fast_finwait2_recycle && inp->inp_socket && 363*9eb0e832SGleb Smirnoff (inp->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { 36478b50714SRobert Watson TCPSTAT_INC(tcps_finwait2_drops); 36577198a94SGleb Smirnoff tcp_timer_close(tp); 36677198a94SGleb Smirnoff CURVNET_RESTORE(); 36777198a94SGleb Smirnoff return; 3687c72af87SMohan Srinivasan } else { 369d6de19acSJulien Charbon if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) { 370b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_2msl, 371b07fef50SRandall Stewart TP_KEEPINTVL(tp), tcp_timer_2msl, tp); 372b07fef50SRandall Stewart } else { 37377198a94SGleb Smirnoff tcp_timer_close(tp); 37477198a94SGleb Smirnoff CURVNET_RESTORE(); 37577198a94SGleb Smirnoff return; 376b07fef50SRandall Stewart } 3777c72af87SMohan Srinivasan } 378df8bae1dSRodney W. Grimes 3799b8b58e0SJonathan Lemon #ifdef TCPDEBUG 380*9eb0e832SGleb Smirnoff if (tptosocket(tp)->so_options & SO_DEBUG) 381fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 3829b8b58e0SJonathan Lemon PRU_SLOWTIMO); 3839b8b58e0SJonathan Lemon #endif 3845d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 3855d06879aSGeorge V. Neville-Neil 3868501a69cSRobert Watson INP_WUNLOCK(inp); 3878b615593SMarko Zec CURVNET_RESTORE(); 3889b8b58e0SJonathan Lemon } 3899b8b58e0SJonathan Lemon 39085d94372SRobert Watson void 39185d94372SRobert Watson tcp_timer_keep(void *xtp) 3929b8b58e0SJonathan Lemon { 3936573d758SMatt Macy struct epoch_tracker et; 394*9eb0e832SGleb Smirnoff struct tcpcb *tp = xtp; 395*9eb0e832SGleb Smirnoff struct inpcb *inp = tptoinpcb(tp); 396*9eb0e832SGleb Smirnoff struct tcptemp *t_template; 3978b615593SMarko Zec CURVNET_SET(tp->t_vnet); 3989b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3999b8b58e0SJonathan Lemon int ostate; 4009b8b58e0SJonathan Lemon 4019b8b58e0SJonathan Lemon ostate = tp->t_state; 4029b8b58e0SJonathan Lemon #endif 403*9eb0e832SGleb Smirnoff 4048501a69cSRobert Watson INP_WLOCK(inp); 405655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_keep) || 406655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_keep)) { 4078501a69cSRobert Watson INP_WUNLOCK(inp); 4088b615593SMarko Zec CURVNET_RESTORE(); 40985d94372SRobert Watson return; 41085d94372SRobert Watson } 411e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_keep); 41253af6903SGleb Smirnoff if (inp->inp_flags & INP_DROPPED) { 413655f934bSMikolaj Golub INP_WUNLOCK(inp); 414655f934bSMikolaj Golub CURVNET_RESTORE(); 415655f934bSMikolaj Golub return; 416655f934bSMikolaj Golub } 4175571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 4185571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 4196d172f58SJonathan T. Looney 4206d172f58SJonathan T. Looney /* 4216d172f58SJonathan T. Looney * Because we don't regularly reset the keepalive callout in 4226d172f58SJonathan T. Looney * the ESTABLISHED state, it may be that we don't actually need 4236d172f58SJonathan T. Looney * to send a keepalive yet. If that occurs, schedule another 4246d172f58SJonathan T. Looney * call for the next time the keepalive timer might expire. 4256d172f58SJonathan T. Looney */ 4266d172f58SJonathan T. Looney if (TCPS_HAVEESTABLISHED(tp->t_state)) { 4276d172f58SJonathan T. Looney u_int idletime; 4286d172f58SJonathan T. Looney 4296d172f58SJonathan T. Looney idletime = ticks - tp->t_rcvtime; 4306d172f58SJonathan T. Looney if (idletime < TP_KEEPIDLE(tp)) { 4316d172f58SJonathan T. Looney callout_reset(&tp->t_timers->tt_keep, 4326d172f58SJonathan T. Looney TP_KEEPIDLE(tp) - idletime, tcp_timer_keep, tp); 4336d172f58SJonathan T. Looney INP_WUNLOCK(inp); 4346d172f58SJonathan T. Looney CURVNET_RESTORE(); 4356d172f58SJonathan T. Looney return; 4366d172f58SJonathan T. Looney } 4376d172f58SJonathan T. Looney } 4386d172f58SJonathan T. Looney 4399b8b58e0SJonathan Lemon /* 4409b8b58e0SJonathan Lemon * Keep-alive timer went off; send something 4419b8b58e0SJonathan Lemon * or drop connection if idle for too long. 4429b8b58e0SJonathan Lemon */ 44378b50714SRobert Watson TCPSTAT_INC(tcps_keeptimeo); 4449b8b58e0SJonathan Lemon if (tp->t_state < TCPS_ESTABLISHED) 4459b8b58e0SJonathan Lemon goto dropit; 446334fc582SBjoern A. Zeeb if ((V_tcp_always_keepalive || 447f1798531SJohn Baldwin inp->inp_socket->so_options & SO_KEEPALIVE) && 4489b8b58e0SJonathan Lemon tp->t_state <= TCPS_CLOSING) { 4499077f387SGleb Smirnoff if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp)) 4509b8b58e0SJonathan Lemon goto dropit; 4519b8b58e0SJonathan Lemon /* 4529b8b58e0SJonathan Lemon * Send a packet designed to force a response 4539b8b58e0SJonathan Lemon * if the peer is up and reachable: 4549b8b58e0SJonathan Lemon * either an ACK if the connection is still alive, 4559b8b58e0SJonathan Lemon * or an RST if the peer has closed the connection 4569b8b58e0SJonathan Lemon * due to timeout or reboot. 4579b8b58e0SJonathan Lemon * Using sequence number tp->snd_una-1 4589b8b58e0SJonathan Lemon * causes the transmitted zero-length segment 4599b8b58e0SJonathan Lemon * to lie outside the receive window; 4609b8b58e0SJonathan Lemon * by the protocol spec, this requires the 4619b8b58e0SJonathan Lemon * correspondent TCP to respond. 4629b8b58e0SJonathan Lemon */ 46378b50714SRobert Watson TCPSTAT_INC(tcps_keepprobe); 46479909384SJonathan Lemon t_template = tcpip_maketemplate(inp); 46508517d53SMike Silbersack if (t_template) { 466b9555453SGleb Smirnoff NET_EPOCH_ENTER(et); 46708517d53SMike Silbersack tcp_respond(tp, t_template->tt_ipgen, 46808517d53SMike Silbersack &t_template->tt_t, (struct mbuf *)NULL, 4699b8b58e0SJonathan Lemon tp->rcv_nxt, tp->snd_una - 1, 0); 470b9555453SGleb Smirnoff NET_EPOCH_EXIT(et); 47153640b0eSRobert Watson free(t_template, M_TEMP); 47208517d53SMike Silbersack } 473b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_keep, TP_KEEPINTVL(tp), 474b07fef50SRandall Stewart tcp_timer_keep, tp); 475b07fef50SRandall Stewart } else 476b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_keep, TP_KEEPIDLE(tp), 477b07fef50SRandall Stewart tcp_timer_keep, tp); 4789b8b58e0SJonathan Lemon 4799b8b58e0SJonathan Lemon #ifdef TCPDEBUG 4802a074620SSam Leffler if (inp->inp_socket->so_options & SO_DEBUG) 481fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 4829b8b58e0SJonathan Lemon PRU_SLOWTIMO); 4839b8b58e0SJonathan Lemon #endif 4845d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 4858501a69cSRobert Watson INP_WUNLOCK(inp); 4868b615593SMarko Zec CURVNET_RESTORE(); 48785d94372SRobert Watson return; 4889b8b58e0SJonathan Lemon 4899b8b58e0SJonathan Lemon dropit: 49078b50714SRobert Watson TCPSTAT_INC(tcps_keepdrops); 49158d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 492d1b07f36SRandall Stewart tcp_log_end_status(tp, TCP_EI_STATUS_KEEP_MAX); 49385d94372SRobert Watson tp = tcp_drop(tp, ETIMEDOUT); 49485d94372SRobert Watson 49585d94372SRobert Watson #ifdef TCPDEBUG 496*9eb0e832SGleb Smirnoff if (tp != NULL && (tptosocket(tp)->so_options & SO_DEBUG)) 49785d94372SRobert Watson tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 49885d94372SRobert Watson PRU_SLOWTIMO); 49985d94372SRobert Watson #endif 5005d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 50158d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 50277198a94SGleb Smirnoff if (tp != NULL) 50377198a94SGleb Smirnoff INP_WUNLOCK(inp); 5048b615593SMarko Zec CURVNET_RESTORE(); 5059b8b58e0SJonathan Lemon } 5069b8b58e0SJonathan Lemon 50708af8aacSRandall Stewart /* 50808af8aacSRandall Stewart * Has this session exceeded the maximum time without seeing a substantive 50908af8aacSRandall Stewart * acknowledgement? If so, return true; otherwise false. 51008af8aacSRandall Stewart */ 51108af8aacSRandall Stewart static bool 51208af8aacSRandall Stewart tcp_maxunacktime_check(struct tcpcb *tp) 51308af8aacSRandall Stewart { 51408af8aacSRandall Stewart 51508af8aacSRandall Stewart /* Are we tracking this timer for this session? */ 51608af8aacSRandall Stewart if (TP_MAXUNACKTIME(tp) == 0) 51708af8aacSRandall Stewart return false; 51808af8aacSRandall Stewart 51908af8aacSRandall Stewart /* Do we have a current measurement. */ 52008af8aacSRandall Stewart if (tp->t_acktime == 0) 52108af8aacSRandall Stewart return false; 52208af8aacSRandall Stewart 52308af8aacSRandall Stewart /* Are we within the acceptable range? */ 52408af8aacSRandall Stewart if (TSTMP_GT(TP_MAXUNACKTIME(tp) + tp->t_acktime, (u_int)ticks)) 52508af8aacSRandall Stewart return false; 52608af8aacSRandall Stewart 52708af8aacSRandall Stewart /* We exceeded the timer. */ 52808af8aacSRandall Stewart TCPSTAT_INC(tcps_progdrops); 52908af8aacSRandall Stewart return true; 53008af8aacSRandall Stewart } 53108af8aacSRandall Stewart 53285d94372SRobert Watson void 53385d94372SRobert Watson tcp_timer_persist(void *xtp) 5349b8b58e0SJonathan Lemon { 5356573d758SMatt Macy struct epoch_tracker et; 536*9eb0e832SGleb Smirnoff struct tcpcb *tp = xtp; 537*9eb0e832SGleb Smirnoff #if defined(INVARIANTS) || defined(VIMAGE) 538*9eb0e832SGleb Smirnoff struct inpcb *inp = tptoinpcb(tp); 539*9eb0e832SGleb Smirnoff #endif 54008af8aacSRandall Stewart bool progdrop; 541f64dc2abSGleb Smirnoff int outrv; 5428b615593SMarko Zec CURVNET_SET(tp->t_vnet); 5439b8b58e0SJonathan Lemon #ifdef TCPDEBUG 5449b8b58e0SJonathan Lemon int ostate; 5459b8b58e0SJonathan Lemon 5469b8b58e0SJonathan Lemon ostate = tp->t_state; 5479b8b58e0SJonathan Lemon #endif 548*9eb0e832SGleb Smirnoff 5498501a69cSRobert Watson INP_WLOCK(inp); 550655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_persist) || 551655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_persist)) { 5528501a69cSRobert Watson INP_WUNLOCK(inp); 5538b615593SMarko Zec CURVNET_RESTORE(); 55485d94372SRobert Watson return; 55585d94372SRobert Watson } 556e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_persist); 55753af6903SGleb Smirnoff if (inp->inp_flags & INP_DROPPED) { 558655f934bSMikolaj Golub INP_WUNLOCK(inp); 559655f934bSMikolaj Golub CURVNET_RESTORE(); 560655f934bSMikolaj Golub return; 561655f934bSMikolaj Golub } 5625571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 5635571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 5649b8b58e0SJonathan Lemon /* 565a4641f4eSPedro F. Giffuni * Persistence timer into zero window. 5669b8b58e0SJonathan Lemon * Force a byte to be output, if possible. 5679b8b58e0SJonathan Lemon */ 56878b50714SRobert Watson TCPSTAT_INC(tcps_persisttimeo); 5699b8b58e0SJonathan Lemon /* 5709b8b58e0SJonathan Lemon * Hack: if the peer is dead/unreachable, we do not 5719b8b58e0SJonathan Lemon * time out if the window is closed. After a full 5729b8b58e0SJonathan Lemon * backoff, drop the connection if the idle time 5739b8b58e0SJonathan Lemon * (no responses to probes) reaches the maximum 5749b8b58e0SJonathan Lemon * backoff that we would use if retransmitting. 57508af8aacSRandall Stewart * Also, drop the connection if we haven't been making 57608af8aacSRandall Stewart * progress. 5779b8b58e0SJonathan Lemon */ 57808af8aacSRandall Stewart progdrop = tcp_maxunacktime_check(tp); 57908af8aacSRandall Stewart if (progdrop || (tp->t_rxtshift == TCP_MAXRXTSHIFT && 5806b0c5521SJohn Baldwin (ticks - tp->t_rcvtime >= tcp_maxpersistidle || 58108af8aacSRandall Stewart ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff))) { 58208af8aacSRandall Stewart if (!progdrop) 58378b50714SRobert Watson TCPSTAT_INC(tcps_persistdrop); 584d1b07f36SRandall Stewart tcp_log_end_status(tp, TCP_EI_STATUS_PERSIST_MAX); 58577198a94SGleb Smirnoff tcp_timer_drop(tp); 58677198a94SGleb Smirnoff CURVNET_RESTORE(); 58777198a94SGleb Smirnoff return; 5889b8b58e0SJonathan Lemon } 589322181c9SAndre Oppermann /* 590322181c9SAndre Oppermann * If the user has closed the socket then drop a persisting 591322181c9SAndre Oppermann * connection after a much reduced timeout. 592322181c9SAndre Oppermann */ 593322181c9SAndre Oppermann if (tp->t_state > TCPS_CLOSE_WAIT && 594322181c9SAndre Oppermann (ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) { 595322181c9SAndre Oppermann TCPSTAT_INC(tcps_persistdrop); 596d1b07f36SRandall Stewart tcp_log_end_status(tp, TCP_EI_STATUS_PERSIST_MAX); 59777198a94SGleb Smirnoff tcp_timer_drop(tp); 59877198a94SGleb Smirnoff CURVNET_RESTORE(); 59977198a94SGleb Smirnoff return; 600322181c9SAndre Oppermann } 6019b8b58e0SJonathan Lemon tcp_setpersist(tp); 6022cdbfa66SPaul Saab tp->t_flags |= TF_FORCEDATA; 603109eb549SGleb Smirnoff NET_EPOCH_ENTER(et); 604f64dc2abSGleb Smirnoff outrv = tcp_output_nodrop(tp); 6052cdbfa66SPaul Saab tp->t_flags &= ~TF_FORCEDATA; 6069b8b58e0SJonathan Lemon 6079b8b58e0SJonathan Lemon #ifdef TCPDEBUG 608*9eb0e832SGleb Smirnoff if (tp != NULL && tptosocket(tp)->so_options & SO_DEBUG) 609ffb761f6SGleb Smirnoff tcp_trace(TA_USER, ostate, tp, NULL, NULL, PRU_SLOWTIMO); 6109b8b58e0SJonathan Lemon #endif 6115d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 612f64dc2abSGleb Smirnoff (void) tcp_unlock_or_drop(tp, outrv); 613f64dc2abSGleb Smirnoff NET_EPOCH_EXIT(et); 6148b615593SMarko Zec CURVNET_RESTORE(); 6159b8b58e0SJonathan Lemon } 6169b8b58e0SJonathan Lemon 61785d94372SRobert Watson void 61885d94372SRobert Watson tcp_timer_rexmt(void * xtp) 6199b8b58e0SJonathan Lemon { 620*9eb0e832SGleb Smirnoff struct epoch_tracker et; 62185d94372SRobert Watson struct tcpcb *tp = xtp; 6228b615593SMarko Zec CURVNET_SET(tp->t_vnet); 623*9eb0e832SGleb Smirnoff struct inpcb *inp = tptoinpcb(tp); 624f64dc2abSGleb Smirnoff int rexmt, outrv; 625413c3db1SMichael Tuexen bool isipv6; 6269b8b58e0SJonathan Lemon #ifdef TCPDEBUG 6279b8b58e0SJonathan Lemon int ostate; 6289b8b58e0SJonathan Lemon 6299b8b58e0SJonathan Lemon ostate = tp->t_state; 6309b8b58e0SJonathan Lemon #endif 631*9eb0e832SGleb Smirnoff 6328501a69cSRobert Watson INP_WLOCK(inp); 633655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_rexmt) || 634655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_rexmt)) { 6358501a69cSRobert Watson INP_WUNLOCK(inp); 6368b615593SMarko Zec CURVNET_RESTORE(); 63785d94372SRobert Watson return; 63885d94372SRobert Watson } 639e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_rexmt); 64053af6903SGleb Smirnoff if (inp->inp_flags & INP_DROPPED) { 641655f934bSMikolaj Golub INP_WUNLOCK(inp); 642655f934bSMikolaj Golub CURVNET_RESTORE(); 643655f934bSMikolaj Golub return; 644655f934bSMikolaj Golub } 6455571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 6465571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 6476d90faf3SPaul Saab tcp_free_sackholes(tp); 6482529f56eSJonathan T. Looney TCP_LOG_EVENT(tp, NULL, NULL, NULL, TCP_LOG_RTO, 0, 0, NULL, false); 6495105a92cSRandall Stewart if (tp->t_fb->tfb_tcp_rexmit_tmr) { 6505105a92cSRandall Stewart /* The stack has a timer action too. */ 6515105a92cSRandall Stewart (*tp->t_fb->tfb_tcp_rexmit_tmr)(tp); 6525105a92cSRandall Stewart } 653df8bae1dSRodney W. Grimes /* 654df8bae1dSRodney W. Grimes * Retransmission timer went off. Message has not 655df8bae1dSRodney W. Grimes * been acked within retransmit interval. Back off 656df8bae1dSRodney W. Grimes * to a longer retransmit interval and retransmit one segment. 65708af8aacSRandall Stewart * 65808af8aacSRandall Stewart * If we've either exceeded the maximum number of retransmissions, 65908af8aacSRandall Stewart * or we've gone long enough without making progress, then drop 66008af8aacSRandall Stewart * the session. 661df8bae1dSRodney W. Grimes */ 66208af8aacSRandall Stewart if (++tp->t_rxtshift > TCP_MAXRXTSHIFT || tcp_maxunacktime_check(tp)) { 66308af8aacSRandall Stewart if (tp->t_rxtshift > TCP_MAXRXTSHIFT) 66478b50714SRobert Watson TCPSTAT_INC(tcps_timeoutdrop); 66508af8aacSRandall Stewart tp->t_rxtshift = TCP_MAXRXTSHIFT; 666d1b07f36SRandall Stewart tcp_log_end_status(tp, TCP_EI_STATUS_RETRAN); 66777198a94SGleb Smirnoff tcp_timer_drop(tp); 66877198a94SGleb Smirnoff CURVNET_RESTORE(); 66977198a94SGleb Smirnoff return; 670b07fef50SRandall Stewart } 671cf8f04f4SAndre Oppermann if (tp->t_state == TCPS_SYN_SENT) { 672cf8f04f4SAndre Oppermann /* 673cf8f04f4SAndre Oppermann * If the SYN was retransmitted, indicate CWND to be 674cf8f04f4SAndre Oppermann * limited to 1 segment in cc_conn_init(). 675cf8f04f4SAndre Oppermann */ 676cf8f04f4SAndre Oppermann tp->snd_cwnd = 1; 677cf8f04f4SAndre Oppermann } else if (tp->t_rxtshift == 1) { 6789b8b58e0SJonathan Lemon /* 6799b8b58e0SJonathan Lemon * first retransmit; record ssthresh and cwnd so they can 6809b8b58e0SJonathan Lemon * be recovered if this turns out to be a "bad" retransmit. 6819b8b58e0SJonathan Lemon * A retransmit is considered "bad" if an ACK for this 6829b8b58e0SJonathan Lemon * segment is received within RTT/2 interval; the assumption 6839b8b58e0SJonathan Lemon * here is that the ACK was already in flight. See 6849b8b58e0SJonathan Lemon * "On Estimating End-to-End Network Path Properties" by 6859b8b58e0SJonathan Lemon * Allman and Paxson for more details. 6869b8b58e0SJonathan Lemon */ 6879b8b58e0SJonathan Lemon tp->snd_cwnd_prev = tp->snd_cwnd; 6889b8b58e0SJonathan Lemon tp->snd_ssthresh_prev = tp->snd_ssthresh; 6899d11646dSJeffrey Hsu tp->snd_recover_prev = tp->snd_recover; 690dbc42409SLawrence Stewart if (IN_FASTRECOVERY(tp->t_flags)) 6919d11646dSJeffrey Hsu tp->t_flags |= TF_WASFRECOVERY; 6929d11646dSJeffrey Hsu else 6939d11646dSJeffrey Hsu tp->t_flags &= ~TF_WASFRECOVERY; 694dbc42409SLawrence Stewart if (IN_CONGRECOVERY(tp->t_flags)) 695dbc42409SLawrence Stewart tp->t_flags |= TF_WASCRECOVERY; 696dbc42409SLawrence Stewart else 697dbc42409SLawrence Stewart tp->t_flags &= ~TF_WASCRECOVERY; 69810d20c84SMatt Macy if ((tp->t_flags & TF_RCVD_TSTMP) == 0) 6999b8b58e0SJonathan Lemon tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); 70010d20c84SMatt Macy /* In the event that we've negotiated timestamps 70110d20c84SMatt Macy * badrxtwin will be set to the value that we set 70210d20c84SMatt Macy * the retransmitted packet's to_tsval to by tcp_output 70310d20c84SMatt Macy */ 704672dc4aeSJohn Baldwin tp->t_flags |= TF_PREVVALID; 705672dc4aeSJohn Baldwin } else 706672dc4aeSJohn Baldwin tp->t_flags &= ~TF_PREVVALID; 70778b50714SRobert Watson TCPSTAT_INC(tcps_rexmttimeo); 708281a0fd4SPatrick Kelsey if ((tp->t_state == TCPS_SYN_SENT) || 709281a0fd4SPatrick Kelsey (tp->t_state == TCPS_SYN_RECEIVED)) 7100999766dSMichael Tuexen rexmt = tcp_rexmit_initial * tcp_backoff[tp->t_rxtshift]; 7117d42e30cSJonathan Lemon else 712df8bae1dSRodney W. Grimes rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; 713df8bae1dSRodney W. Grimes TCPT_RANGESET(tp->t_rxtcur, rexmt, 714df8bae1dSRodney W. Grimes tp->t_rttmin, TCPTV_REXMTMAX); 715f6f6703fSSean Bruno 716882ac53eSSean Bruno /* 717882ac53eSSean Bruno * We enter the path for PLMTUD if connection is established or, if 718882ac53eSSean Bruno * connection is FIN_WAIT_1 status, reason for the last is that if 719882ac53eSSean Bruno * amount of data we send is very small, we could send it in couple of 720882ac53eSSean Bruno * packets and process straight to FIN. In that case we won't catch 721882ac53eSSean Bruno * ESTABLISHED state. 722882ac53eSSean Bruno */ 723f6f6703fSSean Bruno #ifdef INET6 724*9eb0e832SGleb Smirnoff isipv6 = (inp->inp_vflag & INP_IPV6) ? true : false; 725413c3db1SMichael Tuexen #else 726413c3db1SMichael Tuexen isipv6 = false; 727f6f6703fSSean Bruno #endif 728413c3db1SMichael Tuexen if (((V_tcp_pmtud_blackhole_detect == 1) || 729413c3db1SMichael Tuexen (V_tcp_pmtud_blackhole_detect == 2 && !isipv6) || 730413c3db1SMichael Tuexen (V_tcp_pmtud_blackhole_detect == 3 && isipv6)) && 731413c3db1SMichael Tuexen ((tp->t_state == TCPS_ESTABLISHED) || 732413c3db1SMichael Tuexen (tp->t_state == TCPS_FIN_WAIT_1))) { 733b89af8e1SMichael Tuexen if (tp->t_rxtshift == 1) { 734adf43a92SHiren Panchasara /* 735b89af8e1SMichael Tuexen * We enter blackhole detection after the first 736b89af8e1SMichael Tuexen * unsuccessful timer based retransmission. 737b89af8e1SMichael Tuexen * Then we reduce up to two times the MSS, each 738b89af8e1SMichael Tuexen * candidate giving two tries of retransmissions. 739b89af8e1SMichael Tuexen * But we give a candidate only two tries, if it 740b89af8e1SMichael Tuexen * actually reduces the MSS. 741adf43a92SHiren Panchasara */ 742b89af8e1SMichael Tuexen tp->t_blackhole_enter = 2; 743b89af8e1SMichael Tuexen tp->t_blackhole_exit = tp->t_blackhole_enter; 744b89af8e1SMichael Tuexen if (isipv6) { 745b89af8e1SMichael Tuexen #ifdef INET6 746b89af8e1SMichael Tuexen if (tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss) 747b89af8e1SMichael Tuexen tp->t_blackhole_exit += 2; 748b89af8e1SMichael Tuexen if (tp->t_maxseg > V_tcp_v6mssdflt && 749b89af8e1SMichael Tuexen V_tcp_v6pmtud_blackhole_mss > V_tcp_v6mssdflt) 750b89af8e1SMichael Tuexen tp->t_blackhole_exit += 2; 751b89af8e1SMichael Tuexen #endif 752b89af8e1SMichael Tuexen } else { 753b89af8e1SMichael Tuexen #ifdef INET 754b89af8e1SMichael Tuexen if (tp->t_maxseg > V_tcp_pmtud_blackhole_mss) 755b89af8e1SMichael Tuexen tp->t_blackhole_exit += 2; 756b89af8e1SMichael Tuexen if (tp->t_maxseg > V_tcp_mssdflt && 757b89af8e1SMichael Tuexen V_tcp_pmtud_blackhole_mss > V_tcp_mssdflt) 758b89af8e1SMichael Tuexen tp->t_blackhole_exit += 2; 759b89af8e1SMichael Tuexen #endif 760b89af8e1SMichael Tuexen } 761b89af8e1SMichael Tuexen } 762f6f6703fSSean Bruno if (((tp->t_flags2 & (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) == 763f6f6703fSSean Bruno (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) && 764b89af8e1SMichael Tuexen (tp->t_rxtshift >= tp->t_blackhole_enter && 765b89af8e1SMichael Tuexen tp->t_rxtshift < tp->t_blackhole_exit && 766b89af8e1SMichael Tuexen (tp->t_rxtshift - tp->t_blackhole_enter) % 2 == 0)) { 767f6f6703fSSean Bruno /* 768f6f6703fSSean Bruno * Enter Path MTU Black-hole Detection mechanism: 769f6f6703fSSean Bruno * - Disable Path MTU Discovery (IP "DF" bit). 770f6f6703fSSean Bruno * - Reduce MTU to lower value than what we 771f6f6703fSSean Bruno * negotiated with peer. 772f6f6703fSSean Bruno */ 7733d5af7a1SMichael Tuexen if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) == 0) { 774f6f6703fSSean Bruno /* Record that we may have found a black hole. */ 775f6f6703fSSean Bruno tp->t_flags2 |= TF2_PLPMTU_BLACKHOLE; 776f6f6703fSSean Bruno /* Keep track of previous MSS. */ 7770c39d38dSGleb Smirnoff tp->t_pmtud_saved_maxseg = tp->t_maxseg; 7783d5af7a1SMichael Tuexen } 779f6f6703fSSean Bruno 780f6f6703fSSean Bruno /* 781f6f6703fSSean Bruno * Reduce the MSS to blackhole value or to the default 782f6f6703fSSean Bruno * in an attempt to retransmit. 783f6f6703fSSean Bruno */ 784f6f6703fSSean Bruno #ifdef INET6 785f6f6703fSSean Bruno if (isipv6 && 786b89af8e1SMichael Tuexen tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss && 787b89af8e1SMichael Tuexen V_tcp_v6pmtud_blackhole_mss > V_tcp_v6mssdflt) { 788f6f6703fSSean Bruno /* Use the sysctl tuneable blackhole MSS. */ 7890c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_v6pmtud_blackhole_mss; 79032a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated); 791f6f6703fSSean Bruno } else if (isipv6) { 792f6f6703fSSean Bruno /* Use the default MSS. */ 7930c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_v6mssdflt; 794f6f6703fSSean Bruno /* 795f6f6703fSSean Bruno * Disable Path MTU Discovery when we switch to 796f6f6703fSSean Bruno * minmss. 797f6f6703fSSean Bruno */ 798f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 79932a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); 800f6f6703fSSean Bruno } 801f6f6703fSSean Bruno #endif 802f6f6703fSSean Bruno #if defined(INET6) && defined(INET) 803f6f6703fSSean Bruno else 804f6f6703fSSean Bruno #endif 805f6f6703fSSean Bruno #ifdef INET 806b89af8e1SMichael Tuexen if (tp->t_maxseg > V_tcp_pmtud_blackhole_mss && 807b89af8e1SMichael Tuexen V_tcp_pmtud_blackhole_mss > V_tcp_mssdflt) { 808f6f6703fSSean Bruno /* Use the sysctl tuneable blackhole MSS. */ 8090c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_pmtud_blackhole_mss; 81032a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated); 811f6f6703fSSean Bruno } else { 812f6f6703fSSean Bruno /* Use the default MSS. */ 8130c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_mssdflt; 814f6f6703fSSean Bruno /* 815f6f6703fSSean Bruno * Disable Path MTU Discovery when we switch to 816f6f6703fSSean Bruno * minmss. 817f6f6703fSSean Bruno */ 818f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 81932a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); 820f6f6703fSSean Bruno } 821f6f6703fSSean Bruno #endif 822f6f6703fSSean Bruno /* 823f6f6703fSSean Bruno * Reset the slow-start flight size 824f6f6703fSSean Bruno * as it may depend on the new MSS. 825f6f6703fSSean Bruno */ 826f6f6703fSSean Bruno if (CC_ALGO(tp)->conn_init != NULL) 827f6f6703fSSean Bruno CC_ALGO(tp)->conn_init(tp->ccv); 828f6f6703fSSean Bruno } else { 829f6f6703fSSean Bruno /* 830f6f6703fSSean Bruno * If further retransmissions are still unsuccessful 831f6f6703fSSean Bruno * with a lowered MTU, maybe this isn't a blackhole and 832f6f6703fSSean Bruno * we restore the previous MSS and blackhole detection 833f6f6703fSSean Bruno * flags. 834f6f6703fSSean Bruno */ 835f6f6703fSSean Bruno if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) && 836b89af8e1SMichael Tuexen (tp->t_rxtshift >= tp->t_blackhole_exit)) { 837f6f6703fSSean Bruno tp->t_flags2 |= TF2_PLPMTU_PMTUD; 838f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_BLACKHOLE; 8390c39d38dSGleb Smirnoff tp->t_maxseg = tp->t_pmtud_saved_maxseg; 84032a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_failed); 841f6f6703fSSean Bruno /* 842f6f6703fSSean Bruno * Reset the slow-start flight size as it 843f6f6703fSSean Bruno * may depend on the new MSS. 844f6f6703fSSean Bruno */ 845f6f6703fSSean Bruno if (CC_ALGO(tp)->conn_init != NULL) 846f6f6703fSSean Bruno CC_ALGO(tp)->conn_init(tp->ccv); 847f6f6703fSSean Bruno } 848f6f6703fSSean Bruno } 849f6f6703fSSean Bruno } 850f6f6703fSSean Bruno 851df8bae1dSRodney W. Grimes /* 85277339e1cSAndre Oppermann * Disable RFC1323 and SACK if we haven't got any response to 8537ceb7783SJesper Skriver * our third SYN to work-around some broken terminal servers 8547ceb7783SJesper Skriver * (most of which have hopefully been retired) that have bad VJ 8557ceb7783SJesper Skriver * header compression code which trashes TCP segments containing 8567ceb7783SJesper Skriver * unknown-to-them TCP options. 8577ceb7783SJesper Skriver */ 8586c0ef895SJohn Baldwin if (tcp_rexmit_drop_options && (tp->t_state == TCPS_SYN_SENT) && 8596c0ef895SJohn Baldwin (tp->t_rxtshift == 3)) 860c4ab59c1SAndre Oppermann tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_SACK_PERMIT); 8617ceb7783SJesper Skriver /* 8625ede40dcSRyan Stone * If we backed off this far, notify the L3 protocol that we're having 8635ede40dcSRyan Stone * connection problems. 864df8bae1dSRodney W. Grimes */ 8655ede40dcSRyan Stone if (tp->t_rxtshift > TCP_RTT_INVALIDATE) { 866fb59c426SYoshinobu Inoue #ifdef INET6 867*9eb0e832SGleb Smirnoff if ((inp->inp_vflag & INP_IPV6) != 0) 868*9eb0e832SGleb Smirnoff in6_losing(inp); 86984cc0778SGeorge V. Neville-Neil else 870fb59c426SYoshinobu Inoue #endif 871*9eb0e832SGleb Smirnoff in_losing(inp); 872df8bae1dSRodney W. Grimes } 873df8bae1dSRodney W. Grimes tp->snd_nxt = tp->snd_una; 8749d11646dSJeffrey Hsu tp->snd_recover = tp->snd_max; 87546f58482SJonathan Lemon /* 87674b48c1dSAndras Olah * Force a segment to be sent. 87774b48c1dSAndras Olah */ 87874b48c1dSAndras Olah tp->t_flags |= TF_ACKNOW; 87974b48c1dSAndras Olah /* 880df8bae1dSRodney W. Grimes * If timing a segment in this window, stop the timer. 881df8bae1dSRodney W. Grimes */ 8829b8b58e0SJonathan Lemon tp->t_rtttime = 0; 883dbc42409SLawrence Stewart 884b5af1b88SLawrence Stewart cc_cong_signal(tp, NULL, CC_RTO); 885109eb549SGleb Smirnoff NET_EPOCH_ENTER(et); 886f64dc2abSGleb Smirnoff outrv = tcp_output_nodrop(tp); 8879b8b58e0SJonathan Lemon #ifdef TCPDEBUG 888*9eb0e832SGleb Smirnoff if (tp != NULL && (tptosocket(tp)->so_options & SO_DEBUG)) 889fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 8909b8b58e0SJonathan Lemon PRU_SLOWTIMO); 891df8bae1dSRodney W. Grimes #endif 8925d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 893f64dc2abSGleb Smirnoff (void) tcp_unlock_or_drop(tp, outrv); 894f64dc2abSGleb Smirnoff NET_EPOCH_EXIT(et); 8958b615593SMarko Zec CURVNET_RESTORE(); 89685d94372SRobert Watson } 89785d94372SRobert Watson 89885d94372SRobert Watson void 8995571f9cfSJulien Charbon tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, u_int delta) 90085d94372SRobert Watson { 90185d94372SRobert Watson struct callout *t_callout; 9025773ac11SJohn Baldwin callout_func_t *f_callout; 903*9eb0e832SGleb Smirnoff struct inpcb *inp = tptoinpcb(tp); 904883831c6SAdrian Chadd int cpu = inp_to_cpuid(inp); 90585d94372SRobert Watson 90609fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD 90709fe6320SNavdeep Parhar if (tp->t_flags & TF_TOE) 90809fe6320SNavdeep Parhar return; 90909fe6320SNavdeep Parhar #endif 91009fe6320SNavdeep Parhar 9115571f9cfSJulien Charbon if (tp->t_timers->tt_flags & TT_STOPPED) 9125571f9cfSJulien Charbon return; 9135571f9cfSJulien Charbon 91485d94372SRobert Watson switch (timer_type) { 91585d94372SRobert Watson case TT_DELACK: 916e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 91785d94372SRobert Watson f_callout = tcp_timer_delack; 91885d94372SRobert Watson break; 91985d94372SRobert Watson case TT_REXMT: 920e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 92185d94372SRobert Watson f_callout = tcp_timer_rexmt; 92285d94372SRobert Watson break; 92385d94372SRobert Watson case TT_PERSIST: 924e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 92585d94372SRobert Watson f_callout = tcp_timer_persist; 92685d94372SRobert Watson break; 92785d94372SRobert Watson case TT_KEEP: 928e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 92985d94372SRobert Watson f_callout = tcp_timer_keep; 93085d94372SRobert Watson break; 93185d94372SRobert Watson case TT_2MSL: 932e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 93385d94372SRobert Watson f_callout = tcp_timer_2msl; 93485d94372SRobert Watson break; 93585d94372SRobert Watson default: 93655bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_activate) { 93755bceb1eSRandall Stewart tp->t_fb->tfb_tcp_timer_activate(tp, timer_type, delta); 93855bceb1eSRandall Stewart return; 93955bceb1eSRandall Stewart } 94003374917SJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 94185d94372SRobert Watson } 94285d94372SRobert Watson if (delta == 0) { 943b07fef50SRandall Stewart callout_stop(t_callout); 94485d94372SRobert Watson } else { 94587aedea4SKip Macy callout_reset_on(t_callout, delta, f_callout, tp, cpu); 94685d94372SRobert Watson } 94785d94372SRobert Watson } 94885d94372SRobert Watson 94985d94372SRobert Watson int 9505571f9cfSJulien Charbon tcp_timer_active(struct tcpcb *tp, uint32_t timer_type) 95185d94372SRobert Watson { 95285d94372SRobert Watson struct callout *t_callout; 95385d94372SRobert Watson 95485d94372SRobert Watson switch (timer_type) { 95585d94372SRobert Watson case TT_DELACK: 956e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 95785d94372SRobert Watson break; 95885d94372SRobert Watson case TT_REXMT: 959e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 96085d94372SRobert Watson break; 96185d94372SRobert Watson case TT_PERSIST: 962e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 96385d94372SRobert Watson break; 96485d94372SRobert Watson case TT_KEEP: 965e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 96685d94372SRobert Watson break; 96785d94372SRobert Watson case TT_2MSL: 968e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 96985d94372SRobert Watson break; 97085d94372SRobert Watson default: 97155bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_active) { 97255bceb1eSRandall Stewart return(tp->t_fb->tfb_tcp_timer_active(tp, timer_type)); 97355bceb1eSRandall Stewart } 97403374917SJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 97585d94372SRobert Watson } 97685d94372SRobert Watson return callout_active(t_callout); 977df8bae1dSRodney W. Grimes } 978b8614722SMike Silbersack 97989e560f4SRandall Stewart /* 98089e560f4SRandall Stewart * Stop the timer from running, and apply a flag 98189e560f4SRandall Stewart * against the timer_flags that will force the 98289e560f4SRandall Stewart * timer never to run. The flag is needed to assure 98389e560f4SRandall Stewart * a race does not leave it running and cause 98489e560f4SRandall Stewart * the timer to possibly restart itself (keep and persist 98589e560f4SRandall Stewart * especially do this). 98689e560f4SRandall Stewart */ 98789e560f4SRandall Stewart int 98889e560f4SRandall Stewart tcp_timer_suspend(struct tcpcb *tp, uint32_t timer_type) 98989e560f4SRandall Stewart { 99089e560f4SRandall Stewart struct callout *t_callout; 99189e560f4SRandall Stewart uint32_t t_flags; 99289e560f4SRandall Stewart 99389e560f4SRandall Stewart switch (timer_type) { 99489e560f4SRandall Stewart case TT_DELACK: 99589e560f4SRandall Stewart t_flags = TT_DELACK_SUS; 99689e560f4SRandall Stewart t_callout = &tp->t_timers->tt_delack; 99789e560f4SRandall Stewart break; 99889e560f4SRandall Stewart case TT_REXMT: 99989e560f4SRandall Stewart t_flags = TT_REXMT_SUS; 100089e560f4SRandall Stewart t_callout = &tp->t_timers->tt_rexmt; 100189e560f4SRandall Stewart break; 100289e560f4SRandall Stewart case TT_PERSIST: 100389e560f4SRandall Stewart t_flags = TT_PERSIST_SUS; 100489e560f4SRandall Stewart t_callout = &tp->t_timers->tt_persist; 100589e560f4SRandall Stewart break; 100689e560f4SRandall Stewart case TT_KEEP: 100789e560f4SRandall Stewart t_flags = TT_KEEP_SUS; 100889e560f4SRandall Stewart t_callout = &tp->t_timers->tt_keep; 100989e560f4SRandall Stewart break; 101089e560f4SRandall Stewart case TT_2MSL: 101189e560f4SRandall Stewart t_flags = TT_2MSL_SUS; 101289e560f4SRandall Stewart t_callout = &tp->t_timers->tt_2msl; 101389e560f4SRandall Stewart break; 101489e560f4SRandall Stewart default: 101589e560f4SRandall Stewart panic("tp:%p bad timer_type 0x%x", tp, timer_type); 101689e560f4SRandall Stewart } 101789e560f4SRandall Stewart tp->t_timers->tt_flags |= t_flags; 101889e560f4SRandall Stewart return (callout_stop(t_callout)); 101989e560f4SRandall Stewart } 102089e560f4SRandall Stewart 102189e560f4SRandall Stewart void 102289e560f4SRandall Stewart tcp_timers_unsuspend(struct tcpcb *tp, uint32_t timer_type) 102389e560f4SRandall Stewart { 102489e560f4SRandall Stewart switch (timer_type) { 102589e560f4SRandall Stewart case TT_DELACK: 102689e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_DELACK_SUS) { 102789e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_DELACK_SUS; 102889e560f4SRandall Stewart if (tp->t_flags & TF_DELACK) { 102989e560f4SRandall Stewart /* Delayed ack timer should be up activate a timer */ 103089e560f4SRandall Stewart tp->t_flags &= ~TF_DELACK; 103189e560f4SRandall Stewart tcp_timer_activate(tp, TT_DELACK, 103289e560f4SRandall Stewart tcp_delacktime); 103389e560f4SRandall Stewart } 103489e560f4SRandall Stewart } 103589e560f4SRandall Stewart break; 103689e560f4SRandall Stewart case TT_REXMT: 103789e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_REXMT_SUS) { 103889e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_REXMT_SUS; 103989e560f4SRandall Stewart if (SEQ_GT(tp->snd_max, tp->snd_una) && 104089e560f4SRandall Stewart (tcp_timer_active((tp), TT_PERSIST) == 0) && 104189e560f4SRandall Stewart tp->snd_wnd) { 104289e560f4SRandall Stewart /* We have outstanding data activate a timer */ 104389e560f4SRandall Stewart tcp_timer_activate(tp, TT_REXMT, 104489e560f4SRandall Stewart tp->t_rxtcur); 104589e560f4SRandall Stewart } 104689e560f4SRandall Stewart } 104789e560f4SRandall Stewart break; 104889e560f4SRandall Stewart case TT_PERSIST: 104989e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_PERSIST_SUS) { 105089e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_PERSIST_SUS; 105189e560f4SRandall Stewart if (tp->snd_wnd == 0) { 105289e560f4SRandall Stewart /* Activate the persists timer */ 105389e560f4SRandall Stewart tp->t_rxtshift = 0; 105489e560f4SRandall Stewart tcp_setpersist(tp); 105589e560f4SRandall Stewart } 105689e560f4SRandall Stewart } 105789e560f4SRandall Stewart break; 105889e560f4SRandall Stewart case TT_KEEP: 105989e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_KEEP_SUS) { 106089e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_KEEP_SUS; 106189e560f4SRandall Stewart tcp_timer_activate(tp, TT_KEEP, 106289e560f4SRandall Stewart TCPS_HAVEESTABLISHED(tp->t_state) ? 106389e560f4SRandall Stewart TP_KEEPIDLE(tp) : TP_KEEPINIT(tp)); 106489e560f4SRandall Stewart } 106589e560f4SRandall Stewart break; 106689e560f4SRandall Stewart case TT_2MSL: 106789e560f4SRandall Stewart if (tp->t_timers->tt_flags &= TT_2MSL_SUS) { 1068*9eb0e832SGleb Smirnoff struct socket *so = tptosocket(tp); 1069*9eb0e832SGleb Smirnoff 107089e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_2MSL_SUS; 107189e560f4SRandall Stewart if ((tp->t_state == TCPS_FIN_WAIT_2) && 1072*9eb0e832SGleb Smirnoff (so == NULL || /* XXXGL: needed? */ 1073*9eb0e832SGleb Smirnoff (so->so_rcv.sb_state & SBS_CANTRCVMORE))) { 107489e560f4SRandall Stewart /* Star the 2MSL timer */ 107589e560f4SRandall Stewart tcp_timer_activate(tp, TT_2MSL, 107689e560f4SRandall Stewart (tcp_fast_finwait2_recycle) ? 107789e560f4SRandall Stewart tcp_finwait2_timeout : TP_MAXIDLE(tp)); 107889e560f4SRandall Stewart } 107989e560f4SRandall Stewart } 108089e560f4SRandall Stewart break; 108189e560f4SRandall Stewart default: 108289e560f4SRandall Stewart panic("tp:%p bad timer_type 0x%x", tp, timer_type); 108389e560f4SRandall Stewart } 108489e560f4SRandall Stewart } 108589e560f4SRandall Stewart 1086ff945008SGleb Smirnoff static void 1087ff945008SGleb Smirnoff tcp_timer_discard(void *ptp) 1088ff945008SGleb Smirnoff { 1089ff945008SGleb Smirnoff struct epoch_tracker et; 1090*9eb0e832SGleb Smirnoff struct tcpcb *tp = (struct tcpcb *)ptp; 1091*9eb0e832SGleb Smirnoff struct inpcb *inp = tptoinpcb(tp); 1092ff945008SGleb Smirnoff 1093ff945008SGleb Smirnoff CURVNET_SET(tp->t_vnet); 1094ff945008SGleb Smirnoff INP_WLOCK(inp); 1095*9eb0e832SGleb Smirnoff NET_EPOCH_ENTER(et); 1096*9eb0e832SGleb Smirnoff 1097ff945008SGleb Smirnoff KASSERT((tp->t_timers->tt_flags & TT_STOPPED) != 0, 1098ff945008SGleb Smirnoff ("%s: tcpcb has to be stopped here", __func__)); 1099ff945008SGleb Smirnoff if (--tp->t_timers->tt_draincnt > 0 || 1100ff945008SGleb Smirnoff tcp_freecb(tp) == false) 1101ff945008SGleb Smirnoff INP_WUNLOCK(inp); 1102ff945008SGleb Smirnoff NET_EPOCH_EXIT(et); 1103ff945008SGleb Smirnoff CURVNET_RESTORE(); 1104ff945008SGleb Smirnoff } 1105ff945008SGleb Smirnoff 11065571f9cfSJulien Charbon void 11075571f9cfSJulien Charbon tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type) 11085571f9cfSJulien Charbon { 11095571f9cfSJulien Charbon struct callout *t_callout; 11105571f9cfSJulien Charbon 11115571f9cfSJulien Charbon tp->t_timers->tt_flags |= TT_STOPPED; 11125571f9cfSJulien Charbon switch (timer_type) { 11135571f9cfSJulien Charbon case TT_DELACK: 11145571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_delack; 11155571f9cfSJulien Charbon break; 11165571f9cfSJulien Charbon case TT_REXMT: 11175571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_rexmt; 11185571f9cfSJulien Charbon break; 11195571f9cfSJulien Charbon case TT_PERSIST: 11205571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_persist; 11215571f9cfSJulien Charbon break; 11225571f9cfSJulien Charbon case TT_KEEP: 11235571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_keep; 11245571f9cfSJulien Charbon break; 11255571f9cfSJulien Charbon case TT_2MSL: 11265571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_2msl; 11275571f9cfSJulien Charbon break; 11285571f9cfSJulien Charbon default: 112955bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_stop) { 113055bceb1eSRandall Stewart /* 113155bceb1eSRandall Stewart * XXXrrs we need to look at this with the 113255bceb1eSRandall Stewart * stop case below (flags). 113355bceb1eSRandall Stewart */ 113455bceb1eSRandall Stewart tp->t_fb->tfb_tcp_timer_stop(tp, timer_type); 113555bceb1eSRandall Stewart return; 113655bceb1eSRandall Stewart } 11375571f9cfSJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 11385571f9cfSJulien Charbon } 11395571f9cfSJulien Charbon 1140e5ad6456SRandall Stewart if (callout_async_drain(t_callout, tcp_timer_discard) == 0) { 11415571f9cfSJulien Charbon /* 11425571f9cfSJulien Charbon * Can't stop the callout, defer tcpcb actual deletion 1143e5ad6456SRandall Stewart * to the last one. We do this using the async drain 1144e5ad6456SRandall Stewart * function and incrementing the count in 11455571f9cfSJulien Charbon */ 1146e5ad6456SRandall Stewart tp->t_timers->tt_draincnt++; 11475571f9cfSJulien Charbon } 11485571f9cfSJulien Charbon } 1149