1c398230bSWarner Losh /*- 2e79adb8eSGarrett Wollman * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 14df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 15df8bae1dSRodney W. Grimes * without specific prior written permission. 16df8bae1dSRodney W. Grimes * 17df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27df8bae1dSRodney W. Grimes * SUCH DAMAGE. 28df8bae1dSRodney W. Grimes * 29e79adb8eSGarrett Wollman * @(#)tcp_timer.c 8.2 (Berkeley) 5/24/95 30df8bae1dSRodney W. Grimes */ 31df8bae1dSRodney W. Grimes 324b421e2dSMike Silbersack #include <sys/cdefs.h> 334b421e2dSMike Silbersack __FBSDID("$FreeBSD$"); 344b421e2dSMike Silbersack 35825fd1e4SNavdeep Parhar #include "opt_inet.h" 36fb59c426SYoshinobu Inoue #include "opt_inet6.h" 370cc12cc5SJoerg Wunsch #include "opt_tcpdebug.h" 38883831c6SAdrian Chadd #include "opt_rss.h" 390cc12cc5SJoerg Wunsch 40df8bae1dSRodney W. Grimes #include <sys/param.h> 4198163b98SPoul-Henning Kamp #include <sys/kernel.h> 42c74af4faSBruce Evans #include <sys/lock.h> 4308517d53SMike Silbersack #include <sys/mbuf.h> 44c74af4faSBruce Evans #include <sys/mutex.h> 45c74af4faSBruce Evans #include <sys/protosw.h> 4687aedea4SKip Macy #include <sys/smp.h> 47df8bae1dSRodney W. Grimes #include <sys/socket.h> 48df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 49c74af4faSBruce Evans #include <sys/sysctl.h> 50c74af4faSBruce Evans #include <sys/systm.h> 51e79adb8eSGarrett Wollman 524b79449eSBjoern A. Zeeb #include <net/if.h> 53df8bae1dSRodney W. Grimes #include <net/route.h> 54b2bdc62aSAdrian Chadd #include <net/rss_config.h> 55530c0060SRobert Watson #include <net/vnet.h> 56883831c6SAdrian Chadd #include <net/netisr.h> 57df8bae1dSRodney W. Grimes 58df8bae1dSRodney W. Grimes #include <netinet/in.h> 595d06879aSGeorge V. Neville-Neil #include <netinet/in_kdtrace.h> 60df8bae1dSRodney W. Grimes #include <netinet/in_pcb.h> 61883831c6SAdrian Chadd #include <netinet/in_rss.h> 62c74af4faSBruce Evans #include <netinet/in_systm.h> 63fb59c426SYoshinobu Inoue #ifdef INET6 64fb59c426SYoshinobu Inoue #include <netinet6/in6_pcb.h> 65fb59c426SYoshinobu Inoue #endif 66df8bae1dSRodney W. Grimes #include <netinet/ip_var.h> 672de3e790SGleb Smirnoff #include <netinet/tcp.h> 68df8bae1dSRodney W. Grimes #include <netinet/tcp_fsm.h> 69df8bae1dSRodney W. Grimes #include <netinet/tcp_timer.h> 70df8bae1dSRodney W. Grimes #include <netinet/tcp_var.h> 712de3e790SGleb Smirnoff #include <netinet/tcp_cc.h> 72f6f6703fSSean Bruno #ifdef INET6 73f6f6703fSSean Bruno #include <netinet6/tcp6_var.h> 74f6f6703fSSean Bruno #endif 75df8bae1dSRodney W. Grimes #include <netinet/tcpip.h> 76af7a2999SDavid Greenman #ifdef TCPDEBUG 77af7a2999SDavid Greenman #include <netinet/tcp_debug.h> 78af7a2999SDavid Greenman #endif 79df8bae1dSRodney W. Grimes 80*0645c604SHiren Panchasara int tcp_persmin; 81*0645c604SHiren Panchasara SYSCTL_PROC(_net_inet_tcp, OID_AUTO, persmin, CTLTYPE_INT|CTLFLAG_RW, 82*0645c604SHiren Panchasara &tcp_persmin, 0, sysctl_msec_to_ticks, "I", "minimum persistence interval"); 83*0645c604SHiren Panchasara 84*0645c604SHiren Panchasara int tcp_persmax; 85*0645c604SHiren Panchasara SYSCTL_PROC(_net_inet_tcp, OID_AUTO, persmax, CTLTYPE_INT|CTLFLAG_RW, 86*0645c604SHiren Panchasara &tcp_persmax, 0, sysctl_msec_to_ticks, "I", "maximum persistence interval"); 87*0645c604SHiren Panchasara 889b8b58e0SJonathan Lemon int tcp_keepinit; 89ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, CTLTYPE_INT|CTLFLAG_RW, 9041698ebfSTom Rhodes &tcp_keepinit, 0, sysctl_msec_to_ticks, "I", "time to establish connection"); 917b40aa32SPaul Traina 929b8b58e0SJonathan Lemon int tcp_keepidle; 93ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, CTLTYPE_INT|CTLFLAG_RW, 9441698ebfSTom Rhodes &tcp_keepidle, 0, sysctl_msec_to_ticks, "I", "time before keepalive probes begin"); 9598163b98SPoul-Henning Kamp 969b8b58e0SJonathan Lemon int tcp_keepintvl; 97ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, CTLTYPE_INT|CTLFLAG_RW, 9841698ebfSTom Rhodes &tcp_keepintvl, 0, sysctl_msec_to_ticks, "I", "time between keepalive probes"); 9998163b98SPoul-Henning Kamp 1009b8b58e0SJonathan Lemon int tcp_delacktime; 1016489fe65SAndre Oppermann SYSCTL_PROC(_net_inet_tcp, TCPCTL_DELACKTIME, delacktime, CTLTYPE_INT|CTLFLAG_RW, 1026489fe65SAndre Oppermann &tcp_delacktime, 0, sysctl_msec_to_ticks, "I", 103ccb4d0c6SJonathan Lemon "Time before a delayed ACK is sent"); 1049b8b58e0SJonathan Lemon 1059b8b58e0SJonathan Lemon int tcp_msl; 106ccb4d0c6SJonathan Lemon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl, CTLTYPE_INT|CTLFLAG_RW, 107ccb4d0c6SJonathan Lemon &tcp_msl, 0, sysctl_msec_to_ticks, "I", "Maximum segment lifetime"); 1089b8b58e0SJonathan Lemon 109701bec5aSMatthew Dillon int tcp_rexmit_min; 110701bec5aSMatthew Dillon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_min, CTLTYPE_INT|CTLFLAG_RW, 1116489fe65SAndre Oppermann &tcp_rexmit_min, 0, sysctl_msec_to_ticks, "I", 1126489fe65SAndre Oppermann "Minimum Retransmission Timeout"); 113701bec5aSMatthew Dillon 114701bec5aSMatthew Dillon int tcp_rexmit_slop; 115701bec5aSMatthew Dillon SYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_slop, CTLTYPE_INT|CTLFLAG_RW, 1166489fe65SAndre Oppermann &tcp_rexmit_slop, 0, sysctl_msec_to_ticks, "I", 1176489fe65SAndre Oppermann "Retransmission Timer Slop"); 118701bec5aSMatthew Dillon 119c39a614eSRobert Watson static int always_keepalive = 1; 1203d177f46SBill Fumerola SYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW, 1213d177f46SBill Fumerola &always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections"); 12234be9bf3SPoul-Henning Kamp 1237c72af87SMohan Srinivasan int tcp_fast_finwait2_recycle = 0; 1247c72af87SMohan Srinivasan SYSCTL_INT(_net_inet_tcp, OID_AUTO, fast_finwait2_recycle, CTLFLAG_RW, 1256489fe65SAndre Oppermann &tcp_fast_finwait2_recycle, 0, 1266489fe65SAndre Oppermann "Recycle closed FIN_WAIT_2 connections faster"); 1277c72af87SMohan Srinivasan 1287c72af87SMohan Srinivasan int tcp_finwait2_timeout; 1297c72af87SMohan Srinivasan SYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, CTLTYPE_INT|CTLFLAG_RW, 1306489fe65SAndre Oppermann &tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", "FIN-WAIT2 timeout"); 1317c72af87SMohan Srinivasan 1329077f387SGleb Smirnoff int tcp_keepcnt = TCPTV_KEEPCNT; 1339077f387SGleb Smirnoff SYSCTL_INT(_net_inet_tcp, OID_AUTO, keepcnt, CTLFLAG_RW, &tcp_keepcnt, 0, 1349077f387SGleb Smirnoff "Number of keepalive probes to send"); 1357c72af87SMohan Srinivasan 1360312fbe9SPoul-Henning Kamp /* max idle probes */ 1379b8b58e0SJonathan Lemon int tcp_maxpersistidle; 138e79adb8eSGarrett Wollman 1396c0ef895SJohn Baldwin static int tcp_rexmit_drop_options = 0; 1406c0ef895SJohn Baldwin SYSCTL_INT(_net_inet_tcp, OID_AUTO, rexmit_drop_options, CTLFLAG_RW, 1416c0ef895SJohn Baldwin &tcp_rexmit_drop_options, 0, 1426c0ef895SJohn Baldwin "Drop TCP options from 3rd and later retransmitted SYN"); 1436c0ef895SJohn Baldwin 144f6f6703fSSean Bruno static VNET_DEFINE(int, tcp_pmtud_blackhole_detect); 145f6f6703fSSean Bruno #define V_tcp_pmtud_blackhole_detect VNET(tcp_pmtud_blackhole_detect) 146f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_detection, 147f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 148f6f6703fSSean Bruno &VNET_NAME(tcp_pmtud_blackhole_detect), 0, 149f6f6703fSSean Bruno "Path MTU Discovery Black Hole Detection Enabled"); 150f6f6703fSSean Bruno 151f6f6703fSSean Bruno static VNET_DEFINE(int, tcp_pmtud_blackhole_activated); 152f6f6703fSSean Bruno #define V_tcp_pmtud_blackhole_activated \ 153f6f6703fSSean Bruno VNET(tcp_pmtud_blackhole_activated) 154f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_activated, 155f0188618SHans Petter Selasky CTLFLAG_RD|CTLFLAG_VNET, 156f6f6703fSSean Bruno &VNET_NAME(tcp_pmtud_blackhole_activated), 0, 157f6f6703fSSean Bruno "Path MTU Discovery Black Hole Detection, Activation Count"); 158f6f6703fSSean Bruno 159f6f6703fSSean Bruno static VNET_DEFINE(int, tcp_pmtud_blackhole_activated_min_mss); 160f6f6703fSSean Bruno #define V_tcp_pmtud_blackhole_activated_min_mss \ 161f6f6703fSSean Bruno VNET(tcp_pmtud_blackhole_activated_min_mss) 162f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_activated_min_mss, 163f0188618SHans Petter Selasky CTLFLAG_RD|CTLFLAG_VNET, 164f6f6703fSSean Bruno &VNET_NAME(tcp_pmtud_blackhole_activated_min_mss), 0, 165f6f6703fSSean Bruno "Path MTU Discovery Black Hole Detection, Activation Count at min MSS"); 166f6f6703fSSean Bruno 167f6f6703fSSean Bruno static VNET_DEFINE(int, tcp_pmtud_blackhole_failed); 168f6f6703fSSean Bruno #define V_tcp_pmtud_blackhole_failed VNET(tcp_pmtud_blackhole_failed) 169f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_failed, 170f0188618SHans Petter Selasky CTLFLAG_RD|CTLFLAG_VNET, 171f6f6703fSSean Bruno &VNET_NAME(tcp_pmtud_blackhole_failed), 0, 172f6f6703fSSean Bruno "Path MTU Discovery Black Hole Detection, Failure Count"); 173f6f6703fSSean Bruno 174f6f6703fSSean Bruno #ifdef INET 175f6f6703fSSean Bruno static VNET_DEFINE(int, tcp_pmtud_blackhole_mss) = 1200; 176f6f6703fSSean Bruno #define V_tcp_pmtud_blackhole_mss VNET(tcp_pmtud_blackhole_mss) 177f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_mss, 178f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 179f6f6703fSSean Bruno &VNET_NAME(tcp_pmtud_blackhole_mss), 0, 180f6f6703fSSean Bruno "Path MTU Discovery Black Hole Detection lowered MSS"); 181f6f6703fSSean Bruno #endif 182f6f6703fSSean Bruno 183f6f6703fSSean Bruno #ifdef INET6 184f6f6703fSSean Bruno static VNET_DEFINE(int, tcp_v6pmtud_blackhole_mss) = 1220; 185f6f6703fSSean Bruno #define V_tcp_v6pmtud_blackhole_mss VNET(tcp_v6pmtud_blackhole_mss) 186f6f6703fSSean Bruno SYSCTL_INT(_net_inet_tcp, OID_AUTO, v6pmtud_blackhole_mss, 187f0188618SHans Petter Selasky CTLFLAG_RW|CTLFLAG_VNET, 188f6f6703fSSean Bruno &VNET_NAME(tcp_v6pmtud_blackhole_mss), 0, 189f6f6703fSSean Bruno "Path MTU Discovery IPv6 Black Hole Detection lowered MSS"); 190f6f6703fSSean Bruno #endif 191f6f6703fSSean Bruno 1928f7e75cbSAdrian Chadd #ifdef RSS 1938f7e75cbSAdrian Chadd static int per_cpu_timers = 1; 1948f7e75cbSAdrian Chadd #else 19587aedea4SKip Macy static int per_cpu_timers = 0; 1968f7e75cbSAdrian Chadd #endif 19787aedea4SKip Macy SYSCTL_INT(_net_inet_tcp, OID_AUTO, per_cpu_timers, CTLFLAG_RW, 19887aedea4SKip Macy &per_cpu_timers , 0, "run tcp timers on all cpus"); 19987aedea4SKip Macy 200883831c6SAdrian Chadd #if 0 20187aedea4SKip Macy #define INP_CPU(inp) (per_cpu_timers ? (!CPU_ABSENT(((inp)->inp_flowid % (mp_maxid+1))) ? \ 20287aedea4SKip Macy ((inp)->inp_flowid % (mp_maxid+1)) : curcpu) : 0) 203883831c6SAdrian Chadd #endif 204883831c6SAdrian Chadd 205883831c6SAdrian Chadd /* 206883831c6SAdrian Chadd * Map the given inp to a CPU id. 207883831c6SAdrian Chadd * 208883831c6SAdrian Chadd * This queries RSS if it's compiled in, else it defaults to the current 209883831c6SAdrian Chadd * CPU ID. 210883831c6SAdrian Chadd */ 211883831c6SAdrian Chadd static inline int 212883831c6SAdrian Chadd inp_to_cpuid(struct inpcb *inp) 213883831c6SAdrian Chadd { 214883831c6SAdrian Chadd u_int cpuid; 215883831c6SAdrian Chadd 216883831c6SAdrian Chadd #ifdef RSS 217883831c6SAdrian Chadd if (per_cpu_timers) { 218883831c6SAdrian Chadd cpuid = rss_hash2cpuid(inp->inp_flowid, inp->inp_flowtype); 219883831c6SAdrian Chadd if (cpuid == NETISR_CPUID_NONE) 220883831c6SAdrian Chadd return (curcpu); /* XXX */ 221883831c6SAdrian Chadd else 222883831c6SAdrian Chadd return (cpuid); 223883831c6SAdrian Chadd } 224883831c6SAdrian Chadd #else 225883831c6SAdrian Chadd /* Legacy, pre-RSS behaviour */ 226883831c6SAdrian Chadd if (per_cpu_timers) { 227883831c6SAdrian Chadd /* 228883831c6SAdrian Chadd * We don't have a flowid -> cpuid mapping, so cheat and 229883831c6SAdrian Chadd * just map unknown cpuids to curcpu. Not the best, but 230883831c6SAdrian Chadd * apparently better than defaulting to swi 0. 231883831c6SAdrian Chadd */ 232883831c6SAdrian Chadd cpuid = inp->inp_flowid % (mp_maxid + 1); 233883831c6SAdrian Chadd if (! CPU_ABSENT(cpuid)) 234883831c6SAdrian Chadd return (cpuid); 235883831c6SAdrian Chadd return (curcpu); 236883831c6SAdrian Chadd } 237883831c6SAdrian Chadd #endif 238883831c6SAdrian Chadd /* Default for RSS and non-RSS - cpuid 0 */ 239883831c6SAdrian Chadd else { 240883831c6SAdrian Chadd return (0); 241883831c6SAdrian Chadd } 242883831c6SAdrian Chadd } 24387aedea4SKip Macy 244df8bae1dSRodney W. Grimes /* 245df8bae1dSRodney W. Grimes * Tcp protocol timeout routine called every 500 ms. 2469b8b58e0SJonathan Lemon * Updates timestamps used for TCP 247df8bae1dSRodney W. Grimes * causes finite state machine actions if timers expire. 248df8bae1dSRodney W. Grimes */ 249df8bae1dSRodney W. Grimes void 250e2f2059fSMike Silbersack tcp_slowtimo(void) 251df8bae1dSRodney W. Grimes { 2528b615593SMarko Zec VNET_ITERATOR_DECL(vnet_iter); 25315bd2b43SDavid Greenman 2545ee847d3SRobert Watson VNET_LIST_RLOCK_NOSLEEP(); 2558b615593SMarko Zec VNET_FOREACH(vnet_iter) { 2568b615593SMarko Zec CURVNET_SET(vnet_iter); 257cea40c48SJulien Charbon (void) tcp_tw_2msl_scan(0); 2588b615593SMarko Zec CURVNET_RESTORE(); 2598b615593SMarko Zec } 2605ee847d3SRobert Watson VNET_LIST_RUNLOCK_NOSLEEP(); 261df8bae1dSRodney W. Grimes } 262df8bae1dSRodney W. Grimes 2637d42e30cSJonathan Lemon int tcp_syn_backoff[TCP_MAXRXTSHIFT + 1] = 2647d42e30cSJonathan Lemon { 1, 1, 1, 1, 1, 2, 4, 8, 16, 32, 64, 64, 64 }; 2657d42e30cSJonathan Lemon 266df8bae1dSRodney W. Grimes int tcp_backoff[TCP_MAXRXTSHIFT + 1] = 267f058535dSJeffrey Hsu { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 512, 512, 512 }; 268df8bae1dSRodney W. Grimes 269f058535dSJeffrey Hsu static int tcp_totbackoff = 2559; /* sum of tcp_backoff[] */ 270e79adb8eSGarrett Wollman 271df8bae1dSRodney W. Grimes /* 272df8bae1dSRodney W. Grimes * TCP timer processing. 273df8bae1dSRodney W. Grimes */ 27485d94372SRobert Watson 27585d94372SRobert Watson void 27685d94372SRobert Watson tcp_timer_delack(void *xtp) 277df8bae1dSRodney W. Grimes { 27885d94372SRobert Watson struct tcpcb *tp = xtp; 27985d94372SRobert Watson struct inpcb *inp; 2808b615593SMarko Zec CURVNET_SET(tp->t_vnet); 28185d94372SRobert Watson 28285d94372SRobert Watson inp = tp->t_inpcb; 2835571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 2848501a69cSRobert Watson INP_WLOCK(inp); 285655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_delack) || 286655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_delack)) { 2878501a69cSRobert Watson INP_WUNLOCK(inp); 2888b615593SMarko Zec CURVNET_RESTORE(); 28985d94372SRobert Watson return; 29085d94372SRobert Watson } 291e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_delack); 292655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 293655f934bSMikolaj Golub INP_WUNLOCK(inp); 294655f934bSMikolaj Golub CURVNET_RESTORE(); 295655f934bSMikolaj Golub return; 296655f934bSMikolaj Golub } 2975571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 2985571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 2995571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_DELACK) != 0, 3005571f9cfSJulien Charbon ("%s: tp %p delack callout should be running", __func__, tp)); 301df8bae1dSRodney W. Grimes 3029b8b58e0SJonathan Lemon tp->t_flags |= TF_ACKNOW; 30378b50714SRobert Watson TCPSTAT_INC(tcps_delack); 30455bceb1eSRandall Stewart (void) tp->t_fb->tfb_tcp_output(tp); 3058501a69cSRobert Watson INP_WUNLOCK(inp); 3068b615593SMarko Zec CURVNET_RESTORE(); 3079b8b58e0SJonathan Lemon } 3089b8b58e0SJonathan Lemon 30985d94372SRobert Watson void 31085d94372SRobert Watson tcp_timer_2msl(void *xtp) 3119b8b58e0SJonathan Lemon { 31285d94372SRobert Watson struct tcpcb *tp = xtp; 31385d94372SRobert Watson struct inpcb *inp; 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 320ff9b006dSJulien Charbon INP_INFO_RLOCK(&V_tcbinfo); 32185d94372SRobert Watson inp = tp->t_inpcb; 3225571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 3238501a69cSRobert Watson INP_WLOCK(inp); 32485d94372SRobert Watson tcp_free_sackholes(tp); 325655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_2msl) || 326e2f2059fSMike Silbersack !callout_active(&tp->t_timers->tt_2msl)) { 3278501a69cSRobert Watson INP_WUNLOCK(tp->t_inpcb); 328ff9b006dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 3298b615593SMarko Zec CURVNET_RESTORE(); 33085d94372SRobert Watson return; 33185d94372SRobert Watson } 332e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_2msl); 333655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 334655f934bSMikolaj Golub INP_WUNLOCK(inp); 335ff9b006dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 336655f934bSMikolaj Golub CURVNET_RESTORE(); 337655f934bSMikolaj Golub return; 338655f934bSMikolaj Golub } 3395571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 3405571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 3415571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_2MSL) != 0, 3425571f9cfSJulien Charbon ("%s: tp %p 2msl callout should be running", __func__, tp)); 34385d94372SRobert Watson /* 344df8bae1dSRodney W. Grimes * 2 MSL timeout in shutdown went off. If we're closed but 345df8bae1dSRodney W. Grimes * still waiting for peer to close and connection has been idle 34631a7749dSJulien Charbon * too long delete connection control block. Otherwise, check 34731a7749dSJulien Charbon * again in a bit. 34831a7749dSJulien Charbon * 34931a7749dSJulien Charbon * If in TIME_WAIT state just ignore as this timeout is handled in 35031a7749dSJulien Charbon * tcp_tw_2msl_scan(). 3517c72af87SMohan Srinivasan * 3527c72af87SMohan Srinivasan * If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, 3537c72af87SMohan Srinivasan * there's no point in hanging onto FIN_WAIT_2 socket. Just close it. 3547c72af87SMohan Srinivasan * Ignore fact that there were recent incoming segments. 355df8bae1dSRodney W. Grimes */ 35631a7749dSJulien Charbon if ((inp->inp_flags & INP_TIMEWAIT) != 0) { 35731a7749dSJulien Charbon INP_WUNLOCK(inp); 35831a7749dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 35931a7749dSJulien Charbon CURVNET_RESTORE(); 36031a7749dSJulien Charbon return; 36131a7749dSJulien Charbon } 3627c72af87SMohan Srinivasan if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && 36385d94372SRobert Watson tp->t_inpcb && tp->t_inpcb->inp_socket && 3647c72af87SMohan Srinivasan (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { 36578b50714SRobert Watson TCPSTAT_INC(tcps_finwait2_drops); 36685d94372SRobert Watson tp = tcp_close(tp); 3677c72af87SMohan Srinivasan } else { 368d6de19acSJulien Charbon if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) { 369d6de19acSJulien Charbon if (!callout_reset(&tp->t_timers->tt_2msl, 370d6de19acSJulien Charbon TP_KEEPINTVL(tp), tcp_timer_2msl, tp)) { 371d6de19acSJulien Charbon tp->t_timers->tt_flags &= ~TT_2MSL_RST; 372d6de19acSJulien Charbon } 373d6de19acSJulien Charbon } else 37485d94372SRobert Watson tp = tcp_close(tp); 3757c72af87SMohan Srinivasan } 376df8bae1dSRodney W. Grimes 3779b8b58e0SJonathan Lemon #ifdef TCPDEBUG 378586b4a0eSKonstantin Belousov if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 379fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 3809b8b58e0SJonathan Lemon PRU_SLOWTIMO); 3819b8b58e0SJonathan Lemon #endif 3825d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 3835d06879aSGeorge V. Neville-Neil 38485d94372SRobert Watson if (tp != NULL) 3858501a69cSRobert Watson INP_WUNLOCK(inp); 386ff9b006dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 3878b615593SMarko Zec CURVNET_RESTORE(); 3889b8b58e0SJonathan Lemon } 3899b8b58e0SJonathan Lemon 39085d94372SRobert Watson void 39185d94372SRobert Watson tcp_timer_keep(void *xtp) 3929b8b58e0SJonathan Lemon { 39385d94372SRobert Watson struct tcpcb *tp = xtp; 39408517d53SMike Silbersack struct tcptemp *t_template; 39585d94372SRobert Watson struct inpcb *inp; 3968b615593SMarko Zec CURVNET_SET(tp->t_vnet); 3979b8b58e0SJonathan Lemon #ifdef TCPDEBUG 3989b8b58e0SJonathan Lemon int ostate; 3999b8b58e0SJonathan Lemon 4009b8b58e0SJonathan Lemon ostate = tp->t_state; 4019b8b58e0SJonathan Lemon #endif 402ff9b006dSJulien Charbon INP_INFO_RLOCK(&V_tcbinfo); 40385d94372SRobert Watson inp = tp->t_inpcb; 4045571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 4058501a69cSRobert Watson INP_WLOCK(inp); 406655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_keep) || 407655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_keep)) { 4088501a69cSRobert Watson INP_WUNLOCK(inp); 409ff9b006dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 4108b615593SMarko Zec CURVNET_RESTORE(); 41185d94372SRobert Watson return; 41285d94372SRobert Watson } 413e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_keep); 414655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 415655f934bSMikolaj Golub INP_WUNLOCK(inp); 416ff9b006dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 417655f934bSMikolaj Golub CURVNET_RESTORE(); 418655f934bSMikolaj Golub return; 419655f934bSMikolaj Golub } 4205571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 4215571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 4225571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_KEEP) != 0, 4235571f9cfSJulien Charbon ("%s: tp %p keep callout should be running", __func__, tp)); 4249b8b58e0SJonathan Lemon /* 4259b8b58e0SJonathan Lemon * Keep-alive timer went off; send something 4269b8b58e0SJonathan Lemon * or drop connection if idle for too long. 4279b8b58e0SJonathan Lemon */ 42878b50714SRobert Watson TCPSTAT_INC(tcps_keeptimeo); 4299b8b58e0SJonathan Lemon if (tp->t_state < TCPS_ESTABLISHED) 4309b8b58e0SJonathan Lemon goto dropit; 4312a074620SSam Leffler if ((always_keepalive || inp->inp_socket->so_options & SO_KEEPALIVE) && 4329b8b58e0SJonathan Lemon tp->t_state <= TCPS_CLOSING) { 4339077f387SGleb Smirnoff if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp)) 4349b8b58e0SJonathan Lemon goto dropit; 4359b8b58e0SJonathan Lemon /* 4369b8b58e0SJonathan Lemon * Send a packet designed to force a response 4379b8b58e0SJonathan Lemon * if the peer is up and reachable: 4389b8b58e0SJonathan Lemon * either an ACK if the connection is still alive, 4399b8b58e0SJonathan Lemon * or an RST if the peer has closed the connection 4409b8b58e0SJonathan Lemon * due to timeout or reboot. 4419b8b58e0SJonathan Lemon * Using sequence number tp->snd_una-1 4429b8b58e0SJonathan Lemon * causes the transmitted zero-length segment 4439b8b58e0SJonathan Lemon * to lie outside the receive window; 4449b8b58e0SJonathan Lemon * by the protocol spec, this requires the 4459b8b58e0SJonathan Lemon * correspondent TCP to respond. 4469b8b58e0SJonathan Lemon */ 44778b50714SRobert Watson TCPSTAT_INC(tcps_keepprobe); 44879909384SJonathan Lemon t_template = tcpip_maketemplate(inp); 44908517d53SMike Silbersack if (t_template) { 45008517d53SMike Silbersack tcp_respond(tp, t_template->tt_ipgen, 45108517d53SMike Silbersack &t_template->tt_t, (struct mbuf *)NULL, 4529b8b58e0SJonathan Lemon tp->rcv_nxt, tp->snd_una - 1, 0); 45353640b0eSRobert Watson free(t_template, M_TEMP); 45408517d53SMike Silbersack } 455d6de19acSJulien Charbon if (!callout_reset(&tp->t_timers->tt_keep, TP_KEEPINTVL(tp), 456d6de19acSJulien Charbon tcp_timer_keep, tp)) { 457d6de19acSJulien Charbon tp->t_timers->tt_flags &= ~TT_KEEP_RST; 458d6de19acSJulien Charbon } 459d6de19acSJulien Charbon } else if (!callout_reset(&tp->t_timers->tt_keep, TP_KEEPIDLE(tp), 460d6de19acSJulien Charbon tcp_timer_keep, tp)) { 461d6de19acSJulien Charbon tp->t_timers->tt_flags &= ~TT_KEEP_RST; 462d6de19acSJulien Charbon } 4639b8b58e0SJonathan Lemon 4649b8b58e0SJonathan Lemon #ifdef TCPDEBUG 4652a074620SSam Leffler if (inp->inp_socket->so_options & SO_DEBUG) 466fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 4679b8b58e0SJonathan Lemon PRU_SLOWTIMO); 4689b8b58e0SJonathan Lemon #endif 4695d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 4708501a69cSRobert Watson INP_WUNLOCK(inp); 471ff9b006dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 4728b615593SMarko Zec CURVNET_RESTORE(); 47385d94372SRobert Watson return; 4749b8b58e0SJonathan Lemon 4759b8b58e0SJonathan Lemon dropit: 47678b50714SRobert Watson TCPSTAT_INC(tcps_keepdrops); 47785d94372SRobert Watson tp = tcp_drop(tp, ETIMEDOUT); 47885d94372SRobert Watson 47985d94372SRobert Watson #ifdef TCPDEBUG 48085d94372SRobert Watson if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 48185d94372SRobert Watson tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 48285d94372SRobert Watson PRU_SLOWTIMO); 48385d94372SRobert Watson #endif 4845d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 48585d94372SRobert Watson if (tp != NULL) 4868501a69cSRobert Watson INP_WUNLOCK(tp->t_inpcb); 487ff9b006dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 4888b615593SMarko Zec CURVNET_RESTORE(); 4899b8b58e0SJonathan Lemon } 4909b8b58e0SJonathan Lemon 49185d94372SRobert Watson void 49285d94372SRobert Watson tcp_timer_persist(void *xtp) 4939b8b58e0SJonathan Lemon { 49485d94372SRobert Watson struct tcpcb *tp = xtp; 49585d94372SRobert Watson struct inpcb *inp; 4968b615593SMarko Zec CURVNET_SET(tp->t_vnet); 4979b8b58e0SJonathan Lemon #ifdef TCPDEBUG 4989b8b58e0SJonathan Lemon int ostate; 4999b8b58e0SJonathan Lemon 5009b8b58e0SJonathan Lemon ostate = tp->t_state; 5019b8b58e0SJonathan Lemon #endif 502ff9b006dSJulien Charbon INP_INFO_RLOCK(&V_tcbinfo); 50385d94372SRobert Watson inp = tp->t_inpcb; 5045571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 5058501a69cSRobert Watson INP_WLOCK(inp); 506655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_persist) || 507655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_persist)) { 5088501a69cSRobert Watson INP_WUNLOCK(inp); 509ff9b006dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 5108b615593SMarko Zec CURVNET_RESTORE(); 51185d94372SRobert Watson return; 51285d94372SRobert Watson } 513e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_persist); 514655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 515655f934bSMikolaj Golub INP_WUNLOCK(inp); 516ff9b006dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 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)); 5225571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_PERSIST) != 0, 5235571f9cfSJulien Charbon ("%s: tp %p persist callout should be running", __func__, tp)); 5249b8b58e0SJonathan Lemon /* 5259b8b58e0SJonathan Lemon * Persistance timer into zero window. 5269b8b58e0SJonathan Lemon * Force a byte to be output, if possible. 5279b8b58e0SJonathan Lemon */ 52878b50714SRobert Watson TCPSTAT_INC(tcps_persisttimeo); 5299b8b58e0SJonathan Lemon /* 5309b8b58e0SJonathan Lemon * Hack: if the peer is dead/unreachable, we do not 5319b8b58e0SJonathan Lemon * time out if the window is closed. After a full 5329b8b58e0SJonathan Lemon * backoff, drop the connection if the idle time 5339b8b58e0SJonathan Lemon * (no responses to probes) reaches the maximum 5349b8b58e0SJonathan Lemon * backoff that we would use if retransmitting. 5359b8b58e0SJonathan Lemon */ 5369b8b58e0SJonathan Lemon if (tp->t_rxtshift == TCP_MAXRXTSHIFT && 5376b0c5521SJohn Baldwin (ticks - tp->t_rcvtime >= tcp_maxpersistidle || 5386b0c5521SJohn Baldwin ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { 53978b50714SRobert Watson TCPSTAT_INC(tcps_persistdrop); 54085d94372SRobert Watson tp = tcp_drop(tp, ETIMEDOUT); 54185d94372SRobert Watson goto out; 5429b8b58e0SJonathan Lemon } 543322181c9SAndre Oppermann /* 544322181c9SAndre Oppermann * If the user has closed the socket then drop a persisting 545322181c9SAndre Oppermann * connection after a much reduced timeout. 546322181c9SAndre Oppermann */ 547322181c9SAndre Oppermann if (tp->t_state > TCPS_CLOSE_WAIT && 548322181c9SAndre Oppermann (ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) { 549322181c9SAndre Oppermann TCPSTAT_INC(tcps_persistdrop); 550322181c9SAndre Oppermann tp = tcp_drop(tp, ETIMEDOUT); 551322181c9SAndre Oppermann goto out; 552322181c9SAndre Oppermann } 5539b8b58e0SJonathan Lemon tcp_setpersist(tp); 5542cdbfa66SPaul Saab tp->t_flags |= TF_FORCEDATA; 55555bceb1eSRandall Stewart (void) tp->t_fb->tfb_tcp_output(tp); 5562cdbfa66SPaul Saab tp->t_flags &= ~TF_FORCEDATA; 5579b8b58e0SJonathan Lemon 55885d94372SRobert Watson out: 5599b8b58e0SJonathan Lemon #ifdef TCPDEBUG 560ffb761f6SGleb Smirnoff if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 561ffb761f6SGleb Smirnoff tcp_trace(TA_USER, ostate, tp, NULL, NULL, PRU_SLOWTIMO); 5629b8b58e0SJonathan Lemon #endif 5635d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 56485d94372SRobert Watson if (tp != NULL) 5658501a69cSRobert Watson INP_WUNLOCK(inp); 566ff9b006dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 5678b615593SMarko Zec CURVNET_RESTORE(); 5689b8b58e0SJonathan Lemon } 5699b8b58e0SJonathan Lemon 57085d94372SRobert Watson void 57185d94372SRobert Watson tcp_timer_rexmt(void * xtp) 5729b8b58e0SJonathan Lemon { 57385d94372SRobert Watson struct tcpcb *tp = xtp; 5748b615593SMarko Zec CURVNET_SET(tp->t_vnet); 5759b8b58e0SJonathan Lemon int rexmt; 57685d94372SRobert Watson int headlocked; 57785d94372SRobert Watson struct inpcb *inp; 5789b8b58e0SJonathan Lemon #ifdef TCPDEBUG 5799b8b58e0SJonathan Lemon int ostate; 5809b8b58e0SJonathan Lemon 5819b8b58e0SJonathan Lemon ostate = tp->t_state; 5829b8b58e0SJonathan Lemon #endif 583f6f6703fSSean Bruno 58487aedea4SKip Macy INP_INFO_RLOCK(&V_tcbinfo); 58585d94372SRobert Watson inp = tp->t_inpcb; 5865571f9cfSJulien Charbon KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 5878501a69cSRobert Watson INP_WLOCK(inp); 588655f934bSMikolaj Golub if (callout_pending(&tp->t_timers->tt_rexmt) || 589655f934bSMikolaj Golub !callout_active(&tp->t_timers->tt_rexmt)) { 5908501a69cSRobert Watson INP_WUNLOCK(inp); 59187aedea4SKip Macy INP_INFO_RUNLOCK(&V_tcbinfo); 5928b615593SMarko Zec CURVNET_RESTORE(); 59385d94372SRobert Watson return; 59485d94372SRobert Watson } 595e2f2059fSMike Silbersack callout_deactivate(&tp->t_timers->tt_rexmt); 596655f934bSMikolaj Golub if ((inp->inp_flags & INP_DROPPED) != 0) { 597655f934bSMikolaj Golub INP_WUNLOCK(inp); 598655f934bSMikolaj Golub INP_INFO_RUNLOCK(&V_tcbinfo); 599655f934bSMikolaj Golub CURVNET_RESTORE(); 600655f934bSMikolaj Golub return; 601655f934bSMikolaj Golub } 6025571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 6035571f9cfSJulien Charbon ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 6045571f9cfSJulien Charbon KASSERT((tp->t_timers->tt_flags & TT_REXMT) != 0, 6055571f9cfSJulien Charbon ("%s: tp %p rexmt callout should be running", __func__, tp)); 6066d90faf3SPaul Saab tcp_free_sackholes(tp); 607df8bae1dSRodney W. Grimes /* 608df8bae1dSRodney W. Grimes * Retransmission timer went off. Message has not 609df8bae1dSRodney W. Grimes * been acked within retransmit interval. Back off 610df8bae1dSRodney W. Grimes * to a longer retransmit interval and retransmit one segment. 611df8bae1dSRodney W. Grimes */ 612df8bae1dSRodney W. Grimes if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 613df8bae1dSRodney W. Grimes tp->t_rxtshift = TCP_MAXRXTSHIFT; 61478b50714SRobert Watson TCPSTAT_INC(tcps_timeoutdrop); 615aa4b09c5SNavdeep Parhar 61685d94372SRobert Watson tp = tcp_drop(tp, tp->t_softerror ? 61785d94372SRobert Watson tp->t_softerror : ETIMEDOUT); 61887aedea4SKip Macy headlocked = 1; 61985d94372SRobert Watson goto out; 6209b8b58e0SJonathan Lemon } 62187aedea4SKip Macy INP_INFO_RUNLOCK(&V_tcbinfo); 62285d94372SRobert Watson headlocked = 0; 623cf8f04f4SAndre Oppermann if (tp->t_state == TCPS_SYN_SENT) { 624cf8f04f4SAndre Oppermann /* 625cf8f04f4SAndre Oppermann * If the SYN was retransmitted, indicate CWND to be 626cf8f04f4SAndre Oppermann * limited to 1 segment in cc_conn_init(). 627cf8f04f4SAndre Oppermann */ 628cf8f04f4SAndre Oppermann tp->snd_cwnd = 1; 629cf8f04f4SAndre Oppermann } else if (tp->t_rxtshift == 1) { 6309b8b58e0SJonathan Lemon /* 6319b8b58e0SJonathan Lemon * first retransmit; record ssthresh and cwnd so they can 6329b8b58e0SJonathan Lemon * be recovered if this turns out to be a "bad" retransmit. 6339b8b58e0SJonathan Lemon * A retransmit is considered "bad" if an ACK for this 6349b8b58e0SJonathan Lemon * segment is received within RTT/2 interval; the assumption 6359b8b58e0SJonathan Lemon * here is that the ACK was already in flight. See 6369b8b58e0SJonathan Lemon * "On Estimating End-to-End Network Path Properties" by 6379b8b58e0SJonathan Lemon * Allman and Paxson for more details. 6389b8b58e0SJonathan Lemon */ 6399b8b58e0SJonathan Lemon tp->snd_cwnd_prev = tp->snd_cwnd; 6409b8b58e0SJonathan Lemon tp->snd_ssthresh_prev = tp->snd_ssthresh; 6419d11646dSJeffrey Hsu tp->snd_recover_prev = tp->snd_recover; 642dbc42409SLawrence Stewart if (IN_FASTRECOVERY(tp->t_flags)) 6439d11646dSJeffrey Hsu tp->t_flags |= TF_WASFRECOVERY; 6449d11646dSJeffrey Hsu else 6459d11646dSJeffrey Hsu tp->t_flags &= ~TF_WASFRECOVERY; 646dbc42409SLawrence Stewart if (IN_CONGRECOVERY(tp->t_flags)) 647dbc42409SLawrence Stewart tp->t_flags |= TF_WASCRECOVERY; 648dbc42409SLawrence Stewart else 649dbc42409SLawrence Stewart tp->t_flags &= ~TF_WASCRECOVERY; 6509b8b58e0SJonathan Lemon tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); 651672dc4aeSJohn Baldwin tp->t_flags |= TF_PREVVALID; 652672dc4aeSJohn Baldwin } else 653672dc4aeSJohn Baldwin tp->t_flags &= ~TF_PREVVALID; 65478b50714SRobert Watson TCPSTAT_INC(tcps_rexmttimeo); 655281a0fd4SPatrick Kelsey if ((tp->t_state == TCPS_SYN_SENT) || 656281a0fd4SPatrick Kelsey (tp->t_state == TCPS_SYN_RECEIVED)) 657f4748ef5SAndre Oppermann rexmt = TCPTV_RTOBASE * tcp_syn_backoff[tp->t_rxtshift]; 6587d42e30cSJonathan Lemon else 659df8bae1dSRodney W. Grimes rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; 660df8bae1dSRodney W. Grimes TCPT_RANGESET(tp->t_rxtcur, rexmt, 661df8bae1dSRodney W. Grimes tp->t_rttmin, TCPTV_REXMTMAX); 662f6f6703fSSean Bruno 663882ac53eSSean Bruno /* 664882ac53eSSean Bruno * We enter the path for PLMTUD if connection is established or, if 665882ac53eSSean Bruno * connection is FIN_WAIT_1 status, reason for the last is that if 666882ac53eSSean Bruno * amount of data we send is very small, we could send it in couple of 667882ac53eSSean Bruno * packets and process straight to FIN. In that case we won't catch 668882ac53eSSean Bruno * ESTABLISHED state. 669882ac53eSSean Bruno */ 670882ac53eSSean Bruno if (V_tcp_pmtud_blackhole_detect && (((tp->t_state == TCPS_ESTABLISHED)) 671882ac53eSSean Bruno || (tp->t_state == TCPS_FIN_WAIT_1))) { 672f6f6703fSSean Bruno #ifdef INET6 673f6f6703fSSean Bruno int isipv6; 674f6f6703fSSean Bruno #endif 675f6f6703fSSean Bruno 676adf43a92SHiren Panchasara /* 677adf43a92SHiren Panchasara * Idea here is that at each stage of mtu probe (usually, 1448 678adf43a92SHiren Panchasara * -> 1188 -> 524) should be given 2 chances to recover before 679adf43a92SHiren Panchasara * further clamping down. 'tp->t_rxtshift % 2 == 0' should 680adf43a92SHiren Panchasara * take care of that. 681adf43a92SHiren Panchasara */ 682f6f6703fSSean Bruno if (((tp->t_flags2 & (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) == 683f6f6703fSSean Bruno (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) && 684adf43a92SHiren Panchasara (tp->t_rxtshift >= 2 && tp->t_rxtshift % 2 == 0)) { 685f6f6703fSSean Bruno /* 686f6f6703fSSean Bruno * Enter Path MTU Black-hole Detection mechanism: 687f6f6703fSSean Bruno * - Disable Path MTU Discovery (IP "DF" bit). 688f6f6703fSSean Bruno * - Reduce MTU to lower value than what we 689f6f6703fSSean Bruno * negotiated with peer. 690f6f6703fSSean Bruno */ 691f6f6703fSSean Bruno /* Record that we may have found a black hole. */ 692f6f6703fSSean Bruno tp->t_flags2 |= TF2_PLPMTU_BLACKHOLE; 693f6f6703fSSean Bruno 694f6f6703fSSean Bruno /* Keep track of previous MSS. */ 6950c39d38dSGleb Smirnoff tp->t_pmtud_saved_maxseg = tp->t_maxseg; 696f6f6703fSSean Bruno 697f6f6703fSSean Bruno /* 698f6f6703fSSean Bruno * Reduce the MSS to blackhole value or to the default 699f6f6703fSSean Bruno * in an attempt to retransmit. 700f6f6703fSSean Bruno */ 701f6f6703fSSean Bruno #ifdef INET6 702f6f6703fSSean Bruno isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) ? 1 : 0; 703f6f6703fSSean Bruno if (isipv6 && 7040c39d38dSGleb Smirnoff tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss) { 705f6f6703fSSean Bruno /* Use the sysctl tuneable blackhole MSS. */ 7060c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_v6pmtud_blackhole_mss; 707f6f6703fSSean Bruno V_tcp_pmtud_blackhole_activated++; 708f6f6703fSSean Bruno } else if (isipv6) { 709f6f6703fSSean Bruno /* Use the default MSS. */ 7100c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_v6mssdflt; 711f6f6703fSSean Bruno /* 712f6f6703fSSean Bruno * Disable Path MTU Discovery when we switch to 713f6f6703fSSean Bruno * minmss. 714f6f6703fSSean Bruno */ 715f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 716f6f6703fSSean Bruno V_tcp_pmtud_blackhole_activated_min_mss++; 717f6f6703fSSean Bruno } 718f6f6703fSSean Bruno #endif 719f6f6703fSSean Bruno #if defined(INET6) && defined(INET) 720f6f6703fSSean Bruno else 721f6f6703fSSean Bruno #endif 722f6f6703fSSean Bruno #ifdef INET 7230c39d38dSGleb Smirnoff if (tp->t_maxseg > V_tcp_pmtud_blackhole_mss) { 724f6f6703fSSean Bruno /* Use the sysctl tuneable blackhole MSS. */ 7250c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_pmtud_blackhole_mss; 726f6f6703fSSean Bruno V_tcp_pmtud_blackhole_activated++; 727f6f6703fSSean Bruno } else { 728f6f6703fSSean Bruno /* Use the default MSS. */ 7290c39d38dSGleb Smirnoff tp->t_maxseg = V_tcp_mssdflt; 730f6f6703fSSean Bruno /* 731f6f6703fSSean Bruno * Disable Path MTU Discovery when we switch to 732f6f6703fSSean Bruno * minmss. 733f6f6703fSSean Bruno */ 734f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 735f6f6703fSSean Bruno V_tcp_pmtud_blackhole_activated_min_mss++; 736f6f6703fSSean Bruno } 737f6f6703fSSean Bruno #endif 738f6f6703fSSean Bruno /* 739f6f6703fSSean Bruno * Reset the slow-start flight size 740f6f6703fSSean Bruno * as it may depend on the new MSS. 741f6f6703fSSean Bruno */ 742f6f6703fSSean Bruno if (CC_ALGO(tp)->conn_init != NULL) 743f6f6703fSSean Bruno CC_ALGO(tp)->conn_init(tp->ccv); 744f6f6703fSSean Bruno } else { 745f6f6703fSSean Bruno /* 746f6f6703fSSean Bruno * If further retransmissions are still unsuccessful 747f6f6703fSSean Bruno * with a lowered MTU, maybe this isn't a blackhole and 748f6f6703fSSean Bruno * we restore the previous MSS and blackhole detection 749f6f6703fSSean Bruno * flags. 750adf43a92SHiren Panchasara * The limit '6' is determined by giving each probe 751adf43a92SHiren Panchasara * stage (1448, 1188, 524) 2 chances to recover. 752f6f6703fSSean Bruno */ 753f6f6703fSSean Bruno if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) && 754adf43a92SHiren Panchasara (tp->t_rxtshift > 6)) { 755f6f6703fSSean Bruno tp->t_flags2 |= TF2_PLPMTU_PMTUD; 756f6f6703fSSean Bruno tp->t_flags2 &= ~TF2_PLPMTU_BLACKHOLE; 7570c39d38dSGleb Smirnoff tp->t_maxseg = tp->t_pmtud_saved_maxseg; 758f6f6703fSSean Bruno V_tcp_pmtud_blackhole_failed++; 759f6f6703fSSean Bruno /* 760f6f6703fSSean Bruno * Reset the slow-start flight size as it 761f6f6703fSSean Bruno * may depend on the new MSS. 762f6f6703fSSean Bruno */ 763f6f6703fSSean Bruno if (CC_ALGO(tp)->conn_init != NULL) 764f6f6703fSSean Bruno CC_ALGO(tp)->conn_init(tp->ccv); 765f6f6703fSSean Bruno } 766f6f6703fSSean Bruno } 767f6f6703fSSean Bruno } 768f6f6703fSSean Bruno 769df8bae1dSRodney W. Grimes /* 77077339e1cSAndre Oppermann * Disable RFC1323 and SACK if we haven't got any response to 7717ceb7783SJesper Skriver * our third SYN to work-around some broken terminal servers 7727ceb7783SJesper Skriver * (most of which have hopefully been retired) that have bad VJ 7737ceb7783SJesper Skriver * header compression code which trashes TCP segments containing 7747ceb7783SJesper Skriver * unknown-to-them TCP options. 7757ceb7783SJesper Skriver */ 7766c0ef895SJohn Baldwin if (tcp_rexmit_drop_options && (tp->t_state == TCPS_SYN_SENT) && 7776c0ef895SJohn Baldwin (tp->t_rxtshift == 3)) 778c4ab59c1SAndre Oppermann tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_SACK_PERMIT); 7797ceb7783SJesper Skriver /* 78097d8d152SAndre Oppermann * If we backed off this far, our srtt estimate is probably bogus. 78197d8d152SAndre Oppermann * Clobber it so we'll take the next rtt measurement as our srtt; 782df8bae1dSRodney W. Grimes * move the current srtt into rttvar to keep the current 783df8bae1dSRodney W. Grimes * retransmit times until then. 784df8bae1dSRodney W. Grimes */ 785df8bae1dSRodney W. Grimes if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { 786fb59c426SYoshinobu Inoue #ifdef INET6 787fb59c426SYoshinobu Inoue if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) 788fb59c426SYoshinobu Inoue in6_losing(tp->t_inpcb); 789fb59c426SYoshinobu Inoue #endif 790df8bae1dSRodney W. Grimes tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); 791df8bae1dSRodney W. Grimes tp->t_srtt = 0; 792df8bae1dSRodney W. Grimes } 793df8bae1dSRodney W. Grimes tp->snd_nxt = tp->snd_una; 7949d11646dSJeffrey Hsu tp->snd_recover = tp->snd_max; 79546f58482SJonathan Lemon /* 79674b48c1dSAndras Olah * Force a segment to be sent. 79774b48c1dSAndras Olah */ 79874b48c1dSAndras Olah tp->t_flags |= TF_ACKNOW; 79974b48c1dSAndras Olah /* 800df8bae1dSRodney W. Grimes * If timing a segment in this window, stop the timer. 801df8bae1dSRodney W. Grimes */ 8029b8b58e0SJonathan Lemon tp->t_rtttime = 0; 803dbc42409SLawrence Stewart 804b5af1b88SLawrence Stewart cc_cong_signal(tp, NULL, CC_RTO); 805dbc42409SLawrence Stewart 80655bceb1eSRandall Stewart (void) tp->t_fb->tfb_tcp_output(tp); 807df8bae1dSRodney W. Grimes 80885d94372SRobert Watson out: 8099b8b58e0SJonathan Lemon #ifdef TCPDEBUG 8101c53f806SRobert Watson if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 811fb59c426SYoshinobu Inoue tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 8129b8b58e0SJonathan Lemon PRU_SLOWTIMO); 813df8bae1dSRodney W. Grimes #endif 8145d06879aSGeorge V. Neville-Neil TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 81585d94372SRobert Watson if (tp != NULL) 8168501a69cSRobert Watson INP_WUNLOCK(inp); 81785d94372SRobert Watson if (headlocked) 818ff9b006dSJulien Charbon INP_INFO_RUNLOCK(&V_tcbinfo); 8198b615593SMarko Zec CURVNET_RESTORE(); 82085d94372SRobert Watson } 82185d94372SRobert Watson 82285d94372SRobert Watson void 8235571f9cfSJulien Charbon tcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, u_int delta) 82485d94372SRobert Watson { 82585d94372SRobert Watson struct callout *t_callout; 82618832f1fSJulien Charbon timeout_t *f_callout; 82787aedea4SKip Macy struct inpcb *inp = tp->t_inpcb; 828883831c6SAdrian Chadd int cpu = inp_to_cpuid(inp); 829d6de19acSJulien Charbon uint32_t f_reset; 83085d94372SRobert Watson 83109fe6320SNavdeep Parhar #ifdef TCP_OFFLOAD 83209fe6320SNavdeep Parhar if (tp->t_flags & TF_TOE) 83309fe6320SNavdeep Parhar return; 83409fe6320SNavdeep Parhar #endif 83509fe6320SNavdeep Parhar 8365571f9cfSJulien Charbon if (tp->t_timers->tt_flags & TT_STOPPED) 8375571f9cfSJulien Charbon return; 8385571f9cfSJulien Charbon 83985d94372SRobert Watson switch (timer_type) { 84085d94372SRobert Watson case TT_DELACK: 841e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 84285d94372SRobert Watson f_callout = tcp_timer_delack; 843d6de19acSJulien Charbon f_reset = TT_DELACK_RST; 84485d94372SRobert Watson break; 84585d94372SRobert Watson case TT_REXMT: 846e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 84785d94372SRobert Watson f_callout = tcp_timer_rexmt; 848d6de19acSJulien Charbon f_reset = TT_REXMT_RST; 84985d94372SRobert Watson break; 85085d94372SRobert Watson case TT_PERSIST: 851e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 85285d94372SRobert Watson f_callout = tcp_timer_persist; 853d6de19acSJulien Charbon f_reset = TT_PERSIST_RST; 85485d94372SRobert Watson break; 85585d94372SRobert Watson case TT_KEEP: 856e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 85785d94372SRobert Watson f_callout = tcp_timer_keep; 858d6de19acSJulien Charbon f_reset = TT_KEEP_RST; 85985d94372SRobert Watson break; 86085d94372SRobert Watson case TT_2MSL: 861e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 86285d94372SRobert Watson f_callout = tcp_timer_2msl; 863d6de19acSJulien Charbon f_reset = TT_2MSL_RST; 86485d94372SRobert Watson break; 86585d94372SRobert Watson default: 86655bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_activate) { 86755bceb1eSRandall Stewart tp->t_fb->tfb_tcp_timer_activate(tp, timer_type, delta); 86855bceb1eSRandall Stewart return; 86955bceb1eSRandall Stewart } 87003374917SJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 87185d94372SRobert Watson } 87285d94372SRobert Watson if (delta == 0) { 8735571f9cfSJulien Charbon if ((tp->t_timers->tt_flags & timer_type) && 8747c4676ddSRandall Stewart (callout_stop(t_callout) > 0) && 875d6de19acSJulien Charbon (tp->t_timers->tt_flags & f_reset)) { 876d6de19acSJulien Charbon tp->t_timers->tt_flags &= ~(timer_type | f_reset); 8775571f9cfSJulien Charbon } 87885d94372SRobert Watson } else { 8795571f9cfSJulien Charbon if ((tp->t_timers->tt_flags & timer_type) == 0) { 880d6de19acSJulien Charbon tp->t_timers->tt_flags |= (timer_type | f_reset); 88187aedea4SKip Macy callout_reset_on(t_callout, delta, f_callout, tp, cpu); 8825571f9cfSJulien Charbon } else { 8835571f9cfSJulien Charbon /* Reset already running callout on the same CPU. */ 884d6de19acSJulien Charbon if (!callout_reset(t_callout, delta, f_callout, tp)) { 885d6de19acSJulien Charbon /* 886d6de19acSJulien Charbon * Callout not cancelled, consider it as not 887d6de19acSJulien Charbon * properly restarted. */ 888d6de19acSJulien Charbon tp->t_timers->tt_flags &= ~f_reset; 889d6de19acSJulien Charbon } 8905571f9cfSJulien Charbon } 89185d94372SRobert Watson } 89285d94372SRobert Watson } 89385d94372SRobert Watson 89485d94372SRobert Watson int 8955571f9cfSJulien Charbon tcp_timer_active(struct tcpcb *tp, uint32_t timer_type) 89685d94372SRobert Watson { 89785d94372SRobert Watson struct callout *t_callout; 89885d94372SRobert Watson 89985d94372SRobert Watson switch (timer_type) { 90085d94372SRobert Watson case TT_DELACK: 901e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_delack; 90285d94372SRobert Watson break; 90385d94372SRobert Watson case TT_REXMT: 904e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_rexmt; 90585d94372SRobert Watson break; 90685d94372SRobert Watson case TT_PERSIST: 907e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_persist; 90885d94372SRobert Watson break; 90985d94372SRobert Watson case TT_KEEP: 910e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_keep; 91185d94372SRobert Watson break; 91285d94372SRobert Watson case TT_2MSL: 913e2f2059fSMike Silbersack t_callout = &tp->t_timers->tt_2msl; 91485d94372SRobert Watson break; 91585d94372SRobert Watson default: 91655bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_active) { 91755bceb1eSRandall Stewart return(tp->t_fb->tfb_tcp_timer_active(tp, timer_type)); 91855bceb1eSRandall Stewart } 91903374917SJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 92085d94372SRobert Watson } 92185d94372SRobert Watson return callout_active(t_callout); 922df8bae1dSRodney W. Grimes } 923b8614722SMike Silbersack 9245571f9cfSJulien Charbon void 9255571f9cfSJulien Charbon tcp_timer_stop(struct tcpcb *tp, uint32_t timer_type) 9265571f9cfSJulien Charbon { 9275571f9cfSJulien Charbon struct callout *t_callout; 9285571f9cfSJulien Charbon timeout_t *f_callout; 929d6de19acSJulien Charbon uint32_t f_reset; 9305571f9cfSJulien Charbon 9315571f9cfSJulien Charbon tp->t_timers->tt_flags |= TT_STOPPED; 9325571f9cfSJulien Charbon 9335571f9cfSJulien Charbon switch (timer_type) { 9345571f9cfSJulien Charbon case TT_DELACK: 9355571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_delack; 9365571f9cfSJulien Charbon f_callout = tcp_timer_delack_discard; 937d6de19acSJulien Charbon f_reset = TT_DELACK_RST; 9385571f9cfSJulien Charbon break; 9395571f9cfSJulien Charbon case TT_REXMT: 9405571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_rexmt; 9415571f9cfSJulien Charbon f_callout = tcp_timer_rexmt_discard; 942d6de19acSJulien Charbon f_reset = TT_REXMT_RST; 9435571f9cfSJulien Charbon break; 9445571f9cfSJulien Charbon case TT_PERSIST: 9455571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_persist; 9465571f9cfSJulien Charbon f_callout = tcp_timer_persist_discard; 947d6de19acSJulien Charbon f_reset = TT_PERSIST_RST; 9485571f9cfSJulien Charbon break; 9495571f9cfSJulien Charbon case TT_KEEP: 9505571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_keep; 9515571f9cfSJulien Charbon f_callout = tcp_timer_keep_discard; 952d6de19acSJulien Charbon f_reset = TT_KEEP_RST; 9535571f9cfSJulien Charbon break; 9545571f9cfSJulien Charbon case TT_2MSL: 9555571f9cfSJulien Charbon t_callout = &tp->t_timers->tt_2msl; 9565571f9cfSJulien Charbon f_callout = tcp_timer_2msl_discard; 957d6de19acSJulien Charbon f_reset = TT_2MSL_RST; 9585571f9cfSJulien Charbon break; 9595571f9cfSJulien Charbon default: 96055bceb1eSRandall Stewart if (tp->t_fb->tfb_tcp_timer_stop) { 96155bceb1eSRandall Stewart /* 96255bceb1eSRandall Stewart * XXXrrs we need to look at this with the 96355bceb1eSRandall Stewart * stop case below (flags). 96455bceb1eSRandall Stewart */ 96555bceb1eSRandall Stewart tp->t_fb->tfb_tcp_timer_stop(tp, timer_type); 96655bceb1eSRandall Stewart return; 96755bceb1eSRandall Stewart } 9685571f9cfSJulien Charbon panic("tp %p bad timer_type %#x", tp, timer_type); 9695571f9cfSJulien Charbon } 9705571f9cfSJulien Charbon 9715571f9cfSJulien Charbon if (tp->t_timers->tt_flags & timer_type) { 9727c4676ddSRandall Stewart if ((callout_stop(t_callout) > 0) && 973d6de19acSJulien Charbon (tp->t_timers->tt_flags & f_reset)) { 974d6de19acSJulien Charbon tp->t_timers->tt_flags &= ~(timer_type | f_reset); 9755571f9cfSJulien Charbon } else { 9765571f9cfSJulien Charbon /* 9775571f9cfSJulien Charbon * Can't stop the callout, defer tcpcb actual deletion 9785571f9cfSJulien Charbon * to the last tcp timer discard callout. 9795571f9cfSJulien Charbon * The TT_STOPPED flag will ensure that no tcp timer 9805571f9cfSJulien Charbon * callouts can be restarted on our behalf, and 9815571f9cfSJulien Charbon * past this point currently running callouts waiting 9825571f9cfSJulien Charbon * on inp lock will return right away after the 9835571f9cfSJulien Charbon * classical check for callout reset/stop events: 9845571f9cfSJulien Charbon * callout_pending() || !callout_active() 9855571f9cfSJulien Charbon */ 9865571f9cfSJulien Charbon callout_reset(t_callout, 1, f_callout, tp); 9875571f9cfSJulien Charbon } 9885571f9cfSJulien Charbon } 9895571f9cfSJulien Charbon } 9905571f9cfSJulien Charbon 991b8614722SMike Silbersack #define ticks_to_msecs(t) (1000*(t) / hz) 992b8614722SMike Silbersack 993b8614722SMike Silbersack void 9945b999a6bSDavide Italiano tcp_timer_to_xtimer(struct tcpcb *tp, struct tcp_timer *timer, 9955b999a6bSDavide Italiano struct xtcp_timer *xtimer) 996b8614722SMike Silbersack { 9975b999a6bSDavide Italiano sbintime_t now; 9985b999a6bSDavide Italiano 9995b999a6bSDavide Italiano bzero(xtimer, sizeof(*xtimer)); 1000b8614722SMike Silbersack if (timer == NULL) 1001b8614722SMike Silbersack return; 10025b999a6bSDavide Italiano now = getsbinuptime(); 1003b8614722SMike Silbersack if (callout_active(&timer->tt_delack)) 10045b999a6bSDavide Italiano xtimer->tt_delack = (timer->tt_delack.c_time - now) / SBT_1MS; 1005b8614722SMike Silbersack if (callout_active(&timer->tt_rexmt)) 10065b999a6bSDavide Italiano xtimer->tt_rexmt = (timer->tt_rexmt.c_time - now) / SBT_1MS; 1007b8614722SMike Silbersack if (callout_active(&timer->tt_persist)) 10085b999a6bSDavide Italiano xtimer->tt_persist = (timer->tt_persist.c_time - now) / SBT_1MS; 1009b8614722SMike Silbersack if (callout_active(&timer->tt_keep)) 10105b999a6bSDavide Italiano xtimer->tt_keep = (timer->tt_keep.c_time - now) / SBT_1MS; 1011b8614722SMike Silbersack if (callout_active(&timer->tt_2msl)) 10125b999a6bSDavide Italiano xtimer->tt_2msl = (timer->tt_2msl.c_time - now) / SBT_1MS; 1013b8614722SMike Silbersack xtimer->t_rcvtime = ticks_to_msecs(ticks - tp->t_rcvtime); 1014b8614722SMike Silbersack } 1015