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 120c2c8e360SAlexander V. Chernikov VNET_DEFINE(int, tcp_msl); 1217029da5cSPawel Biernacki SYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl, 122c2c8e360SAlexander V. Chernikov CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_VNET, 123c2c8e360SAlexander V. Chernikov &VNET_NAME(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 if (per_cpu_timers) { 214*47ded797SFranco Fichtner #ifdef RSS 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); 220*47ded797SFranco Fichtner #endif 221883831c6SAdrian Chadd /* 222883831c6SAdrian Chadd * We don't have a flowid -> cpuid mapping, so cheat and 223883831c6SAdrian Chadd * just map unknown cpuids to curcpu. Not the best, but 224883831c6SAdrian Chadd * apparently better than defaulting to swi 0. 225883831c6SAdrian Chadd */ 226883831c6SAdrian Chadd cpuid = inp->inp_flowid % (mp_maxid + 1); 227883831c6SAdrian Chadd if (! CPU_ABSENT(cpuid)) 228883831c6SAdrian Chadd return (cpuid); 229883831c6SAdrian Chadd return (curcpu); 230*47ded797SFranco Fichtner } else { 231883831c6SAdrian Chadd return (0); 232883831c6SAdrian Chadd } 233883831c6SAdrian Chadd } 23487aedea4SKip Macy 235df8bae1dSRodney W. Grimes /* 236df8bae1dSRodney W. Grimes * Tcp protocol timeout routine called every 500 ms. 2379b8b58e0SJonathan Lemon * Updates timestamps used for TCP 238df8bae1dSRodney W. Grimes * causes finite state machine actions if timers expire. 239df8bae1dSRodney W. Grimes */ 240df8bae1dSRodney W. Grimes void 241e2f2059fSMike Silbersack tcp_slowtimo(void) 242df8bae1dSRodney W. Grimes { 2438b615593SMarko Zec VNET_ITERATOR_DECL(vnet_iter); 24415bd2b43SDavid Greenman 2455ee847d3SRobert Watson VNET_LIST_RLOCK_NOSLEEP(); 2468b615593SMarko Zec VNET_FOREACH(vnet_iter) { 2478b615593SMarko Zec CURVNET_SET(vnet_iter); 248cea40c48SJulien Charbon (void) tcp_tw_2msl_scan(0); 2498b615593SMarko Zec CURVNET_RESTORE(); 2508b615593SMarko Zec } 2515ee847d3SRobert Watson VNET_LIST_RUNLOCK_NOSLEEP(); 252df8bae1dSRodney W. Grimes } 253df8bae1dSRodney W. Grimes 254df8bae1dSRodney W. Grimes int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 255f058535dSJeffrey Hsu { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 512, 512, 512 }; 256df8bae1dSRodney W. Grimes 25789e560f4SRandall Stewart int tcp_totbackoff = 2559; /* sum of tcp_backoff[] */ 258e79adb8eSGarrett Wollman 259df8bae1dSRodney W. Grimes /* 260df8bae1dSRodney W. Grimes * TCP timer processing. 261df8bae1dSRodney W. Grimes */ 26285d94372SRobert Watson 26385d94372SRobert Watson void 26485d94372SRobert Watson tcp_timer_delack(void *xtp) 265df8bae1dSRodney W. Grimes { 266109eb549SGleb Smirnoff struct epoch_tracker et; 26785d94372SRobert Watson struct tcpcb *tp = xtp; 26885d94372SRobert Watson struct inpcb *inp; 2698b615593SMarko Zec CURVNET_SET(tp->t_vnet); 27085d94372SRobert Watson 27185d94372SRobert Watson inp = tp->t_inpcb; 2725571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 2738501a69cSRobert Watson INP_WLOCK(inp); 274655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_delack) || 275655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_delack)) { 2768501a69cSRobert Watson INP_WUNLOCK(inp); 2778b615593SMarko Zec CURVNET_RESTORE(); 27885d94372SRobert Watson return; 27985d94372SRobert Watson } 280e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_delack); 281655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 282655f934bSMikolaj Golub INP_WUNLOCK(inp); 283655f934bSMikolaj Golub CURVNET_RESTORE(); 284655f934bSMikolaj Golub return; 285655f934bSMikolaj Golub } 2869b8b58e0SJonathan Lemon tp->t_flags |= TF_ACKNOW; 28778b50714SRobert Watson TCPSTAT_INC(tcps_delack); 288109eb549SGleb Smirnoff NET_EPOCH_ENTER(et); 289f64dc2abSGleb Smirnoff (void) tcp_output_unlock(tp); 290109eb549SGleb Smirnoff NET_EPOCH_EXIT(et); 2918b615593SMarko Zec CURVNET_RESTORE(); 2929b8b58e0SJonathan Lemon } 2939b8b58e0SJonathan Lemon 294b07fef50SRandall Stewart void 295b07fef50SRandall Stewart tcp_inpinfo_lock_del(struct inpcb *inp, struct tcpcb *tp) 296b07fef50SRandall Stewart { 2976573d758SMatt Macy if (inp && tp != NULL) 298b07fef50SRandall Stewart INP_WUNLOCK(inp); 299b07fef50SRandall Stewart } 300b07fef50SRandall Stewart 30185d94372SRobert Watson void 30285d94372SRobert Watson tcp_timer_2msl(void *xtp) 3039b8b58e0SJonathan Lemon { 30485d94372SRobert Watson struct tcpcb *tp = xtp; 30585d94372SRobert Watson struct inpcb *inp; 3066573d758SMatt Macy struct epoch_tracker et; 3078b615593SMarko Zec CURVNET_SET(tp->t_vnet); 3089b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3099b8b58e0SJonathan Lemon int ostate; 3109b8b58e0SJonathan Lemon 3119b8b58e0SJonathan Lemon ostate = tp->t_state; 3129b8b58e0SJonathan Lemon #endif 31385d94372SRobert Watson inp = tp->t_inpcb; 3145571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 3158501a69cSRobert Watson INP_WLOCK(inp); 31685d94372SRobert Watson tcp_free_sackholes(tp); 317655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_2msl) || 318e2f2059fSMike Silbersack !callout_active(&tp->t_timers->tt_2msl)) { 3198501a69cSRobert Watson INP_WUNLOCK(tp->t_inpcb); 3208b615593SMarko Zec CURVNET_RESTORE(); 32185d94372SRobert Watson return; 32285d94372SRobert Watson } 323e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_2msl); 3249a06a824SGleb Smirnoff if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 325655f934bSMikolaj Golub INP_WUNLOCK(inp); 326655f934bSMikolaj Golub CURVNET_RESTORE(); 327655f934bSMikolaj Golub return; 328655f934bSMikolaj Golub } 3295571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 3305571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 33185d94372SRobert Watson /* 332df8bae1dSRodney W. Grimes * 2 MSL timeout in shutdown went off. If we're closed but 333df8bae1dSRodney W. Grimes * still waiting for peer to close and connection has been idle 33431a7749dSJulien Charbon * too long delete connection control block. Otherwise, check 33531a7749dSJulien Charbon * again in a bit. 33631a7749dSJulien Charbon * 3377c72af87SMohan Srinivasan * If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, 3387c72af87SMohan Srinivasan * there's no point in hanging onto FIN_WAIT_2 socket. Just close it. 3397c72af87SMohan Srinivasan * Ignore fact that there were recent incoming segments. 340df8bae1dSRodney W. Grimes */ 3417c72af87SMohan Srinivasan if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && 34285d94372SRobert Watson tp->t_inpcb && tp->t_inpcb->inp_socket && 3437c72af87SMohan Srinivasan (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { 34478b50714SRobert Watson TCPSTAT_INC(tcps_finwait2_drops); 34558d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 34685d94372SRobert Watson tp = tcp_close(tp); 34758d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 348b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 349b07fef50SRandall Stewart goto out; 3507c72af87SMohan Srinivasan } else { 351d6de19acSJulien Charbon if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) { 352b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_2msl, 353b07fef50SRandall Stewart TP_KEEPINTVL(tp), tcp_timer_2msl, tp); 354b07fef50SRandall Stewart } else { 35558d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 35685d94372SRobert Watson tp = tcp_close(tp); 35758d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 358b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 359b07fef50SRandall Stewart goto out; 360b07fef50SRandall Stewart } 3617c72af87SMohan Srinivasan } 362df8bae1dSRodney W. Grimes 3639b8b58e0SJonathan Lemon #ifdef TCPDEBUG 364586b4a0eSKonstantin Belousov if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 365fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 3669b8b58e0SJonathan Lemon PRU_SLOWTIMO); 3679b8b58e0SJonathan Lemon #endif 3685d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 3695d06879aSGeorge V. Neville-Neil 37085d94372SRobert Watson if (tp != NULL) 3718501a69cSRobert Watson INP_WUNLOCK(inp); 372b07fef50SRandall Stewart out: 3738b615593SMarko Zec CURVNET_RESTORE(); 3749b8b58e0SJonathan Lemon } 3759b8b58e0SJonathan Lemon 37685d94372SRobert Watson void 37785d94372SRobert Watson tcp_timer_keep(void *xtp) 3789b8b58e0SJonathan Lemon { 37985d94372SRobert Watson struct tcpcb *tp = xtp; 38008517d53SMike Silbersack struct tcptemp *t_template; 38185d94372SRobert Watson struct inpcb *inp; 3826573d758SMatt Macy struct epoch_tracker et; 3838b615593SMarko Zec CURVNET_SET(tp->t_vnet); 3849b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3859b8b58e0SJonathan Lemon int ostate; 3869b8b58e0SJonathan Lemon 3879b8b58e0SJonathan Lemon ostate = tp->t_state; 3889b8b58e0SJonathan Lemon #endif 38985d94372SRobert Watson inp = tp->t_inpcb; 3905571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 3918501a69cSRobert Watson INP_WLOCK(inp); 392655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_keep) || 393655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_keep)) { 3948501a69cSRobert Watson INP_WUNLOCK(inp); 3958b615593SMarko Zec CURVNET_RESTORE(); 39685d94372SRobert Watson return; 39785d94372SRobert Watson } 398e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_keep); 3999a06a824SGleb Smirnoff if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 400655f934bSMikolaj Golub INP_WUNLOCK(inp); 401655f934bSMikolaj Golub CURVNET_RESTORE(); 402655f934bSMikolaj Golub return; 403655f934bSMikolaj Golub } 4045571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 4055571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 4066d172f58SJonathan T. Looney 4076d172f58SJonathan T. Looney /* 4086d172f58SJonathan T. Looney * Because we don't regularly reset the keepalive callout in 4096d172f58SJonathan T. Looney * the ESTABLISHED state, it may be that we don't actually need 4106d172f58SJonathan T. Looney * to send a keepalive yet. If that occurs, schedule another 4116d172f58SJonathan T. Looney * call for the next time the keepalive timer might expire. 4126d172f58SJonathan T. Looney */ 4136d172f58SJonathan T. Looney if (TCPS_HAVEESTABLISHED(tp->t_state)) { 4146d172f58SJonathan T. Looney u_int idletime; 4156d172f58SJonathan T. Looney 4166d172f58SJonathan T. Looney idletime = ticks - tp->t_rcvtime; 4176d172f58SJonathan T. Looney if (idletime < TP_KEEPIDLE(tp)) { 4186d172f58SJonathan T. Looney callout_reset(&tp->t_timers->tt_keep, 4196d172f58SJonathan T. Looney TP_KEEPIDLE(tp) - idletime, tcp_timer_keep, tp); 4206d172f58SJonathan T. Looney INP_WUNLOCK(inp); 4216d172f58SJonathan T. Looney CURVNET_RESTORE(); 4226d172f58SJonathan T. Looney return; 4236d172f58SJonathan T. Looney } 4246d172f58SJonathan T. Looney } 4256d172f58SJonathan T. Looney 4269b8b58e0SJonathan Lemon /* 4279b8b58e0SJonathan Lemon * Keep-alive timer went off; send something 4289b8b58e0SJonathan Lemon * or drop connection if idle for too long. 4299b8b58e0SJonathan Lemon */ 43078b50714SRobert Watson TCPSTAT_INC(tcps_keeptimeo); 4319b8b58e0SJonathan Lemon if (tp->t_state < TCPS_ESTABLISHED) 4329b8b58e0SJonathan Lemon goto dropit; 433334fc582SBjoern A. Zeeb if ((V_tcp_always_keepalive || 434f1798531SJohn Baldwin inp->inp_socket->so_options & SO_KEEPALIVE) && 4359b8b58e0SJonathan Lemon tp->t_state <= TCPS_CLOSING) { 4369077f387SGleb Smirnoff if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp)) 4379b8b58e0SJonathan Lemon goto dropit; 4389b8b58e0SJonathan Lemon /* 4399b8b58e0SJonathan Lemon * Send a packet designed to force a response 4409b8b58e0SJonathan Lemon * if the peer is up and reachable: 4419b8b58e0SJonathan Lemon * either an ACK if the connection is still alive, 4429b8b58e0SJonathan Lemon * or an RST if the peer has closed the connection 4439b8b58e0SJonathan Lemon * due to timeout or reboot. 4449b8b58e0SJonathan Lemon * Using sequence number tp->snd_una-1 4459b8b58e0SJonathan Lemon * causes the transmitted zero-length segment 4469b8b58e0SJonathan Lemon * to lie outside the receive window; 4479b8b58e0SJonathan Lemon * by the protocol spec, this requires the 4489b8b58e0SJonathan Lemon * correspondent TCP to respond. 4499b8b58e0SJonathan Lemon */ 45078b50714SRobert Watson TCPSTAT_INC(tcps_keepprobe); 45179909384SJonathan Lemon t_template = tcpip_maketemplate(inp); 45208517d53SMike Silbersack if (t_template) { 453b9555453SGleb Smirnoff NET_EPOCH_ENTER(et); 45408517d53SMike Silbersack tcp_respond(tp, t_template->tt_ipgen, 45508517d53SMike Silbersack &t_template->tt_t, (struct mbuf *)NULL, 4569b8b58e0SJonathan Lemon tp->rcv_nxt, tp->snd_una - 1, 0); 457b9555453SGleb Smirnoff NET_EPOCH_EXIT(et); 45853640b0eSRobert Watson free(t_template, M_TEMP); 45908517d53SMike Silbersack } 460b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_keep, TP_KEEPINTVL(tp), 461b07fef50SRandall Stewart tcp_timer_keep, tp); 462b07fef50SRandall Stewart } else 463b07fef50SRandall Stewart callout_reset(&tp->t_timers->tt_keep, TP_KEEPIDLE(tp), 464b07fef50SRandall Stewart tcp_timer_keep, tp); 4659b8b58e0SJonathan Lemon 4669b8b58e0SJonathan Lemon #ifdef TCPDEBUG 4672a074620SSam Leffler if (inp->inp_socket->so_options & SO_DEBUG) 468fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 4699b8b58e0SJonathan Lemon PRU_SLOWTIMO); 4709b8b58e0SJonathan Lemon #endif 4715d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 4728501a69cSRobert Watson INP_WUNLOCK(inp); 4738b615593SMarko Zec CURVNET_RESTORE(); 47485d94372SRobert Watson return; 4759b8b58e0SJonathan Lemon 4769b8b58e0SJonathan Lemon dropit: 47778b50714SRobert Watson TCPSTAT_INC(tcps_keepdrops); 47858d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 47985d94372SRobert Watson tp = tcp_drop(tp, ETIMEDOUT); 48085d94372SRobert Watson 48185d94372SRobert Watson #ifdef TCPDEBUG 48285d94372SRobert Watson if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 48385d94372SRobert Watson tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 48485d94372SRobert Watson PRU_SLOWTIMO); 48585d94372SRobert Watson #endif 4865d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 48758d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 488b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 4898b615593SMarko Zec CURVNET_RESTORE(); 4909b8b58e0SJonathan Lemon } 4919b8b58e0SJonathan Lemon 49285d94372SRobert Watson void 49385d94372SRobert Watson tcp_timer_persist(void *xtp) 4949b8b58e0SJonathan Lemon { 49585d94372SRobert Watson struct tcpcb *tp = xtp; 49685d94372SRobert Watson struct inpcb *inp; 4976573d758SMatt Macy struct epoch_tracker et; 498f64dc2abSGleb Smirnoff int outrv; 4998b615593SMarko Zec CURVNET_SET(tp->t_vnet); 5009b8b58e0SJonathan Lemon #ifdef TCPDEBUG 5019b8b58e0SJonathan Lemon int ostate; 5029b8b58e0SJonathan Lemon 5039b8b58e0SJonathan Lemon ostate = tp->t_state; 5049b8b58e0SJonathan Lemon #endif 50585d94372SRobert Watson inp = tp->t_inpcb; 5065571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 5078501a69cSRobert Watson INP_WLOCK(inp); 508655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_persist) || 509655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_persist)) { 5108501a69cSRobert Watson INP_WUNLOCK(inp); 5118b615593SMarko Zec CURVNET_RESTORE(); 51285d94372SRobert Watson return; 51385d94372SRobert Watson } 514e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_persist); 5159a06a824SGleb Smirnoff if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 516655f934bSMikolaj Golub INP_WUNLOCK(inp); 517655f934bSMikolaj Golub CURVNET_RESTORE(); 518655f934bSMikolaj Golub return; 519655f934bSMikolaj Golub } 5205571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 5215571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 5229b8b58e0SJonathan Lemon /* 523a4641f4eSPedro F. Giffuni * Persistence timer into zero window. 5249b8b58e0SJonathan Lemon * Force a byte to be output, if possible. 5259b8b58e0SJonathan Lemon */ 52678b50714SRobert Watson TCPSTAT_INC(tcps_persisttimeo); 5279b8b58e0SJonathan Lemon /* 5289b8b58e0SJonathan Lemon * Hack: if the peer is dead/unreachable, we do not 5299b8b58e0SJonathan Lemon * time out if the window is closed. After a full 5309b8b58e0SJonathan Lemon * backoff, drop the connection if the idle time 5319b8b58e0SJonathan Lemon * (no responses to probes) reaches the maximum 5329b8b58e0SJonathan Lemon * backoff that we would use if retransmitting. 5339b8b58e0SJonathan Lemon */ 5349b8b58e0SJonathan Lemon if (tp->t_rxtshift == TCP_MAXRXTSHIFT && 5356b0c5521SJohn Baldwin (ticks - tp->t_rcvtime >= tcp_maxpersistidle || 5366b0c5521SJohn Baldwin ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { 53778b50714SRobert Watson TCPSTAT_INC(tcps_persistdrop); 53858d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 53985d94372SRobert Watson tp = tcp_drop(tp, ETIMEDOUT); 54058d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 541b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 54285d94372SRobert Watson goto out; 5439b8b58e0SJonathan Lemon } 544322181c9SAndre Oppermann /* 545322181c9SAndre Oppermann * If the user has closed the socket then drop a persisting 546322181c9SAndre Oppermann * connection after a much reduced timeout. 547322181c9SAndre Oppermann */ 548322181c9SAndre Oppermann if (tp->t_state > TCPS_CLOSE_WAIT && 549322181c9SAndre Oppermann (ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) { 550322181c9SAndre Oppermann TCPSTAT_INC(tcps_persistdrop); 55158d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 552322181c9SAndre Oppermann tp = tcp_drop(tp, ETIMEDOUT); 55358d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 554b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 555322181c9SAndre Oppermann goto out; 556322181c9SAndre Oppermann } 5579b8b58e0SJonathan Lemon tcp_setpersist(tp); 5582cdbfa66SPaul Saab tp->t_flags |= TF_FORCEDATA; 559109eb549SGleb Smirnoff NET_EPOCH_ENTER(et); 560f64dc2abSGleb Smirnoff outrv = tcp_output_nodrop(tp); 5612cdbfa66SPaul Saab tp->t_flags &= ~TF_FORCEDATA; 5629b8b58e0SJonathan Lemon 5639b8b58e0SJonathan Lemon #ifdef TCPDEBUG 564ffb761f6SGleb Smirnoff if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 565ffb761f6SGleb Smirnoff tcp_trace(TA_USER, ostate, tp, NULL, NULL, PRU_SLOWTIMO); 5669b8b58e0SJonathan Lemon #endif 5675d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 568f64dc2abSGleb Smirnoff (void) tcp_unlock_or_drop(tp, outrv); 569f64dc2abSGleb Smirnoff NET_EPOCH_EXIT(et); 570b07fef50SRandall Stewart out: 5718b615593SMarko Zec CURVNET_RESTORE(); 5729b8b58e0SJonathan Lemon } 5739b8b58e0SJonathan Lemon 57485d94372SRobert Watson void 57585d94372SRobert Watson tcp_timer_rexmt(void * xtp) 5769b8b58e0SJonathan Lemon { 57785d94372SRobert Watson struct tcpcb *tp = xtp; 5788b615593SMarko Zec CURVNET_SET(tp->t_vnet); 579f64dc2abSGleb Smirnoff int rexmt, outrv; 58085d94372SRobert Watson struct inpcb *inp; 5816573d758SMatt Macy struct epoch_tracker et; 582413c3db1SMichael Tuexen bool isipv6; 5839b8b58e0SJonathan Lemon #ifdef TCPDEBUG 5849b8b58e0SJonathan Lemon int ostate; 5859b8b58e0SJonathan Lemon 5869b8b58e0SJonathan Lemon ostate = tp->t_state; 5879b8b58e0SJonathan Lemon #endif 58885d94372SRobert Watson inp = tp->t_inpcb; 5895571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 5908501a69cSRobert Watson INP_WLOCK(inp); 591655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_rexmt) || 592655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_rexmt)) { 5938501a69cSRobert Watson INP_WUNLOCK(inp); 5948b615593SMarko Zec CURVNET_RESTORE(); 59585d94372SRobert Watson return; 59685d94372SRobert Watson } 597e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_rexmt); 5989a06a824SGleb Smirnoff if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) { 599655f934bSMikolaj Golub INP_WUNLOCK(inp); 600655f934bSMikolaj Golub CURVNET_RESTORE(); 601655f934bSMikolaj Golub return; 602655f934bSMikolaj Golub } 6035571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 6045571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 6056d90faf3SPaul Saab tcp_free_sackholes(tp); 6062529f56eSJonathan T. Looney TCP_LOG_EVENT(tp, NULL, NULL, NULL, TCP_LOG_RTO, 0, 0, NULL, false); 6075105a92cSRandall Stewart if (tp->t_fb->tfb_tcp_rexmit_tmr) { 6085105a92cSRandall Stewart /* The stack has a timer action too. */ 6095105a92cSRandall Stewart (*tp->t_fb->tfb_tcp_rexmit_tmr)(tp); 6105105a92cSRandall Stewart } 611df8bae1dSRodney W. Grimes /* 612df8bae1dSRodney W. Grimes * Retransmission timer went off. Message has not 613df8bae1dSRodney W. Grimes * been acked within retransmit interval. Back off 614df8bae1dSRodney W. Grimes * to a longer retransmit interval and retransmit one segment. 615df8bae1dSRodney W. Grimes */ 616df8bae1dSRodney W. Grimes if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 617df8bae1dSRodney W. Grimes tp->t_rxtshift = TCP_MAXRXTSHIFT; 61878b50714SRobert Watson TCPSTAT_INC(tcps_timeoutdrop); 61958d94bd0SGleb Smirnoff NET_EPOCH_ENTER(et); 6204c6a1090SMichael Tuexen tp = tcp_drop(tp, ETIMEDOUT); 62158d94bd0SGleb Smirnoff NET_EPOCH_EXIT(et); 622b07fef50SRandall Stewart tcp_inpinfo_lock_del(inp, tp); 623b07fef50SRandall Stewart goto out; 624b07fef50SRandall Stewart } 625cf8f04f4SAndre Oppermann if (tp->t_state == TCPS_SYN_SENT) { 626cf8f04f4SAndre Oppermann /* 627cf8f04f4SAndre Oppermann * If the SYN was retransmitted, indicate CWND to be 628cf8f04f4SAndre Oppermann * limited to 1 segment in cc_conn_init(). 629cf8f04f4SAndre Oppermann */ 630cf8f04f4SAndre Oppermann tp->snd_cwnd = 1; 631cf8f04f4SAndre Oppermann } else if (tp->t_rxtshift == 1) { 6329b8b58e0SJonathan Lemon /* 6339b8b58e0SJonathan Lemon * first retransmit; record ssthresh and cwnd so they can 6349b8b58e0SJonathan Lemon * be recovered if this turns out to be a "bad" retransmit. 6359b8b58e0SJonathan Lemon * A retransmit is considered "bad" if an ACK for this 6369b8b58e0SJonathan Lemon * segment is received within RTT/2 interval; the assumption 6379b8b58e0SJonathan Lemon * here is that the ACK was already in flight. See 6389b8b58e0SJonathan Lemon * "On Estimating End-to-End Network Path Properties" by 6399b8b58e0SJonathan Lemon * Allman and Paxson for more details. 6409b8b58e0SJonathan Lemon */ 6419b8b58e0SJonathan Lemon tp->snd_cwnd_prev = tp->snd_cwnd; 6429b8b58e0SJonathan Lemon tp->snd_ssthresh_prev = tp->snd_ssthresh; 6439d11646dSJeffrey Hsu tp->snd_recover_prev = tp->snd_recover; 644dbc42409SLawrence Stewart if (IN_FASTRECOVERY(tp->t_flags)) 6459d11646dSJeffrey Hsu tp->t_flags |= TF_WASFRECOVERY; 6469d11646dSJeffrey Hsu else 6479d11646dSJeffrey Hsu tp->t_flags &= ~TF_WASFRECOVERY; 648dbc42409SLawrence Stewart if (IN_CONGRECOVERY(tp->t_flags)) 649dbc42409SLawrence Stewart tp->t_flags |= TF_WASCRECOVERY; 650dbc42409SLawrence Stewart else 651dbc42409SLawrence Stewart tp->t_flags &= ~TF_WASCRECOVERY; 65210d20c84SMatt Macy if ((tp->t_flags & TF_RCVD_TSTMP) == 0) 6539b8b58e0SJonathan Lemon tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); 65410d20c84SMatt Macy /* In the event that we've negotiated timestamps 65510d20c84SMatt Macy * badrxtwin will be set to the value that we set 65610d20c84SMatt Macy * the retransmitted packet's to_tsval to by tcp_output 65710d20c84SMatt Macy */ 658672dc4aeSJohn Baldwin tp->t_flags |= TF_PREVVALID; 659672dc4aeSJohn Baldwin } else 660672dc4aeSJohn Baldwin tp->t_flags &= ~TF_PREVVALID; 66178b50714SRobert Watson TCPSTAT_INC(tcps_rexmttimeo); 662281a0fd4SPatrick Kelsey if ((tp->t_state == TCPS_SYN_SENT) || 663281a0fd4SPatrick Kelsey (tp->t_state == TCPS_SYN_RECEIVED)) 6640999766dSMichael Tuexen rexmt = tcp_rexmit_initial * tcp_backoff[tp->t_rxtshift]; 6657d42e30cSJonathan Lemon else 666df8bae1dSRodney W. Grimes rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; 667df8bae1dSRodney W. Grimes TCPT_RANGESET(tp->t_rxtcur, rexmt, 668df8bae1dSRodney W. Grimes tp->t_rttmin, TCPTV_REXMTMAX); 669f6f6703fSSean Bruno 670882ac53eSSean Bruno /* 671882ac53eSSean Bruno * We enter the path for PLMTUD if connection is established or, if 672882ac53eSSean Bruno * connection is FIN_WAIT_1 status, reason for the last is that if 673882ac53eSSean Bruno * amount of data we send is very small, we could send it in couple of 674882ac53eSSean Bruno * packets and process straight to FIN. In that case we won't catch 675882ac53eSSean Bruno * ESTABLISHED state. 676882ac53eSSean Bruno */ 677f6f6703fSSean Bruno #ifdef INET6 678413c3db1SMichael Tuexen isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) ? true : false; 679413c3db1SMichael Tuexen #else 680413c3db1SMichael Tuexen isipv6 = false; 681f6f6703fSSean Bruno #endif 682413c3db1SMichael Tuexen if (((V_tcp_pmtud_blackhole_detect == 1) || 683413c3db1SMichael Tuexen (V_tcp_pmtud_blackhole_detect == 2 && !isipv6) || 684413c3db1SMichael Tuexen (V_tcp_pmtud_blackhole_detect == 3 && isipv6)) && 685413c3db1SMichael Tuexen ((tp->t_state == TCPS_ESTABLISHED) || 686413c3db1SMichael Tuexen (tp->t_state == TCPS_FIN_WAIT_1))) { 687b89af8e1SMichael Tuexen if (tp->t_rxtshift == 1) { 688adf43a92SHiren Panchasara /* 689b89af8e1SMichael Tuexen * We enter blackhole detection after the first 690b89af8e1SMichael Tuexen * unsuccessful timer based retransmission. 691b89af8e1SMichael Tuexen * Then we reduce up to two times the MSS, each 692b89af8e1SMichael Tuexen * candidate giving two tries of retransmissions. 693b89af8e1SMichael Tuexen * But we give a candidate only two tries, if it 694b89af8e1SMichael Tuexen * actually reduces the MSS. 695adf43a92SHiren Panchasara */ 696b89af8e1SMichael Tuexen tp->t_blackhole_enter = 2; 697b89af8e1SMichael Tuexen tp->t_blackhole_exit = tp->t_blackhole_enter; 698b89af8e1SMichael Tuexen if (isipv6) { 699b89af8e1SMichael Tuexen #ifdef INET6 700b89af8e1SMichael Tuexen if (tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss) 701b89af8e1SMichael Tuexen tp->t_blackhole_exit += 2; 702b89af8e1SMichael Tuexen if (tp->t_maxseg > V_tcp_v6mssdflt && 703b89af8e1SMichael Tuexen V_tcp_v6pmtud_blackhole_mss > V_tcp_v6mssdflt) 704b89af8e1SMichael Tuexen tp->t_blackhole_exit += 2; 705b89af8e1SMichael Tuexen #endif 706b89af8e1SMichael Tuexen } else { 707b89af8e1SMichael Tuexen #ifdef INET 708b89af8e1SMichael Tuexen if (tp->t_maxseg > V_tcp_pmtud_blackhole_mss) 709b89af8e1SMichael Tuexen tp->t_blackhole_exit += 2; 710b89af8e1SMichael Tuexen if (tp->t_maxseg > V_tcp_mssdflt && 711b89af8e1SMichael Tuexen V_tcp_pmtud_blackhole_mss > V_tcp_mssdflt) 712b89af8e1SMichael Tuexen tp->t_blackhole_exit += 2; 713b89af8e1SMichael Tuexen #endif 714b89af8e1SMichael Tuexen } 715b89af8e1SMichael Tuexen } 716f6f6703fSSean Bruno if (((tp->t_flags2 & (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) == 717f6f6703fSSean Bruno (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) && 718b89af8e1SMichael Tuexen (tp->t_rxtshift >= tp->t_blackhole_enter && 719b89af8e1SMichael Tuexen tp->t_rxtshift < tp->t_blackhole_exit && 720b89af8e1SMichael Tuexen (tp->t_rxtshift - tp->t_blackhole_enter) % 2 == 0)) { 721f6f6703fSSean Bruno /* 722f6f6703fSSean Bruno * Enter Path MTU Black-hole Detection mechanism: 723f6f6703fSSean Bruno * - Disable Path MTU Discovery (IP "DF" bit). 724f6f6703fSSean Bruno * - Reduce MTU to lower value than what we 725f6f6703fSSean Bruno * negotiated with peer. 726f6f6703fSSean Bruno */ 7273d5af7a1SMichael Tuexen if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) == 0) { 728f6f6703fSSean Bruno /* Record that we may have found a black hole. */ 729f6f6703fSSean Bruno tp->t_flags2 |= TF2_PLPMTU_BLACKHOLE; 730f6f6703fSSean Bruno /* Keep track of previous MSS. */ 7310c39d38dSGleb Smirnoff tp->t_pmtud_saved_maxseg = tp->t_maxseg; 7323d5af7a1SMichael Tuexen } 733f6f6703fSSean Bruno 734f6f6703fSSean Bruno /* 735f6f6703fSSean Bruno * Reduce the MSS to blackhole value or to the default 736f6f6703fSSean Bruno * in an attempt to retransmit. 737f6f6703fSSean Bruno */ 738f6f6703fSSean Bruno #ifdef INET6 739f6f6703fSSean Bruno if (isipv6 && 740b89af8e1SMichael Tuexen tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss && 741b89af8e1SMichael Tuexen V_tcp_v6pmtud_blackhole_mss > V_tcp_v6mssdflt) { 742f6f6703fSSean Bruno /* Use the sysctl tuneable blackhole MSS. */ 7430c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_v6pmtud_blackhole_mss; 74432a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated); 745f6f6703fSSean Bruno } else if (isipv6) { 746f6f6703fSSean Bruno /* Use the default MSS. */ 7470c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_v6mssdflt; 748f6f6703fSSean Bruno /* 749f6f6703fSSean Bruno * Disable Path MTU Discovery when we switch to 750f6f6703fSSean Bruno * minmss. 751f6f6703fSSean Bruno */ 752f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 75332a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); 754f6f6703fSSean Bruno } 755f6f6703fSSean Bruno #endif 756f6f6703fSSean Bruno #if defined(INET6) && defined(INET) 757f6f6703fSSean Bruno else 758f6f6703fSSean Bruno #endif 759f6f6703fSSean Bruno #ifdef INET 760b89af8e1SMichael Tuexen if (tp->t_maxseg > V_tcp_pmtud_blackhole_mss && 761b89af8e1SMichael Tuexen V_tcp_pmtud_blackhole_mss > V_tcp_mssdflt) { 762f6f6703fSSean Bruno /* Use the sysctl tuneable blackhole MSS. */ 7630c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_pmtud_blackhole_mss; 76432a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated); 765f6f6703fSSean Bruno } else { 766f6f6703fSSean Bruno /* Use the default MSS. */ 7670c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_mssdflt; 768f6f6703fSSean Bruno /* 769f6f6703fSSean Bruno * Disable Path MTU Discovery when we switch to 770f6f6703fSSean Bruno * minmss. 771f6f6703fSSean Bruno */ 772f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 77332a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_activated_min_mss); 774f6f6703fSSean Bruno } 775f6f6703fSSean Bruno #endif 776f6f6703fSSean Bruno /* 777f6f6703fSSean Bruno * Reset the slow-start flight size 778f6f6703fSSean Bruno * as it may depend on the new MSS. 779f6f6703fSSean Bruno */ 780f6f6703fSSean Bruno if (CC_ALGO(tp)->conn_init != NULL) 781f6f6703fSSean Bruno CC_ALGO(tp)->conn_init(tp->ccv); 782f6f6703fSSean Bruno } else { 783f6f6703fSSean Bruno /* 784f6f6703fSSean Bruno * If further retransmissions are still unsuccessful 785f6f6703fSSean Bruno * with a lowered MTU, maybe this isn't a blackhole and 786f6f6703fSSean Bruno * we restore the previous MSS and blackhole detection 787f6f6703fSSean Bruno * flags. 788f6f6703fSSean Bruno */ 789f6f6703fSSean Bruno if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) && 790b89af8e1SMichael Tuexen (tp->t_rxtshift >= tp->t_blackhole_exit)) { 791f6f6703fSSean Bruno tp->t_flags2 |= TF2_PLPMTU_PMTUD; 792f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_BLACKHOLE; 7930c39d38dSGleb Smirnoff tp->t_maxseg = tp->t_pmtud_saved_maxseg; 79432a04bb8SSean Bruno TCPSTAT_INC(tcps_pmtud_blackhole_failed); 795f6f6703fSSean Bruno /* 796f6f6703fSSean Bruno * Reset the slow-start flight size as it 797f6f6703fSSean Bruno * may depend on the new MSS. 798f6f6703fSSean Bruno */ 799f6f6703fSSean Bruno if (CC_ALGO(tp)->conn_init != NULL) 800f6f6703fSSean Bruno CC_ALGO(tp)->conn_init(tp->ccv); 801f6f6703fSSean Bruno } 802f6f6703fSSean Bruno } 803f6f6703fSSean Bruno } 804f6f6703fSSean Bruno 805df8bae1dSRodney W. Grimes /* 80677339e1cSAndre Oppermann * Disable RFC1323 and SACK if we haven't got any response to 8077ceb7783SJesper Skriver * our third SYN to work-around some broken terminal servers 8087ceb7783SJesper Skriver * (most of which have hopefully been retired) that have bad VJ 8097ceb7783SJesper Skriver * header compression code which trashes TCP segments containing 8107ceb7783SJesper Skriver * unknown-to-them TCP options. 8117ceb7783SJesper Skriver */ 8126c0ef895SJohn Baldwin if (tcp_rexmit_drop_options && (tp->t_state == TCPS_SYN_SENT) && 8136c0ef895SJohn Baldwin (tp->t_rxtshift == 3)) 814c4ab59c1SAndre Oppermann tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_SACK_PERMIT); 8157ceb7783SJesper Skriver /* 8165ede40dcSRyan Stone * If we backed off this far, notify the L3 protocol that we're having 8175ede40dcSRyan Stone * connection problems. 818df8bae1dSRodney W. Grimes */ 8195ede40dcSRyan Stone if (tp->t_rxtshift > TCP_RTT_INVALIDATE) { 820fb59c426SYoshinobu Inoue #ifdef INET6 821fb59c426SYoshinobu Inoue if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) 822fb59c426SYoshinobu Inoue in6_losing(tp->t_inpcb); 82384cc0778SGeorge V. Neville-Neil else 824fb59c426SYoshinobu Inoue #endif 82584cc0778SGeorge V. Neville-Neil in_losing(tp->t_inpcb); 826df8bae1dSRodney W. Grimes } 827df8bae1dSRodney W. Grimes tp->snd_nxt = tp->snd_una; 8289d11646dSJeffrey Hsu tp->snd_recover = tp->snd_max; 82946f58482SJonathan Lemon /* 83074b48c1dSAndras Olah * Force a segment to be sent. 83174b48c1dSAndras Olah */ 83274b48c1dSAndras Olah tp->t_flags |= TF_ACKNOW; 83374b48c1dSAndras Olah /* 834df8bae1dSRodney W. Grimes * If timing a segment in this window, stop the timer. 835df8bae1dSRodney W. Grimes */ 8369b8b58e0SJonathan Lemon tp->t_rtttime = 0; 837dbc42409SLawrence Stewart 838b5af1b88SLawrence Stewart cc_cong_signal(tp, NULL, CC_RTO); 839109eb549SGleb Smirnoff NET_EPOCH_ENTER(et); 840f64dc2abSGleb Smirnoff outrv = tcp_output_nodrop(tp); 8419b8b58e0SJonathan Lemon #ifdef TCPDEBUG 8421c53f806SRobert Watson if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 843fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 8449b8b58e0SJonathan Lemon PRU_SLOWTIMO); 845df8bae1dSRodney W. Grimes #endif 8465d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 847f64dc2abSGleb Smirnoff (void) tcp_unlock_or_drop(tp, outrv); 848f64dc2abSGleb Smirnoff NET_EPOCH_EXIT(et); 849b07fef50SRandall Stewart out: 8508b615593SMarko Zec CURVNET_RESTORE(); 85185d94372SRobert Watson } 85285d94372SRobert Watson 85385d94372SRobert Watson void 8545571f9cfSJulien Charbon tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, u_int delta) 85585d94372SRobert Watson { 85685d94372SRobert Watson struct callout *t_callout; 8575773ac11SJohn Baldwin callout_func_t *f_callout; 85887aedea4SKip Macy struct inpcb *inp = tp->t_inpcb; 859883831c6SAdrian Chadd int cpu = inp_to_cpuid(inp); 86085d94372SRobert Watson 86109fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD 86209fe6320SNavdeep Parhar if (tp->t_flags & TF_TOE) 86309fe6320SNavdeep Parhar return; 86409fe6320SNavdeep Parhar #endif 86509fe6320SNavdeep Parhar 8665571f9cfSJulien Charbon if (tp->t_timers->tt_flags & TT_STOPPED) 8675571f9cfSJulien Charbon return; 8685571f9cfSJulien Charbon 86985d94372SRobert Watson switch (timer_type) { 87085d94372SRobert Watson case TT_DELACK: 871e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 87285d94372SRobert Watson f_callout = tcp_timer_delack; 87385d94372SRobert Watson break; 87485d94372SRobert Watson case TT_REXMT: 875e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 87685d94372SRobert Watson f_callout = tcp_timer_rexmt; 87785d94372SRobert Watson break; 87885d94372SRobert Watson case TT_PERSIST: 879e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 88085d94372SRobert Watson f_callout = tcp_timer_persist; 88185d94372SRobert Watson break; 88285d94372SRobert Watson case TT_KEEP: 883e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 88485d94372SRobert Watson f_callout = tcp_timer_keep; 88585d94372SRobert Watson break; 88685d94372SRobert Watson case TT_2MSL: 887e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 88885d94372SRobert Watson f_callout = tcp_timer_2msl; 88985d94372SRobert Watson break; 89085d94372SRobert Watson default: 89155bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_activate) { 89255bceb1eSRandall Stewart tp->t_fb->tfb_tcp_timer_activate(tp, timer_type, delta); 89355bceb1eSRandall Stewart return; 89455bceb1eSRandall Stewart } 89503374917SJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 89685d94372SRobert Watson } 89785d94372SRobert Watson if (delta == 0) { 898b07fef50SRandall Stewart callout_stop(t_callout); 89985d94372SRobert Watson } else { 90087aedea4SKip Macy callout_reset_on(t_callout, delta, f_callout, tp, cpu); 90185d94372SRobert Watson } 90285d94372SRobert Watson } 90385d94372SRobert Watson 90485d94372SRobert Watson int 9055571f9cfSJulien Charbon tcp_timer_active(struct tcpcb *tp, uint32_t timer_type) 90685d94372SRobert Watson { 90785d94372SRobert Watson struct callout *t_callout; 90885d94372SRobert Watson 90985d94372SRobert Watson switch (timer_type) { 91085d94372SRobert Watson case TT_DELACK: 911e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 91285d94372SRobert Watson break; 91385d94372SRobert Watson case TT_REXMT: 914e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 91585d94372SRobert Watson break; 91685d94372SRobert Watson case TT_PERSIST: 917e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 91885d94372SRobert Watson break; 91985d94372SRobert Watson case TT_KEEP: 920e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 92185d94372SRobert Watson break; 92285d94372SRobert Watson case TT_2MSL: 923e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 92485d94372SRobert Watson break; 92585d94372SRobert Watson default: 92655bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_active) { 92755bceb1eSRandall Stewart return(tp->t_fb->tfb_tcp_timer_active(tp, timer_type)); 92855bceb1eSRandall Stewart } 92903374917SJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 93085d94372SRobert Watson } 93185d94372SRobert Watson return callout_active(t_callout); 932df8bae1dSRodney W. Grimes } 933b8614722SMike Silbersack 93489e560f4SRandall Stewart /* 93589e560f4SRandall Stewart * Stop the timer from running, and apply a flag 93689e560f4SRandall Stewart * against the timer_flags that will force the 93789e560f4SRandall Stewart * timer never to run. The flag is needed to assure 93889e560f4SRandall Stewart * a race does not leave it running and cause 93989e560f4SRandall Stewart * the timer to possibly restart itself (keep and persist 94089e560f4SRandall Stewart * especially do this). 94189e560f4SRandall Stewart */ 94289e560f4SRandall Stewart int 94389e560f4SRandall Stewart tcp_timer_suspend(struct tcpcb *tp, uint32_t timer_type) 94489e560f4SRandall Stewart { 94589e560f4SRandall Stewart struct callout *t_callout; 94689e560f4SRandall Stewart uint32_t t_flags; 94789e560f4SRandall Stewart 94889e560f4SRandall Stewart switch (timer_type) { 94989e560f4SRandall Stewart case TT_DELACK: 95089e560f4SRandall Stewart t_flags = TT_DELACK_SUS; 95189e560f4SRandall Stewart t_callout = &tp->t_timers->tt_delack; 95289e560f4SRandall Stewart break; 95389e560f4SRandall Stewart case TT_REXMT: 95489e560f4SRandall Stewart t_flags = TT_REXMT_SUS; 95589e560f4SRandall Stewart t_callout = &tp->t_timers->tt_rexmt; 95689e560f4SRandall Stewart break; 95789e560f4SRandall Stewart case TT_PERSIST: 95889e560f4SRandall Stewart t_flags = TT_PERSIST_SUS; 95989e560f4SRandall Stewart t_callout = &tp->t_timers->tt_persist; 96089e560f4SRandall Stewart break; 96189e560f4SRandall Stewart case TT_KEEP: 96289e560f4SRandall Stewart t_flags = TT_KEEP_SUS; 96389e560f4SRandall Stewart t_callout = &tp->t_timers->tt_keep; 96489e560f4SRandall Stewart break; 96589e560f4SRandall Stewart case TT_2MSL: 96689e560f4SRandall Stewart t_flags = TT_2MSL_SUS; 96789e560f4SRandall Stewart t_callout = &tp->t_timers->tt_2msl; 96889e560f4SRandall Stewart break; 96989e560f4SRandall Stewart default: 97089e560f4SRandall Stewart panic("tp:%p bad timer_type 0x%x", tp, timer_type); 97189e560f4SRandall Stewart } 97289e560f4SRandall Stewart tp->t_timers->tt_flags |= t_flags; 97389e560f4SRandall Stewart return (callout_stop(t_callout)); 97489e560f4SRandall Stewart } 97589e560f4SRandall Stewart 97689e560f4SRandall Stewart void 97789e560f4SRandall Stewart tcp_timers_unsuspend(struct tcpcb *tp, uint32_t timer_type) 97889e560f4SRandall Stewart { 97989e560f4SRandall Stewart switch (timer_type) { 98089e560f4SRandall Stewart case TT_DELACK: 98189e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_DELACK_SUS) { 98289e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_DELACK_SUS; 98389e560f4SRandall Stewart if (tp->t_flags & TF_DELACK) { 98489e560f4SRandall Stewart /* Delayed ack timer should be up activate a timer */ 98589e560f4SRandall Stewart tp->t_flags &= ~TF_DELACK; 98689e560f4SRandall Stewart tcp_timer_activate(tp, TT_DELACK, 98789e560f4SRandall Stewart tcp_delacktime); 98889e560f4SRandall Stewart } 98989e560f4SRandall Stewart } 99089e560f4SRandall Stewart break; 99189e560f4SRandall Stewart case TT_REXMT: 99289e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_REXMT_SUS) { 99389e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_REXMT_SUS; 99489e560f4SRandall Stewart if (SEQ_GT(tp->snd_max, tp->snd_una) && 99589e560f4SRandall Stewart (tcp_timer_active((tp), TT_PERSIST) == 0) && 99689e560f4SRandall Stewart tp->snd_wnd) { 99789e560f4SRandall Stewart /* We have outstanding data activate a timer */ 99889e560f4SRandall Stewart tcp_timer_activate(tp, TT_REXMT, 99989e560f4SRandall Stewart tp->t_rxtcur); 100089e560f4SRandall Stewart } 100189e560f4SRandall Stewart } 100289e560f4SRandall Stewart break; 100389e560f4SRandall Stewart case TT_PERSIST: 100489e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_PERSIST_SUS) { 100589e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_PERSIST_SUS; 100689e560f4SRandall Stewart if (tp->snd_wnd == 0) { 100789e560f4SRandall Stewart /* Activate the persists timer */ 100889e560f4SRandall Stewart tp->t_rxtshift = 0; 100989e560f4SRandall Stewart tcp_setpersist(tp); 101089e560f4SRandall Stewart } 101189e560f4SRandall Stewart } 101289e560f4SRandall Stewart break; 101389e560f4SRandall Stewart case TT_KEEP: 101489e560f4SRandall Stewart if (tp->t_timers->tt_flags & TT_KEEP_SUS) { 101589e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_KEEP_SUS; 101689e560f4SRandall Stewart tcp_timer_activate(tp, TT_KEEP, 101789e560f4SRandall Stewart TCPS_HAVEESTABLISHED(tp->t_state) ? 101889e560f4SRandall Stewart TP_KEEPIDLE(tp) : TP_KEEPINIT(tp)); 101989e560f4SRandall Stewart } 102089e560f4SRandall Stewart break; 102189e560f4SRandall Stewart case TT_2MSL: 102289e560f4SRandall Stewart if (tp->t_timers->tt_flags &= TT_2MSL_SUS) { 102389e560f4SRandall Stewart tp->t_timers->tt_flags &= ~TT_2MSL_SUS; 102489e560f4SRandall Stewart if ((tp->t_state == TCPS_FIN_WAIT_2) && 102589e560f4SRandall Stewart ((tp->t_inpcb->inp_socket == NULL) || 102689e560f4SRandall Stewart (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE))) { 102789e560f4SRandall Stewart /* Star the 2MSL timer */ 102889e560f4SRandall Stewart tcp_timer_activate(tp, TT_2MSL, 102989e560f4SRandall Stewart (tcp_fast_finwait2_recycle) ? 103089e560f4SRandall Stewart tcp_finwait2_timeout : TP_MAXIDLE(tp)); 103189e560f4SRandall Stewart } 103289e560f4SRandall Stewart } 103389e560f4SRandall Stewart break; 103489e560f4SRandall Stewart default: 103589e560f4SRandall Stewart panic("tp:%p bad timer_type 0x%x", tp, timer_type); 103689e560f4SRandall Stewart } 103789e560f4SRandall Stewart } 103889e560f4SRandall Stewart 1039ff945008SGleb Smirnoff static void 1040ff945008SGleb Smirnoff tcp_timer_discard(void *ptp) 1041ff945008SGleb Smirnoff { 1042ff945008SGleb Smirnoff struct inpcb *inp; 1043ff945008SGleb Smirnoff struct tcpcb *tp; 1044ff945008SGleb Smirnoff struct epoch_tracker et; 1045ff945008SGleb Smirnoff 1046ff945008SGleb Smirnoff tp = (struct tcpcb *)ptp; 1047ff945008SGleb Smirnoff CURVNET_SET(tp->t_vnet); 1048ff945008SGleb Smirnoff NET_EPOCH_ENTER(et); 1049ff945008SGleb Smirnoff inp = tp->t_inpcb; 1050ff945008SGleb Smirnoff KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", 1051ff945008SGleb Smirnoff __func__, tp)); 1052ff945008SGleb Smirnoff INP_WLOCK(inp); 1053ff945008SGleb Smirnoff KASSERT((tp->t_timers->tt_flags & TT_STOPPED) != 0, 1054ff945008SGleb Smirnoff ("%s: tcpcb has to be stopped here", __func__)); 1055ff945008SGleb Smirnoff if (--tp->t_timers->tt_draincnt > 0 || 1056ff945008SGleb Smirnoff tcp_freecb(tp) == false) 1057ff945008SGleb Smirnoff INP_WUNLOCK(inp); 1058ff945008SGleb Smirnoff NET_EPOCH_EXIT(et); 1059ff945008SGleb Smirnoff CURVNET_RESTORE(); 1060ff945008SGleb Smirnoff } 1061ff945008SGleb Smirnoff 10625571f9cfSJulien Charbon void 10635571f9cfSJulien Charbon tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type) 10645571f9cfSJulien Charbon { 10655571f9cfSJulien Charbon struct callout *t_callout; 10665571f9cfSJulien Charbon 10675571f9cfSJulien Charbon tp->t_timers->tt_flags |= TT_STOPPED; 10685571f9cfSJulien Charbon switch (timer_type) { 10695571f9cfSJulien Charbon case TT_DELACK: 10705571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_delack; 10715571f9cfSJulien Charbon break; 10725571f9cfSJulien Charbon case TT_REXMT: 10735571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_rexmt; 10745571f9cfSJulien Charbon break; 10755571f9cfSJulien Charbon case TT_PERSIST: 10765571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_persist; 10775571f9cfSJulien Charbon break; 10785571f9cfSJulien Charbon case TT_KEEP: 10795571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_keep; 10805571f9cfSJulien Charbon break; 10815571f9cfSJulien Charbon case TT_2MSL: 10825571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_2msl; 10835571f9cfSJulien Charbon break; 10845571f9cfSJulien Charbon default: 108555bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_stop) { 108655bceb1eSRandall Stewart /* 108755bceb1eSRandall Stewart * XXXrrs we need to look at this with the 108855bceb1eSRandall Stewart * stop case below (flags). 108955bceb1eSRandall Stewart */ 109055bceb1eSRandall Stewart tp->t_fb->tfb_tcp_timer_stop(tp, timer_type); 109155bceb1eSRandall Stewart return; 109255bceb1eSRandall Stewart } 10935571f9cfSJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 10945571f9cfSJulien Charbon } 10955571f9cfSJulien Charbon 1096e5ad6456SRandall Stewart if (callout_async_drain(t_callout, tcp_timer_discard) == 0) { 10975571f9cfSJulien Charbon /* 10985571f9cfSJulien Charbon * Can't stop the callout, defer tcpcb actual deletion 1099e5ad6456SRandall Stewart * to the last one. We do this using the async drain 1100e5ad6456SRandall Stewart * function and incrementing the count in 11015571f9cfSJulien Charbon */ 1102e5ad6456SRandall Stewart tp->t_timers->tt_draincnt++; 11035571f9cfSJulien Charbon } 11045571f9cfSJulien Charbon } 1105