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 #ifdef TCPDEBUG 81af7a2999SDavid Greenman #include <netinet/tcp_debug.h> 82af7a2999SDavid Greenman #endif 83df8bae1dSRodney W. Grimes 840645c604SHiren Panchasara int tcp_persmin; 850645c604SHiren Panchasara SYSCTL_PROC(_net_inet_tcp, OID_AUTO, persmin, CTLTYPE_INT|CTLFLAG_RW, 860645c604SHiren Panchasara &tcp_persmin, 0, sysctl_msec_to_ticks, "I", "minimum persistence interval"); 870645c604SHiren Panchasara 880645c604SHiren Panchasara int tcp_persmax; 890645c604SHiren Panchasara SYSCTL_PROC(_net_inet_tcp, OID_AUTO, persmax, CTLTYPE_INT|CTLFLAG_RW, 900645c604SHiren Panchasara &tcp_persmax, 0, sysctl_msec_to_ticks, "I", "maximum persistence interval"); 910645c604SHiren Panchasara 929b8b58e0SJonathan Lemon int tcp_keepinit; 93ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, CTLTYPE_INT|CTLFLAG_RW, 9441698ebfSTom Rhodes &tcp_keepinit, 0, sysctl_msec_to_ticks, "I", "time to establish connection"); 957b40aa32SPaul Traina 969b8b58e0SJonathan Lemon int tcp_keepidle; 97ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, CTLTYPE_INT|CTLFLAG_RW, 9841698ebfSTom Rhodes &tcp_keepidle, 0, sysctl_msec_to_ticks, "I", "time before keepalive probes begin"); 9998163b98SPoul-Henning Kamp 1009b8b58e0SJonathan Lemon int tcp_keepintvl; 101ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, CTLTYPE_INT|CTLFLAG_RW, 10241698ebfSTom Rhodes &tcp_keepintvl, 0, sysctl_msec_to_ticks, "I", "time between keepalive probes"); 10398163b98SPoul-Henning Kamp 1049b8b58e0SJonathan Lemon int tcp_delacktime; 1056489fe65SAndre Oppermann SYSCTL_PROC(_net_inet_tcp, TCPCTL_DELACKTIME, delacktime, CTLTYPE_INT|CTLFLAG_RW, 1066489fe65SAndre Oppermann &tcp_delacktime, 0, sysctl_msec_to_ticks, "I", 107ccb4d0c6SJonathan Lemon "Time before a delayed ACK is sent"); 1089b8b58e0SJonathan Lemon 1099b8b58e0SJonathan Lemon int tcp_msl; 110ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl, CTLTYPE_INT|CTLFLAG_RW, 111ccb4d0c6SJonathan Lemon &tcp_msl, 0, sysctl_msec_to_ticks, "I", "Maximum segment lifetime"); 1129b8b58e0SJonathan Lemon 113701bec5aSMatthew Dillon int tcp_rexmit_min; 114701bec5aSMatthew Dillon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_min, CTLTYPE_INT|CTLFLAG_RW, 1156489fe65SAndre Oppermann &tcp_rexmit_min, 0, sysctl_msec_to_ticks, "I", 1166489fe65SAndre Oppermann "Minimum Retransmission Timeout"); 117701bec5aSMatthew Dillon 118701bec5aSMatthew Dillon int tcp_rexmit_slop; 119701bec5aSMatthew Dillon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_slop, CTLTYPE_INT|CTLFLAG_RW, 1206489fe65SAndre Oppermann &tcp_rexmit_slop, 0, sysctl_msec_to_ticks, "I", 1216489fe65SAndre Oppermann "Retransmission Timer Slop"); 122701bec5aSMatthew Dillon 123f1798531SJohn Baldwin int tcp_always_keepalive = 1; 1243d177f46SBill Fumerola SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW, 125f1798531SJohn Baldwin &tcp_always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections"); 12634be9bf3SPoul-Henning Kamp 1277c72af87SMohan Srinivasan int tcp_fast_finwait2_recycle = 0; 1287c72af87SMohan Srinivasan SYSCTL_INT(_net_inet_tcp, OID_AUTO, fast_finwait2_recycle, CTLFLAG_RW, 1296489fe65SAndre Oppermann &tcp_fast_finwait2_recycle, 0, 1306489fe65SAndre Oppermann "Recycle closed FIN_WAIT_2 connections faster"); 1317c72af87SMohan Srinivasan 1327c72af87SMohan Srinivasan int tcp_finwait2_timeout; 1337c72af87SMohan Srinivasan SYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, CTLTYPE_INT|CTLFLAG_RW, 1346489fe65SAndre Oppermann &tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", "FIN-WAIT2 timeout"); 1357c72af87SMohan Srinivasan 1369077f387SGleb Smirnoff int tcp_keepcnt = TCPTV_KEEPCNT; 1379077f387SGleb Smirnoff SYSCTL_INT(_net_inet_tcp, OID_AUTO, keepcnt, CTLFLAG_RW, &tcp_keepcnt, 0, 1389077f387SGleb Smirnoff "Number of keepalive probes to send"); 1397c72af87SMohan Srinivasan 1400312fbe9SPoul-Henning Kamp /* max idle probes */ 1419b8b58e0SJonathan Lemon int tcp_maxpersistidle; 142e79adb8eSGarrett Wollman 14389e560f4SRandall Stewart int tcp_rexmit_drop_options = 0; 1446c0ef895SJohn Baldwin SYSCTL_INT(_net_inet_tcp, OID_AUTO, rexmit_drop_options, CTLFLAG_RW, 1456c0ef895SJohn Baldwin &tcp_rexmit_drop_options, 0, 1466c0ef895SJohn Baldwin "Drop TCP options from 3rd and later retransmitted SYN"); 1476c0ef895SJohn Baldwin 148e29c55e4SGleb Smirnoff VNET_DEFINE(int, tcp_pmtud_blackhole_detect); 149f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_detection, 150f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 151f6f6703fSSean Bruno &VNET_NAME(tcp_pmtud_blackhole_detect), 0, 152f6f6703fSSean Bruno "Path MTU Discovery Black Hole Detection Enabled"); 153f6f6703fSSean Bruno 154f6f6703fSSean Bruno #ifdef INET 155e29c55e4SGleb Smirnoff VNET_DEFINE(int, tcp_pmtud_blackhole_mss) = 1200; 156f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_mss, 157f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 158f6f6703fSSean Bruno &VNET_NAME(tcp_pmtud_blackhole_mss), 0, 159f6f6703fSSean Bruno "Path MTU Discovery Black Hole Detection lowered MSS"); 160f6f6703fSSean Bruno #endif 161f6f6703fSSean Bruno 162f6f6703fSSean Bruno #ifdef INET6 163e29c55e4SGleb Smirnoff VNET_DEFINE(int, tcp_v6pmtud_blackhole_mss) = 1220; 164f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, v6pmtud_blackhole_mss, 165f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 166f6f6703fSSean Bruno &VNET_NAME(tcp_v6pmtud_blackhole_mss), 0, 167f6f6703fSSean Bruno "Path MTU Discovery IPv6 Black Hole Detection lowered MSS"); 168f6f6703fSSean Bruno #endif 169f6f6703fSSean Bruno 1708f7e75cbSAdrian Chadd #ifdef RSS 1718f7e75cbSAdrian Chadd static int per_cpu_timers = 1; 1728f7e75cbSAdrian Chadd #else 17387aedea4SKip Macy static int per_cpu_timers = 0; 1748f7e75cbSAdrian Chadd #endif 17587aedea4SKip Macy SYSCTL_INT(_net_inet_tcp, OID_AUTO, per_cpu_timers, CTLFLAG_RW, 17687aedea4SKip Macy &per_cpu_timers , 0, "run tcp timers on all cpus"); 17787aedea4SKip Macy 178883831c6SAdrian Chadd /* 179883831c6SAdrian Chadd * Map the given inp to a CPU id. 180883831c6SAdrian Chadd * 181883831c6SAdrian Chadd * This queries RSS if it's compiled in, else it defaults to the current 182883831c6SAdrian Chadd * CPU ID. 183883831c6SAdrian Chadd */ 18489e560f4SRandall Stewart inline int 185883831c6SAdrian Chadd inp_to_cpuid(struct inpcb *inp) 186883831c6SAdrian Chadd { 187883831c6SAdrian Chadd u_int cpuid; 188883831c6SAdrian Chadd 189883831c6SAdrian Chadd #ifdef RSS 190883831c6SAdrian Chadd if (per_cpu_timers) { 191883831c6SAdrian Chadd cpuid = rss_hash2cpuid(inp->inp_flowid, inp->inp_flowtype); 192883831c6SAdrian Chadd if (cpuid == NETISR_CPUID_NONE) 193883831c6SAdrian Chadd return (curcpu); /* XXX */ 194883831c6SAdrian Chadd else 195883831c6SAdrian Chadd return (cpuid); 196883831c6SAdrian Chadd } 197883831c6SAdrian Chadd #else 198883831c6SAdrian Chadd /* Legacy, pre-RSS behaviour */ 199883831c6SAdrian Chadd if (per_cpu_timers) { 200883831c6SAdrian Chadd /* 201883831c6SAdrian Chadd * We don't have a flowid -> cpuid mapping, so cheat and 202883831c6SAdrian Chadd * just map unknown cpuids to curcpu. Not the best, but 203883831c6SAdrian Chadd * apparently better than defaulting to swi 0. 204883831c6SAdrian Chadd */ 205883831c6SAdrian Chadd cpuid = inp->inp_flowid % (mp_maxid + 1); 206883831c6SAdrian Chadd if (! CPU_ABSENT(cpuid)) 207883831c6SAdrian Chadd return (cpuid); 208883831c6SAdrian Chadd return (curcpu); 209883831c6SAdrian Chadd } 210883831c6SAdrian Chadd #endif 211883831c6SAdrian Chadd /* Default for RSS and non-RSS - cpuid 0 */ 212883831c6SAdrian Chadd else { 213883831c6SAdrian Chadd return (0); 214883831c6SAdrian Chadd } 215883831c6SAdrian Chadd } 21687aedea4SKip Macy 217df8bae1dSRodney W. Grimes /* 218df8bae1dSRodney W. Grimes * Tcp protocol timeout routine called every 500 ms. 2199b8b58e0SJonathan Lemon * Updates timestamps used for TCP 220df8bae1dSRodney W. Grimes * causes finite state machine actions if timers expire. 221df8bae1dSRodney W. Grimes */ 222df8bae1dSRodney W. Grimes void 223e2f2059fSMike Silbersack tcp_slowtimo(void) 224df8bae1dSRodney W. Grimes { 2258b615593SMarko Zec VNET_ITERATOR_DECL(vnet_iter); 22615bd2b43SDavid Greenman 2275ee847d3SRobert Watson VNET_LIST_RLOCK_NOSLEEP(); 2288b615593SMarko Zec VNET_FOREACH(vnet_iter) { 2298b615593SMarko Zec CURVNET_SET(vnet_iter); 230cea40c48SJulien Charbon (void) tcp_tw_2msl_scan(0); 2318b615593SMarko Zec CURVNET_RESTORE(); 2328b615593SMarko Zec } 2335ee847d3SRobert Watson VNET_LIST_RUNLOCK_NOSLEEP(); 234df8bae1dSRodney W. Grimes } 235df8bae1dSRodney W. Grimes 2367d42e30cSJonathan Lemon int tcp_syn_backoff[TCP_MAXRXTSHIFT + 1] = 2377d42e30cSJonathan Lemon { 1, 1, 1, 1, 1, 2, 4, 8, 16, 32, 64, 64, 64 }; 2387d42e30cSJonathan Lemon 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 { 25185d94372SRobert Watson struct tcpcb *tp = xtp; 25285d94372SRobert Watson struct inpcb *inp; 2538b615593SMarko Zec CURVNET_SET(tp->t_vnet); 25485d94372SRobert Watson 25585d94372SRobert Watson inp = tp->t_inpcb; 2565571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 2578501a69cSRobert Watson INP_WLOCK(inp); 258655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_delack) || 259655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_delack)) { 2608501a69cSRobert Watson INP_WUNLOCK(inp); 2618b615593SMarko Zec CURVNET_RESTORE(); 26285d94372SRobert Watson return; 26385d94372SRobert Watson } 264e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_delack); 265655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 266655f934bSMikolaj Golub INP_WUNLOCK(inp); 267655f934bSMikolaj Golub CURVNET_RESTORE(); 268655f934bSMikolaj Golub return; 269655f934bSMikolaj Golub } 2709b8b58e0SJonathan Lemon tp->t_flags |= TF_ACKNOW; 27178b50714SRobert Watson TCPSTAT_INC(tcps_delack); 27255bceb1eSRandall Stewart (void) tp->t_fb->tfb_tcp_output(tp); 2738501a69cSRobert Watson INP_WUNLOCK(inp); 2748b615593SMarko Zec CURVNET_RESTORE(); 2759b8b58e0SJonathan Lemon } 2769b8b58e0SJonathan Lemon 277b07fef50SRandall Stewart void 278b07fef50SRandall Stewart tcp_inpinfo_lock_del(struct inpcb *inp, struct tcpcb *tp) 279b07fef50SRandall Stewart { 280*6573d758SMatt Macy if (inp && tp != NULL) 281b07fef50SRandall Stewart INP_WUNLOCK(inp); 282b07fef50SRandall Stewart } 283b07fef50SRandall Stewart 28485d94372SRobert Watson void 28585d94372SRobert Watson tcp_timer_2msl(void *xtp) 2869b8b58e0SJonathan Lemon { 28785d94372SRobert Watson struct tcpcb *tp = xtp; 28885d94372SRobert Watson struct inpcb *inp; 289*6573d758SMatt Macy struct epoch_tracker et; 2908b615593SMarko Zec CURVNET_SET(tp->t_vnet); 2919b8b58e0SJonathan Lemon #ifdef TCPDEBUG 2929b8b58e0SJonathan Lemon int ostate; 2939b8b58e0SJonathan Lemon 2949b8b58e0SJonathan Lemon ostate = tp->t_state; 2959b8b58e0SJonathan Lemon #endif 29685d94372SRobert Watson inp = tp->t_inpcb; 2975571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 2988501a69cSRobert Watson INP_WLOCK(inp); 29985d94372SRobert Watson tcp_free_sackholes(tp); 300655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_2msl) || 301e2f2059fSMike Silbersack !callout_active(&tp->t_timers->tt_2msl)) { 3028501a69cSRobert Watson INP_WUNLOCK(tp->t_inpcb); 3038b615593SMarko Zec CURVNET_RESTORE(); 30485d94372SRobert Watson return; 30585d94372SRobert Watson } 306e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_2msl); 307655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 308655f934bSMikolaj Golub INP_WUNLOCK(inp); 309655f934bSMikolaj Golub CURVNET_RESTORE(); 310655f934bSMikolaj Golub return; 311655f934bSMikolaj Golub } 3125571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 3135571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 31485d94372SRobert Watson /* 315df8bae1dSRodney W. Grimes * 2 MSL timeout in shutdown went off. If we're closed but 316df8bae1dSRodney W. Grimes * still waiting for peer to close and connection has been idle 31731a7749dSJulien Charbon * too long delete connection control block. Otherwise, check 31831a7749dSJulien Charbon * again in a bit. 31931a7749dSJulien Charbon * 32031a7749dSJulien Charbon * If in TIME_WAIT state just ignore as this timeout is handled in 32131a7749dSJulien Charbon * tcp_tw_2msl_scan(). 3227c72af87SMohan Srinivasan * 3237c72af87SMohan Srinivasan * If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, 3247c72af87SMohan Srinivasan * there's no point in hanging onto FIN_WAIT_2 socket. Just close it. 3257c72af87SMohan Srinivasan * Ignore fact that there were recent incoming segments. 326df8bae1dSRodney W. Grimes */ 32731a7749dSJulien Charbon if ((inp->inp_flags & INP_TIMEWAIT) != 0) { 32831a7749dSJulien Charbon INP_WUNLOCK(inp); 32931a7749dSJulien Charbon CURVNET_RESTORE(); 33031a7749dSJulien Charbon return; 33131a7749dSJulien Charbon } 3327c72af87SMohan Srinivasan if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && 33385d94372SRobert Watson tp->t_inpcb && tp->t_inpcb->inp_socket && 3347c72af87SMohan Srinivasan (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { 33578b50714SRobert Watson TCPSTAT_INC(tcps_finwait2_drops); 336*6573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 337b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 338b07fef50SRandall Stewart goto out; 339b07fef50SRandall Stewart } 340*6573d758SMatt Macy INP_INFO_RLOCK_ET(&V_tcbinfo, et); 34185d94372SRobert Watson tp = tcp_close(tp); 342*6573d758SMatt Macy INP_INFO_RUNLOCK_ET(&V_tcbinfo, et); 343b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 344b07fef50SRandall Stewart goto out; 3457c72af87SMohan Srinivasan } else { 346d6de19acSJulien Charbon if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) { 347b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_2msl, 348b07fef50SRandall Stewart TP_KEEPINTVL(tp), tcp_timer_2msl, tp); 349b07fef50SRandall Stewart } else { 350*6573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 351b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 352b07fef50SRandall Stewart goto out; 353d6de19acSJulien Charbon } 354*6573d758SMatt Macy INP_INFO_RLOCK_ET(&V_tcbinfo, et); 35585d94372SRobert Watson tp = tcp_close(tp); 356*6573d758SMatt Macy INP_INFO_RUNLOCK_ET(&V_tcbinfo, et); 357b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 358b07fef50SRandall Stewart goto out; 359b07fef50SRandall Stewart } 3607c72af87SMohan Srinivasan } 361df8bae1dSRodney W. Grimes 3629b8b58e0SJonathan Lemon #ifdef TCPDEBUG 363586b4a0eSKonstantin Belousov if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 364fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 3659b8b58e0SJonathan Lemon PRU_SLOWTIMO); 3669b8b58e0SJonathan Lemon #endif 3675d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 3685d06879aSGeorge V. Neville-Neil 36985d94372SRobert Watson if (tp != NULL) 3708501a69cSRobert Watson INP_WUNLOCK(inp); 371b07fef50SRandall Stewart out: 3728b615593SMarko Zec CURVNET_RESTORE(); 3739b8b58e0SJonathan Lemon } 3749b8b58e0SJonathan Lemon 37585d94372SRobert Watson void 37685d94372SRobert Watson tcp_timer_keep(void *xtp) 3779b8b58e0SJonathan Lemon { 37885d94372SRobert Watson struct tcpcb *tp = xtp; 37908517d53SMike Silbersack struct tcptemp *t_template; 38085d94372SRobert Watson struct inpcb *inp; 381*6573d758SMatt Macy struct epoch_tracker et; 3828b615593SMarko Zec CURVNET_SET(tp->t_vnet); 3839b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3849b8b58e0SJonathan Lemon int ostate; 3859b8b58e0SJonathan Lemon 3869b8b58e0SJonathan Lemon ostate = tp->t_state; 3879b8b58e0SJonathan Lemon #endif 38885d94372SRobert Watson inp = tp->t_inpcb; 3895571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 3908501a69cSRobert Watson INP_WLOCK(inp); 391655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_keep) || 392655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_keep)) { 3938501a69cSRobert Watson INP_WUNLOCK(inp); 3948b615593SMarko Zec CURVNET_RESTORE(); 39585d94372SRobert Watson return; 39685d94372SRobert Watson } 397e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_keep); 398655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 399655f934bSMikolaj Golub INP_WUNLOCK(inp); 400655f934bSMikolaj Golub CURVNET_RESTORE(); 401655f934bSMikolaj Golub return; 402655f934bSMikolaj Golub } 4035571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 4045571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 4056d172f58SJonathan T. Looney 4066d172f58SJonathan T. Looney /* 4076d172f58SJonathan T. Looney * Because we don't regularly reset the keepalive callout in 4086d172f58SJonathan T. Looney * the ESTABLISHED state, it may be that we don't actually need 4096d172f58SJonathan T. Looney * to send a keepalive yet. If that occurs, schedule another 4106d172f58SJonathan T. Looney * call for the next time the keepalive timer might expire. 4116d172f58SJonathan T. Looney */ 4126d172f58SJonathan T. Looney if (TCPS_HAVEESTABLISHED(tp->t_state)) { 4136d172f58SJonathan T. Looney u_int idletime; 4146d172f58SJonathan T. Looney 4156d172f58SJonathan T. Looney idletime = ticks - tp->t_rcvtime; 4166d172f58SJonathan T. Looney if (idletime < TP_KEEPIDLE(tp)) { 4176d172f58SJonathan T. Looney callout_reset(&tp->t_timers->tt_keep, 4186d172f58SJonathan T. Looney TP_KEEPIDLE(tp) - idletime, tcp_timer_keep, tp); 4196d172f58SJonathan T. Looney INP_WUNLOCK(inp); 4206d172f58SJonathan T. Looney CURVNET_RESTORE(); 4216d172f58SJonathan T. Looney return; 4226d172f58SJonathan T. Looney } 4236d172f58SJonathan T. Looney } 4246d172f58SJonathan T. Looney 4259b8b58e0SJonathan Lemon /* 4269b8b58e0SJonathan Lemon * Keep-alive timer went off; send something 4279b8b58e0SJonathan Lemon * or drop connection if idle for too long. 4289b8b58e0SJonathan Lemon */ 42978b50714SRobert Watson TCPSTAT_INC(tcps_keeptimeo); 4309b8b58e0SJonathan Lemon if (tp->t_state < TCPS_ESTABLISHED) 4319b8b58e0SJonathan Lemon goto dropit; 432f1798531SJohn Baldwin if ((tcp_always_keepalive || 433f1798531SJohn Baldwin inp->inp_socket->so_options & SO_KEEPALIVE) && 4349b8b58e0SJonathan Lemon tp->t_state <= TCPS_CLOSING) { 4359077f387SGleb Smirnoff if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp)) 4369b8b58e0SJonathan Lemon goto dropit; 4379b8b58e0SJonathan Lemon /* 4389b8b58e0SJonathan Lemon * Send a packet designed to force a response 4399b8b58e0SJonathan Lemon * if the peer is up and reachable: 4409b8b58e0SJonathan Lemon * either an ACK if the connection is still alive, 4419b8b58e0SJonathan Lemon * or an RST if the peer has closed the connection 4429b8b58e0SJonathan Lemon * due to timeout or reboot. 4439b8b58e0SJonathan Lemon * Using sequence number tp->snd_una-1 4449b8b58e0SJonathan Lemon * causes the transmitted zero-length segment 4459b8b58e0SJonathan Lemon * to lie outside the receive window; 4469b8b58e0SJonathan Lemon * by the protocol spec, this requires the 4479b8b58e0SJonathan Lemon * correspondent TCP to respond. 4489b8b58e0SJonathan Lemon */ 44978b50714SRobert Watson TCPSTAT_INC(tcps_keepprobe); 45079909384SJonathan Lemon t_template = tcpip_maketemplate(inp); 45108517d53SMike Silbersack if (t_template) { 45208517d53SMike Silbersack tcp_respond(tp, t_template->tt_ipgen, 45308517d53SMike Silbersack &t_template->tt_t, (struct mbuf *)NULL, 4549b8b58e0SJonathan Lemon tp->rcv_nxt, tp->snd_una - 1, 0); 45553640b0eSRobert Watson free(t_template, M_TEMP); 45608517d53SMike Silbersack } 457b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_keep, TP_KEEPINTVL(tp), 458b07fef50SRandall Stewart tcp_timer_keep, tp); 459b07fef50SRandall Stewart } else 460b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_keep, TP_KEEPIDLE(tp), 461b07fef50SRandall Stewart tcp_timer_keep, tp); 4629b8b58e0SJonathan Lemon 4639b8b58e0SJonathan Lemon #ifdef TCPDEBUG 4642a074620SSam Leffler if (inp->inp_socket->so_options & SO_DEBUG) 465fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 4669b8b58e0SJonathan Lemon PRU_SLOWTIMO); 4679b8b58e0SJonathan Lemon #endif 4685d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 4698501a69cSRobert Watson INP_WUNLOCK(inp); 4708b615593SMarko Zec CURVNET_RESTORE(); 47185d94372SRobert Watson return; 4729b8b58e0SJonathan Lemon 4739b8b58e0SJonathan Lemon dropit: 47478b50714SRobert Watson TCPSTAT_INC(tcps_keepdrops); 475*6573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 476b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 477b07fef50SRandall Stewart goto out; 478b07fef50SRandall Stewart } 479*6573d758SMatt Macy INP_INFO_RLOCK_ET(&V_tcbinfo, et); 48085d94372SRobert Watson tp = tcp_drop(tp, ETIMEDOUT); 48185d94372SRobert Watson 48285d94372SRobert Watson #ifdef TCPDEBUG 48385d94372SRobert Watson if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 48485d94372SRobert Watson tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 48585d94372SRobert Watson PRU_SLOWTIMO); 48685d94372SRobert Watson #endif 4875d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 488*6573d758SMatt Macy INP_INFO_RUNLOCK_ET(&V_tcbinfo, et); 489b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 490b07fef50SRandall Stewart out: 4918b615593SMarko Zec CURVNET_RESTORE(); 4929b8b58e0SJonathan Lemon } 4939b8b58e0SJonathan Lemon 49485d94372SRobert Watson void 49585d94372SRobert Watson tcp_timer_persist(void *xtp) 4969b8b58e0SJonathan Lemon { 49785d94372SRobert Watson struct tcpcb *tp = xtp; 49885d94372SRobert Watson struct inpcb *inp; 499*6573d758SMatt Macy struct epoch_tracker et; 5008b615593SMarko Zec CURVNET_SET(tp->t_vnet); 5019b8b58e0SJonathan Lemon #ifdef TCPDEBUG 5029b8b58e0SJonathan Lemon int ostate; 5039b8b58e0SJonathan Lemon 5049b8b58e0SJonathan Lemon ostate = tp->t_state; 5059b8b58e0SJonathan Lemon #endif 50685d94372SRobert Watson inp = tp->t_inpcb; 5075571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 5088501a69cSRobert Watson INP_WLOCK(inp); 509655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_persist) || 510655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_persist)) { 5118501a69cSRobert Watson INP_WUNLOCK(inp); 5128b615593SMarko Zec CURVNET_RESTORE(); 51385d94372SRobert Watson return; 51485d94372SRobert Watson } 515e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_persist); 516655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 517655f934bSMikolaj Golub INP_WUNLOCK(inp); 518655f934bSMikolaj Golub CURVNET_RESTORE(); 519655f934bSMikolaj Golub return; 520655f934bSMikolaj Golub } 5215571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 5225571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 5239b8b58e0SJonathan Lemon /* 524a4641f4eSPedro F. Giffuni * Persistence timer into zero window. 5259b8b58e0SJonathan Lemon * Force a byte to be output, if possible. 5269b8b58e0SJonathan Lemon */ 52778b50714SRobert Watson TCPSTAT_INC(tcps_persisttimeo); 5289b8b58e0SJonathan Lemon /* 5299b8b58e0SJonathan Lemon * Hack: if the peer is dead/unreachable, we do not 5309b8b58e0SJonathan Lemon * time out if the window is closed. After a full 5319b8b58e0SJonathan Lemon * backoff, drop the connection if the idle time 5329b8b58e0SJonathan Lemon * (no responses to probes) reaches the maximum 5339b8b58e0SJonathan Lemon * backoff that we would use if retransmitting. 5349b8b58e0SJonathan Lemon */ 5359b8b58e0SJonathan Lemon if (tp->t_rxtshift == TCP_MAXRXTSHIFT && 5366b0c5521SJohn Baldwin (ticks - tp->t_rcvtime >= tcp_maxpersistidle || 5376b0c5521SJohn Baldwin ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { 53878b50714SRobert Watson TCPSTAT_INC(tcps_persistdrop); 539*6573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 540b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 541b07fef50SRandall Stewart goto out; 542b07fef50SRandall Stewart } 543*6573d758SMatt Macy INP_INFO_RLOCK_ET(&V_tcbinfo, et); 54485d94372SRobert Watson tp = tcp_drop(tp, ETIMEDOUT); 545*6573d758SMatt Macy INP_INFO_RUNLOCK_ET(&V_tcbinfo, et); 546b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 54785d94372SRobert Watson goto out; 5489b8b58e0SJonathan Lemon } 549322181c9SAndre Oppermann /* 550322181c9SAndre Oppermann * If the user has closed the socket then drop a persisting 551322181c9SAndre Oppermann * connection after a much reduced timeout. 552322181c9SAndre Oppermann */ 553322181c9SAndre Oppermann if (tp->t_state > TCPS_CLOSE_WAIT && 554322181c9SAndre Oppermann (ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) { 555322181c9SAndre Oppermann TCPSTAT_INC(tcps_persistdrop); 556*6573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 557b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 558b07fef50SRandall Stewart goto out; 559b07fef50SRandall Stewart } 560*6573d758SMatt Macy INP_INFO_RLOCK_ET(&V_tcbinfo, et); 561322181c9SAndre Oppermann tp = tcp_drop(tp, ETIMEDOUT); 562*6573d758SMatt Macy INP_INFO_RUNLOCK_ET(&V_tcbinfo, et); 563b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 564322181c9SAndre Oppermann goto out; 565322181c9SAndre Oppermann } 5669b8b58e0SJonathan Lemon tcp_setpersist(tp); 5672cdbfa66SPaul Saab tp->t_flags |= TF_FORCEDATA; 56855bceb1eSRandall Stewart (void) tp->t_fb->tfb_tcp_output(tp); 5692cdbfa66SPaul Saab tp->t_flags &= ~TF_FORCEDATA; 5709b8b58e0SJonathan Lemon 5719b8b58e0SJonathan Lemon #ifdef TCPDEBUG 572ffb761f6SGleb Smirnoff if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 573ffb761f6SGleb Smirnoff tcp_trace(TA_USER, ostate, tp, NULL, NULL, PRU_SLOWTIMO); 5749b8b58e0SJonathan Lemon #endif 5755d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 5768501a69cSRobert Watson INP_WUNLOCK(inp); 577b07fef50SRandall Stewart out: 5788b615593SMarko Zec CURVNET_RESTORE(); 5799b8b58e0SJonathan Lemon } 5809b8b58e0SJonathan Lemon 58185d94372SRobert Watson void 58285d94372SRobert Watson tcp_timer_rexmt(void * xtp) 5839b8b58e0SJonathan Lemon { 58485d94372SRobert Watson struct tcpcb *tp = xtp; 5858b615593SMarko Zec CURVNET_SET(tp->t_vnet); 5869b8b58e0SJonathan Lemon int rexmt; 58785d94372SRobert Watson struct inpcb *inp; 588*6573d758SMatt Macy struct epoch_tracker et; 5899b8b58e0SJonathan Lemon #ifdef TCPDEBUG 5909b8b58e0SJonathan Lemon int ostate; 5919b8b58e0SJonathan Lemon 5929b8b58e0SJonathan Lemon ostate = tp->t_state; 5939b8b58e0SJonathan Lemon #endif 59485d94372SRobert Watson inp = tp->t_inpcb; 5955571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 5968501a69cSRobert Watson INP_WLOCK(inp); 597655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_rexmt) || 598655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_rexmt)) { 5998501a69cSRobert Watson INP_WUNLOCK(inp); 6008b615593SMarko Zec CURVNET_RESTORE(); 60185d94372SRobert Watson return; 60285d94372SRobert Watson } 603e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_rexmt); 604655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 605655f934bSMikolaj Golub INP_WUNLOCK(inp); 606655f934bSMikolaj Golub CURVNET_RESTORE(); 607655f934bSMikolaj Golub return; 608655f934bSMikolaj Golub } 6095571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 6105571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 6116d90faf3SPaul Saab tcp_free_sackholes(tp); 6122529f56eSJonathan T. Looney TCP_LOG_EVENT(tp, NULL, NULL, NULL, TCP_LOG_RTO, 0, 0, NULL, false); 6135105a92cSRandall Stewart if (tp->t_fb->tfb_tcp_rexmit_tmr) { 6145105a92cSRandall Stewart /* The stack has a timer action too. */ 6155105a92cSRandall Stewart (*tp->t_fb->tfb_tcp_rexmit_tmr)(tp); 6165105a92cSRandall Stewart } 617df8bae1dSRodney W. Grimes /* 618df8bae1dSRodney W. Grimes * Retransmission timer went off. Message has not 619df8bae1dSRodney W. Grimes * been acked within retransmit interval. Back off 620df8bae1dSRodney W. Grimes * to a longer retransmit interval and retransmit one segment. 621df8bae1dSRodney W. Grimes */ 622df8bae1dSRodney W. Grimes if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 623df8bae1dSRodney W. Grimes tp->t_rxtshift = TCP_MAXRXTSHIFT; 62478b50714SRobert Watson TCPSTAT_INC(tcps_timeoutdrop); 625*6573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 626b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 62785d94372SRobert Watson goto out; 6289b8b58e0SJonathan Lemon } 629*6573d758SMatt Macy INP_INFO_RLOCK_ET(&V_tcbinfo, et); 6304c6a1090SMichael Tuexen tp = tcp_drop(tp, ETIMEDOUT); 631*6573d758SMatt Macy INP_INFO_RUNLOCK_ET(&V_tcbinfo, et); 632b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 633b07fef50SRandall Stewart goto out; 634b07fef50SRandall Stewart } 635cf8f04f4SAndre Oppermann if (tp->t_state == TCPS_SYN_SENT) { 636cf8f04f4SAndre Oppermann /* 637cf8f04f4SAndre Oppermann * If the SYN was retransmitted, indicate CWND to be 638cf8f04f4SAndre Oppermann * limited to 1 segment in cc_conn_init(). 639cf8f04f4SAndre Oppermann */ 640cf8f04f4SAndre Oppermann tp->snd_cwnd = 1; 641cf8f04f4SAndre Oppermann } else if (tp->t_rxtshift == 1) { 6429b8b58e0SJonathan Lemon /* 6439b8b58e0SJonathan Lemon * first retransmit; record ssthresh and cwnd so they can 6449b8b58e0SJonathan Lemon * be recovered if this turns out to be a "bad" retransmit. 6459b8b58e0SJonathan Lemon * A retransmit is considered "bad" if an ACK for this 6469b8b58e0SJonathan Lemon * segment is received within RTT/2 interval; the assumption 6479b8b58e0SJonathan Lemon * here is that the ACK was already in flight. See 6489b8b58e0SJonathan Lemon * "On Estimating End-to-End Network Path Properties" by 6499b8b58e0SJonathan Lemon * Allman and Paxson for more details. 6509b8b58e0SJonathan Lemon */ 6519b8b58e0SJonathan Lemon tp->snd_cwnd_prev = tp->snd_cwnd; 6529b8b58e0SJonathan Lemon tp->snd_ssthresh_prev = tp->snd_ssthresh; 6539d11646dSJeffrey Hsu tp->snd_recover_prev = tp->snd_recover; 654dbc42409SLawrence Stewart if (IN_FASTRECOVERY(tp->t_flags)) 6559d11646dSJeffrey Hsu tp->t_flags |= TF_WASFRECOVERY; 6569d11646dSJeffrey Hsu else 6579d11646dSJeffrey Hsu tp->t_flags &= ~TF_WASFRECOVERY; 658dbc42409SLawrence Stewart if (IN_CONGRECOVERY(tp->t_flags)) 659dbc42409SLawrence Stewart tp->t_flags |= TF_WASCRECOVERY; 660dbc42409SLawrence Stewart else 661dbc42409SLawrence Stewart tp->t_flags &= ~TF_WASCRECOVERY; 66210d20c84SMatt Macy if ((tp->t_flags & TF_RCVD_TSTMP) == 0) 6639b8b58e0SJonathan Lemon tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); 66410d20c84SMatt Macy /* In the event that we've negotiated timestamps 66510d20c84SMatt Macy * badrxtwin will be set to the value that we set 66610d20c84SMatt Macy * the retransmitted packet's to_tsval to by tcp_output 66710d20c84SMatt Macy */ 668672dc4aeSJohn Baldwin tp->t_flags |= TF_PREVVALID; 669672dc4aeSJohn Baldwin } else 670672dc4aeSJohn Baldwin tp->t_flags &= ~TF_PREVVALID; 67178b50714SRobert Watson TCPSTAT_INC(tcps_rexmttimeo); 672281a0fd4SPatrick Kelsey if ((tp->t_state == TCPS_SYN_SENT) || 673281a0fd4SPatrick Kelsey (tp->t_state == TCPS_SYN_RECEIVED)) 674f4748ef5SAndre Oppermann rexmt = TCPTV_RTOBASE * tcp_syn_backoff[tp->t_rxtshift]; 6757d42e30cSJonathan Lemon else 676df8bae1dSRodney W. Grimes rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; 677df8bae1dSRodney W. Grimes TCPT_RANGESET(tp->t_rxtcur, rexmt, 678df8bae1dSRodney W. Grimes tp->t_rttmin, TCPTV_REXMTMAX); 679f6f6703fSSean Bruno 680882ac53eSSean Bruno /* 681882ac53eSSean Bruno * We enter the path for PLMTUD if connection is established or, if 682882ac53eSSean Bruno * connection is FIN_WAIT_1 status, reason for the last is that if 683882ac53eSSean Bruno * amount of data we send is very small, we could send it in couple of 684882ac53eSSean Bruno * packets and process straight to FIN. In that case we won't catch 685882ac53eSSean Bruno * ESTABLISHED state. 686882ac53eSSean Bruno */ 687882ac53eSSean Bruno if (V_tcp_pmtud_blackhole_detect && (((tp->t_state == TCPS_ESTABLISHED)) 688882ac53eSSean Bruno || (tp->t_state == TCPS_FIN_WAIT_1))) { 689f6f6703fSSean Bruno #ifdef INET6 690f6f6703fSSean Bruno int isipv6; 691f6f6703fSSean Bruno #endif 692f6f6703fSSean Bruno 693adf43a92SHiren Panchasara /* 694adf43a92SHiren Panchasara * Idea here is that at each stage of mtu probe (usually, 1448 695adf43a92SHiren Panchasara * -> 1188 -> 524) should be given 2 chances to recover before 696adf43a92SHiren Panchasara * further clamping down. 'tp->t_rxtshift % 2 == 0' should 697adf43a92SHiren Panchasara * take care of that. 698adf43a92SHiren Panchasara */ 699f6f6703fSSean Bruno if (((tp->t_flags2 & (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) == 700f6f6703fSSean Bruno (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) && 7013d5af7a1SMichael Tuexen (tp->t_rxtshift >= 2 && tp->t_rxtshift < 6 && 7023d5af7a1SMichael Tuexen tp->t_rxtshift % 2 == 0)) { 703f6f6703fSSean Bruno /* 704f6f6703fSSean Bruno * Enter Path MTU Black-hole Detection mechanism: 705f6f6703fSSean Bruno * - Disable Path MTU Discovery (IP "DF" bit). 706f6f6703fSSean Bruno * - Reduce MTU to lower value than what we 707f6f6703fSSean Bruno * negotiated with peer. 708f6f6703fSSean Bruno */ 7093d5af7a1SMichael Tuexen if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) == 0) { 710f6f6703fSSean Bruno /* Record that we may have found a black hole. */ 711f6f6703fSSean Bruno tp->t_flags2 |= TF2_PLPMTU_BLACKHOLE; 712f6f6703fSSean Bruno /* Keep track of previous MSS. */ 7130c39d38dSGleb Smirnoff tp->t_pmtud_saved_maxseg = tp->t_maxseg; 7143d5af7a1SMichael Tuexen } 715f6f6703fSSean Bruno 716f6f6703fSSean Bruno /* 717f6f6703fSSean Bruno * Reduce the MSS to blackhole value or to the default 718f6f6703fSSean Bruno * in an attempt to retransmit. 719f6f6703fSSean Bruno */ 720f6f6703fSSean Bruno #ifdef INET6 721f6f6703fSSean Bruno isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) ? 1 : 0; 722f6f6703fSSean Bruno if (isipv6 && 7230c39d38dSGleb Smirnoff tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss) { 724f6f6703fSSean Bruno /* Use the sysctl tuneable blackhole MSS. */ 7250c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_v6pmtud_blackhole_mss; 72632a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated); 727f6f6703fSSean Bruno } else if (isipv6) { 728f6f6703fSSean Bruno /* Use the default MSS. */ 7290c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_v6mssdflt; 730f6f6703fSSean Bruno /* 731f6f6703fSSean Bruno * Disable Path MTU Discovery when we switch to 732f6f6703fSSean Bruno * minmss. 733f6f6703fSSean Bruno */ 734f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 73532a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); 736f6f6703fSSean Bruno } 737f6f6703fSSean Bruno #endif 738f6f6703fSSean Bruno #if defined(INET6) && defined(INET) 739f6f6703fSSean Bruno else 740f6f6703fSSean Bruno #endif 741f6f6703fSSean Bruno #ifdef INET 7420c39d38dSGleb Smirnoff if (tp->t_maxseg > V_tcp_pmtud_blackhole_mss) { 743f6f6703fSSean Bruno /* Use the sysctl tuneable blackhole MSS. */ 7440c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_pmtud_blackhole_mss; 74532a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated); 746f6f6703fSSean Bruno } else { 747f6f6703fSSean Bruno /* Use the default MSS. */ 7480c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_mssdflt; 749f6f6703fSSean Bruno /* 750f6f6703fSSean Bruno * Disable Path MTU Discovery when we switch to 751f6f6703fSSean Bruno * minmss. 752f6f6703fSSean Bruno */ 753f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 75432a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); 755f6f6703fSSean Bruno } 756f6f6703fSSean Bruno #endif 757f6f6703fSSean Bruno /* 758f6f6703fSSean Bruno * Reset the slow-start flight size 759f6f6703fSSean Bruno * as it may depend on the new MSS. 760f6f6703fSSean Bruno */ 761f6f6703fSSean Bruno if (CC_ALGO(tp)->conn_init != NULL) 762f6f6703fSSean Bruno CC_ALGO(tp)->conn_init(tp->ccv); 763f6f6703fSSean Bruno } else { 764f6f6703fSSean Bruno /* 765f6f6703fSSean Bruno * If further retransmissions are still unsuccessful 766f6f6703fSSean Bruno * with a lowered MTU, maybe this isn't a blackhole and 767f6f6703fSSean Bruno * we restore the previous MSS and blackhole detection 768f6f6703fSSean Bruno * flags. 769adf43a92SHiren Panchasara * The limit '6' is determined by giving each probe 770adf43a92SHiren Panchasara * stage (1448, 1188, 524) 2 chances to recover. 771f6f6703fSSean Bruno */ 772f6f6703fSSean Bruno if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) && 7733d5af7a1SMichael Tuexen (tp->t_rxtshift >= 6)) { 774f6f6703fSSean Bruno tp->t_flags2 |= TF2_PLPMTU_PMTUD; 775f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_BLACKHOLE; 7760c39d38dSGleb Smirnoff tp->t_maxseg = tp->t_pmtud_saved_maxseg; 77732a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_failed); 778f6f6703fSSean Bruno /* 779f6f6703fSSean Bruno * Reset the slow-start flight size as it 780f6f6703fSSean Bruno * may depend on the new MSS. 781f6f6703fSSean Bruno */ 782f6f6703fSSean Bruno if (CC_ALGO(tp)->conn_init != NULL) 783f6f6703fSSean Bruno CC_ALGO(tp)->conn_init(tp->ccv); 784f6f6703fSSean Bruno } 785f6f6703fSSean Bruno } 786f6f6703fSSean Bruno } 787f6f6703fSSean Bruno 788df8bae1dSRodney W. Grimes /* 78977339e1cSAndre Oppermann * Disable RFC1323 and SACK if we haven't got any response to 7907ceb7783SJesper Skriver * our third SYN to work-around some broken terminal servers 7917ceb7783SJesper Skriver * (most of which have hopefully been retired) that have bad VJ 7927ceb7783SJesper Skriver * header compression code which trashes TCP segments containing 7937ceb7783SJesper Skriver * unknown-to-them TCP options. 7947ceb7783SJesper Skriver */ 7956c0ef895SJohn Baldwin if (tcp_rexmit_drop_options && (tp->t_state == TCPS_SYN_SENT) && 7966c0ef895SJohn Baldwin (tp->t_rxtshift == 3)) 797c4ab59c1SAndre Oppermann tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_SACK_PERMIT); 7987ceb7783SJesper Skriver /* 7995ede40dcSRyan Stone * If we backed off this far, notify the L3 protocol that we're having 8005ede40dcSRyan Stone * connection problems. 801df8bae1dSRodney W. Grimes */ 8025ede40dcSRyan Stone if (tp->t_rxtshift > TCP_RTT_INVALIDATE) { 803fb59c426SYoshinobu Inoue #ifdef INET6 804fb59c426SYoshinobu Inoue if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) 805fb59c426SYoshinobu Inoue in6_losing(tp->t_inpcb); 80684cc0778SGeorge V. Neville-Neil else 807fb59c426SYoshinobu Inoue #endif 80884cc0778SGeorge V. Neville-Neil in_losing(tp->t_inpcb); 809df8bae1dSRodney W. Grimes } 810df8bae1dSRodney W. Grimes tp->snd_nxt = tp->snd_una; 8119d11646dSJeffrey Hsu tp->snd_recover = tp->snd_max; 81246f58482SJonathan Lemon /* 81374b48c1dSAndras Olah * Force a segment to be sent. 81474b48c1dSAndras Olah */ 81574b48c1dSAndras Olah tp->t_flags |= TF_ACKNOW; 81674b48c1dSAndras Olah /* 817df8bae1dSRodney W. Grimes * If timing a segment in this window, stop the timer. 818df8bae1dSRodney W. Grimes */ 8199b8b58e0SJonathan Lemon tp->t_rtttime = 0; 820dbc42409SLawrence Stewart 821b5af1b88SLawrence Stewart cc_cong_signal(tp, NULL, CC_RTO); 822dbc42409SLawrence Stewart 82355bceb1eSRandall Stewart (void) tp->t_fb->tfb_tcp_output(tp); 824df8bae1dSRodney W. Grimes 8259b8b58e0SJonathan Lemon #ifdef TCPDEBUG 8261c53f806SRobert Watson if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 827fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 8289b8b58e0SJonathan Lemon PRU_SLOWTIMO); 829df8bae1dSRodney W. Grimes #endif 8305d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 8318501a69cSRobert Watson INP_WUNLOCK(inp); 832b07fef50SRandall Stewart out: 8338b615593SMarko Zec CURVNET_RESTORE(); 83485d94372SRobert Watson } 83585d94372SRobert Watson 83685d94372SRobert Watson void 8375571f9cfSJulien Charbon tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, u_int delta) 83885d94372SRobert Watson { 83985d94372SRobert Watson struct callout *t_callout; 84018832f1fSJulien Charbon timeout_t *f_callout; 84187aedea4SKip Macy struct inpcb *inp = tp->t_inpcb; 842883831c6SAdrian Chadd int cpu = inp_to_cpuid(inp); 84385d94372SRobert Watson 84409fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD 84509fe6320SNavdeep Parhar if (tp->t_flags & TF_TOE) 84609fe6320SNavdeep Parhar return; 84709fe6320SNavdeep Parhar #endif 84809fe6320SNavdeep Parhar 8495571f9cfSJulien Charbon if (tp->t_timers->tt_flags & TT_STOPPED) 8505571f9cfSJulien Charbon return; 8515571f9cfSJulien Charbon 85285d94372SRobert Watson switch (timer_type) { 85385d94372SRobert Watson case TT_DELACK: 854e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 85585d94372SRobert Watson f_callout = tcp_timer_delack; 85685d94372SRobert Watson break; 85785d94372SRobert Watson case TT_REXMT: 858e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 85985d94372SRobert Watson f_callout = tcp_timer_rexmt; 86085d94372SRobert Watson break; 86185d94372SRobert Watson case TT_PERSIST: 862e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 86385d94372SRobert Watson f_callout = tcp_timer_persist; 86485d94372SRobert Watson break; 86585d94372SRobert Watson case TT_KEEP: 866e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 86785d94372SRobert Watson f_callout = tcp_timer_keep; 86885d94372SRobert Watson break; 86985d94372SRobert Watson case TT_2MSL: 870e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 87185d94372SRobert Watson f_callout = tcp_timer_2msl; 87285d94372SRobert Watson break; 87385d94372SRobert Watson default: 87455bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_activate) { 87555bceb1eSRandall Stewart tp->t_fb->tfb_tcp_timer_activate(tp, timer_type, delta); 87655bceb1eSRandall Stewart return; 87755bceb1eSRandall Stewart } 87803374917SJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 87985d94372SRobert Watson } 88085d94372SRobert Watson if (delta == 0) { 881b07fef50SRandall Stewart callout_stop(t_callout); 88285d94372SRobert Watson } else { 88387aedea4SKip Macy callout_reset_on(t_callout, delta, f_callout, tp, cpu); 88485d94372SRobert Watson } 88585d94372SRobert Watson } 88685d94372SRobert Watson 88785d94372SRobert Watson int 8885571f9cfSJulien Charbon tcp_timer_active(struct tcpcb *tp, uint32_t timer_type) 88985d94372SRobert Watson { 89085d94372SRobert Watson struct callout *t_callout; 89185d94372SRobert Watson 89285d94372SRobert Watson switch (timer_type) { 89385d94372SRobert Watson case TT_DELACK: 894e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 89585d94372SRobert Watson break; 89685d94372SRobert Watson case TT_REXMT: 897e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 89885d94372SRobert Watson break; 89985d94372SRobert Watson case TT_PERSIST: 900e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 90185d94372SRobert Watson break; 90285d94372SRobert Watson case TT_KEEP: 903e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 90485d94372SRobert Watson break; 90585d94372SRobert Watson case TT_2MSL: 906e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 90785d94372SRobert Watson break; 90885d94372SRobert Watson default: 90955bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_active) { 91055bceb1eSRandall Stewart return(tp->t_fb->tfb_tcp_timer_active(tp, timer_type)); 91155bceb1eSRandall Stewart } 91203374917SJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 91385d94372SRobert Watson } 91485d94372SRobert Watson return callout_active(t_callout); 915df8bae1dSRodney W. Grimes } 916b8614722SMike Silbersack 91789e560f4SRandall Stewart /* 91889e560f4SRandall Stewart * Stop the timer from running, and apply a flag 91989e560f4SRandall Stewart * against the timer_flags that will force the 92089e560f4SRandall Stewart * timer never to run. The flag is needed to assure 92189e560f4SRandall Stewart * a race does not leave it running and cause 92289e560f4SRandall Stewart * the timer to possibly restart itself (keep and persist 92389e560f4SRandall Stewart * especially do this). 92489e560f4SRandall Stewart */ 92589e560f4SRandall Stewart int 92689e560f4SRandall Stewart tcp_timer_suspend(struct tcpcb *tp, uint32_t timer_type) 92789e560f4SRandall Stewart { 92889e560f4SRandall Stewart struct callout *t_callout; 92989e560f4SRandall Stewart uint32_t t_flags; 93089e560f4SRandall Stewart 93189e560f4SRandall Stewart switch (timer_type) { 93289e560f4SRandall Stewart case TT_DELACK: 93389e560f4SRandall Stewart t_flags = TT_DELACK_SUS; 93489e560f4SRandall Stewart t_callout = &tp->t_timers->tt_delack; 93589e560f4SRandall Stewart break; 93689e560f4SRandall Stewart case TT_REXMT: 93789e560f4SRandall Stewart t_flags = TT_REXMT_SUS; 93889e560f4SRandall Stewart t_callout = &tp->t_timers->tt_rexmt; 93989e560f4SRandall Stewart break; 94089e560f4SRandall Stewart case TT_PERSIST: 94189e560f4SRandall Stewart t_flags = TT_PERSIST_SUS; 94289e560f4SRandall Stewart t_callout = &tp->t_timers->tt_persist; 94389e560f4SRandall Stewart break; 94489e560f4SRandall Stewart case TT_KEEP: 94589e560f4SRandall Stewart t_flags = TT_KEEP_SUS; 94689e560f4SRandall Stewart t_callout = &tp->t_timers->tt_keep; 94789e560f4SRandall Stewart break; 94889e560f4SRandall Stewart case TT_2MSL: 94989e560f4SRandall Stewart t_flags = TT_2MSL_SUS; 95089e560f4SRandall Stewart t_callout = &tp->t_timers->tt_2msl; 95189e560f4SRandall Stewart break; 95289e560f4SRandall Stewart default: 95389e560f4SRandall Stewart panic("tp:%p bad timer_type 0x%x", tp, timer_type); 95489e560f4SRandall Stewart } 95589e560f4SRandall Stewart tp->t_timers->tt_flags |= t_flags; 95689e560f4SRandall Stewart return (callout_stop(t_callout)); 95789e560f4SRandall Stewart } 95889e560f4SRandall Stewart 95989e560f4SRandall Stewart void 96089e560f4SRandall Stewart tcp_timers_unsuspend(struct tcpcb *tp, uint32_t timer_type) 96189e560f4SRandall Stewart { 96289e560f4SRandall Stewart switch (timer_type) { 96389e560f4SRandall Stewart case TT_DELACK: 96489e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_DELACK_SUS) { 96589e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_DELACK_SUS; 96689e560f4SRandall Stewart if (tp->t_flags & TF_DELACK) { 96789e560f4SRandall Stewart /* Delayed ack timer should be up activate a timer */ 96889e560f4SRandall Stewart tp->t_flags &= ~TF_DELACK; 96989e560f4SRandall Stewart tcp_timer_activate(tp, TT_DELACK, 97089e560f4SRandall Stewart tcp_delacktime); 97189e560f4SRandall Stewart } 97289e560f4SRandall Stewart } 97389e560f4SRandall Stewart break; 97489e560f4SRandall Stewart case TT_REXMT: 97589e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_REXMT_SUS) { 97689e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_REXMT_SUS; 97789e560f4SRandall Stewart if (SEQ_GT(tp->snd_max, tp->snd_una) && 97889e560f4SRandall Stewart (tcp_timer_active((tp), TT_PERSIST) == 0) && 97989e560f4SRandall Stewart tp->snd_wnd) { 98089e560f4SRandall Stewart /* We have outstanding data activate a timer */ 98189e560f4SRandall Stewart tcp_timer_activate(tp, TT_REXMT, 98289e560f4SRandall Stewart tp->t_rxtcur); 98389e560f4SRandall Stewart } 98489e560f4SRandall Stewart } 98589e560f4SRandall Stewart break; 98689e560f4SRandall Stewart case TT_PERSIST: 98789e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_PERSIST_SUS) { 98889e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_PERSIST_SUS; 98989e560f4SRandall Stewart if (tp->snd_wnd == 0) { 99089e560f4SRandall Stewart /* Activate the persists timer */ 99189e560f4SRandall Stewart tp->t_rxtshift = 0; 99289e560f4SRandall Stewart tcp_setpersist(tp); 99389e560f4SRandall Stewart } 99489e560f4SRandall Stewart } 99589e560f4SRandall Stewart break; 99689e560f4SRandall Stewart case TT_KEEP: 99789e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_KEEP_SUS) { 99889e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_KEEP_SUS; 99989e560f4SRandall Stewart tcp_timer_activate(tp, TT_KEEP, 100089e560f4SRandall Stewart TCPS_HAVEESTABLISHED(tp->t_state) ? 100189e560f4SRandall Stewart TP_KEEPIDLE(tp) : TP_KEEPINIT(tp)); 100289e560f4SRandall Stewart } 100389e560f4SRandall Stewart break; 100489e560f4SRandall Stewart case TT_2MSL: 100589e560f4SRandall Stewart if (tp->t_timers->tt_flags &= TT_2MSL_SUS) { 100689e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_2MSL_SUS; 100789e560f4SRandall Stewart if ((tp->t_state == TCPS_FIN_WAIT_2) && 100889e560f4SRandall Stewart ((tp->t_inpcb->inp_socket == NULL) || 100989e560f4SRandall Stewart (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE))) { 101089e560f4SRandall Stewart /* Star the 2MSL timer */ 101189e560f4SRandall Stewart tcp_timer_activate(tp, TT_2MSL, 101289e560f4SRandall Stewart (tcp_fast_finwait2_recycle) ? 101389e560f4SRandall Stewart tcp_finwait2_timeout : TP_MAXIDLE(tp)); 101489e560f4SRandall Stewart } 101589e560f4SRandall Stewart } 101689e560f4SRandall Stewart break; 101789e560f4SRandall Stewart default: 101889e560f4SRandall Stewart panic("tp:%p bad timer_type 0x%x", tp, timer_type); 101989e560f4SRandall Stewart } 102089e560f4SRandall Stewart } 102189e560f4SRandall Stewart 10225571f9cfSJulien Charbon void 10235571f9cfSJulien Charbon tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type) 10245571f9cfSJulien Charbon { 10255571f9cfSJulien Charbon struct callout *t_callout; 10265571f9cfSJulien Charbon 10275571f9cfSJulien Charbon tp->t_timers->tt_flags |= TT_STOPPED; 10285571f9cfSJulien Charbon switch (timer_type) { 10295571f9cfSJulien Charbon case TT_DELACK: 10305571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_delack; 10315571f9cfSJulien Charbon break; 10325571f9cfSJulien Charbon case TT_REXMT: 10335571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_rexmt; 10345571f9cfSJulien Charbon break; 10355571f9cfSJulien Charbon case TT_PERSIST: 10365571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_persist; 10375571f9cfSJulien Charbon break; 10385571f9cfSJulien Charbon case TT_KEEP: 10395571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_keep; 10405571f9cfSJulien Charbon break; 10415571f9cfSJulien Charbon case TT_2MSL: 10425571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_2msl; 10435571f9cfSJulien Charbon break; 10445571f9cfSJulien Charbon default: 104555bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_stop) { 104655bceb1eSRandall Stewart /* 104755bceb1eSRandall Stewart * XXXrrs we need to look at this with the 104855bceb1eSRandall Stewart * stop case below (flags). 104955bceb1eSRandall Stewart */ 105055bceb1eSRandall Stewart tp->t_fb->tfb_tcp_timer_stop(tp, timer_type); 105155bceb1eSRandall Stewart return; 105255bceb1eSRandall Stewart } 10535571f9cfSJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 10545571f9cfSJulien Charbon } 10555571f9cfSJulien Charbon 1056e5ad6456SRandall Stewart if (callout_async_drain(t_callout, tcp_timer_discard) == 0) { 10575571f9cfSJulien Charbon /* 10585571f9cfSJulien Charbon * Can't stop the callout, defer tcpcb actual deletion 1059e5ad6456SRandall Stewart * to the last one. We do this using the async drain 1060e5ad6456SRandall Stewart * function and incrementing the count in 10615571f9cfSJulien Charbon */ 1062e5ad6456SRandall Stewart tp->t_timers->tt_draincnt++; 10635571f9cfSJulien Charbon } 10645571f9cfSJulien Charbon } 1065