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; 857029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, persmin, 867029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 877029da5cSPawel Biernacki &tcp_persmin, 0, sysctl_msec_to_ticks, "I", 887029da5cSPawel Biernacki "minimum persistence interval"); 890645c604SHiren Panchasara 900645c604SHiren Panchasara int tcp_persmax; 917029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, persmax, 927029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 937029da5cSPawel Biernacki &tcp_persmax, 0, sysctl_msec_to_ticks, "I", 947029da5cSPawel Biernacki "maximum persistence interval"); 950645c604SHiren Panchasara 969b8b58e0SJonathan Lemon int tcp_keepinit; 977029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, 987029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 997029da5cSPawel Biernacki &tcp_keepinit, 0, sysctl_msec_to_ticks, "I", 1007029da5cSPawel Biernacki "time to establish connection"); 1017b40aa32SPaul Traina 1029b8b58e0SJonathan Lemon int tcp_keepidle; 1037029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, 1047029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1057029da5cSPawel Biernacki &tcp_keepidle, 0, sysctl_msec_to_ticks, "I", 1067029da5cSPawel Biernacki "time before keepalive probes begin"); 10798163b98SPoul-Henning Kamp 1089b8b58e0SJonathan Lemon int tcp_keepintvl; 1097029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, 1107029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1117029da5cSPawel Biernacki &tcp_keepintvl, 0, sysctl_msec_to_ticks, "I", 1127029da5cSPawel Biernacki "time between keepalive probes"); 11398163b98SPoul-Henning Kamp 1149b8b58e0SJonathan Lemon int tcp_delacktime; 1157029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, TCPCTL_DELACKTIME, delacktime, 1167029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1176489fe65SAndre Oppermann &tcp_delacktime, 0, sysctl_msec_to_ticks, "I", 118ccb4d0c6SJonathan Lemon "Time before a delayed ACK is sent"); 1199b8b58e0SJonathan Lemon 1209b8b58e0SJonathan Lemon int tcp_msl; 1217029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl, 1227029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1237029da5cSPawel Biernacki &tcp_msl, 0, sysctl_msec_to_ticks, "I", 1247029da5cSPawel Biernacki "Maximum segment lifetime"); 1259b8b58e0SJonathan Lemon 1260999766dSMichael Tuexen int tcp_rexmit_initial; 1277029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_initial, 1287029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1290999766dSMichael Tuexen &tcp_rexmit_initial, 0, sysctl_msec_to_ticks, "I", 1300999766dSMichael Tuexen "Initial Retransmission Timeout"); 1310999766dSMichael Tuexen 132701bec5aSMatthew Dillon int tcp_rexmit_min; 1337029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_min, 1347029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1356489fe65SAndre Oppermann &tcp_rexmit_min, 0, sysctl_msec_to_ticks, "I", 1366489fe65SAndre Oppermann "Minimum Retransmission Timeout"); 137701bec5aSMatthew Dillon 138701bec5aSMatthew Dillon int tcp_rexmit_slop; 1397029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_slop, 1407029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1416489fe65SAndre Oppermann &tcp_rexmit_slop, 0, sysctl_msec_to_ticks, "I", 1426489fe65SAndre Oppermann "Retransmission Timer Slop"); 143701bec5aSMatthew Dillon 144334fc582SBjoern A. Zeeb VNET_DEFINE(int, tcp_always_keepalive) = 1; 145334fc582SBjoern A. Zeeb SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_VNET|CTLFLAG_RW, 146334fc582SBjoern A. Zeeb &VNET_NAME(tcp_always_keepalive) , 0, 147334fc582SBjoern A. Zeeb "Assume SO_KEEPALIVE on all TCP connections"); 14834be9bf3SPoul-Henning Kamp 1497c72af87SMohan Srinivasan int tcp_fast_finwait2_recycle = 0; 1507c72af87SMohan Srinivasan SYSCTL_INT(_net_inet_tcp, OID_AUTO, fast_finwait2_recycle, CTLFLAG_RW, 1516489fe65SAndre Oppermann &tcp_fast_finwait2_recycle, 0, 1526489fe65SAndre Oppermann "Recycle closed FIN_WAIT_2 connections faster"); 1537c72af87SMohan Srinivasan 1547c72af87SMohan Srinivasan int tcp_finwait2_timeout; 1557029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, 1567029da5cSPawel Biernacki CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NEEDGIANT, 1577029da5cSPawel Biernacki &tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", 1587029da5cSPawel Biernacki "FIN-WAIT2 timeout"); 1597c72af87SMohan Srinivasan 1609077f387SGleb Smirnoff int tcp_keepcnt = TCPTV_KEEPCNT; 1619077f387SGleb Smirnoff SYSCTL_INT(_net_inet_tcp, OID_AUTO, keepcnt, CTLFLAG_RW, &tcp_keepcnt, 0, 1629077f387SGleb Smirnoff "Number of keepalive probes to send"); 1637c72af87SMohan Srinivasan 1640312fbe9SPoul-Henning Kamp /* max idle probes */ 1659b8b58e0SJonathan Lemon int tcp_maxpersistidle; 166e79adb8eSGarrett Wollman 16789e560f4SRandall Stewart int tcp_rexmit_drop_options = 0; 1686c0ef895SJohn Baldwin SYSCTL_INT(_net_inet_tcp, OID_AUTO, rexmit_drop_options, CTLFLAG_RW, 1696c0ef895SJohn Baldwin &tcp_rexmit_drop_options, 0, 1706c0ef895SJohn Baldwin "Drop TCP options from 3rd and later retransmitted SYN"); 1716c0ef895SJohn Baldwin 172e29c55e4SGleb Smirnoff VNET_DEFINE(int, tcp_pmtud_blackhole_detect); 173f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_detection, 174f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 175f6f6703fSSean Bruno &VNET_NAME(tcp_pmtud_blackhole_detect), 0, 176f6f6703fSSean Bruno "Path MTU Discovery Black Hole Detection Enabled"); 177f6f6703fSSean Bruno 178f6f6703fSSean Bruno #ifdef INET 179e29c55e4SGleb Smirnoff VNET_DEFINE(int, tcp_pmtud_blackhole_mss) = 1200; 180f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_mss, 181f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 182f6f6703fSSean Bruno &VNET_NAME(tcp_pmtud_blackhole_mss), 0, 183f6f6703fSSean Bruno "Path MTU Discovery Black Hole Detection lowered MSS"); 184f6f6703fSSean Bruno #endif 185f6f6703fSSean Bruno 186f6f6703fSSean Bruno #ifdef INET6 187e29c55e4SGleb Smirnoff VNET_DEFINE(int, tcp_v6pmtud_blackhole_mss) = 1220; 188f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, v6pmtud_blackhole_mss, 189f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 190f6f6703fSSean Bruno &VNET_NAME(tcp_v6pmtud_blackhole_mss), 0, 191f6f6703fSSean Bruno "Path MTU Discovery IPv6 Black Hole Detection lowered MSS"); 192f6f6703fSSean Bruno #endif 193f6f6703fSSean Bruno 1948f7e75cbSAdrian Chadd #ifdef RSS 1958f7e75cbSAdrian Chadd static int per_cpu_timers = 1; 1968f7e75cbSAdrian Chadd #else 19787aedea4SKip Macy static int per_cpu_timers = 0; 1988f7e75cbSAdrian Chadd #endif 19987aedea4SKip Macy SYSCTL_INT(_net_inet_tcp, OID_AUTO, per_cpu_timers, CTLFLAG_RW, 20087aedea4SKip Macy &per_cpu_timers , 0, "run tcp timers on all cpus"); 20187aedea4SKip Macy 202883831c6SAdrian Chadd /* 203883831c6SAdrian Chadd * Map the given inp to a CPU id. 204883831c6SAdrian Chadd * 205883831c6SAdrian Chadd * This queries RSS if it's compiled in, else it defaults to the current 206883831c6SAdrian Chadd * CPU ID. 207883831c6SAdrian Chadd */ 20889e560f4SRandall Stewart inline int 209883831c6SAdrian Chadd inp_to_cpuid(struct inpcb *inp) 210883831c6SAdrian Chadd { 211883831c6SAdrian Chadd u_int cpuid; 212883831c6SAdrian Chadd 213883831c6SAdrian Chadd #ifdef RSS 214883831c6SAdrian Chadd if (per_cpu_timers) { 215883831c6SAdrian Chadd cpuid = rss_hash2cpuid(inp->inp_flowid, inp->inp_flowtype); 216883831c6SAdrian Chadd if (cpuid == NETISR_CPUID_NONE) 217883831c6SAdrian Chadd return (curcpu); /* XXX */ 218883831c6SAdrian Chadd else 219883831c6SAdrian Chadd return (cpuid); 220883831c6SAdrian Chadd } 221883831c6SAdrian Chadd #else 222883831c6SAdrian Chadd /* Legacy, pre-RSS behaviour */ 223883831c6SAdrian Chadd if (per_cpu_timers) { 224883831c6SAdrian Chadd /* 225883831c6SAdrian Chadd * We don't have a flowid -> cpuid mapping, so cheat and 226883831c6SAdrian Chadd * just map unknown cpuids to curcpu. Not the best, but 227883831c6SAdrian Chadd * apparently better than defaulting to swi 0. 228883831c6SAdrian Chadd */ 229883831c6SAdrian Chadd cpuid = inp->inp_flowid % (mp_maxid + 1); 230883831c6SAdrian Chadd if (! CPU_ABSENT(cpuid)) 231883831c6SAdrian Chadd return (cpuid); 232883831c6SAdrian Chadd return (curcpu); 233883831c6SAdrian Chadd } 234883831c6SAdrian Chadd #endif 235883831c6SAdrian Chadd /* Default for RSS and non-RSS - cpuid 0 */ 236883831c6SAdrian Chadd else { 237883831c6SAdrian Chadd return (0); 238883831c6SAdrian Chadd } 239883831c6SAdrian Chadd } 24087aedea4SKip Macy 241df8bae1dSRodney W. Grimes /* 242df8bae1dSRodney W. Grimes * Tcp protocol timeout routine called every 500 ms. 2439b8b58e0SJonathan Lemon * Updates timestamps used for TCP 244df8bae1dSRodney W. Grimes * causes finite state machine actions if timers expire. 245df8bae1dSRodney W. Grimes */ 246df8bae1dSRodney W. Grimes void 247e2f2059fSMike Silbersack tcp_slowtimo(void) 248df8bae1dSRodney W. Grimes { 2498b615593SMarko Zec VNET_ITERATOR_DECL(vnet_iter); 25015bd2b43SDavid Greenman 2515ee847d3SRobert Watson VNET_LIST_RLOCK_NOSLEEP(); 2528b615593SMarko Zec VNET_FOREACH(vnet_iter) { 2538b615593SMarko Zec CURVNET_SET(vnet_iter); 254cea40c48SJulien Charbon (void) tcp_tw_2msl_scan(0); 2558b615593SMarko Zec CURVNET_RESTORE(); 2568b615593SMarko Zec } 2575ee847d3SRobert Watson VNET_LIST_RUNLOCK_NOSLEEP(); 258df8bae1dSRodney W. Grimes } 259df8bae1dSRodney W. Grimes 260df8bae1dSRodney W. Grimes int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 261f058535dSJeffrey Hsu { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 512, 512, 512 }; 262df8bae1dSRodney W. Grimes 26389e560f4SRandall Stewart int tcp_totbackoff = 2559; /* sum of tcp_backoff[] */ 264e79adb8eSGarrett Wollman 265df8bae1dSRodney W. Grimes /* 266df8bae1dSRodney W. Grimes * TCP timer processing. 267df8bae1dSRodney W. Grimes */ 26885d94372SRobert Watson 26985d94372SRobert Watson void 27085d94372SRobert Watson tcp_timer_delack(void *xtp) 271df8bae1dSRodney W. Grimes { 272109eb549SGleb Smirnoff struct epoch_tracker et; 27385d94372SRobert Watson struct tcpcb *tp = xtp; 27485d94372SRobert Watson struct inpcb *inp; 2758b615593SMarko Zec CURVNET_SET(tp->t_vnet); 27685d94372SRobert Watson 27785d94372SRobert Watson inp = tp->t_inpcb; 2785571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 2798501a69cSRobert Watson INP_WLOCK(inp); 280655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_delack) || 281655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_delack)) { 2828501a69cSRobert Watson INP_WUNLOCK(inp); 2838b615593SMarko Zec CURVNET_RESTORE(); 28485d94372SRobert Watson return; 28585d94372SRobert Watson } 286e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_delack); 287655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 288655f934bSMikolaj Golub INP_WUNLOCK(inp); 289655f934bSMikolaj Golub CURVNET_RESTORE(); 290655f934bSMikolaj Golub return; 291655f934bSMikolaj Golub } 2929b8b58e0SJonathan Lemon tp->t_flags |= TF_ACKNOW; 29378b50714SRobert Watson TCPSTAT_INC(tcps_delack); 294109eb549SGleb Smirnoff NET_EPOCH_ENTER(et); 29555bceb1eSRandall Stewart (void) tp->t_fb->tfb_tcp_output(tp); 2968501a69cSRobert Watson INP_WUNLOCK(inp); 297109eb549SGleb Smirnoff NET_EPOCH_EXIT(et); 2988b615593SMarko Zec CURVNET_RESTORE(); 2999b8b58e0SJonathan Lemon } 3009b8b58e0SJonathan Lemon 301b07fef50SRandall Stewart void 302b07fef50SRandall Stewart tcp_inpinfo_lock_del(struct inpcb *inp, struct tcpcb *tp) 303b07fef50SRandall Stewart { 3046573d758SMatt Macy if (inp && tp != NULL) 305b07fef50SRandall Stewart INP_WUNLOCK(inp); 306b07fef50SRandall Stewart } 307b07fef50SRandall Stewart 30885d94372SRobert Watson void 30985d94372SRobert Watson tcp_timer_2msl(void *xtp) 3109b8b58e0SJonathan Lemon { 31185d94372SRobert Watson struct tcpcb *tp = xtp; 31285d94372SRobert Watson struct inpcb *inp; 3136573d758SMatt Macy struct epoch_tracker et; 3148b615593SMarko Zec CURVNET_SET(tp->t_vnet); 3159b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3169b8b58e0SJonathan Lemon int ostate; 3179b8b58e0SJonathan Lemon 3189b8b58e0SJonathan Lemon ostate = tp->t_state; 3199b8b58e0SJonathan Lemon #endif 32085d94372SRobert Watson inp = tp->t_inpcb; 3215571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 3228501a69cSRobert Watson INP_WLOCK(inp); 32385d94372SRobert Watson tcp_free_sackholes(tp); 324655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_2msl) || 325e2f2059fSMike Silbersack !callout_active(&tp->t_timers->tt_2msl)) { 3268501a69cSRobert Watson INP_WUNLOCK(tp->t_inpcb); 3278b615593SMarko Zec CURVNET_RESTORE(); 32885d94372SRobert Watson return; 32985d94372SRobert Watson } 330e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_2msl); 331655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 332655f934bSMikolaj Golub INP_WUNLOCK(inp); 333655f934bSMikolaj Golub CURVNET_RESTORE(); 334655f934bSMikolaj Golub return; 335655f934bSMikolaj Golub } 3365571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 3375571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 33885d94372SRobert Watson /* 339df8bae1dSRodney W. Grimes * 2 MSL timeout in shutdown went off. If we're closed but 340df8bae1dSRodney W. Grimes * still waiting for peer to close and connection has been idle 34131a7749dSJulien Charbon * too long delete connection control block. Otherwise, check 34231a7749dSJulien Charbon * again in a bit. 34331a7749dSJulien Charbon * 34431a7749dSJulien Charbon * If in TIME_WAIT state just ignore as this timeout is handled in 34531a7749dSJulien Charbon * tcp_tw_2msl_scan(). 3467c72af87SMohan Srinivasan * 3477c72af87SMohan Srinivasan * If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, 3487c72af87SMohan Srinivasan * there's no point in hanging onto FIN_WAIT_2 socket. Just close it. 3497c72af87SMohan Srinivasan * Ignore fact that there were recent incoming segments. 350df8bae1dSRodney W. Grimes */ 35131a7749dSJulien Charbon if ((inp->inp_flags & INP_TIMEWAIT) != 0) { 35231a7749dSJulien Charbon INP_WUNLOCK(inp); 35331a7749dSJulien Charbon CURVNET_RESTORE(); 35431a7749dSJulien Charbon return; 35531a7749dSJulien Charbon } 3567c72af87SMohan Srinivasan if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && 35785d94372SRobert Watson tp->t_inpcb && tp->t_inpcb->inp_socket && 3587c72af87SMohan Srinivasan (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { 35978b50714SRobert Watson TCPSTAT_INC(tcps_finwait2_drops); 3606573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 361b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 362b07fef50SRandall Stewart goto out; 363b07fef50SRandall Stewart } 36458d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 36585d94372SRobert Watson tp = tcp_close(tp); 36658d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 367b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 368b07fef50SRandall Stewart goto out; 3697c72af87SMohan Srinivasan } else { 370d6de19acSJulien Charbon if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) { 371b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_2msl, 372b07fef50SRandall Stewart TP_KEEPINTVL(tp), tcp_timer_2msl, tp); 373b07fef50SRandall Stewart } else { 3746573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 375b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 376b07fef50SRandall Stewart goto out; 377d6de19acSJulien Charbon } 37858d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 37985d94372SRobert Watson tp = tcp_close(tp); 38058d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 381b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 382b07fef50SRandall Stewart goto out; 383b07fef50SRandall Stewart } 3847c72af87SMohan Srinivasan } 385df8bae1dSRodney W. Grimes 3869b8b58e0SJonathan Lemon #ifdef TCPDEBUG 387586b4a0eSKonstantin Belousov if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 388fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 3899b8b58e0SJonathan Lemon PRU_SLOWTIMO); 3909b8b58e0SJonathan Lemon #endif 3915d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 3925d06879aSGeorge V. Neville-Neil 39385d94372SRobert Watson if (tp != NULL) 3948501a69cSRobert Watson INP_WUNLOCK(inp); 395b07fef50SRandall Stewart out: 3968b615593SMarko Zec CURVNET_RESTORE(); 3979b8b58e0SJonathan Lemon } 3989b8b58e0SJonathan Lemon 39985d94372SRobert Watson void 40085d94372SRobert Watson tcp_timer_keep(void *xtp) 4019b8b58e0SJonathan Lemon { 40285d94372SRobert Watson struct tcpcb *tp = xtp; 40308517d53SMike Silbersack struct tcptemp *t_template; 40485d94372SRobert Watson struct inpcb *inp; 4056573d758SMatt Macy struct epoch_tracker et; 4068b615593SMarko Zec CURVNET_SET(tp->t_vnet); 4079b8b58e0SJonathan Lemon #ifdef TCPDEBUG 4089b8b58e0SJonathan Lemon int ostate; 4099b8b58e0SJonathan Lemon 4109b8b58e0SJonathan Lemon ostate = tp->t_state; 4119b8b58e0SJonathan Lemon #endif 41285d94372SRobert Watson inp = tp->t_inpcb; 4135571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 4148501a69cSRobert Watson INP_WLOCK(inp); 415655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_keep) || 416655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_keep)) { 4178501a69cSRobert Watson INP_WUNLOCK(inp); 4188b615593SMarko Zec CURVNET_RESTORE(); 41985d94372SRobert Watson return; 42085d94372SRobert Watson } 421e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_keep); 422655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 423655f934bSMikolaj Golub INP_WUNLOCK(inp); 424655f934bSMikolaj Golub CURVNET_RESTORE(); 425655f934bSMikolaj Golub return; 426655f934bSMikolaj Golub } 4275571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 4285571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 4296d172f58SJonathan T. Looney 4306d172f58SJonathan T. Looney /* 4316d172f58SJonathan T. Looney * Because we don't regularly reset the keepalive callout in 4326d172f58SJonathan T. Looney * the ESTABLISHED state, it may be that we don't actually need 4336d172f58SJonathan T. Looney * to send a keepalive yet. If that occurs, schedule another 4346d172f58SJonathan T. Looney * call for the next time the keepalive timer might expire. 4356d172f58SJonathan T. Looney */ 4366d172f58SJonathan T. Looney if (TCPS_HAVEESTABLISHED(tp->t_state)) { 4376d172f58SJonathan T. Looney u_int idletime; 4386d172f58SJonathan T. Looney 4396d172f58SJonathan T. Looney idletime = ticks - tp->t_rcvtime; 4406d172f58SJonathan T. Looney if (idletime < TP_KEEPIDLE(tp)) { 4416d172f58SJonathan T. Looney callout_reset(&tp->t_timers->tt_keep, 4426d172f58SJonathan T. Looney TP_KEEPIDLE(tp) - idletime, tcp_timer_keep, tp); 4436d172f58SJonathan T. Looney INP_WUNLOCK(inp); 4446d172f58SJonathan T. Looney CURVNET_RESTORE(); 4456d172f58SJonathan T. Looney return; 4466d172f58SJonathan T. Looney } 4476d172f58SJonathan T. Looney } 4486d172f58SJonathan T. Looney 4499b8b58e0SJonathan Lemon /* 4509b8b58e0SJonathan Lemon * Keep-alive timer went off; send something 4519b8b58e0SJonathan Lemon * or drop connection if idle for too long. 4529b8b58e0SJonathan Lemon */ 45378b50714SRobert Watson TCPSTAT_INC(tcps_keeptimeo); 4549b8b58e0SJonathan Lemon if (tp->t_state < TCPS_ESTABLISHED) 4559b8b58e0SJonathan Lemon goto dropit; 456334fc582SBjoern A. Zeeb if ((V_tcp_always_keepalive || 457f1798531SJohn Baldwin inp->inp_socket->so_options & SO_KEEPALIVE) && 4589b8b58e0SJonathan Lemon tp->t_state <= TCPS_CLOSING) { 4599077f387SGleb Smirnoff if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp)) 4609b8b58e0SJonathan Lemon goto dropit; 4619b8b58e0SJonathan Lemon /* 4629b8b58e0SJonathan Lemon * Send a packet designed to force a response 4639b8b58e0SJonathan Lemon * if the peer is up and reachable: 4649b8b58e0SJonathan Lemon * either an ACK if the connection is still alive, 4659b8b58e0SJonathan Lemon * or an RST if the peer has closed the connection 4669b8b58e0SJonathan Lemon * due to timeout or reboot. 4679b8b58e0SJonathan Lemon * Using sequence number tp->snd_una-1 4689b8b58e0SJonathan Lemon * causes the transmitted zero-length segment 4699b8b58e0SJonathan Lemon * to lie outside the receive window; 4709b8b58e0SJonathan Lemon * by the protocol spec, this requires the 4719b8b58e0SJonathan Lemon * correspondent TCP to respond. 4729b8b58e0SJonathan Lemon */ 47378b50714SRobert Watson TCPSTAT_INC(tcps_keepprobe); 47479909384SJonathan Lemon t_template = tcpip_maketemplate(inp); 47508517d53SMike Silbersack if (t_template) { 476b9555453SGleb Smirnoff NET_EPOCH_ENTER(et); 47708517d53SMike Silbersack tcp_respond(tp, t_template->tt_ipgen, 47808517d53SMike Silbersack &t_template->tt_t, (struct mbuf *)NULL, 4799b8b58e0SJonathan Lemon tp->rcv_nxt, tp->snd_una - 1, 0); 480b9555453SGleb Smirnoff NET_EPOCH_EXIT(et); 48153640b0eSRobert Watson free(t_template, M_TEMP); 48208517d53SMike Silbersack } 483b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_keep, TP_KEEPINTVL(tp), 484b07fef50SRandall Stewart tcp_timer_keep, tp); 485b07fef50SRandall Stewart } else 486b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_keep, TP_KEEPIDLE(tp), 487b07fef50SRandall Stewart tcp_timer_keep, tp); 4889b8b58e0SJonathan Lemon 4899b8b58e0SJonathan Lemon #ifdef TCPDEBUG 4902a074620SSam Leffler if (inp->inp_socket->so_options & SO_DEBUG) 491fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 4929b8b58e0SJonathan Lemon PRU_SLOWTIMO); 4939b8b58e0SJonathan Lemon #endif 4945d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 4958501a69cSRobert Watson INP_WUNLOCK(inp); 4968b615593SMarko Zec CURVNET_RESTORE(); 49785d94372SRobert Watson return; 4989b8b58e0SJonathan Lemon 4999b8b58e0SJonathan Lemon dropit: 50078b50714SRobert Watson TCPSTAT_INC(tcps_keepdrops); 5016573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 502b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 503b07fef50SRandall Stewart goto out; 504b07fef50SRandall Stewart } 50558d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 50685d94372SRobert Watson tp = tcp_drop(tp, ETIMEDOUT); 50785d94372SRobert Watson 50885d94372SRobert Watson #ifdef TCPDEBUG 50985d94372SRobert Watson if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 51085d94372SRobert Watson tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 51185d94372SRobert Watson PRU_SLOWTIMO); 51285d94372SRobert Watson #endif 5135d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 51458d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 515b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 516b07fef50SRandall Stewart out: 5178b615593SMarko Zec CURVNET_RESTORE(); 5189b8b58e0SJonathan Lemon } 5199b8b58e0SJonathan Lemon 52085d94372SRobert Watson void 52185d94372SRobert Watson tcp_timer_persist(void *xtp) 5229b8b58e0SJonathan Lemon { 52385d94372SRobert Watson struct tcpcb *tp = xtp; 52485d94372SRobert Watson struct inpcb *inp; 5256573d758SMatt Macy struct epoch_tracker et; 5268b615593SMarko Zec CURVNET_SET(tp->t_vnet); 5279b8b58e0SJonathan Lemon #ifdef TCPDEBUG 5289b8b58e0SJonathan Lemon int ostate; 5299b8b58e0SJonathan Lemon 5309b8b58e0SJonathan Lemon ostate = tp->t_state; 5319b8b58e0SJonathan Lemon #endif 53285d94372SRobert Watson inp = tp->t_inpcb; 5335571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 5348501a69cSRobert Watson INP_WLOCK(inp); 535655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_persist) || 536655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_persist)) { 5378501a69cSRobert Watson INP_WUNLOCK(inp); 5388b615593SMarko Zec CURVNET_RESTORE(); 53985d94372SRobert Watson return; 54085d94372SRobert Watson } 541e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_persist); 542655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 543655f934bSMikolaj Golub INP_WUNLOCK(inp); 544655f934bSMikolaj Golub CURVNET_RESTORE(); 545655f934bSMikolaj Golub return; 546655f934bSMikolaj Golub } 5475571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 5485571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 5499b8b58e0SJonathan Lemon /* 550a4641f4eSPedro F. Giffuni * Persistence timer into zero window. 5519b8b58e0SJonathan Lemon * Force a byte to be output, if possible. 5529b8b58e0SJonathan Lemon */ 55378b50714SRobert Watson TCPSTAT_INC(tcps_persisttimeo); 5549b8b58e0SJonathan Lemon /* 5559b8b58e0SJonathan Lemon * Hack: if the peer is dead/unreachable, we do not 5569b8b58e0SJonathan Lemon * time out if the window is closed. After a full 5579b8b58e0SJonathan Lemon * backoff, drop the connection if the idle time 5589b8b58e0SJonathan Lemon * (no responses to probes) reaches the maximum 5599b8b58e0SJonathan Lemon * backoff that we would use if retransmitting. 5609b8b58e0SJonathan Lemon */ 5619b8b58e0SJonathan Lemon if (tp->t_rxtshift == TCP_MAXRXTSHIFT && 5626b0c5521SJohn Baldwin (ticks - tp->t_rcvtime >= tcp_maxpersistidle || 5636b0c5521SJohn Baldwin ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { 56478b50714SRobert Watson TCPSTAT_INC(tcps_persistdrop); 5656573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 566b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 567b07fef50SRandall Stewart goto out; 568b07fef50SRandall Stewart } 56958d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 57085d94372SRobert Watson tp = tcp_drop(tp, ETIMEDOUT); 57158d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 572b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 57385d94372SRobert Watson goto out; 5749b8b58e0SJonathan Lemon } 575322181c9SAndre Oppermann /* 576322181c9SAndre Oppermann * If the user has closed the socket then drop a persisting 577322181c9SAndre Oppermann * connection after a much reduced timeout. 578322181c9SAndre Oppermann */ 579322181c9SAndre Oppermann if (tp->t_state > TCPS_CLOSE_WAIT && 580322181c9SAndre Oppermann (ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) { 581322181c9SAndre Oppermann TCPSTAT_INC(tcps_persistdrop); 5826573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 583b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 584b07fef50SRandall Stewart goto out; 585b07fef50SRandall Stewart } 58658d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 587322181c9SAndre Oppermann tp = tcp_drop(tp, ETIMEDOUT); 58858d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 589b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 590322181c9SAndre Oppermann goto out; 591322181c9SAndre Oppermann } 5929b8b58e0SJonathan Lemon tcp_setpersist(tp); 5932cdbfa66SPaul Saab tp->t_flags |= TF_FORCEDATA; 594109eb549SGleb Smirnoff NET_EPOCH_ENTER(et); 59555bceb1eSRandall Stewart (void) tp->t_fb->tfb_tcp_output(tp); 596109eb549SGleb Smirnoff NET_EPOCH_EXIT(et); 5972cdbfa66SPaul Saab tp->t_flags &= ~TF_FORCEDATA; 5989b8b58e0SJonathan Lemon 5999b8b58e0SJonathan Lemon #ifdef TCPDEBUG 600ffb761f6SGleb Smirnoff if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 601ffb761f6SGleb Smirnoff tcp_trace(TA_USER, ostate, tp, NULL, NULL, PRU_SLOWTIMO); 6029b8b58e0SJonathan Lemon #endif 6035d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 6048501a69cSRobert Watson INP_WUNLOCK(inp); 605b07fef50SRandall Stewart out: 6068b615593SMarko Zec CURVNET_RESTORE(); 6079b8b58e0SJonathan Lemon } 6089b8b58e0SJonathan Lemon 60985d94372SRobert Watson void 61085d94372SRobert Watson tcp_timer_rexmt(void * xtp) 6119b8b58e0SJonathan Lemon { 61285d94372SRobert Watson struct tcpcb *tp = xtp; 6138b615593SMarko Zec CURVNET_SET(tp->t_vnet); 6149b8b58e0SJonathan Lemon int rexmt; 61585d94372SRobert Watson struct inpcb *inp; 6166573d758SMatt Macy struct epoch_tracker et; 617*413c3db1SMichael Tuexen bool isipv6; 6189b8b58e0SJonathan Lemon #ifdef TCPDEBUG 6199b8b58e0SJonathan Lemon int ostate; 6209b8b58e0SJonathan Lemon 6219b8b58e0SJonathan Lemon ostate = tp->t_state; 6229b8b58e0SJonathan Lemon #endif 62385d94372SRobert Watson inp = tp->t_inpcb; 6245571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 6258501a69cSRobert Watson INP_WLOCK(inp); 626655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_rexmt) || 627655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_rexmt)) { 6288501a69cSRobert Watson INP_WUNLOCK(inp); 6298b615593SMarko Zec CURVNET_RESTORE(); 63085d94372SRobert Watson return; 63185d94372SRobert Watson } 632e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_rexmt); 633655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 634655f934bSMikolaj Golub INP_WUNLOCK(inp); 635655f934bSMikolaj Golub CURVNET_RESTORE(); 636655f934bSMikolaj Golub return; 637655f934bSMikolaj Golub } 6385571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 6395571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 6406d90faf3SPaul Saab tcp_free_sackholes(tp); 6412529f56eSJonathan T. Looney TCP_LOG_EVENT(tp, NULL, NULL, NULL, TCP_LOG_RTO, 0, 0, NULL, false); 6425105a92cSRandall Stewart if (tp->t_fb->tfb_tcp_rexmit_tmr) { 6435105a92cSRandall Stewart /* The stack has a timer action too. */ 6445105a92cSRandall Stewart (*tp->t_fb->tfb_tcp_rexmit_tmr)(tp); 6455105a92cSRandall Stewart } 646df8bae1dSRodney W. Grimes /* 647df8bae1dSRodney W. Grimes * Retransmission timer went off. Message has not 648df8bae1dSRodney W. Grimes * been acked within retransmit interval. Back off 649df8bae1dSRodney W. Grimes * to a longer retransmit interval and retransmit one segment. 650df8bae1dSRodney W. Grimes */ 651df8bae1dSRodney W. Grimes if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 652df8bae1dSRodney W. Grimes tp->t_rxtshift = TCP_MAXRXTSHIFT; 65378b50714SRobert Watson TCPSTAT_INC(tcps_timeoutdrop); 6546573d758SMatt Macy if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 655b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 65685d94372SRobert Watson goto out; 6579b8b58e0SJonathan Lemon } 65858d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 6594c6a1090SMichael Tuexen tp = tcp_drop(tp, ETIMEDOUT); 66058d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 661b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 662b07fef50SRandall Stewart goto out; 663b07fef50SRandall Stewart } 664cf8f04f4SAndre Oppermann if (tp->t_state == TCPS_SYN_SENT) { 665cf8f04f4SAndre Oppermann /* 666cf8f04f4SAndre Oppermann * If the SYN was retransmitted, indicate CWND to be 667cf8f04f4SAndre Oppermann * limited to 1 segment in cc_conn_init(). 668cf8f04f4SAndre Oppermann */ 669cf8f04f4SAndre Oppermann tp->snd_cwnd = 1; 670cf8f04f4SAndre Oppermann } else if (tp->t_rxtshift == 1) { 6719b8b58e0SJonathan Lemon /* 6729b8b58e0SJonathan Lemon * first retransmit; record ssthresh and cwnd so they can 6739b8b58e0SJonathan Lemon * be recovered if this turns out to be a "bad" retransmit. 6749b8b58e0SJonathan Lemon * A retransmit is considered "bad" if an ACK for this 6759b8b58e0SJonathan Lemon * segment is received within RTT/2 interval; the assumption 6769b8b58e0SJonathan Lemon * here is that the ACK was already in flight. See 6779b8b58e0SJonathan Lemon * "On Estimating End-to-End Network Path Properties" by 6789b8b58e0SJonathan Lemon * Allman and Paxson for more details. 6799b8b58e0SJonathan Lemon */ 6809b8b58e0SJonathan Lemon tp->snd_cwnd_prev = tp->snd_cwnd; 6819b8b58e0SJonathan Lemon tp->snd_ssthresh_prev = tp->snd_ssthresh; 6829d11646dSJeffrey Hsu tp->snd_recover_prev = tp->snd_recover; 683dbc42409SLawrence Stewart if (IN_FASTRECOVERY(tp->t_flags)) 6849d11646dSJeffrey Hsu tp->t_flags |= TF_WASFRECOVERY; 6859d11646dSJeffrey Hsu else 6869d11646dSJeffrey Hsu tp->t_flags &= ~TF_WASFRECOVERY; 687dbc42409SLawrence Stewart if (IN_CONGRECOVERY(tp->t_flags)) 688dbc42409SLawrence Stewart tp->t_flags |= TF_WASCRECOVERY; 689dbc42409SLawrence Stewart else 690dbc42409SLawrence Stewart tp->t_flags &= ~TF_WASCRECOVERY; 69110d20c84SMatt Macy if ((tp->t_flags & TF_RCVD_TSTMP) == 0) 6929b8b58e0SJonathan Lemon tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); 69310d20c84SMatt Macy /* In the event that we've negotiated timestamps 69410d20c84SMatt Macy * badrxtwin will be set to the value that we set 69510d20c84SMatt Macy * the retransmitted packet's to_tsval to by tcp_output 69610d20c84SMatt Macy */ 697672dc4aeSJohn Baldwin tp->t_flags |= TF_PREVVALID; 698672dc4aeSJohn Baldwin } else 699672dc4aeSJohn Baldwin tp->t_flags &= ~TF_PREVVALID; 70078b50714SRobert Watson TCPSTAT_INC(tcps_rexmttimeo); 701281a0fd4SPatrick Kelsey if ((tp->t_state == TCPS_SYN_SENT) || 702281a0fd4SPatrick Kelsey (tp->t_state == TCPS_SYN_RECEIVED)) 7030999766dSMichael Tuexen rexmt = tcp_rexmit_initial * tcp_backoff[tp->t_rxtshift]; 7047d42e30cSJonathan Lemon else 705df8bae1dSRodney W. Grimes rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; 706df8bae1dSRodney W. Grimes TCPT_RANGESET(tp->t_rxtcur, rexmt, 707df8bae1dSRodney W. Grimes tp->t_rttmin, TCPTV_REXMTMAX); 708f6f6703fSSean Bruno 709882ac53eSSean Bruno /* 710882ac53eSSean Bruno * We enter the path for PLMTUD if connection is established or, if 711882ac53eSSean Bruno * connection is FIN_WAIT_1 status, reason for the last is that if 712882ac53eSSean Bruno * amount of data we send is very small, we could send it in couple of 713882ac53eSSean Bruno * packets and process straight to FIN. In that case we won't catch 714882ac53eSSean Bruno * ESTABLISHED state. 715882ac53eSSean Bruno */ 716f6f6703fSSean Bruno #ifdef INET6 717*413c3db1SMichael Tuexen isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) ? true : false; 718*413c3db1SMichael Tuexen #else 719*413c3db1SMichael Tuexen isipv6 = false; 720f6f6703fSSean Bruno #endif 721*413c3db1SMichael Tuexen if (((V_tcp_pmtud_blackhole_detect == 1) || 722*413c3db1SMichael Tuexen (V_tcp_pmtud_blackhole_detect == 2 && !isipv6) || 723*413c3db1SMichael Tuexen (V_tcp_pmtud_blackhole_detect == 3 && isipv6)) && 724*413c3db1SMichael Tuexen ((tp->t_state == TCPS_ESTABLISHED) || 725*413c3db1SMichael Tuexen (tp->t_state == TCPS_FIN_WAIT_1))) { 726adf43a92SHiren Panchasara /* 727adf43a92SHiren Panchasara * Idea here is that at each stage of mtu probe (usually, 1448 728adf43a92SHiren Panchasara * -> 1188 -> 524) should be given 2 chances to recover before 729adf43a92SHiren Panchasara * further clamping down. 'tp->t_rxtshift % 2 == 0' should 730adf43a92SHiren Panchasara * take care of that. 731adf43a92SHiren Panchasara */ 732f6f6703fSSean Bruno if (((tp->t_flags2 & (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) == 733f6f6703fSSean Bruno (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) && 7343d5af7a1SMichael Tuexen (tp->t_rxtshift >= 2 && tp->t_rxtshift < 6 && 7353d5af7a1SMichael Tuexen tp->t_rxtshift % 2 == 0)) { 736f6f6703fSSean Bruno /* 737f6f6703fSSean Bruno * Enter Path MTU Black-hole Detection mechanism: 738f6f6703fSSean Bruno * - Disable Path MTU Discovery (IP "DF" bit). 739f6f6703fSSean Bruno * - Reduce MTU to lower value than what we 740f6f6703fSSean Bruno * negotiated with peer. 741f6f6703fSSean Bruno */ 7423d5af7a1SMichael Tuexen if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) == 0) { 743f6f6703fSSean Bruno /* Record that we may have found a black hole. */ 744f6f6703fSSean Bruno tp->t_flags2 |= TF2_PLPMTU_BLACKHOLE; 745f6f6703fSSean Bruno /* Keep track of previous MSS. */ 7460c39d38dSGleb Smirnoff tp->t_pmtud_saved_maxseg = tp->t_maxseg; 7473d5af7a1SMichael Tuexen } 748f6f6703fSSean Bruno 749f6f6703fSSean Bruno /* 750f6f6703fSSean Bruno * Reduce the MSS to blackhole value or to the default 751f6f6703fSSean Bruno * in an attempt to retransmit. 752f6f6703fSSean Bruno */ 753f6f6703fSSean Bruno #ifdef INET6 754f6f6703fSSean Bruno if (isipv6 && 7550c39d38dSGleb Smirnoff tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss) { 756f6f6703fSSean Bruno /* Use the sysctl tuneable blackhole MSS. */ 7570c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_v6pmtud_blackhole_mss; 75832a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated); 759f6f6703fSSean Bruno } else if (isipv6) { 760f6f6703fSSean Bruno /* Use the default MSS. */ 7610c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_v6mssdflt; 762f6f6703fSSean Bruno /* 763f6f6703fSSean Bruno * Disable Path MTU Discovery when we switch to 764f6f6703fSSean Bruno * minmss. 765f6f6703fSSean Bruno */ 766f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 76732a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); 768f6f6703fSSean Bruno } 769f6f6703fSSean Bruno #endif 770f6f6703fSSean Bruno #if defined(INET6) && defined(INET) 771f6f6703fSSean Bruno else 772f6f6703fSSean Bruno #endif 773f6f6703fSSean Bruno #ifdef INET 7740c39d38dSGleb Smirnoff if (tp->t_maxseg > V_tcp_pmtud_blackhole_mss) { 775f6f6703fSSean Bruno /* Use the sysctl tuneable blackhole MSS. */ 7760c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_pmtud_blackhole_mss; 77732a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated); 778f6f6703fSSean Bruno } else { 779f6f6703fSSean Bruno /* Use the default MSS. */ 7800c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_mssdflt; 781f6f6703fSSean Bruno /* 782f6f6703fSSean Bruno * Disable Path MTU Discovery when we switch to 783f6f6703fSSean Bruno * minmss. 784f6f6703fSSean Bruno */ 785f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 78632a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); 787f6f6703fSSean Bruno } 788f6f6703fSSean Bruno #endif 789f6f6703fSSean Bruno /* 790f6f6703fSSean Bruno * Reset the slow-start flight size 791f6f6703fSSean Bruno * as it may depend on the new MSS. 792f6f6703fSSean Bruno */ 793f6f6703fSSean Bruno if (CC_ALGO(tp)->conn_init != NULL) 794f6f6703fSSean Bruno CC_ALGO(tp)->conn_init(tp->ccv); 795f6f6703fSSean Bruno } else { 796f6f6703fSSean Bruno /* 797f6f6703fSSean Bruno * If further retransmissions are still unsuccessful 798f6f6703fSSean Bruno * with a lowered MTU, maybe this isn't a blackhole and 799f6f6703fSSean Bruno * we restore the previous MSS and blackhole detection 800f6f6703fSSean Bruno * flags. 801adf43a92SHiren Panchasara * The limit '6' is determined by giving each probe 802adf43a92SHiren Panchasara * stage (1448, 1188, 524) 2 chances to recover. 803f6f6703fSSean Bruno */ 804f6f6703fSSean Bruno if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) && 8053d5af7a1SMichael Tuexen (tp->t_rxtshift >= 6)) { 806f6f6703fSSean Bruno tp->t_flags2 |= TF2_PLPMTU_PMTUD; 807f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_BLACKHOLE; 8080c39d38dSGleb Smirnoff tp->t_maxseg = tp->t_pmtud_saved_maxseg; 80932a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_failed); 810f6f6703fSSean Bruno /* 811f6f6703fSSean Bruno * Reset the slow-start flight size as it 812f6f6703fSSean Bruno * may depend on the new MSS. 813f6f6703fSSean Bruno */ 814f6f6703fSSean Bruno if (CC_ALGO(tp)->conn_init != NULL) 815f6f6703fSSean Bruno CC_ALGO(tp)->conn_init(tp->ccv); 816f6f6703fSSean Bruno } 817f6f6703fSSean Bruno } 818f6f6703fSSean Bruno } 819f6f6703fSSean Bruno 820df8bae1dSRodney W. Grimes /* 82177339e1cSAndre Oppermann * Disable RFC1323 and SACK if we haven't got any response to 8227ceb7783SJesper Skriver * our third SYN to work-around some broken terminal servers 8237ceb7783SJesper Skriver * (most of which have hopefully been retired) that have bad VJ 8247ceb7783SJesper Skriver * header compression code which trashes TCP segments containing 8257ceb7783SJesper Skriver * unknown-to-them TCP options. 8267ceb7783SJesper Skriver */ 8276c0ef895SJohn Baldwin if (tcp_rexmit_drop_options && (tp->t_state == TCPS_SYN_SENT) && 8286c0ef895SJohn Baldwin (tp->t_rxtshift == 3)) 829c4ab59c1SAndre Oppermann tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_SACK_PERMIT); 8307ceb7783SJesper Skriver /* 8315ede40dcSRyan Stone * If we backed off this far, notify the L3 protocol that we're having 8325ede40dcSRyan Stone * connection problems. 833df8bae1dSRodney W. Grimes */ 8345ede40dcSRyan Stone if (tp->t_rxtshift > TCP_RTT_INVALIDATE) { 835fb59c426SYoshinobu Inoue #ifdef INET6 836fb59c426SYoshinobu Inoue if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) 837fb59c426SYoshinobu Inoue in6_losing(tp->t_inpcb); 83884cc0778SGeorge V. Neville-Neil else 839fb59c426SYoshinobu Inoue #endif 84084cc0778SGeorge V. Neville-Neil in_losing(tp->t_inpcb); 841df8bae1dSRodney W. Grimes } 842df8bae1dSRodney W. Grimes tp->snd_nxt = tp->snd_una; 8439d11646dSJeffrey Hsu tp->snd_recover = tp->snd_max; 84446f58482SJonathan Lemon /* 84574b48c1dSAndras Olah * Force a segment to be sent. 84674b48c1dSAndras Olah */ 84774b48c1dSAndras Olah tp->t_flags |= TF_ACKNOW; 84874b48c1dSAndras Olah /* 849df8bae1dSRodney W. Grimes * If timing a segment in this window, stop the timer. 850df8bae1dSRodney W. Grimes */ 8519b8b58e0SJonathan Lemon tp->t_rtttime = 0; 852dbc42409SLawrence Stewart 853b5af1b88SLawrence Stewart cc_cong_signal(tp, NULL, CC_RTO); 854109eb549SGleb Smirnoff NET_EPOCH_ENTER(et); 85555bceb1eSRandall Stewart (void) tp->t_fb->tfb_tcp_output(tp); 856109eb549SGleb Smirnoff NET_EPOCH_EXIT(et); 8579b8b58e0SJonathan Lemon #ifdef TCPDEBUG 8581c53f806SRobert Watson if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 859fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 8609b8b58e0SJonathan Lemon PRU_SLOWTIMO); 861df8bae1dSRodney W. Grimes #endif 8625d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 8638501a69cSRobert Watson INP_WUNLOCK(inp); 864b07fef50SRandall Stewart out: 8658b615593SMarko Zec CURVNET_RESTORE(); 86685d94372SRobert Watson } 86785d94372SRobert Watson 86885d94372SRobert Watson void 8695571f9cfSJulien Charbon tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, u_int delta) 87085d94372SRobert Watson { 87185d94372SRobert Watson struct callout *t_callout; 8725773ac11SJohn Baldwin callout_func_t *f_callout; 87387aedea4SKip Macy struct inpcb *inp = tp->t_inpcb; 874883831c6SAdrian Chadd int cpu = inp_to_cpuid(inp); 87585d94372SRobert Watson 87609fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD 87709fe6320SNavdeep Parhar if (tp->t_flags & TF_TOE) 87809fe6320SNavdeep Parhar return; 87909fe6320SNavdeep Parhar #endif 88009fe6320SNavdeep Parhar 8815571f9cfSJulien Charbon if (tp->t_timers->tt_flags & TT_STOPPED) 8825571f9cfSJulien Charbon return; 8835571f9cfSJulien Charbon 88485d94372SRobert Watson switch (timer_type) { 88585d94372SRobert Watson case TT_DELACK: 886e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 88785d94372SRobert Watson f_callout = tcp_timer_delack; 88885d94372SRobert Watson break; 88985d94372SRobert Watson case TT_REXMT: 890e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 89185d94372SRobert Watson f_callout = tcp_timer_rexmt; 89285d94372SRobert Watson break; 89385d94372SRobert Watson case TT_PERSIST: 894e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 89585d94372SRobert Watson f_callout = tcp_timer_persist; 89685d94372SRobert Watson break; 89785d94372SRobert Watson case TT_KEEP: 898e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 89985d94372SRobert Watson f_callout = tcp_timer_keep; 90085d94372SRobert Watson break; 90185d94372SRobert Watson case TT_2MSL: 902e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 90385d94372SRobert Watson f_callout = tcp_timer_2msl; 90485d94372SRobert Watson break; 90585d94372SRobert Watson default: 90655bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_activate) { 90755bceb1eSRandall Stewart tp->t_fb->tfb_tcp_timer_activate(tp, timer_type, delta); 90855bceb1eSRandall Stewart return; 90955bceb1eSRandall Stewart } 91003374917SJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 91185d94372SRobert Watson } 91285d94372SRobert Watson if (delta == 0) { 913b07fef50SRandall Stewart callout_stop(t_callout); 91485d94372SRobert Watson } else { 91587aedea4SKip Macy callout_reset_on(t_callout, delta, f_callout, tp, cpu); 91685d94372SRobert Watson } 91785d94372SRobert Watson } 91885d94372SRobert Watson 91985d94372SRobert Watson int 9205571f9cfSJulien Charbon tcp_timer_active(struct tcpcb *tp, uint32_t timer_type) 92185d94372SRobert Watson { 92285d94372SRobert Watson struct callout *t_callout; 92385d94372SRobert Watson 92485d94372SRobert Watson switch (timer_type) { 92585d94372SRobert Watson case TT_DELACK: 926e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 92785d94372SRobert Watson break; 92885d94372SRobert Watson case TT_REXMT: 929e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 93085d94372SRobert Watson break; 93185d94372SRobert Watson case TT_PERSIST: 932e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 93385d94372SRobert Watson break; 93485d94372SRobert Watson case TT_KEEP: 935e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 93685d94372SRobert Watson break; 93785d94372SRobert Watson case TT_2MSL: 938e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 93985d94372SRobert Watson break; 94085d94372SRobert Watson default: 94155bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_active) { 94255bceb1eSRandall Stewart return(tp->t_fb->tfb_tcp_timer_active(tp, timer_type)); 94355bceb1eSRandall Stewart } 94403374917SJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 94585d94372SRobert Watson } 94685d94372SRobert Watson return callout_active(t_callout); 947df8bae1dSRodney W. Grimes } 948b8614722SMike Silbersack 94989e560f4SRandall Stewart /* 95089e560f4SRandall Stewart * Stop the timer from running, and apply a flag 95189e560f4SRandall Stewart * against the timer_flags that will force the 95289e560f4SRandall Stewart * timer never to run. The flag is needed to assure 95389e560f4SRandall Stewart * a race does not leave it running and cause 95489e560f4SRandall Stewart * the timer to possibly restart itself (keep and persist 95589e560f4SRandall Stewart * especially do this). 95689e560f4SRandall Stewart */ 95789e560f4SRandall Stewart int 95889e560f4SRandall Stewart tcp_timer_suspend(struct tcpcb *tp, uint32_t timer_type) 95989e560f4SRandall Stewart { 96089e560f4SRandall Stewart struct callout *t_callout; 96189e560f4SRandall Stewart uint32_t t_flags; 96289e560f4SRandall Stewart 96389e560f4SRandall Stewart switch (timer_type) { 96489e560f4SRandall Stewart case TT_DELACK: 96589e560f4SRandall Stewart t_flags = TT_DELACK_SUS; 96689e560f4SRandall Stewart t_callout = &tp->t_timers->tt_delack; 96789e560f4SRandall Stewart break; 96889e560f4SRandall Stewart case TT_REXMT: 96989e560f4SRandall Stewart t_flags = TT_REXMT_SUS; 97089e560f4SRandall Stewart t_callout = &tp->t_timers->tt_rexmt; 97189e560f4SRandall Stewart break; 97289e560f4SRandall Stewart case TT_PERSIST: 97389e560f4SRandall Stewart t_flags = TT_PERSIST_SUS; 97489e560f4SRandall Stewart t_callout = &tp->t_timers->tt_persist; 97589e560f4SRandall Stewart break; 97689e560f4SRandall Stewart case TT_KEEP: 97789e560f4SRandall Stewart t_flags = TT_KEEP_SUS; 97889e560f4SRandall Stewart t_callout = &tp->t_timers->tt_keep; 97989e560f4SRandall Stewart break; 98089e560f4SRandall Stewart case TT_2MSL: 98189e560f4SRandall Stewart t_flags = TT_2MSL_SUS; 98289e560f4SRandall Stewart t_callout = &tp->t_timers->tt_2msl; 98389e560f4SRandall Stewart break; 98489e560f4SRandall Stewart default: 98589e560f4SRandall Stewart panic("tp:%p bad timer_type 0x%x", tp, timer_type); 98689e560f4SRandall Stewart } 98789e560f4SRandall Stewart tp->t_timers->tt_flags |= t_flags; 98889e560f4SRandall Stewart return (callout_stop(t_callout)); 98989e560f4SRandall Stewart } 99089e560f4SRandall Stewart 99189e560f4SRandall Stewart void 99289e560f4SRandall Stewart tcp_timers_unsuspend(struct tcpcb *tp, uint32_t timer_type) 99389e560f4SRandall Stewart { 99489e560f4SRandall Stewart switch (timer_type) { 99589e560f4SRandall Stewart case TT_DELACK: 99689e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_DELACK_SUS) { 99789e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_DELACK_SUS; 99889e560f4SRandall Stewart if (tp->t_flags & TF_DELACK) { 99989e560f4SRandall Stewart /* Delayed ack timer should be up activate a timer */ 100089e560f4SRandall Stewart tp->t_flags &= ~TF_DELACK; 100189e560f4SRandall Stewart tcp_timer_activate(tp, TT_DELACK, 100289e560f4SRandall Stewart tcp_delacktime); 100389e560f4SRandall Stewart } 100489e560f4SRandall Stewart } 100589e560f4SRandall Stewart break; 100689e560f4SRandall Stewart case TT_REXMT: 100789e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_REXMT_SUS) { 100889e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_REXMT_SUS; 100989e560f4SRandall Stewart if (SEQ_GT(tp->snd_max, tp->snd_una) && 101089e560f4SRandall Stewart (tcp_timer_active((tp), TT_PERSIST) == 0) && 101189e560f4SRandall Stewart tp->snd_wnd) { 101289e560f4SRandall Stewart /* We have outstanding data activate a timer */ 101389e560f4SRandall Stewart tcp_timer_activate(tp, TT_REXMT, 101489e560f4SRandall Stewart tp->t_rxtcur); 101589e560f4SRandall Stewart } 101689e560f4SRandall Stewart } 101789e560f4SRandall Stewart break; 101889e560f4SRandall Stewart case TT_PERSIST: 101989e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_PERSIST_SUS) { 102089e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_PERSIST_SUS; 102189e560f4SRandall Stewart if (tp->snd_wnd == 0) { 102289e560f4SRandall Stewart /* Activate the persists timer */ 102389e560f4SRandall Stewart tp->t_rxtshift = 0; 102489e560f4SRandall Stewart tcp_setpersist(tp); 102589e560f4SRandall Stewart } 102689e560f4SRandall Stewart } 102789e560f4SRandall Stewart break; 102889e560f4SRandall Stewart case TT_KEEP: 102989e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_KEEP_SUS) { 103089e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_KEEP_SUS; 103189e560f4SRandall Stewart tcp_timer_activate(tp, TT_KEEP, 103289e560f4SRandall Stewart TCPS_HAVEESTABLISHED(tp->t_state) ? 103389e560f4SRandall Stewart TP_KEEPIDLE(tp) : TP_KEEPINIT(tp)); 103489e560f4SRandall Stewart } 103589e560f4SRandall Stewart break; 103689e560f4SRandall Stewart case TT_2MSL: 103789e560f4SRandall Stewart if (tp->t_timers->tt_flags &= TT_2MSL_SUS) { 103889e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_2MSL_SUS; 103989e560f4SRandall Stewart if ((tp->t_state == TCPS_FIN_WAIT_2) && 104089e560f4SRandall Stewart ((tp->t_inpcb->inp_socket == NULL) || 104189e560f4SRandall Stewart (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE))) { 104289e560f4SRandall Stewart /* Star the 2MSL timer */ 104389e560f4SRandall Stewart tcp_timer_activate(tp, TT_2MSL, 104489e560f4SRandall Stewart (tcp_fast_finwait2_recycle) ? 104589e560f4SRandall Stewart tcp_finwait2_timeout : TP_MAXIDLE(tp)); 104689e560f4SRandall Stewart } 104789e560f4SRandall Stewart } 104889e560f4SRandall Stewart break; 104989e560f4SRandall Stewart default: 105089e560f4SRandall Stewart panic("tp:%p bad timer_type 0x%x", tp, timer_type); 105189e560f4SRandall Stewart } 105289e560f4SRandall Stewart } 105389e560f4SRandall Stewart 10545571f9cfSJulien Charbon void 10555571f9cfSJulien Charbon tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type) 10565571f9cfSJulien Charbon { 10575571f9cfSJulien Charbon struct callout *t_callout; 10585571f9cfSJulien Charbon 10595571f9cfSJulien Charbon tp->t_timers->tt_flags |= TT_STOPPED; 10605571f9cfSJulien Charbon switch (timer_type) { 10615571f9cfSJulien Charbon case TT_DELACK: 10625571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_delack; 10635571f9cfSJulien Charbon break; 10645571f9cfSJulien Charbon case TT_REXMT: 10655571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_rexmt; 10665571f9cfSJulien Charbon break; 10675571f9cfSJulien Charbon case TT_PERSIST: 10685571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_persist; 10695571f9cfSJulien Charbon break; 10705571f9cfSJulien Charbon case TT_KEEP: 10715571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_keep; 10725571f9cfSJulien Charbon break; 10735571f9cfSJulien Charbon case TT_2MSL: 10745571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_2msl; 10755571f9cfSJulien Charbon break; 10765571f9cfSJulien Charbon default: 107755bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_stop) { 107855bceb1eSRandall Stewart /* 107955bceb1eSRandall Stewart * XXXrrs we need to look at this with the 108055bceb1eSRandall Stewart * stop case below (flags). 108155bceb1eSRandall Stewart */ 108255bceb1eSRandall Stewart tp->t_fb->tfb_tcp_timer_stop(tp, timer_type); 108355bceb1eSRandall Stewart return; 108455bceb1eSRandall Stewart } 10855571f9cfSJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 10865571f9cfSJulien Charbon } 10875571f9cfSJulien Charbon 1088e5ad6456SRandall Stewart if (callout_async_drain(t_callout, tcp_timer_discard) == 0) { 10895571f9cfSJulien Charbon /* 10905571f9cfSJulien Charbon * Can't stop the callout, defer tcpcb actual deletion 1091e5ad6456SRandall Stewart * to the last one. We do this using the async drain 1092e5ad6456SRandall Stewart * function and incrementing the count in 10935571f9cfSJulien Charbon */ 1094e5ad6456SRandall Stewart tp->t_timers->tt_draincnt++; 10955571f9cfSJulien Charbon } 10965571f9cfSJulien Charbon } 1097