git: cda6bdbaa15e - main - tcp: Don't try to disconnect a socket multiple times.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Fri, 17 Feb 2023 17:14:34 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=cda6bdbaa15e04857e2c0ae7ac06e9dbabac9835

commit cda6bdbaa15e04857e2c0ae7ac06e9dbabac9835
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2023-02-17 17:13:53 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2023-02-17 17:13:53 +0000

    tcp: Don't try to disconnect a socket multiple times.
    
    When the checks for INP_TIMEWAIT were removed, tcp_usr_close() and
    tcp_usr_disconnect() were no longer prevented from calling
    tcp_disconnect() on a socket that was already disconnected.  This
    triggered a panic in cxgbe(4) for TOE where the tcp_disconnect() on an
    already-disconnected socket invoked tcp_output() on a socket that was
    already in time-wait.
    
    Reviewed by:    rrs, np
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D37112
---
 sys/netinet/tcp_usrreq.c | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 1dbf4659ad00..0c36e4281010 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -654,6 +654,8 @@ tcp_usr_disconnect(struct socket *so)
 		goto out;
 	}
 	tp = intotcpcb(inp);
+	if (tp->t_state == TCPS_TIME_WAIT)
+		goto out;
 	tcp_disconnect(tp);
 out:
 	TCP_PROBE2(debug__user, tp, PRU_DISCONNECT);
@@ -1248,14 +1250,16 @@ tcp_usr_close(struct socket *so)
 	    ("tcp_usr_close: inp_socket == NULL"));
 
 	/*
-	 * If we still have full TCP state, and we're not dropped, initiate
+	 * If we are still connected and we're not dropped, initiate
 	 * a disconnect.
 	 */
 	if (!(inp->inp_flags & INP_DROPPED)) {
 		tp = intotcpcb(inp);
-		tp->t_flags |= TF_CLOSED;
-		tcp_disconnect(tp);
-		TCP_PROBE2(debug__user, tp, PRU_CLOSE);
+		if (tp->t_state != TCPS_TIME_WAIT) {
+			tp->t_flags |= TF_CLOSED;
+			tcp_disconnect(tp);
+			TCP_PROBE2(debug__user, tp, PRU_CLOSE);
+		}
 	}
 	if (!(inp->inp_flags & INP_DROPPED)) {
 		soref(so);