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