tcp_timer.c revision 1.93
1/*	$NetBSD: tcp_timer.c,v 1.93 2018/01/19 07:53:01 ozaki-r Exp $	*/
2
3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*-
33 * Copyright (c) 1997, 1998, 2001, 2005 The NetBSD Foundation, Inc.
34 * All rights reserved.
35 *
36 * This code is derived from software contributed to The NetBSD Foundation
37 * by Jason R. Thorpe and Kevin M. Lahey of the Numerical Aerospace Simulation
38 * Facility, NASA Ames Research Center.
39 * This code is derived from software contributed to The NetBSD Foundation
40 * by Charles M. Hannum.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 *    notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 *    notice, this list of conditions and the following disclaimer in the
49 *    documentation and/or other materials provided with the distribution.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
52 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
53 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
54 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
55 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
56 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
57 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
58 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
59 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
60 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
61 * POSSIBILITY OF SUCH DAMAGE.
62 */
63
64/*
65 * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995
66 *	The Regents of the University of California.  All rights reserved.
67 *
68 * Redistribution and use in source and binary forms, with or without
69 * modification, are permitted provided that the following conditions
70 * are met:
71 * 1. Redistributions of source code must retain the above copyright
72 *    notice, this list of conditions and the following disclaimer.
73 * 2. Redistributions in binary form must reproduce the above copyright
74 *    notice, this list of conditions and the following disclaimer in the
75 *    documentation and/or other materials provided with the distribution.
76 * 3. Neither the name of the University nor the names of its contributors
77 *    may be used to endorse or promote products derived from this software
78 *    without specific prior written permission.
79 *
80 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
81 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
82 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
83 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
84 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
85 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
86 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
87 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
88 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
89 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
90 * SUCH DAMAGE.
91 *
92 *	@(#)tcp_timer.c	8.2 (Berkeley) 5/24/95
93 */
94
95#include <sys/cdefs.h>
96__KERNEL_RCSID(0, "$NetBSD: tcp_timer.c,v 1.93 2018/01/19 07:53:01 ozaki-r Exp $");
97
98#ifdef _KERNEL_OPT
99#include "opt_inet.h"
100#include "opt_tcp_debug.h"
101#include "opt_net_mpsafe.h"
102#endif
103
104#include <sys/param.h>
105#include <sys/systm.h>
106#include <sys/mbuf.h>
107#include <sys/socket.h>
108#include <sys/socketvar.h>
109#include <sys/protosw.h>
110#include <sys/errno.h>
111#include <sys/kernel.h>
112#include <sys/callout.h>
113#include <sys/workqueue.h>
114
115#include <net/if.h>
116
117#include <netinet/in.h>
118#include <netinet/in_systm.h>
119#include <netinet/ip.h>
120#include <netinet/in_pcb.h>
121#include <netinet/ip_var.h>
122#include <netinet/ip_icmp.h>
123
124#ifdef INET6
125#ifndef INET
126#include <netinet/in.h>
127#endif
128#include <netinet/ip6.h>
129#include <netinet6/in6_pcb.h>
130#endif
131
132#include <netinet/tcp.h>
133#include <netinet/tcp_fsm.h>
134#include <netinet/tcp_seq.h>
135#include <netinet/tcp_timer.h>
136#include <netinet/tcp_var.h>
137#include <netinet/tcp_private.h>
138#include <netinet/tcp_congctl.h>
139#include <netinet/tcpip.h>
140#ifdef TCP_DEBUG
141#include <netinet/tcp_debug.h>
142#endif
143
144/*
145 * Various tunable timer parameters.  These are initialized in tcp_init(),
146 * unless they are patched.
147 */
148u_int	tcp_keepinit = 0;
149u_int	tcp_keepidle = 0;
150u_int	tcp_keepintvl = 0;
151u_int	tcp_keepcnt = 0;		/* max idle probes */
152
153int	tcp_maxpersistidle = 0;		/* max idle time in persist */
154
155static callout_t	tcp_slowtimo_ch;
156#ifdef NET_MPSAFE
157static struct workqueue	*tcp_slowtimo_wq;
158static struct work	tcp_slowtimo_wk;
159#endif
160
161static void tcp_slowtimo_work(struct work *, void *);
162static void tcp_slowtimo(void *);
163
164/*
165 * Time to delay the ACK.  This is initialized in tcp_init(), unless
166 * its patched.
167 */
168int	tcp_delack_ticks = 0;
169
170void	tcp_timer_rexmt(void *);
171void	tcp_timer_persist(void *);
172void	tcp_timer_keep(void *);
173void	tcp_timer_2msl(void *);
174
175const tcp_timer_func_t tcp_timer_funcs[TCPT_NTIMERS] = {
176	tcp_timer_rexmt,
177	tcp_timer_persist,
178	tcp_timer_keep,
179	tcp_timer_2msl,
180};
181
182/*
183 * Timer state initialization, called from tcp_init().
184 */
185void
186tcp_timer_init(void)
187{
188
189	if (tcp_keepinit == 0)
190		tcp_keepinit = TCPTV_KEEP_INIT;
191
192	if (tcp_keepidle == 0)
193		tcp_keepidle = TCPTV_KEEP_IDLE;
194
195	if (tcp_keepintvl == 0)
196		tcp_keepintvl = TCPTV_KEEPINTVL;
197
198	if (tcp_keepcnt == 0)
199		tcp_keepcnt = TCPTV_KEEPCNT;
200
201	if (tcp_maxpersistidle == 0)
202		tcp_maxpersistidle = TCPTV_KEEP_IDLE;
203
204	if (tcp_delack_ticks == 0)
205		tcp_delack_ticks = TCP_DELACK_TICKS;
206}
207
208void
209tcp_slowtimo_init(void)
210{
211#ifdef NET_MPSAFE
212	int error;
213
214	error = workqueue_create(&tcp_slowtimo_wq, "tcp_slowtimo",
215	    tcp_slowtimo_work, NULL, PRI_SOFTNET, IPL_SOFTNET, WQ_MPSAFE);
216	if (error != 0)
217		panic("%s: workqueue_create failed (%d)\n", __func__, error);
218#endif
219	callout_init(&tcp_slowtimo_ch, CALLOUT_MPSAFE);
220	callout_reset(&tcp_slowtimo_ch, 1, tcp_slowtimo, NULL);
221}
222
223/*
224 * Callout to process delayed ACKs for a TCPCB.
225 */
226void
227tcp_delack(void *arg)
228{
229	struct tcpcb *tp = arg;
230
231	/*
232	 * If tcp_output() wasn't able to transmit the ACK
233	 * for whatever reason, it will restart the delayed
234	 * ACK callout.
235	 */
236
237	mutex_enter(softnet_lock);
238	if ((tp->t_flags & (TF_DEAD | TF_DELACK)) != TF_DELACK) {
239		mutex_exit(softnet_lock);
240		return;
241	}
242	if (!callout_expired(&tp->t_delack_ch)) {
243		mutex_exit(softnet_lock);
244		return;
245	}
246
247	tp->t_flags |= TF_ACKNOW;
248	KERNEL_LOCK(1, NULL);
249	(void) tcp_output(tp);
250	KERNEL_UNLOCK_ONE(NULL);
251	mutex_exit(softnet_lock);
252}
253
254/*
255 * Tcp protocol timeout routine called every 500 ms.
256 * Updates the timers in all active tcb's and
257 * causes finite state machine actions if timers expire.
258 */
259static void
260tcp_slowtimo_work(struct work *wk, void *arg)
261{
262
263	mutex_enter(softnet_lock);
264	tcp_iss_seq += TCP_ISSINCR;			/* increment iss */
265	tcp_now++;					/* for timestamps */
266	mutex_exit(softnet_lock);
267
268	callout_schedule(&tcp_slowtimo_ch, hz / PR_SLOWHZ);
269}
270
271static void
272tcp_slowtimo(void *arg)
273{
274
275#ifdef NET_MPSAFE
276	workqueue_enqueue(tcp_slowtimo_wq, &tcp_slowtimo_wk, NULL);
277#else
278	tcp_slowtimo_work(NULL, NULL);
279#endif
280}
281
282/*
283 * Cancel all timers for TCP tp.
284 */
285void
286tcp_canceltimers(struct tcpcb *tp)
287{
288	int i;
289
290	for (i = 0; i < TCPT_NTIMERS; i++)
291		TCP_TIMER_DISARM(tp, i);
292}
293
294const int	tcp_backoff[TCP_MAXRXTSHIFT + 1] =
295    { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 };
296
297const int	tcp_totbackoff = 511;	/* sum of tcp_backoff[] */
298
299/*
300 * TCP timer processing.
301 */
302
303void
304tcp_timer_rexmt(void *arg)
305{
306	struct tcpcb *tp = arg;
307	uint32_t rto;
308#ifdef TCP_DEBUG
309	struct socket *so = NULL;
310	short ostate;
311#endif
312
313	mutex_enter(softnet_lock);
314	if ((tp->t_flags & TF_DEAD) != 0) {
315		mutex_exit(softnet_lock);
316		return;
317	}
318	if (!callout_expired(&tp->t_timer[TCPT_REXMT])) {
319		mutex_exit(softnet_lock);
320		return;
321	}
322
323	KERNEL_LOCK(1, NULL);
324	if ((tp->t_flags & TF_PMTUD_PEND) && tp->t_inpcb &&
325	    SEQ_GEQ(tp->t_pmtud_th_seq, tp->snd_una) &&
326	    SEQ_LT(tp->t_pmtud_th_seq, (int)(tp->snd_una + tp->t_ourmss))) {
327		extern struct sockaddr_in icmpsrc;
328		struct icmp icmp;
329
330		tp->t_flags &= ~TF_PMTUD_PEND;
331
332		/* XXX create fake icmp message with relevant entries */
333		icmp.icmp_nextmtu = tp->t_pmtud_nextmtu;
334		icmp.icmp_ip.ip_len = tp->t_pmtud_ip_len;
335		icmp.icmp_ip.ip_hl = tp->t_pmtud_ip_hl;
336		icmpsrc.sin_addr = tp->t_inpcb->inp_faddr;
337		icmp_mtudisc(&icmp, icmpsrc.sin_addr);
338
339		/*
340		 * Notify all connections to the same peer about
341		 * new mss and trigger retransmit.
342		 */
343		in_pcbnotifyall(&tcbtable, icmpsrc.sin_addr, EMSGSIZE,
344		    tcp_mtudisc);
345		KERNEL_UNLOCK_ONE(NULL);
346		mutex_exit(softnet_lock);
347 		return;
348 	}
349#ifdef TCP_DEBUG
350#ifdef INET
351	if (tp->t_inpcb)
352		so = tp->t_inpcb->inp_socket;
353#endif
354#ifdef INET6
355	if (tp->t_in6pcb)
356		so = tp->t_in6pcb->in6p_socket;
357#endif
358	ostate = tp->t_state;
359#endif /* TCP_DEBUG */
360
361	/*
362	 * Clear the SACK scoreboard, reset FACK estimate.
363	 */
364	tcp_free_sackholes(tp);
365	tp->snd_fack = tp->snd_una;
366
367	/*
368	 * Retransmission timer went off.  Message has not
369	 * been acked within retransmit interval.  Back off
370	 * to a longer retransmit interval and retransmit one segment.
371	 */
372
373	if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) {
374		tp->t_rxtshift = TCP_MAXRXTSHIFT;
375		TCP_STATINC(TCP_STAT_TIMEOUTDROP);
376		tp = tcp_drop(tp, tp->t_softerror ?
377		    tp->t_softerror : ETIMEDOUT);
378		goto out;
379	}
380	TCP_STATINC(TCP_STAT_REXMTTIMEO);
381	rto = TCP_REXMTVAL(tp);
382	if (rto < tp->t_rttmin)
383		rto = tp->t_rttmin;
384	TCPT_RANGESET(tp->t_rxtcur, rto * tcp_backoff[tp->t_rxtshift],
385	    tp->t_rttmin, TCPTV_REXMTMAX);
386	TCP_TIMER_ARM(tp, TCPT_REXMT, tp->t_rxtcur);
387
388	/*
389	 * If we are losing and we are trying path MTU discovery,
390	 * try turning it off.  This will avoid black holes in
391	 * the network which suppress or fail to send "packet
392	 * too big" ICMP messages.  We should ideally do
393	 * lots more sophisticated searching to find the right
394	 * value here...
395	 */
396	if (tp->t_mtudisc && tp->t_rxtshift > TCP_MAXRXTSHIFT / 6) {
397		TCP_STATINC(TCP_STAT_PMTUBLACKHOLE);
398
399#ifdef INET
400		/* try turning PMTUD off */
401		if (tp->t_inpcb)
402			tp->t_mtudisc = 0;
403#endif
404#ifdef INET6
405		/* try using IPv6 minimum MTU */
406		if (tp->t_in6pcb)
407			tp->t_mtudisc = 0;
408#endif
409
410		/* XXX: more sophisticated Black hole recovery code? */
411	}
412
413	/*
414	 * If losing, let the lower level know and try for
415	 * a better route.  Also, if we backed off this far,
416	 * our srtt estimate is probably bogus.  Clobber it
417	 * so we'll take the next rtt measurement as our srtt;
418	 * move the current srtt into rttvar to keep the current
419	 * retransmit times until then.
420	 */
421	if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) {
422#ifdef INET
423		if (tp->t_inpcb)
424			in_losing(tp->t_inpcb);
425#endif
426#ifdef INET6
427		if (tp->t_in6pcb)
428			in6_losing(tp->t_in6pcb);
429#endif
430		/*
431		 * This operation is not described in RFC2988.  The
432		 * point is to keep srtt+4*rttvar constant, so we
433		 * should shift right 2 bits to divide by 4, and then
434		 * shift right one bit because the storage
435		 * representation of rttvar is 1/16s vs 1/32s for
436		 * srtt.
437		 */
438		tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT);
439		tp->t_srtt = 0;
440	}
441	tp->snd_nxt = tp->snd_una;
442	tp->snd_high = tp->snd_max;
443	/*
444	 * If timing a segment in this window, stop the timer.
445	 */
446	tp->t_rtttime = 0;
447	/*
448	 * Remember if we are retransmitting a SYN, because if
449	 * we do, set the initial congestion window must be set
450	 * to 1 segment.
451	 */
452	if (tp->t_state == TCPS_SYN_SENT)
453		tp->t_flags |= TF_SYN_REXMT;
454
455	/*
456	 * Adjust congestion control parameters.
457	 */
458	tp->t_congctl->slow_retransmit(tp);
459
460	(void) tcp_output(tp);
461
462 out:
463#ifdef TCP_DEBUG
464	if (tp && so->so_options & SO_DEBUG)
465		tcp_trace(TA_USER, ostate, tp, NULL,
466		    PRU_SLOWTIMO | (TCPT_REXMT << 8));
467#endif
468	KERNEL_UNLOCK_ONE(NULL);
469	mutex_exit(softnet_lock);
470}
471
472void
473tcp_timer_persist(void *arg)
474{
475	struct tcpcb *tp = arg;
476	uint32_t rto;
477#ifdef TCP_DEBUG
478	struct socket *so = NULL;
479	short ostate;
480#endif
481
482	mutex_enter(softnet_lock);
483	if ((tp->t_flags & TF_DEAD) != 0) {
484		mutex_exit(softnet_lock);
485		return;
486	}
487	if (!callout_expired(&tp->t_timer[TCPT_PERSIST])) {
488		mutex_exit(softnet_lock);
489		return;
490	}
491
492	KERNEL_LOCK(1, NULL);
493#ifdef TCP_DEBUG
494#ifdef INET
495	if (tp->t_inpcb)
496		so = tp->t_inpcb->inp_socket;
497#endif
498#ifdef INET6
499	if (tp->t_in6pcb)
500		so = tp->t_in6pcb->in6p_socket;
501#endif
502
503	ostate = tp->t_state;
504#endif /* TCP_DEBUG */
505
506	/*
507	 * Persistance timer into zero window.
508	 * Force a byte to be output, if possible.
509	 */
510
511	/*
512	 * Hack: if the peer is dead/unreachable, we do not
513	 * time out if the window is closed.  After a full
514	 * backoff, drop the connection if the idle time
515	 * (no responses to probes) reaches the maximum
516	 * backoff that we would use if retransmitting.
517	 */
518	rto = TCP_REXMTVAL(tp);
519	if (rto < tp->t_rttmin)
520		rto = tp->t_rttmin;
521	if (tp->t_rxtshift == TCP_MAXRXTSHIFT &&
522	    ((tcp_now - tp->t_rcvtime) >= tcp_maxpersistidle ||
523	    (tcp_now - tp->t_rcvtime) >= rto * tcp_totbackoff)) {
524		TCP_STATINC(TCP_STAT_PERSISTDROPS);
525		tp = tcp_drop(tp, ETIMEDOUT);
526		goto out;
527	}
528	TCP_STATINC(TCP_STAT_PERSISTTIMEO);
529	tcp_setpersist(tp);
530	tp->t_force = 1;
531	(void) tcp_output(tp);
532	tp->t_force = 0;
533
534 out:
535#ifdef TCP_DEBUG
536	if (tp && so->so_options & SO_DEBUG)
537		tcp_trace(TA_USER, ostate, tp, NULL,
538		    PRU_SLOWTIMO | (TCPT_PERSIST << 8));
539#endif
540	KERNEL_UNLOCK_ONE(NULL);
541	mutex_exit(softnet_lock);
542}
543
544void
545tcp_timer_keep(void *arg)
546{
547	struct tcpcb *tp = arg;
548	struct socket *so = NULL;	/* Quell compiler warning */
549#ifdef TCP_DEBUG
550	short ostate;
551#endif
552
553	mutex_enter(softnet_lock);
554	if ((tp->t_flags & TF_DEAD) != 0) {
555		mutex_exit(softnet_lock);
556		return;
557	}
558	if (!callout_expired(&tp->t_timer[TCPT_KEEP])) {
559		mutex_exit(softnet_lock);
560		return;
561	}
562
563	KERNEL_LOCK(1, NULL);
564
565#ifdef TCP_DEBUG
566	ostate = tp->t_state;
567#endif /* TCP_DEBUG */
568
569	/*
570	 * Keep-alive timer went off; send something
571	 * or drop connection if idle for too long.
572	 */
573
574	TCP_STATINC(TCP_STAT_KEEPTIMEO);
575	if (TCPS_HAVEESTABLISHED(tp->t_state) == 0)
576		goto dropit;
577#ifdef INET
578	if (tp->t_inpcb)
579		so = tp->t_inpcb->inp_socket;
580#endif
581#ifdef INET6
582	if (tp->t_in6pcb)
583		so = tp->t_in6pcb->in6p_socket;
584#endif
585	KASSERT(so != NULL);
586	if (so->so_options & SO_KEEPALIVE &&
587	    tp->t_state <= TCPS_CLOSE_WAIT) {
588	    	if ((tp->t_maxidle > 0) &&
589		    ((tcp_now - tp->t_rcvtime) >=
590		     tp->t_keepidle + tp->t_maxidle))
591			goto dropit;
592		/*
593		 * Send a packet designed to force a response
594		 * if the peer is up and reachable:
595		 * either an ACK if the connection is still alive,
596		 * or an RST if the peer has closed the connection
597		 * due to timeout or reboot.
598		 * Using sequence number tp->snd_una-1
599		 * causes the transmitted zero-length segment
600		 * to lie outside the receive window;
601		 * by the protocol spec, this requires the
602		 * correspondent TCP to respond.
603		 */
604		TCP_STATINC(TCP_STAT_KEEPPROBE);
605
606		(void)tcp_respond(tp, tp->t_template,
607		    NULL, NULL, tp->rcv_nxt,
608		    tp->snd_una - 1, 0);
609
610		TCP_TIMER_ARM(tp, TCPT_KEEP, tp->t_keepintvl);
611	} else
612		TCP_TIMER_ARM(tp, TCPT_KEEP, tp->t_keepidle);
613
614#ifdef TCP_DEBUG
615	if (tp && so->so_options & SO_DEBUG)
616		tcp_trace(TA_USER, ostate, tp, NULL,
617		    PRU_SLOWTIMO | (TCPT_KEEP << 8));
618#endif
619	KERNEL_UNLOCK_ONE(NULL);
620	mutex_exit(softnet_lock);
621	return;
622
623 dropit:
624	TCP_STATINC(TCP_STAT_KEEPDROPS);
625	(void) tcp_drop(tp, ETIMEDOUT);
626	KERNEL_UNLOCK_ONE(NULL);
627	mutex_exit(softnet_lock);
628}
629
630void
631tcp_timer_2msl(void *arg)
632{
633	struct tcpcb *tp = arg;
634#ifdef TCP_DEBUG
635	struct socket *so = NULL;
636	short ostate;
637#endif
638
639	mutex_enter(softnet_lock);
640	if ((tp->t_flags & TF_DEAD) != 0) {
641		mutex_exit(softnet_lock);
642		return;
643	}
644	if (!callout_expired(&tp->t_timer[TCPT_2MSL])) {
645		mutex_exit(softnet_lock);
646		return;
647	}
648
649	/*
650	 * 2 MSL timeout went off, clear the SACK scoreboard, reset
651	 * the FACK estimate.
652	 */
653	KERNEL_LOCK(1, NULL);
654	tcp_free_sackholes(tp);
655	tp->snd_fack = tp->snd_una;
656
657#ifdef TCP_DEBUG
658#ifdef INET
659	if (tp->t_inpcb)
660		so = tp->t_inpcb->inp_socket;
661#endif
662#ifdef INET6
663	if (tp->t_in6pcb)
664		so = tp->t_in6pcb->in6p_socket;
665#endif
666
667	ostate = tp->t_state;
668#endif /* TCP_DEBUG */
669
670	/*
671	 * 2 MSL timeout in shutdown went off.  If we're closed but
672	 * still waiting for peer to close and connection has been idle
673	 * too long, or if 2MSL time is up from TIME_WAIT, delete connection
674	 * control block.  Otherwise, check again in a bit.
675	 */
676	if (tp->t_state != TCPS_TIME_WAIT &&
677	    ((tp->t_maxidle == 0) ||
678	    ((tcp_now - tp->t_rcvtime) <= tp->t_maxidle)))
679	    TCP_TIMER_ARM(tp, TCPT_2MSL, tp->t_keepintvl);
680	else
681		tp = tcp_close(tp);
682
683#ifdef TCP_DEBUG
684	if (tp && so->so_options & SO_DEBUG)
685		tcp_trace(TA_USER, ostate, tp, NULL,
686		    PRU_SLOWTIMO | (TCPT_2MSL << 8));
687#endif
688	KERNEL_UNLOCK_ONE(NULL);
689	mutex_exit(softnet_lock);
690}
691