This introduces a regression reported by koobs@ when running a pyhton
test suite on a loaded system.

This patch resulted in a failing accept() call, when the association
was setup and gracefully shutdown by the peer before accept was called.
So the following packetdrill script would fail:

+0.0 socket(..., SOCK_STREAM, IPPROTO_SCTP) = 3
+0.0 bind(3, ..., ...) = 0
+0.0 listen(3, 1) = 0
+0.0 < sctp: INIT[flgs=0, tag=1, a_rwnd=15000, os=1, is=1, tsn=1]
+0.0 > sctp: INIT_ACK[flgs=0, tag=2, a_rwnd=..., os=..., is=..., tsn=1, ...]
+0.1 < sctp: COOKIE_ECHO[flgs=0, len=..., val=...]
+0.0 > sctp: COOKIE_ACK[flgs=0]
+0.0 < sctp: DATA[flgs=BE, len=116, tsn=1, sid=0, ssn=0, ppid=0]
+0.0 > sctp: SACK[flgs=0, cum_tsn=1, a_rwnd=..., gaps=[], dups=[]]
+0.0 < sctp: SHUTDOWN[flgs=0, cum_tsn=0]
+0.0 > sctp: SHUTDOWN_ACK[flgs=0]
+0.0 < sctp: SHUTDOWN_COMPLETE[flgs=0]
+0.0 accept(3, ..., ...) = 4
+0.0 close(3) = 0
+0.0 recv(4, ..., 4096, 0) = 100
+0.0 recv(4, ..., 4096, 0) = 0
+0.0 close(4) = 0

Reported by:		koops@
This commit is contained in:
Michael Tuexen 2020-03-25 15:29:01 +00:00
parent 23e3c0880d
commit 24187cfe72
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=359302

View File

@ -4739,31 +4739,6 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
else
so = inp->sctp_socket;
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
/*
* For TCP type we need special handling when we are
* connected. We also include the peel'ed off ones to.
*/
if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
inp->sctp_flags &= ~SCTP_PCB_FLAGS_CONNECTED;
inp->sctp_flags |= SCTP_PCB_FLAGS_WAS_CONNECTED;
if (so) {
SOCKBUF_LOCK(&so->so_rcv);
so->so_state &= ~(SS_ISCONNECTING |
SS_ISDISCONNECTING |
SS_ISCONFIRMING |
SS_ISCONNECTED);
so->so_state |= SS_ISDISCONNECTED;
socantrcvmore_locked(so);
socantsendmore(so);
sctp_sowwakeup(inp, so);
sctp_sorwakeup(inp, so);
SCTP_SOWAKEUP(so);
}
}
}
/*
* We used timer based freeing if a reader or writer is in the way.
* So we first check if we are actually being called from a timer,
@ -4891,6 +4866,31 @@ sctp_free_assoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, int from_inpcbfre
/* nothing around */
so = NULL;
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||
(inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) {
/*
* For TCP type we need special handling when we are
* connected. We also include the peel'ed off ones to.
*/
if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) {
inp->sctp_flags &= ~SCTP_PCB_FLAGS_CONNECTED;
inp->sctp_flags |= SCTP_PCB_FLAGS_WAS_CONNECTED;
if (so) {
SOCKBUF_LOCK(&so->so_rcv);
so->so_state &= ~(SS_ISCONNECTING |
SS_ISDISCONNECTING |
SS_ISCONFIRMING |
SS_ISCONNECTED);
so->so_state |= SS_ISDISCONNECTED;
socantrcvmore_locked(so);
socantsendmore(so);
sctp_sowwakeup(inp, so);
sctp_sorwakeup(inp, so);
SCTP_SOWAKEUP(so);
}
}
}
/*
* Make it invalid too, that way if its about to run it will abort
* and return.