Index: sys/netinet/tcp_input.c =================================================================== --- sys/netinet/tcp_input.c +++ sys/netinet/tcp_input.c @@ -2864,10 +2864,11 @@ */ if (so->so_rcv.sb_state & SBS_CANTRCVMORE) { soisdisconnected(so); - tcp_timer_activate(tp, TT_2MSL, - (tcp_fast_finwait2_recycle ? - tcp_finwait2_timeout : - TP_MAXIDLE(tp))); + if (!tcp_timer_active(tp, TT_2MSL)) + tcp_timer_activate(tp, TT_2MSL, + (tcp_fast_finwait2_recycle ? + tcp_finwait2_timeout : + TP_MAXIDLE(tp))); } tcp_state_change(tp, TCPS_FIN_WAIT_2); } Index: sys/netinet/tcp_timer.h =================================================================== --- sys/netinet/tcp_timer.h +++ sys/netinet/tcp_timer.h @@ -204,7 +204,9 @@ extern int tcp_rexmit_drop_options; extern int tcp_always_keepalive; +extern int tcp_close_timeout; extern int tcp_finwait2_timeout; +extern int tcp_fast_close_recycle; extern int tcp_fast_finwait2_recycle; VNET_DECLARE(int, tcp_pmtud_blackhole_detect); Index: sys/netinet/tcp_timer.c =================================================================== --- sys/netinet/tcp_timer.c +++ sys/netinet/tcp_timer.c @@ -129,10 +129,19 @@ &tcp_fast_finwait2_recycle, 0, "Recycle closed FIN_WAIT_2 connections faster"); +int tcp_fast_close_recycle = 0; +SYSCTL_INT(_net_inet_tcp, OID_AUTO, fast_close_recycle, CTLFLAG_RW, + &tcp_fast_close_recycle, 0, + "Recycle closed connections faster"); + int tcp_finwait2_timeout; SYSCTL_PROC(_net_inet_tcp, OID_AUTO, finwait2_timeout, CTLTYPE_INT|CTLFLAG_RW, &tcp_finwait2_timeout, 0, sysctl_msec_to_ticks, "I", "FIN-WAIT2 timeout"); +int tcp_close_timeout; +SYSCTL_PROC(_net_inet_tcp, OID_AUTO, close_timeout, CTLTYPE_INT|CTLFLAG_RW, + &tcp_close_timeout, 0, sysctl_msec_to_ticks, "I", "Close timeout"); + int tcp_keepcnt = TCPTV_KEEPCNT; SYSCTL_INT(_net_inet_tcp, OID_AUTO, keepcnt, CTLFLAG_RW, &tcp_keepcnt, 0, "Number of keepalive probes to send"); @@ -329,7 +338,8 @@ CURVNET_RESTORE(); return; } - if (tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2 && + if (((tcp_fast_finwait2_recycle && tp->t_state == TCPS_FIN_WAIT_2) || + tcp_fast_close_recycle) && tp->t_inpcb && tp->t_inpcb->inp_socket && (tp->t_inpcb->inp_socket->so_rcv.sb_state & SBS_CANTRCVMORE)) { TCPSTAT_INC(tcps_finwait2_drops); Index: sys/netinet/tcp_usrreq.c =================================================================== --- sys/netinet/tcp_usrreq.c +++ sys/netinet/tcp_usrreq.c @@ -2350,14 +2350,22 @@ } if (tp->t_state >= TCPS_FIN_WAIT_2) { soisdisconnected(tp->t_inpcb->inp_socket); - /* Prevent the connection hanging in FIN_WAIT_2 forever. */ + } + /* + * Prevent the connection hanging in FIN_WAIT_2, FIN_WAIT_1, + * CLOSING, LAST_ACK forever. + */ + if (tp->t_state != TCPS_TIME_WAIT) { + int timeout = 0; if (tp->t_state == TCPS_FIN_WAIT_2) { - int timeout; - - timeout = (tcp_fast_finwait2_recycle) ? + timeout = tcp_fast_finwait2_recycle ? tcp_finwait2_timeout : TP_MAXIDLE(tp); - tcp_timer_activate(tp, TT_2MSL, timeout); + } else if (tp->t_state >= TCPS_SYN_RECEIVED) { + timeout = tcp_fast_close_recycle ? + tcp_close_timeout : 0; } + if (timeout) + tcp_timer_activate(tp, TT_2MSL, timeout); } }