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
This commit is contained in:
John Baldwin 2023-02-17 09:13:53 -08:00
parent ca457729cc
commit cda6bdbaa1

View File

@ -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);