git: 43f7e2166810 - main - ng_ksocket: fix accept(2)

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Fri, 17 Nov 2023 17:24:53 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=43f7e21668105cc5a3c66eae5ecef0203c2df62f

commit 43f7e21668105cc5a3c66eae5ecef0203c2df62f
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2023-11-17 17:24:30 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2023-11-17 17:24:30 +0000

    ng_ksocket: fix accept(2)
    
    - Provide listen upcall and set it on NGM_KSOCKET_LISTEN
    - Mask EWOULDBLOCK on NGM_KSOCKET_ACCEPT
    
    Reviewed by:            afedorov
    Differential Revision:  https://reviews.freebsd.org/D42637
    PR:                     272319
    PR:                     275106
    Fixes:                  779f106aa169256b7010a1d8f963ff656b881e92
---
 sys/netgraph/ng_ksocket.c | 41 +++++++++++++++++++++++++++++++++++------
 1 file changed, 35 insertions(+), 6 deletions(-)

diff --git a/sys/netgraph/ng_ksocket.c b/sys/netgraph/ng_ksocket.c
index 337248789473..777f3261356d 100644
--- a/sys/netgraph/ng_ksocket.c
+++ b/sys/netgraph/ng_ksocket.c
@@ -152,6 +152,10 @@ static const struct ng_ksocket_alias ng_ksocket_protos[] = {
 
 /* Helper functions */
 static int	ng_ksocket_accept(priv_p);
+static int	ng_ksocket_listen_upcall(struct socket *so, void *arg,
+    int waitflag);
+static void	ng_ksocket_listen_upcall2(node_p node, hook_p hook,
+    void *arg1, int arg2);
 static int	ng_ksocket_incoming(struct socket *so, void *arg, int waitflag);
 static int	ng_ksocket_parse(const struct ng_ksocket_alias *aliases,
 			const char *s, int family);
@@ -695,6 +699,12 @@ ng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook)
 			/* Listen */
 			so->so_state |= SS_NBIO;
 			error = solisten(so, *((int32_t *)msg->data), td);
+			if (error == 0) {
+				SOLISTEN_LOCK(so);
+				solisten_upcall_set(so,
+				    ng_ksocket_listen_upcall, priv);
+				SOLISTEN_UNLOCK(so);
+			}
 			break;
 		    }
 
@@ -715,11 +725,15 @@ ng_ksocket_rcvmsg(node_p node, item_p item, hook_p lasthook)
 			/*
 			 * If a connection is already complete, take it.
 			 * Otherwise let the upcall function deal with
-			 * the connection when it comes in.
+			 * the connection when it comes in.  Don't return
+			 * EWOULDBLOCK, per ng_ksocket(4) documentation.
 			 */
 			error = ng_ksocket_accept(priv);
-			if (error != 0 && error != EWOULDBLOCK)
+			if (error == EWOULDBLOCK)
+				error = 0;
+			if (error != 0)
 				ERROUT(error);
+
 			priv->response_token = msg->header.token;
 			priv->response_addr = NGI_RETADDR(item);
 			break;
@@ -1064,10 +1078,6 @@ ng_ksocket_incoming2(node_p node, hook_p hook, void *arg1, int arg2)
 		}
 	}
 
-	/* Check whether a pending accept operation has completed */
-	if (priv->flags & KSF_ACCEPTING)
-		(void )ng_ksocket_accept(priv);
-
 	/*
 	 * If we don't have a hook, we must handle data events later.  When
 	 * the hook gets created and is connected, this upcall function
@@ -1250,6 +1260,25 @@ out:
 	return (0);
 }
 
+static int
+ng_ksocket_listen_upcall(struct socket *so, void *arg, int waitflag)
+{
+	priv_p priv = arg;
+	int wait = ((waitflag & M_WAITOK) ? NG_WAITOK : 0) | NG_QUEUE;
+
+	ng_send_fn1(priv->node, NULL, &ng_ksocket_listen_upcall2, priv, 0,
+	    wait);
+	return (SU_OK);
+}
+
+static void
+ng_ksocket_listen_upcall2(node_p node, hook_p hook, void *arg1, int arg2)
+{
+	const priv_p priv = NG_NODE_PRIVATE(node);
+
+	(void )ng_ksocket_accept(priv);
+}
+
 /*
  * Parse out either an integer value or an alias.
  */