git: 296a4cb5c5b1 - main - sockets: provide correct pr_shutdown for keysock and SDP

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Tue, 16 Jan 2024 20:03:35 UTC
The branch main has been updated by glebius:

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

commit 296a4cb5c5b18f82da7a365d9f209cb9fc09003b
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2024-01-16 20:00:36 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2024-01-16 20:02:59 +0000

    sockets: provide correct pr_shutdown for keysock and SDP
    
    My failure to run all kinds of kernel builds lead to missing the keysock
    and incorrectly assuming SDP as not having a shutdown method.
    
    Fixes:  5bba2728079ed4da33f727dbc2b6ae1de02ba897
---
 sys/netipsec/keysock.c                         | 19 +++++++++-
 sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c | 52 +++++++++++++++++++-------
 2 files changed, 56 insertions(+), 15 deletions(-)

diff --git a/sys/netipsec/keysock.c b/sys/netipsec/keysock.c
index 18bbdae316f0..d9297d44c18a 100644
--- a/sys/netipsec/keysock.c
+++ b/sys/netipsec/keysock.c
@@ -310,9 +310,24 @@ key_detach(struct socket *so)
 }
 
 static int
-key_shutdown(struct socket *so)
+key_shutdown(struct socket *so, enum shutdown_how how)
 {
-	socantsendmore(so);
+	/*
+	 * Note: key socket marks itself as connected through its lifetime.
+	 */
+	switch (how) {
+	case SHUT_RD:
+		socantrcvmore(so);
+		sbrelease(so, SO_RCV);
+		break;
+	case SHUT_RDWR:
+		socantrcvmore(so);
+		sbrelease(so, SO_RCV);
+		/* FALLTHROUGH */
+	case SHUT_WR:
+		socantsendmore(so);
+	}
+
 	return (0);
 }
 
diff --git a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c
index 95048a1dc186..cfc2390db02e 100644
--- a/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c
+++ b/sys/ofed/drivers/infiniband/ulp/sdp/sdp_main.c
@@ -787,24 +787,50 @@ sdp_accept(struct socket *so, struct sockaddr *sa)
  * Mark the connection as being incapable of further output.
  */
 static int
-sdp_shutdown(struct socket *so)
+sdp_shutdown(struct socket *so, enum shutdown_how how)
 {
+	struct sdp_sock *ssk = sdp_sk(so);
 	int error = 0;
-	struct sdp_sock *ssk;
 
-	ssk = sdp_sk(so);
-	SDP_WLOCK(ssk);
-	if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) {
-		error = ECONNRESET;
-		goto out;
+	SOCK_LOCK(so);
+	if ((so->so_state &
+	    (SS_ISCONNECTED | SS_ISCONNECTING | SS_ISDISCONNECTING)) == 0) {
+		SOCK_UNLOCK(so);
+		return (ENOTCONN);
 	}
-	socantsendmore(so);
-	sdp_usrclosed(ssk);
-	if (!(ssk->flags & SDP_DROPPED))
-		sdp_output_disconnect(ssk);
+	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);
 
-out:
-	SDP_WUNLOCK(ssk);
+	switch (how) {
+	case SHUT_RD:
+		socantrcvmore(so);
+		sbrelease(so, SO_RCV);
+		break;
+	case SHUT_RDWR:
+		socantrcvmore(so);
+		sbrelease(so, SO_RCV);
+		/* FALLTHROUGH */
+	case SHUT_WR:
+		SDP_WLOCK(ssk);
+		if (ssk->flags & (SDP_TIMEWAIT | SDP_DROPPED)) {
+			SDP_WUNLOCK(ssk);
+			error = ECONNRESET;
+			break;
+		}
+		socantsendmore(so);
+		sdp_usrclosed(ssk);
+		if (!(ssk->flags & SDP_DROPPED))
+			sdp_output_disconnect(ssk);
+		SDP_WUNLOCK(ssk);
+	}
+	wakeup(&so->so_timeo);
 
 	return (error);
 }