diff options
author | Gleb Smirnoff <glebius@FreeBSD.org> | 2024-02-15 18:48:44 +0000 |
---|---|---|
committer | Gleb Smirnoff <glebius@FreeBSD.org> | 2024-02-15 18:48:44 +0000 |
commit | abe8379b4f244aa12f13a603124eb6b41faabec5 (patch) | |
tree | ea1e2a27731e3b607c0d7206672716b69b022107 | |
parent | 2c5ff9118c1ed8483a9477db3595b1d154615e2c (diff) | |
download | src-abe8379b4f244aa12f13a603124eb6b41faabec5.tar.gz src-abe8379b4f244aa12f13a603124eb6b41faabec5.zip |
sockets: repair wakeup of accept(2) by shutdown(2)
That was lost in transition from one-for-all soshutdown() to protocol
specific methods. Only protocols that listen(2) were affected. This is
not a documented or specified feature, but some software relies on it. At
least the FreeSWITCH telephony software uses this behavior on
PF_INET/SOCK_STREAM.
Fixes: 5bba2728079ed4da33f727dbc2b6ae1de02ba897
-rw-r--r-- | sys/kern/uipc_usrreq.c | 17 | ||||
-rw-r--r-- | sys/netinet/sctp_usrreq.c | 11 | ||||
-rw-r--r-- | sys/netinet/tcp_usrreq.c | 11 |
3 files changed, 18 insertions, 21 deletions
diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c index db226a16674e..20facd9b0a44 100644 --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -1669,7 +1669,14 @@ uipc_shutdown(struct socket *so, enum shutdown_how how) int error; SOCK_LOCK(so); - if ((so->so_state & + if (SOLISTENING(so)) { + if (how != SHUT_WR) { + so->so_error = ECONNABORTED; + solisten_wakeup(so); /* unlocks so */ + } else + SOCK_UNLOCK(so); + return (ENOTCONN); + } else if ((so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { /* * POSIX mandates us to just return ENOTCONN when shutdown(2) is @@ -1691,14 +1698,6 @@ uipc_shutdown(struct socket *so, enum shutdown_how how) } } else error = 0; - if (SOLISTENING(so)) { - if (how != SHUT_WR) { - so->so_error = ECONNABORTED; - solisten_wakeup(so); /* unlocks so */ - } else - SOCK_UNLOCK(so); - return (0); - } SOCK_UNLOCK(so); switch (how) { diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 70fe021be766..3b0da87edce3 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -794,18 +794,17 @@ sctp_shutdown(struct socket *so, enum shutdown_how how) return (EOPNOTSUPP); SOCK_LOCK(so); - if ((so->so_state & - (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { - SOCK_UNLOCK(so); - return (ENOTCONN); - } if (SOLISTENING(so)) { if (how != SHUT_WR) { so->so_error = ECONNABORTED; solisten_wakeup(so); /* unlocks so */ } else SOCK_UNLOCK(so); - return (0); + return (ENOTCONN); + } else if ((so->so_state & + (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { + SOCK_UNLOCK(so); + return (ENOTCONN); } SOCK_UNLOCK(so); diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c index a283d308801f..9bb953617d99 100644 --- a/sys/netinet/tcp_usrreq.c +++ b/sys/netinet/tcp_usrreq.c @@ -807,18 +807,17 @@ tcp_usr_shutdown(struct socket *so, enum shutdown_how how) int error = 0; SOCK_LOCK(so); - if ((so->so_state & - (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { - SOCK_UNLOCK(so); - return (ENOTCONN); - } if (SOLISTENING(so)) { if (how != SHUT_WR) { so->so_error = ECONNABORTED; solisten_wakeup(so); /* unlocks so */ } else SOCK_UNLOCK(so); - return (0); + return (ENOTCONN); + } else if ((so->so_state & + (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) { + SOCK_UNLOCK(so); + return (ENOTCONN); } SOCK_UNLOCK(so); |