Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sctp: recvmsg should be able to run even if sock is in closing state

Commit d46e416c11c8 missed to update some other places which checked for
the socket being TCP-style AND Established state, as Closing state has
some overlapping with the previous understanding of Established.

Without this fix, one of the effects is that some already queued rx
messages may not be readable anymore depending on how the association
teared down, and sending may also not be possible if peer initiated the
shutdown.

Also merge two if() blocks into one condition on sctp_sendmsg().

Cc: Xin Long <lucien.xin@gmail.com>
Fixes: d46e416c11c8 ("sctp: sctp should change socket state when shutdown is received")
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Marcelo Ricardo Leitner and committed by
David S. Miller
e5b13f34 b3f2cf8f

+17 -15
+17 -15
net/sctp/socket.c
··· 202 202 * could be a TCP-style listening socket or a socket which 203 203 * hasn't yet called connect() to establish an association. 204 204 */ 205 - if (!sctp_sstate(sk, ESTABLISHED)) 205 + if (!sctp_sstate(sk, ESTABLISHED) && !sctp_sstate(sk, CLOSING)) 206 206 return NULL; 207 207 208 208 /* Get the first and the only association from the list. */ ··· 1068 1068 * is already connected. 1069 1069 * It cannot be done even on a TCP-style listening socket. 1070 1070 */ 1071 - if (sctp_sstate(sk, ESTABLISHED) || 1071 + if (sctp_sstate(sk, ESTABLISHED) || sctp_sstate(sk, CLOSING) || 1072 1072 (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) { 1073 1073 err = -EISCONN; 1074 1074 goto out_free; ··· 1705 1705 if (msg_name) { 1706 1706 /* Look for a matching association on the endpoint. */ 1707 1707 asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport); 1708 - if (!asoc) { 1709 - /* If we could not find a matching association on the 1710 - * endpoint, make sure that it is not a TCP-style 1711 - * socket that already has an association or there is 1712 - * no peeled-off association on another socket. 1713 - */ 1714 - if ((sctp_style(sk, TCP) && 1715 - sctp_sstate(sk, ESTABLISHED)) || 1716 - sctp_endpoint_is_peeled_off(ep, &to)) { 1717 - err = -EADDRNOTAVAIL; 1718 - goto out_unlock; 1719 - } 1708 + 1709 + /* If we could not find a matching association on the 1710 + * endpoint, make sure that it is not a TCP-style 1711 + * socket that already has an association or there is 1712 + * no peeled-off association on another socket. 1713 + */ 1714 + if (!asoc && 1715 + ((sctp_style(sk, TCP) && 1716 + (sctp_sstate(sk, ESTABLISHED) || 1717 + sctp_sstate(sk, CLOSING))) || 1718 + sctp_endpoint_is_peeled_off(ep, &to))) { 1719 + err = -EADDRNOTAVAIL; 1720 + goto out_unlock; 1720 1721 } 1721 1722 } else { 1722 1723 asoc = sctp_id2assoc(sk, associd); ··· 2078 2077 2079 2078 lock_sock(sk); 2080 2079 2081 - if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) { 2080 + if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED) && 2081 + !sctp_sstate(sk, CLOSING)) { 2082 2082 err = -ENOTCONN; 2083 2083 goto out; 2084 2084 }