tcp_timer.c revision 330897
1156321Sdamien/*- 2156321Sdamien * SPDX-License-Identifier: BSD-3-Clause 3156321Sdamien * 4156321Sdamien * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 5156321Sdamien * The Regents of the University of California. All rights reserved. 6156321Sdamien * 7156321Sdamien * Redistribution and use in source and binary forms, with or without 8156321Sdamien * modification, are permitted provided that the following conditions 9156321Sdamien * are met: 10156321Sdamien * 1. Redistributions of source code must retain the above copyright 11156321Sdamien * notice, this list of conditions and the following disclaimer. 12156321Sdamien * 2. Redistributions in binary form must reproduce the above copyright 13156321Sdamien * notice, this list of conditions and the following disclaimer in the 14156321Sdamien * documentation and/or other materials provided with the distribution. 15156321Sdamien * 4. Neither the name of the University nor the names of its contributors 16156321Sdamien * may be used to endorse or promote products derived from this software 17156321Sdamien * without specific prior written permission. 18156321Sdamien * 19156321Sdamien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20156321Sdamien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21156321Sdamien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22156321Sdamien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23156321Sdamien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24156321Sdamien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25156321Sdamien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26156321Sdamien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27156321Sdamien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28156321Sdamien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29156321Sdamien * SUCH DAMAGE. 30156321Sdamien * 31156321Sdamien * @(#)tcp_timer.c 8.2 (Berkeley) 5/24/95 32156321Sdamien */ 33156321Sdamien 34156321Sdamien#include <sys/cdefs.h> 35156321Sdamien__FBSDID("$FreeBSD: stable/11/sys/netinet/tcp_timer.c 330897 2018-03-14 03:19:51Z eadler $"); 36164982Skevlo 37164982Skevlo#include "opt_inet.h" 38156321Sdamien#include "opt_inet6.h" 39156321Sdamien#include "opt_tcpdebug.h" 40156321Sdamien#include "opt_rss.h" 41178354Ssam 42156321Sdamien#include <sys/param.h> 43156321Sdamien#include <sys/kernel.h> 44156321Sdamien#include <sys/lock.h> 45156321Sdamien#include <sys/mbuf.h> 46156321Sdamien#include <sys/mutex.h> 47156321Sdamien#include <sys/protosw.h> 48156321Sdamien#include <sys/smp.h> 49257176Sglebius#include <sys/socket.h> 50156321Sdamien#include <sys/socketvar.h> 51156321Sdamien#include <sys/sysctl.h> 52156321Sdamien#include <sys/systm.h> 53156321Sdamien 54156321Sdamien#include <net/if.h> 55156321Sdamien#include <net/route.h> 56156321Sdamien#include <net/rss_config.h> 57156321Sdamien#include <net/vnet.h> 58170530Ssam#include <net/netisr.h> 59206358Srpaulo 60156321Sdamien#include <netinet/in.h> 61156321Sdamien#include <netinet/in_kdtrace.h> 62156321Sdamien#include <netinet/in_pcb.h> 63156321Sdamien#include <netinet/in_rss.h> 64156321Sdamien#include <netinet/in_systm.h> 65156321Sdamien#ifdef INET6 66156321Sdamien#include <netinet6/in6_pcb.h> 67156327Ssilby#endif 68156327Ssilby#include <netinet/ip_var.h> 69156321Sdamien#include <netinet/tcp.h> 70178354Ssam#include <netinet/tcp_fsm.h> 71156321Sdamien#include <netinet/tcp_timer.h> 72178354Ssam#include <netinet/tcp_var.h> 73178354Ssam#include <netinet/cc/cc.h> 74178354Ssam#ifdef INET6 75178354Ssam#include <netinet6/tcp6_var.h> 76178354Ssam#endif 77178354Ssam#include <netinet/tcpip.h> 78178354Ssam#ifdef TCPDEBUG 79178354Ssam#include <netinet/tcp_debug.h> 80156321Sdamien#endif 81178354Ssam 82178354Ssamint tcp_persmin; 83156321SdamienSYSCTL_PROC(_net_inet_tcp, OID_AUTO, persmin, CTLTYPE_INT|CTLFLAG_RW, 84156321Sdamien &tcp_persmin, 0, sysctl_msec_to_ticks, "I", "minimum persistence interval"); 85178354Ssam 86228621Sbschmidtint tcp_persmax; 87228621SbschmidtSYSCTL_PROC(_net_inet_tcp, OID_AUTO, persmax, CTLTYPE_INT|CTLFLAG_RW, 88228621Sbschmidt &tcp_persmax, 0, sysctl_msec_to_ticks, "I", "maximum persistence interval"); 89178354Ssam 90156321Sdamienint tcp_keepinit; 91156321SdamienSYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINIT, keepinit, CTLTYPE_INT|CTLFLAG_RW, 92156321Sdamien &tcp_keepinit, 0, sysctl_msec_to_ticks, "I", "time to establish connection"); 93156321Sdamien 94156321Sdamienint tcp_keepidle; 95156321SdamienSYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPIDLE, keepidle, CTLTYPE_INT|CTLFLAG_RW, 96156321Sdamien &tcp_keepidle, 0, sysctl_msec_to_ticks, "I", "time before keepalive probes begin"); 97156321Sdamien 98156321Sdamienint tcp_keepintvl; 99156321SdamienSYSCTL_PROC(_net_inet_tcp, TCPCTL_KEEPINTVL, keepintvl, CTLTYPE_INT|CTLFLAG_RW, 100156321Sdamien &tcp_keepintvl, 0, sysctl_msec_to_ticks, "I", "time between keepalive probes"); 101156321Sdamien 102156321Sdamienint tcp_delacktime; 103156321SdamienSYSCTL_PROC(_net_inet_tcp, TCPCTL_DELACKTIME, delacktime, CTLTYPE_INT|CTLFLAG_RW, 104178354Ssam &tcp_delacktime, 0, sysctl_msec_to_ticks, "I", 105156321Sdamien "Time before a delayed ACK is sent"); 106156321Sdamien 107156321Sdamienint tcp_msl; 108156321SdamienSYSCTL_PROC(_net_inet_tcp, OID_AUTO, msl, CTLTYPE_INT|CTLFLAG_RW, 109156321Sdamien &tcp_msl, 0, sysctl_msec_to_ticks, "I", "Maximum segment lifetime"); 110156321Sdamien 111156321Sdamienint tcp_rexmit_min; 112156321SdamienSYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_min, CTLTYPE_INT|CTLFLAG_RW, 113156321Sdamien &tcp_rexmit_min, 0, sysctl_msec_to_ticks, "I", 114170530Ssam "Minimum Retransmission Timeout"); 115170530Ssam 116170530Ssamint tcp_rexmit_slop; 117156321SdamienSYSCTL_PROC(_net_inet_tcp, OID_AUTO, rexmit_slop, CTLTYPE_INT|CTLFLAG_RW, 118156321Sdamien &tcp_rexmit_slop, 0, sysctl_msec_to_ticks, "I", 119156321Sdamien "Retransmission Timer Slop"); 120156321Sdamien 121156321Sdamienint tcp_always_keepalive = 1; 122156321SdamienSYSCTL_INT(_net_inet_tcp, OID_AUTO, always_keepalive, CTLFLAG_RW, 123156321Sdamien &tcp_always_keepalive , 0, "Assume SO_KEEPALIVE on all TCP connections"); 124287197Sglebius__strong_reference(tcp_always_keepalive, always_keepalive); 125287197Sglebius 126178354Ssamint tcp_fast_finwait2_recycle = 0; 127178354SsamSYSCTL_INT(_net_inet_tcp, OID_AUTO, fast_finwait2_recycle, CTLFLAG_RW, 128165352Sbms &tcp_fast_finwait2_recycle, 0, 129287197Sglebius "Recycle closed FIN_WAIT_2 connections faster"); 130156321Sdamien 131156321Sdamienint tcp_finwait2_timeout; 132156321SdamienSYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, CTLTYPE_INT|CTLFLAG_RW, 133156321Sdamien &tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", "FIN-WAIT2 timeout"); 134156321Sdamien 135156321Sdamienint tcp_keepcnt = TCPTV_KEEPCNT; 136156321SdamienSYSCTL_INT(_net_inet_tcp, OID_AUTO, keepcnt, CTLFLAG_RW, &tcp_keepcnt, 0, 137156321Sdamien "Number of keepalive probes to send"); 138156321Sdamien 139156321Sdamien /* max idle probes */ 140156321Sdamienint tcp_maxpersistidle; 141156321Sdamien 142156321Sdamienstatic int tcp_rexmit_drop_options = 0; 143156321SdamienSYSCTL_INT(_net_inet_tcp, OID_AUTO, rexmit_drop_options, CTLFLAG_RW, 144156321Sdamien &tcp_rexmit_drop_options, 0, 145156321Sdamien "Drop TCP options from 3rd and later retransmitted SYN"); 146156321Sdamien 147156321Sdamienstatic VNET_DEFINE(int, tcp_pmtud_blackhole_detect); 148156321Sdamien#define V_tcp_pmtud_blackhole_detect VNET(tcp_pmtud_blackhole_detect) 149156321SdamienSYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_detection, 150283540Sglebius CTLFLAG_RW|CTLFLAG_VNET, 151156321Sdamien &VNET_NAME(tcp_pmtud_blackhole_detect), 0, 152283540Sglebius "Path MTU Discovery Black Hole Detection Enabled"); 153156321Sdamien 154178354Ssamstatic VNET_DEFINE(int, tcp_pmtud_blackhole_activated); 155190526Ssam#define V_tcp_pmtud_blackhole_activated \ 156156321Sdamien VNET(tcp_pmtud_blackhole_activated) 157178354SsamSYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_activated, 158156321Sdamien CTLFLAG_RD|CTLFLAG_VNET, 159178354Ssam &VNET_NAME(tcp_pmtud_blackhole_activated), 0, 160156321Sdamien "Path MTU Discovery Black Hole Detection, Activation Count"); 161178354Ssam 162156321Sdamienstatic VNET_DEFINE(int, tcp_pmtud_blackhole_activated_min_mss); 163156321Sdamien#define V_tcp_pmtud_blackhole_activated_min_mss \ 164156321Sdamien VNET(tcp_pmtud_blackhole_activated_min_mss) 165156321SdamienSYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_activated_min_mss, 166156321Sdamien CTLFLAG_RD|CTLFLAG_VNET, 167178354Ssam &VNET_NAME(tcp_pmtud_blackhole_activated_min_mss), 0, 168178354Ssam "Path MTU Discovery Black Hole Detection, Activation Count at min MSS"); 169156321Sdamien 170192468Ssamstatic VNET_DEFINE(int, tcp_pmtud_blackhole_failed); 171156321Sdamien#define V_tcp_pmtud_blackhole_failed VNET(tcp_pmtud_blackhole_failed) 172156321SdamienSYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_failed, 173156321Sdamien CTLFLAG_RD|CTLFLAG_VNET, 174156321Sdamien &VNET_NAME(tcp_pmtud_blackhole_failed), 0, 175156321Sdamien "Path MTU Discovery Black Hole Detection, Failure Count"); 176156321Sdamien 177156321Sdamien#ifdef INET 178156321Sdamienstatic VNET_DEFINE(int, tcp_pmtud_blackhole_mss) = 1200; 179156321Sdamien#define V_tcp_pmtud_blackhole_mss VNET(tcp_pmtud_blackhole_mss) 180156321SdamienSYSCTL_INT(_net_inet_tcp, OID_AUTO, pmtud_blackhole_mss, 181156321Sdamien CTLFLAG_RW|CTLFLAG_VNET, 182156321Sdamien &VNET_NAME(tcp_pmtud_blackhole_mss), 0, 183156321Sdamien "Path MTU Discovery Black Hole Detection lowered MSS"); 184156321Sdamien#endif 185156321Sdamien 186156321Sdamien#ifdef INET6 187156321Sdamienstatic VNET_DEFINE(int, tcp_v6pmtud_blackhole_mss) = 1220; 188156321Sdamien#define V_tcp_v6pmtud_blackhole_mss VNET(tcp_v6pmtud_blackhole_mss) 189156321SdamienSYSCTL_INT(_net_inet_tcp, OID_AUTO, v6pmtud_blackhole_mss, 190156321Sdamien CTLFLAG_RW|CTLFLAG_VNET, 191156321Sdamien &VNET_NAME(tcp_v6pmtud_blackhole_mss), 0, 192156321Sdamien "Path MTU Discovery IPv6 Black Hole Detection lowered MSS"); 193156321Sdamien#endif 194156321Sdamien 195156321Sdamien#ifdef RSS 196156321Sdamienstatic int per_cpu_timers = 1; 197156321Sdamien#else 198156321Sdamienstatic int per_cpu_timers = 0; 199156321Sdamien#endif 200287197SglebiusSYSCTL_INT(_net_inet_tcp, OID_AUTO, per_cpu_timers, CTLFLAG_RW, 201156321Sdamien &per_cpu_timers , 0, "run tcp timers on all cpus"); 202178354Ssam 203178354Ssam#if 0 204156321Sdamien#define INP_CPU(inp) (per_cpu_timers ? (!CPU_ABSENT(((inp)->inp_flowid % (mp_maxid+1))) ? \ 205178354Ssam ((inp)->inp_flowid % (mp_maxid+1)) : curcpu) : 0) 206156321Sdamien#endif 207156321Sdamien 208156321Sdamien/* 209156321Sdamien * Map the given inp to a CPU id. 210156321Sdamien * 211165352Sbms * This queries RSS if it's compiled in, else it defaults to the current 212287197Sglebius * CPU ID. 213156321Sdamien */ 214156321Sdamienstatic inline int 215156321Sdamieninp_to_cpuid(struct inpcb *inp) 216156321Sdamien{ 217156321Sdamien u_int cpuid; 218156321Sdamien 219156321Sdamien#ifdef RSS 220156321Sdamien if (per_cpu_timers) { 221156321Sdamien cpuid = rss_hash2cpuid(inp->inp_flowid, inp->inp_flowtype); 222156321Sdamien if (cpuid == NETISR_CPUID_NONE) 223156321Sdamien return (curcpu); /* XXX */ 224156321Sdamien else 225156321Sdamien return (cpuid); 226156321Sdamien } 227156321Sdamien#else 228287197Sglebius /* Legacy, pre-RSS behaviour */ 229156321Sdamien if (per_cpu_timers) { 230156321Sdamien /* 231156321Sdamien * We don't have a flowid -> cpuid mapping, so cheat and 232156321Sdamien * just map unknown cpuids to curcpu. Not the best, but 233156321Sdamien * apparently better than defaulting to swi 0. 234156321Sdamien */ 235156321Sdamien cpuid = inp->inp_flowid % (mp_maxid + 1); 236156321Sdamien if (! CPU_ABSENT(cpuid)) 237156321Sdamien return (cpuid); 238156321Sdamien return (curcpu); 239156321Sdamien } 240156321Sdamien#endif 241156321Sdamien /* Default for RSS and non-RSS - cpuid 0 */ 242156321Sdamien else { 243156321Sdamien return (0); 244156321Sdamien } 245156321Sdamien} 246156321Sdamien 247156321Sdamien/* 248156321Sdamien * Tcp protocol timeout routine called every 500 ms. 249156321Sdamien * Updates timestamps used for TCP 250156321Sdamien * causes finite state machine actions if timers expire. 251156321Sdamien */ 252156321Sdamienvoid 253156321Sdamientcp_slowtimo(void) 254156321Sdamien{ 255156321Sdamien VNET_ITERATOR_DECL(vnet_iter); 256156321Sdamien 257156321Sdamien VNET_LIST_RLOCK_NOSLEEP(); 258283537Sglebius VNET_FOREACH(vnet_iter) { 259283527Sglebius CURVNET_SET(vnet_iter); 260178354Ssam (void) tcp_tw_2msl_scan(0); 261156321Sdamien CURVNET_RESTORE(); 262156321Sdamien } 263156321Sdamien VNET_LIST_RUNLOCK_NOSLEEP(); 264156321Sdamien} 265178957Ssam 266178957Ssamint tcp_syn_backoff[TCP_MAXRXTSHIFT + 1] = 267178354Ssam { 1, 1, 1, 1, 1, 2, 4, 8, 16, 32, 64, 64, 64 }; 268178354Ssam 269178354Ssamint tcp_backoff[TCP_MAXRXTSHIFT + 1] = 270178354Ssam { 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 512, 512, 512 }; 271195618Srpaulo 272178354Ssamstatic int tcp_totbackoff = 2559; /* sum of tcp_backoff[] */ 273178354Ssam 274178354Ssam/* 275178354Ssam * TCP timer processing. 276156407Sdamien */ 277178354Ssam 278178354Ssamvoid 279156407Sdamientcp_timer_delack(void *xtp) 280178354Ssam{ 281156321Sdamien struct tcpcb *tp = xtp; 282170530Ssam struct inpcb *inp; 283170530Ssam CURVNET_SET(tp->t_vnet); 284170530Ssam 285170530Ssam inp = tp->t_inpcb; 286170530Ssam KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 287178354Ssam INP_WLOCK(inp); 288156321Sdamien if (callout_pending(&tp->t_timers->tt_delack) || 289287197Sglebius !callout_active(&tp->t_timers->tt_delack)) { 290178354Ssam INP_WUNLOCK(inp); 291178354Ssam CURVNET_RESTORE(); 292178354Ssam return; 293170530Ssam } 294170530Ssam callout_deactivate(&tp->t_timers->tt_delack); 295170530Ssam if ((inp->inp_flags & INP_DROPPED) != 0) { 296156321Sdamien INP_WUNLOCK(inp); 297178354Ssam CURVNET_RESTORE(); 298178354Ssam return; 299287197Sglebius } 300287197Sglebius KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 301178354Ssam ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 302178354Ssam KASSERT((tp->t_timers->tt_flags & TT_DELACK) != 0, 303156321Sdamien ("%s: tp %p delack callout should be running", __func__, tp)); 304192468Ssam 305192468Ssam tp->t_flags |= TF_ACKNOW; 306192468Ssam TCPSTAT_INC(tcps_delack); 307192468Ssam (void) tp->t_fb->tfb_tcp_output(tp); 308192468Ssam INP_WUNLOCK(inp); 309178354Ssam CURVNET_RESTORE(); 310178354Ssam} 311156321Sdamien 312178354Ssamvoid 313178354Ssamtcp_timer_2msl(void *xtp) 314178354Ssam{ 315156321Sdamien struct tcpcb *tp = xtp; 316156321Sdamien struct inpcb *inp; 317156321Sdamien CURVNET_SET(tp->t_vnet); 318156321Sdamien#ifdef TCPDEBUG 319156321Sdamien int ostate; 320156321Sdamien 321156321Sdamien ostate = tp->t_state; 322156321Sdamien#endif 323156321Sdamien INP_INFO_RLOCK(&V_tcbinfo); 324156321Sdamien inp = tp->t_inpcb; 325156321Sdamien KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 326156321Sdamien INP_WLOCK(inp); 327156321Sdamien tcp_free_sackholes(tp); 328156321Sdamien if (callout_pending(&tp->t_timers->tt_2msl) || 329156321Sdamien !callout_active(&tp->t_timers->tt_2msl)) { 330156321Sdamien INP_WUNLOCK(tp->t_inpcb); 331287197Sglebius INP_INFO_RUNLOCK(&V_tcbinfo); 332170530Ssam CURVNET_RESTORE(); 333178038Ssam return; 334178038Ssam } 335178038Ssam callout_deactivate(&tp->t_timers->tt_2msl); 336156321Sdamien if ((inp->inp_flags & INP_DROPPED) != 0) { 337156321Sdamien INP_WUNLOCK(inp); 338287197Sglebius INP_INFO_RUNLOCK(&V_tcbinfo); 339156321Sdamien CURVNET_RESTORE(); 340156321Sdamien return; 341156321Sdamien } 342156321Sdamien KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 343156321Sdamien ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 344156321Sdamien KASSERT((tp->t_timers->tt_flags & TT_2MSL) != 0, 345156321Sdamien ("%s: tp %p 2msl callout should be running", __func__, tp)); 346156321Sdamien /* 347156321Sdamien * 2 MSL timeout in shutdown went off. If we're closed but 348156321Sdamien * still waiting for peer to close and connection has been idle 349156321Sdamien * too long delete connection control block. Otherwise, check 350156321Sdamien * again in a bit. 351156321Sdamien * 352178354Ssam * If in TIME_WAIT state just ignore as this timeout is handled in 353228621Sbschmidt * tcp_tw_2msl_scan(). 354228621Sbschmidt * 355228621Sbschmidt * If fastrecycle of FIN_WAIT_2, in FIN_WAIT_2 and receiver has closed, 356228621Sbschmidt * there's no point in hanging onto FIN_WAIT_2 socket. Just close it. 357178354Ssam * Ignore fact that there were recent incoming segments. 358287197Sglebius */ 359178354Ssam if ((inp->inp_flags & INP_TIMEWAIT) != 0) { 360178354Ssam INP_WUNLOCK(inp); 361178354Ssam INP_INFO_RUNLOCK(&V_tcbinfo); 362178354Ssam CURVNET_RESTORE(); 363178354Ssam return; 364178354Ssam } 365178354Ssam if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && 366178354Ssam tp->t_inpcb && tp->t_inpcb->inp_socket && 367178354Ssam (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { 368195618Srpaulo TCPSTAT_INC(tcps_finwait2_drops); 369195618Srpaulo tp = tcp_close(tp); 370178354Ssam } else { 371287197Sglebius if (ticks - tp->t_rcvtime <= TP_MAXIDLE(tp)) { 372178354Ssam if (!callout_reset(&tp->t_timers->tt_2msl, 373178354Ssam TP_KEEPINTVL(tp), tcp_timer_2msl, tp)) { 374178354Ssam tp->t_timers->tt_flags &= ~TT_2MSL_RST; 375178354Ssam } 376178354Ssam } else 377178354Ssam tp = tcp_close(tp); 378178354Ssam } 379178354Ssam 380287197Sglebius#ifdef TCPDEBUG 381287197Sglebius if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 382178354Ssam tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 383178354Ssam PRU_SLOWTIMO); 384178354Ssam#endif 385178354Ssam TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 386178354Ssam 387178354Ssam if (tp != NULL) 388178354Ssam INP_WUNLOCK(inp); 389178354Ssam INP_INFO_RUNLOCK(&V_tcbinfo); 390178354Ssam CURVNET_RESTORE(); 391178354Ssam} 392287197Sglebius 393178354Ssamvoid 394178354Ssamtcp_timer_keep(void *xtp) 395287197Sglebius{ 396178354Ssam struct tcpcb *tp = xtp; 397287197Sglebius struct tcptemp *t_template; 398178354Ssam struct inpcb *inp; 399178354Ssam CURVNET_SET(tp->t_vnet); 400178354Ssam#ifdef TCPDEBUG 401178354Ssam int ostate; 402178354Ssam 403178354Ssam ostate = tp->t_state; 404178354Ssam#endif 405178354Ssam INP_INFO_RLOCK(&V_tcbinfo); 406206358Srpaulo inp = tp->t_inpcb; 407178354Ssam KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 408287197Sglebius INP_WLOCK(inp); 409287197Sglebius if (callout_pending(&tp->t_timers->tt_keep) || 410178354Ssam !callout_active(&tp->t_timers->tt_keep)) { 411178354Ssam INP_WUNLOCK(inp); 412178354Ssam INP_INFO_RUNLOCK(&V_tcbinfo); 413178354Ssam CURVNET_RESTORE(); 414178354Ssam return; 415178354Ssam } 416178354Ssam callout_deactivate(&tp->t_timers->tt_keep); 417178354Ssam if ((inp->inp_flags & INP_DROPPED) != 0) { 418178354Ssam INP_WUNLOCK(inp); 419178354Ssam INP_INFO_RUNLOCK(&V_tcbinfo); 420206358Srpaulo CURVNET_RESTORE(); 421178354Ssam return; 422178354Ssam } 423178354Ssam KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 424178354Ssam ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 425156321Sdamien KASSERT((tp->t_timers->tt_flags & TT_KEEP) != 0, 426156321Sdamien ("%s: tp %p keep callout should be running", __func__, tp)); 427156321Sdamien /* 428156321Sdamien * Keep-alive timer went off; send something 429156321Sdamien * or drop connection if idle for too long. 430156321Sdamien */ 431156321Sdamien TCPSTAT_INC(tcps_keeptimeo); 432156321Sdamien if (tp->t_state < TCPS_ESTABLISHED) 433156321Sdamien goto dropit; 434156321Sdamien if ((tcp_always_keepalive || 435156321Sdamien inp->inp_socket->so_options & SO_KEEPALIVE) && 436156321Sdamien tp->t_state <= TCPS_CLOSING) { 437156321Sdamien if (ticks - tp->t_rcvtime >= TP_KEEPIDLE(tp) + TP_MAXIDLE(tp)) 438156321Sdamien goto dropit; 439156321Sdamien /* 440156321Sdamien * Send a packet designed to force a response 441156321Sdamien * if the peer is up and reachable: 442156321Sdamien * either an ACK if the connection is still alive, 443156321Sdamien * or an RST if the peer has closed the connection 444156321Sdamien * due to timeout or reboot. 445156321Sdamien * Using sequence number tp->snd_una-1 446287197Sglebius * causes the transmitted zero-length segment 447178354Ssam * to lie outside the receive window; 448156321Sdamien * by the protocol spec, this requires the 449156321Sdamien * correspondent TCP to respond. 450156321Sdamien */ 451156321Sdamien TCPSTAT_INC(tcps_keepprobe); 452156321Sdamien t_template = tcpip_maketemplate(inp); 453156321Sdamien if (t_template) { 454156321Sdamien tcp_respond(tp, t_template->tt_ipgen, 455156321Sdamien &t_template->tt_t, (struct mbuf *)NULL, 456156321Sdamien tp->rcv_nxt, tp->snd_una - 1, 0); 457156321Sdamien free(t_template, M_TEMP); 458156321Sdamien } 459156321Sdamien if (!callout_reset(&tp->t_timers->tt_keep, TP_KEEPINTVL(tp), 460156321Sdamien tcp_timer_keep, tp)) { 461156321Sdamien tp->t_timers->tt_flags &= ~TT_KEEP_RST; 462156321Sdamien } 463156321Sdamien } else if (!callout_reset(&tp->t_timers->tt_keep, TP_KEEPIDLE(tp), 464156321Sdamien tcp_timer_keep, tp)) { 465156321Sdamien tp->t_timers->tt_flags &= ~TT_KEEP_RST; 466156321Sdamien } 467156321Sdamien 468156321Sdamien#ifdef TCPDEBUG 469156321Sdamien if (inp->inp_socket->so_options & SO_DEBUG) 470156321Sdamien tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 471171535Skevlo PRU_SLOWTIMO); 472171535Skevlo#endif 473171535Skevlo TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 474171535Skevlo INP_WUNLOCK(inp); 475156321Sdamien INP_INFO_RUNLOCK(&V_tcbinfo); 476156321Sdamien CURVNET_RESTORE(); 477156321Sdamien return; 478156321Sdamien 479156321Sdamiendropit: 480156321Sdamien TCPSTAT_INC(tcps_keepdrops); 481156321Sdamien tp = tcp_drop(tp, ETIMEDOUT); 482156321Sdamien 483156321Sdamien#ifdef TCPDEBUG 484156321Sdamien if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 485156321Sdamien tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 486156321Sdamien PRU_SLOWTIMO); 487156321Sdamien#endif 488156321Sdamien TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 489156321Sdamien if (tp != NULL) 490156321Sdamien INP_WUNLOCK(tp->t_inpcb); 491156321Sdamien INP_INFO_RUNLOCK(&V_tcbinfo); 492156321Sdamien CURVNET_RESTORE(); 493156321Sdamien} 494156321Sdamien 495156321Sdamienvoid 496156321Sdamientcp_timer_persist(void *xtp) 497156321Sdamien{ 498156321Sdamien struct tcpcb *tp = xtp; 499156321Sdamien struct inpcb *inp; 500156321Sdamien CURVNET_SET(tp->t_vnet); 501156321Sdamien#ifdef TCPDEBUG 502156321Sdamien int ostate; 503171535Skevlo 504171535Skevlo ostate = tp->t_state; 505171535Skevlo#endif 506156321Sdamien INP_INFO_RLOCK(&V_tcbinfo); 507156321Sdamien inp = tp->t_inpcb; 508156321Sdamien KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 509156321Sdamien INP_WLOCK(inp); 510156321Sdamien if (callout_pending(&tp->t_timers->tt_persist) || 511156321Sdamien !callout_active(&tp->t_timers->tt_persist)) { 512156321Sdamien INP_WUNLOCK(inp); 513156321Sdamien INP_INFO_RUNLOCK(&V_tcbinfo); 514156321Sdamien CURVNET_RESTORE(); 515156321Sdamien return; 516156321Sdamien } 517156321Sdamien callout_deactivate(&tp->t_timers->tt_persist); 518156321Sdamien if ((inp->inp_flags & INP_DROPPED) != 0) { 519156321Sdamien INP_WUNLOCK(inp); 520156321Sdamien INP_INFO_RUNLOCK(&V_tcbinfo); 521156321Sdamien CURVNET_RESTORE(); 522156321Sdamien return; 523156321Sdamien } 524156321Sdamien KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 525156321Sdamien ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 526156321Sdamien KASSERT((tp->t_timers->tt_flags & TT_PERSIST) != 0, 527156321Sdamien ("%s: tp %p persist callout should be running", __func__, tp)); 528156321Sdamien /* 529156321Sdamien * Persistence timer into zero window. 530156321Sdamien * Force a byte to be output, if possible. 531156321Sdamien */ 532156321Sdamien TCPSTAT_INC(tcps_persisttimeo); 533156321Sdamien /* 534156321Sdamien * Hack: if the peer is dead/unreachable, we do not 535156321Sdamien * time out if the window is closed. After a full 536156321Sdamien * backoff, drop the connection if the idle time 537156321Sdamien * (no responses to probes) reaches the maximum 538156321Sdamien * backoff that we would use if retransmitting. 539156321Sdamien */ 540156321Sdamien if (tp->t_rxtshift == TCP_MAXRXTSHIFT && 541156321Sdamien (ticks - tp->t_rcvtime >= tcp_maxpersistidle || 542156321Sdamien ticks - tp->t_rcvtime >= TCP_REXMTVAL(tp) * tcp_totbackoff)) { 543156321Sdamien TCPSTAT_INC(tcps_persistdrop); 544156321Sdamien tp = tcp_drop(tp, ETIMEDOUT); 545156321Sdamien goto out; 546156321Sdamien } 547156321Sdamien /* 548156321Sdamien * If the user has closed the socket then drop a persisting 549156321Sdamien * connection after a much reduced timeout. 550156321Sdamien */ 551156321Sdamien if (tp->t_state > TCPS_CLOSE_WAIT && 552156321Sdamien (ticks - tp->t_rcvtime) >= TCPTV_PERSMAX) { 553156321Sdamien TCPSTAT_INC(tcps_persistdrop); 554156321Sdamien tp = tcp_drop(tp, ETIMEDOUT); 555156321Sdamien goto out; 556156321Sdamien } 557156321Sdamien tcp_setpersist(tp); 558156321Sdamien tp->t_flags |= TF_FORCEDATA; 559156321Sdamien (void) tp->t_fb->tfb_tcp_output(tp); 560156321Sdamien tp->t_flags &= ~TF_FORCEDATA; 561156321Sdamien 562156321Sdamienout: 563156321Sdamien#ifdef TCPDEBUG 564156321Sdamien if (tp != NULL && tp->t_inpcb->inp_socket->so_options & SO_DEBUG) 565156321Sdamien tcp_trace(TA_USER, ostate, tp, NULL, NULL, PRU_SLOWTIMO); 566156321Sdamien#endif 567156321Sdamien TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 568156321Sdamien if (tp != NULL) 569156321Sdamien INP_WUNLOCK(inp); 570156321Sdamien INP_INFO_RUNLOCK(&V_tcbinfo); 571156321Sdamien CURVNET_RESTORE(); 572156321Sdamien} 573156321Sdamien 574156321Sdamienvoid 575156321Sdamientcp_timer_rexmt(void * xtp) 576156321Sdamien{ 577156321Sdamien struct tcpcb *tp = xtp; 578156321Sdamien CURVNET_SET(tp->t_vnet); 579156321Sdamien int rexmt; 580156321Sdamien int headlocked; 581156321Sdamien struct inpcb *inp; 582156321Sdamien#ifdef TCPDEBUG 583156321Sdamien int ostate; 584156321Sdamien 585156321Sdamien ostate = tp->t_state; 586156321Sdamien#endif 587156321Sdamien 588156321Sdamien INP_INFO_RLOCK(&V_tcbinfo); 589156321Sdamien inp = tp->t_inpcb; 590156321Sdamien KASSERT(inp != NULL, ("%s: tp %p tp->t_inpcb == NULL", __func__, tp)); 591156321Sdamien INP_WLOCK(inp); 592156321Sdamien if (callout_pending(&tp->t_timers->tt_rexmt) || 593156321Sdamien !callout_active(&tp->t_timers->tt_rexmt)) { 594156321Sdamien INP_WUNLOCK(inp); 595156321Sdamien INP_INFO_RUNLOCK(&V_tcbinfo); 596156321Sdamien CURVNET_RESTORE(); 597156321Sdamien return; 598156321Sdamien } 599156321Sdamien callout_deactivate(&tp->t_timers->tt_rexmt); 600156321Sdamien if ((inp->inp_flags & INP_DROPPED) != 0) { 601156321Sdamien INP_WUNLOCK(inp); 602156321Sdamien INP_INFO_RUNLOCK(&V_tcbinfo); 603156321Sdamien CURVNET_RESTORE(); 604156321Sdamien return; 605156321Sdamien } 606156321Sdamien KASSERT((tp->t_timers->tt_flags & TT_STOPPED) == 0, 607156321Sdamien ("%s: tp %p tcpcb can't be stopped here", __func__, tp)); 608156321Sdamien KASSERT((tp->t_timers->tt_flags & TT_REXMT) != 0, 609156321Sdamien ("%s: tp %p rexmt callout should be running", __func__, tp)); 610156321Sdamien tcp_free_sackholes(tp); 611156321Sdamien if (tp->t_fb->tfb_tcp_rexmit_tmr) { 612171535Skevlo /* The stack has a timer action too. */ 613171535Skevlo (*tp->t_fb->tfb_tcp_rexmit_tmr)(tp); 614171535Skevlo } 615171535Skevlo /* 616156321Sdamien * Retransmission timer went off. Message has not 617156321Sdamien * been acked within retransmit interval. Back off 618156321Sdamien * to a longer retransmit interval and retransmit one segment. 619156321Sdamien */ 620156321Sdamien if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { 621156321Sdamien tp->t_rxtshift = TCP_MAXRXTSHIFT; 622156321Sdamien TCPSTAT_INC(tcps_timeoutdrop); 623156321Sdamien 624156321Sdamien tp = tcp_drop(tp, tp->t_softerror ? 625156321Sdamien tp->t_softerror : ETIMEDOUT); 626156321Sdamien headlocked = 1; 627156321Sdamien goto out; 628156321Sdamien } 629156321Sdamien INP_INFO_RUNLOCK(&V_tcbinfo); 630156321Sdamien headlocked = 0; 631156321Sdamien if (tp->t_state == TCPS_SYN_SENT) { 632156321Sdamien /* 633156321Sdamien * If the SYN was retransmitted, indicate CWND to be 634156321Sdamien * limited to 1 segment in cc_conn_init(). 635156321Sdamien */ 636156321Sdamien tp->snd_cwnd = 1; 637156321Sdamien } else if (tp->t_rxtshift == 1) { 638156321Sdamien /* 639156321Sdamien * first retransmit; record ssthresh and cwnd so they can 640156321Sdamien * be recovered if this turns out to be a "bad" retransmit. 641156321Sdamien * A retransmit is considered "bad" if an ACK for this 642156321Sdamien * segment is received within RTT/2 interval; the assumption 643156321Sdamien * here is that the ACK was already in flight. See 644156321Sdamien * "On Estimating End-to-End Network Path Properties" by 645156321Sdamien * Allman and Paxson for more details. 646156321Sdamien */ 647171535Skevlo tp->snd_cwnd_prev = tp->snd_cwnd; 648171535Skevlo tp->snd_ssthresh_prev = tp->snd_ssthresh; 649171535Skevlo tp->snd_recover_prev = tp->snd_recover; 650156321Sdamien if (IN_FASTRECOVERY(tp->t_flags)) 651156321Sdamien tp->t_flags |= TF_WASFRECOVERY; 652156321Sdamien else 653156321Sdamien tp->t_flags &= ~TF_WASFRECOVERY; 654156321Sdamien if (IN_CONGRECOVERY(tp->t_flags)) 655156321Sdamien tp->t_flags |= TF_WASCRECOVERY; 656156321Sdamien else 657156321Sdamien tp->t_flags &= ~TF_WASCRECOVERY; 658156321Sdamien tp->t_badrxtwin = ticks + (tp->t_srtt >> (TCP_RTT_SHIFT + 1)); 659156321Sdamien tp->t_flags |= TF_PREVVALID; 660156321Sdamien } else 661156321Sdamien tp->t_flags &= ~TF_PREVVALID; 662156321Sdamien TCPSTAT_INC(tcps_rexmttimeo); 663156321Sdamien if ((tp->t_state == TCPS_SYN_SENT) || 664156321Sdamien (tp->t_state == TCPS_SYN_RECEIVED)) 665243857Sglebius rexmt = TCPTV_RTOBASE * tcp_syn_backoff[tp->t_rxtshift]; 666156321Sdamien else 667156321Sdamien rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; 668156321Sdamien TCPT_RANGESET(tp->t_rxtcur, rexmt, 669156321Sdamien tp->t_rttmin, TCPTV_REXMTMAX); 670156321Sdamien 671156321Sdamien /* 672156321Sdamien * We enter the path for PLMTUD if connection is established or, if 673156321Sdamien * connection is FIN_WAIT_1 status, reason for the last is that if 674156321Sdamien * amount of data we send is very small, we could send it in couple of 675156321Sdamien * packets and process straight to FIN. In that case we won't catch 676156321Sdamien * ESTABLISHED state. 677156321Sdamien */ 678156321Sdamien if (V_tcp_pmtud_blackhole_detect && (((tp->t_state == TCPS_ESTABLISHED)) 679156321Sdamien || (tp->t_state == TCPS_FIN_WAIT_1))) { 680156321Sdamien#ifdef INET6 681156321Sdamien int isipv6; 682156321Sdamien#endif 683156321Sdamien 684156321Sdamien /* 685156321Sdamien * Idea here is that at each stage of mtu probe (usually, 1448 686156321Sdamien * -> 1188 -> 524) should be given 2 chances to recover before 687156321Sdamien * further clamping down. 'tp->t_rxtshift % 2 == 0' should 688156321Sdamien * take care of that. 689156321Sdamien */ 690156321Sdamien if (((tp->t_flags2 & (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) == 691156321Sdamien (TF2_PLPMTU_PMTUD|TF2_PLPMTU_MAXSEGSNT)) && 692156321Sdamien (tp->t_rxtshift >= 2 && tp->t_rxtshift % 2 == 0)) { 693156321Sdamien /* 694156321Sdamien * Enter Path MTU Black-hole Detection mechanism: 695156321Sdamien * - Disable Path MTU Discovery (IP "DF" bit). 696156321Sdamien * - Reduce MTU to lower value than what we 697156321Sdamien * negotiated with peer. 698156321Sdamien */ 699156321Sdamien /* Record that we may have found a black hole. */ 700156321Sdamien tp->t_flags2 |= TF2_PLPMTU_BLACKHOLE; 701156321Sdamien 702156321Sdamien /* Keep track of previous MSS. */ 703156321Sdamien tp->t_pmtud_saved_maxseg = tp->t_maxseg; 704156321Sdamien 705156321Sdamien /* 706156321Sdamien * Reduce the MSS to blackhole value or to the default 707156321Sdamien * in an attempt to retransmit. 708156321Sdamien */ 709156321Sdamien#ifdef INET6 710156321Sdamien isipv6 = (tp->t_inpcb->inp_vflag & INP_IPV6) ? 1 : 0; 711156321Sdamien if (isipv6 && 712156321Sdamien tp->t_maxseg > V_tcp_v6pmtud_blackhole_mss) { 713156321Sdamien /* Use the sysctl tuneable blackhole MSS. */ 714156321Sdamien tp->t_maxseg = V_tcp_v6pmtud_blackhole_mss; 715156321Sdamien V_tcp_pmtud_blackhole_activated++; 716156321Sdamien } else if (isipv6) { 717156321Sdamien /* Use the default MSS. */ 718156321Sdamien tp->t_maxseg = V_tcp_v6mssdflt; 719156321Sdamien /* 720156321Sdamien * Disable Path MTU Discovery when we switch to 721156321Sdamien * minmss. 722156321Sdamien */ 723156321Sdamien tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 724156321Sdamien V_tcp_pmtud_blackhole_activated_min_mss++; 725156321Sdamien } 726156321Sdamien#endif 727156321Sdamien#if defined(INET6) && defined(INET) 728156321Sdamien else 729156321Sdamien#endif 730156321Sdamien#ifdef INET 731156321Sdamien if (tp->t_maxseg > V_tcp_pmtud_blackhole_mss) { 732156321Sdamien /* Use the sysctl tuneable blackhole MSS. */ 733156321Sdamien tp->t_maxseg = V_tcp_pmtud_blackhole_mss; 734156321Sdamien V_tcp_pmtud_blackhole_activated++; 735156321Sdamien } else { 736156321Sdamien /* Use the default MSS. */ 737156321Sdamien tp->t_maxseg = V_tcp_mssdflt; 738156321Sdamien /* 739156321Sdamien * Disable Path MTU Discovery when we switch to 740156321Sdamien * minmss. 741156321Sdamien */ 742156321Sdamien tp->t_flags2 &= ~TF2_PLPMTU_PMTUD; 743156321Sdamien V_tcp_pmtud_blackhole_activated_min_mss++; 744156321Sdamien } 745156321Sdamien#endif 746178354Ssam /* 747156321Sdamien * Reset the slow-start flight size 748178354Ssam * as it may depend on the new MSS. 749178354Ssam */ 750287197Sglebius if (CC_ALGO(tp)->conn_init != NULL) 751178354Ssam CC_ALGO(tp)->conn_init(tp->ccv); 752156321Sdamien } else { 753178354Ssam /* 754178354Ssam * If further retransmissions are still unsuccessful 755156321Sdamien * with a lowered MTU, maybe this isn't a blackhole and 756178354Ssam * we restore the previous MSS and blackhole detection 757178354Ssam * flags. 758178354Ssam * The limit '6' is determined by giving each probe 759178354Ssam * stage (1448, 1188, 524) 2 chances to recover. 760156321Sdamien */ 761178354Ssam if ((tp->t_flags2 & TF2_PLPMTU_BLACKHOLE) && 762156321Sdamien (tp->t_rxtshift > 6)) { 763178354Ssam tp->t_flags2 |= TF2_PLPMTU_PMTUD; 764178354Ssam tp->t_flags2 &= ~TF2_PLPMTU_BLACKHOLE; 765178354Ssam tp->t_maxseg = tp->t_pmtud_saved_maxseg; 766178354Ssam V_tcp_pmtud_blackhole_failed++; 767156321Sdamien /* 768156321Sdamien * Reset the slow-start flight size as it 769156321Sdamien * may depend on the new MSS. 770156321Sdamien */ 771156321Sdamien if (CC_ALGO(tp)->conn_init != NULL) 772156321Sdamien CC_ALGO(tp)->conn_init(tp->ccv); 773178354Ssam } 774195618Srpaulo } 775195618Srpaulo } 776178354Ssam 777178354Ssam /* 778178354Ssam * Disable RFC1323 and SACK if we haven't got any response to 779156321Sdamien * our third SYN to work-around some broken terminal servers 780184345Ssam * (most of which have hopefully been retired) that have bad VJ 781156321Sdamien * header compression code which trashes TCP segments containing 782192468Ssam * unknown-to-them TCP options. 783192468Ssam */ 784178354Ssam if (tcp_rexmit_drop_options && (tp->t_state == TCPS_SYN_SENT) && 785178354Ssam (tp->t_rxtshift == 3)) 786156321Sdamien tp->t_flags &= ~(TF_REQ_SCALE|TF_REQ_TSTMP|TF_SACK_PERMIT); 787156321Sdamien /* 788156321Sdamien * If we backed off this far, our srtt estimate is probably bogus. 789156321Sdamien * Clobber it so we'll take the next rtt measurement as our srtt; 790156321Sdamien * move the current srtt into rttvar to keep the current 791156321Sdamien * retransmit times until then. 792156321Sdamien */ 793156321Sdamien if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { 794156321Sdamien#ifdef INET6 795156321Sdamien if ((tp->t_inpcb->inp_vflag & INP_IPV6) != 0) 796156321Sdamien in6_losing(tp->t_inpcb); 797156321Sdamien else 798156321Sdamien#endif 799156321Sdamien in_losing(tp->t_inpcb); 800156321Sdamien tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); 801156321Sdamien tp->t_srtt = 0; 802156321Sdamien } 803156321Sdamien tp->snd_nxt = tp->snd_una; 804156321Sdamien tp->snd_recover = tp->snd_max; 805156321Sdamien /* 806156321Sdamien * Force a segment to be sent. 807156321Sdamien */ 808156321Sdamien tp->t_flags |= TF_ACKNOW; 809156321Sdamien /* 810156321Sdamien * If timing a segment in this window, stop the timer. 811156321Sdamien */ 812156321Sdamien tp->t_rtttime = 0; 813156321Sdamien 814156321Sdamien cc_cong_signal(tp, NULL, CC_RTO); 815156321Sdamien 816156321Sdamien (void) tp->t_fb->tfb_tcp_output(tp); 817156321Sdamien 818156321Sdamienout: 819156321Sdamien#ifdef TCPDEBUG 820156321Sdamien if (tp != NULL && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) 821156321Sdamien tcp_trace(TA_USER, ostate, tp, (void *)0, (struct tcphdr *)0, 822156321Sdamien PRU_SLOWTIMO); 823156321Sdamien#endif 824156321Sdamien TCP_PROBE2(debug__user, tp, PRU_SLOWTIMO); 825156321Sdamien if (tp != NULL) 826156321Sdamien INP_WUNLOCK(inp); 827156321Sdamien if (headlocked) 828156321Sdamien INP_INFO_RUNLOCK(&V_tcbinfo); 829156321Sdamien CURVNET_RESTORE(); 830156321Sdamien} 831156321Sdamien 832156321Sdamienvoid 833156321Sdamientcp_timer_activate(struct tcpcb *tp, uint32_t timer_type, u_int delta) 834156321Sdamien{ 835156321Sdamien struct callout *t_callout; 836156321Sdamien timeout_t *f_callout; 837156321Sdamien struct inpcb *inp = tp->t_inpcb; 838156321Sdamien int cpu = inp_to_cpuid(inp); 839156321Sdamien uint32_t f_reset; 840156321Sdamien 841156321Sdamien#ifdef TCP_OFFLOAD 842156321Sdamien if (tp->t_flags & TF_TOE) 843156321Sdamien return; 844156321Sdamien#endif 845156321Sdamien 846156321Sdamien if (tp->t_timers->tt_flags & TT_STOPPED) 847156321Sdamien return; 848156321Sdamien 849156321Sdamien switch (timer_type) { 850156321Sdamien case TT_DELACK: 851156321Sdamien t_callout = &tp->t_timers->tt_delack; 852287197Sglebius f_callout = tcp_timer_delack; 853206358Srpaulo f_reset = TT_DELACK_RST; 854156321Sdamien break; 855156321Sdamien case TT_REXMT: 856170530Ssam t_callout = &tp->t_timers->tt_rexmt; 857170530Ssam f_callout = tcp_timer_rexmt; 858170530Ssam f_reset = TT_REXMT_RST; 859156321Sdamien break; 860156321Sdamien case TT_PERSIST: 861156321Sdamien t_callout = &tp->t_timers->tt_persist; 862156321Sdamien f_callout = tcp_timer_persist; 863156321Sdamien f_reset = TT_PERSIST_RST; 864156321Sdamien break; 865156321Sdamien case TT_KEEP: 866156321Sdamien t_callout = &tp->t_timers->tt_keep; 867156321Sdamien f_callout = tcp_timer_keep; 868156321Sdamien f_reset = TT_KEEP_RST; 869170530Ssam break; 870170530Ssam case TT_2MSL: 871170530Ssam t_callout = &tp->t_timers->tt_2msl; 872170530Ssam f_callout = tcp_timer_2msl; 873156321Sdamien f_reset = TT_2MSL_RST; 874159301Sfjoe break; 875170530Ssam default: 876159301Sfjoe if (tp->t_fb->tfb_tcp_timer_activate) { 877206371Srpaulo tp->t_fb->tfb_tcp_timer_activate(tp, timer_type, delta); 878206371Srpaulo return; 879159301Sfjoe } 880156321Sdamien panic("tp %p bad timer_type %#x", tp, timer_type); 881156321Sdamien } 882156321Sdamien if (delta == 0) { 883156321Sdamien if ((tp->t_timers->tt_flags & timer_type) && 884178354Ssam (callout_stop(t_callout) > 0) && 885178354Ssam (tp->t_timers->tt_flags & f_reset)) { 886178354Ssam tp->t_timers->tt_flags &= ~(timer_type | f_reset); 887206358Srpaulo } 888206358Srpaulo } else { 889206358Srpaulo if ((tp->t_timers->tt_flags & timer_type) == 0) { 890287197Sglebius tp->t_timers->tt_flags |= (timer_type | f_reset); 891156321Sdamien callout_reset_on(t_callout, delta, f_callout, tp, cpu); 892156321Sdamien } else { 893156321Sdamien /* Reset already running callout on the same CPU. */ 894178354Ssam if (!callout_reset(t_callout, delta, f_callout, tp)) { 895178354Ssam /* 896178354Ssam * Callout not cancelled, consider it as not 897178354Ssam * properly restarted. */ 898178354Ssam tp->t_timers->tt_flags &= ~f_reset; 899206358Srpaulo } 900206358Srpaulo } 901206358Srpaulo } 902287197Sglebius} 903156321Sdamien 904156321Sdamienint 905156321Sdamientcp_timer_active(struct tcpcb *tp, uint32_t timer_type) 906156321Sdamien{ 907156321Sdamien struct callout *t_callout; 908156321Sdamien 909287197Sglebius switch (timer_type) { 910156321Sdamien case TT_DELACK: 911156321Sdamien t_callout = &tp->t_timers->tt_delack; 912178354Ssam break; 913156321Sdamien case TT_REXMT: 914156321Sdamien t_callout = &tp->t_timers->tt_rexmt; 915156321Sdamien break; 916156321Sdamien case TT_PERSIST: 917170530Ssam t_callout = &tp->t_timers->tt_persist; 918287197Sglebius break; 919156321Sdamien case TT_KEEP: 920156321Sdamien t_callout = &tp->t_timers->tt_keep; 921156321Sdamien break; 922178354Ssam case TT_2MSL: 923287197Sglebius t_callout = &tp->t_timers->tt_2msl; 924156321Sdamien break; 925156321Sdamien default: 926156321Sdamien if (tp->t_fb->tfb_tcp_timer_active) { 927156321Sdamien return(tp->t_fb->tfb_tcp_timer_active(tp, timer_type)); 928156321Sdamien } 929156321Sdamien panic("tp %p bad timer_type %#x", tp, timer_type); 930156321Sdamien } 931156321Sdamien return callout_active(t_callout); 932156321Sdamien} 933156321Sdamien 934156321Sdamienvoid 935156321Sdamientcp_timer_stop(struct tcpcb *tp, uint32_t timer_type) 936156321Sdamien{ 937156321Sdamien struct callout *t_callout; 938156321Sdamien uint32_t f_reset; 939156321Sdamien 940156321Sdamien tp->t_timers->tt_flags |= TT_STOPPED; 941156321Sdamien 942156321Sdamien switch (timer_type) { 943156321Sdamien case TT_DELACK: 944156321Sdamien t_callout = &tp->t_timers->tt_delack; 945156321Sdamien f_reset = TT_DELACK_RST; 946156321Sdamien break; 947156321Sdamien case TT_REXMT: 948156321Sdamien t_callout = &tp->t_timers->tt_rexmt; 949178354Ssam f_reset = TT_REXMT_RST; 950156321Sdamien break; 951156321Sdamien case TT_PERSIST: 952156321Sdamien t_callout = &tp->t_timers->tt_persist; 953156321Sdamien f_reset = TT_PERSIST_RST; 954156321Sdamien break; 955156321Sdamien case TT_KEEP: 956156321Sdamien t_callout = &tp->t_timers->tt_keep; 957156321Sdamien f_reset = TT_KEEP_RST; 958156321Sdamien break; 959156321Sdamien case TT_2MSL: 960156321Sdamien t_callout = &tp->t_timers->tt_2msl; 961287197Sglebius f_reset = TT_2MSL_RST; 962156321Sdamien break; 963156321Sdamien default: 964156321Sdamien if (tp->t_fb->tfb_tcp_timer_stop) { 965156321Sdamien /* 966156321Sdamien * XXXrrs we need to look at this with the 967156321Sdamien * stop case below (flags). 968156321Sdamien */ 969156321Sdamien tp->t_fb->tfb_tcp_timer_stop(tp, timer_type); 970156321Sdamien return; 971156321Sdamien } 972156321Sdamien panic("tp %p bad timer_type %#x", tp, timer_type); 973156321Sdamien } 974192468Ssam 975170530Ssam if (tp->t_timers->tt_flags & timer_type) { 976156321Sdamien if (callout_async_drain(t_callout, tcp_timer_discard) == 0) { 977156321Sdamien /* 978156321Sdamien * Can't stop the callout, defer tcpcb actual deletion 979156321Sdamien * to the last one. We do this using the async drain 980156321Sdamien * function and incrementing the count in 981156321Sdamien */ 982156321Sdamien tp->t_timers->tt_draincnt++; 983156321Sdamien } 984156321Sdamien } 985156321Sdamien} 986156321Sdamien 987156321Sdamien#define ticks_to_msecs(t) (1000*(t) / hz) 988178354Ssam 989178354Ssamvoid 990287197Sglebiustcp_timer_to_xtimer(struct tcpcb *tp, struct tcp_timer *timer, 991156321Sdamien struct xtcp_timer *xtimer) 992156321Sdamien{ 993156321Sdamien sbintime_t now; 994156321Sdamien 995287197Sglebius bzero(xtimer, sizeof(*xtimer)); 996156321Sdamien if (timer == NULL) 997156321Sdamien return; 998156321Sdamien now = getsbinuptime(); 999156321Sdamien if (callout_active(&timer->tt_delack)) 1000156321Sdamien xtimer->tt_delack = (timer->tt_delack.c_time - now) / SBT_1MS; 1001156321Sdamien if (callout_active(&timer->tt_rexmt)) 1002156321Sdamien xtimer->tt_rexmt = (timer->tt_rexmt.c_time - now) / SBT_1MS; 1003156321Sdamien if (callout_active(&timer->tt_persist)) 1004156321Sdamien xtimer->tt_persist = (timer->tt_persist.c_time - now) / SBT_1MS; 1005156321Sdamien if (callout_active(&timer->tt_keep)) 1006243857Sglebius xtimer->tt_keep = (timer->tt_keep.c_time - now) / SBT_1MS; 1007156321Sdamien if (callout_active(&timer->tt_2msl)) 1008287197Sglebius xtimer->tt_2msl = (timer->tt_2msl.c_time - now) / SBT_1MS; 1009156321Sdamien xtimer->t_rcvtime = ticks_to_msecs(ticks - tp->t_rcvtime); 1010156321Sdamien} 1011156321Sdamien