git: fc4d53cc2ef3 - main - Split tcp_ctloutput() into set/get parts.

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Wed, 27 Oct 2021 15:22:57 UTC
The branch main has been updated by glebius:

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

commit fc4d53cc2ef3345ad36c874010c4abc2317a61f8
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2021-10-26 03:38:31 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2021-10-27 15:21:59 +0000

    Split tcp_ctloutput() into set/get parts.
    
    Reviewed by:            rrs
    Differential Revision:  https://reviews.freebsd.org/D32655
---
 sys/netinet/tcp_usrreq.c | 125 ++++++++++++++++++++++++++++++++++-------------
 1 file changed, 90 insertions(+), 35 deletions(-)

diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index f004d54b4657..0fca9b88e6f3 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -1729,22 +1729,18 @@ tcp_fill_info(struct tcpcb *tp, struct tcp_info *ti)
 } while(0)
 #define INP_WLOCK_RECHECK(inp) INP_WLOCK_RECHECK_CLEANUP((inp), /* noop */)
 
-int
-tcp_ctloutput(struct socket *so, struct sockopt *sopt)
+static int
+tcp_ctloutput_set(struct inpcb *inp, struct sockopt *sopt)
 {
-	int	error;
-	struct	inpcb *inp;
-	struct	tcpcb *tp;
-	struct tcp_function_block *blk;
-	struct tcp_function_set fsn;
+	struct	tcpcb *tp = intotcpcb(inp);
+	int error = 0;
+
+	MPASS(sopt->sopt_dir == SOPT_SET);
 
-	error = 0;
-	inp = sotoinpcb(so);
-	KASSERT(inp != NULL, ("tcp_ctloutput: inp == NULL"));
 	if (sopt->sopt_level != IPPROTO_TCP) {
 #ifdef INET6
 		if (inp->inp_vflag & INP_IPV6PROTO) {
-			error = ip6_ctloutput(so, sopt);
+			error = ip6_ctloutput(inp->inp_socket, sopt);
 			/*
 			 * In case of the IPV6_USE_MIN_MTU socket option,
 			 * the INC_IPV6MINMTU flag to announce a corresponding
@@ -1755,7 +1751,6 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt)
 			 * be fragmented at the IPv6 layer.
 			 */
 			if ((error == 0) &&
-			    (sopt->sopt_dir == SOPT_SET) &&
 			    (sopt->sopt_level == IPPROTO_IPV6) &&
 			    (sopt->sopt_name == IPV6_USE_MIN_MTU)) {
 				INP_WLOCK(inp);
@@ -1788,29 +1783,29 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt)
 #endif
 #ifdef INET
 		{
-			error = ip_ctloutput(so, sopt);
+			error = ip_ctloutput(inp->inp_socket, sopt);
 		}
 #endif
 		return (error);
-	}
-	INP_WLOCK(inp);
-	if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
-		INP_WUNLOCK(inp);
-		return (ECONNRESET);
-	}
-	tp = intotcpcb(inp);
-	/*
-	 * Protect the TCP option TCP_FUNCTION_BLK so
-	 * that a sub-function can *never* overwrite this.
-	 */
-	if ((sopt->sopt_dir == SOPT_SET) &&
-	    (sopt->sopt_name == TCP_FUNCTION_BLK)) {
-		INP_WUNLOCK(inp);
-		error = sooptcopyin(sopt, &fsn, sizeof fsn,
-		    sizeof fsn);
+	} else if (sopt->sopt_name == TCP_FUNCTION_BLK) {
+		/*
+		 * Protect the TCP option TCP_FUNCTION_BLK so
+		 * that a sub-function can *never* overwrite this.
+		 */
+		struct tcp_function_set fsn;
+		struct tcp_function_block *blk;
+
+		error = sooptcopyin(sopt, &fsn, sizeof fsn, sizeof fsn);
 		if (error)
 			return (error);
-		INP_WLOCK_RECHECK(inp);
+
+		INP_WLOCK(inp);
+		if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
+			INP_WUNLOCK(inp);
+			return (ECONNRESET);
+		}
+		tp = intotcpcb(inp);
+
 		blk = find_and_ref_tcp_functions(&fsn);
 		if (blk == NULL) {
 			INP_WUNLOCK(inp);
@@ -1875,7 +1870,7 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt)
 					if((*tp->t_fb->tfb_tcp_fb_init)(tp) != 0)  {
 						/* Fall back failed, drop the connection */
 						INP_WUNLOCK(inp);
-						soabort(so);
+						soabort(inp->inp_socket);
 						return(error);
 					}
 				}
@@ -1893,9 +1888,50 @@ tcp_ctloutput(struct socket *so, struct sockopt *sopt)
 err_out:
 		INP_WUNLOCK(inp);
 		return (error);
-	} else if ((sopt->sopt_dir == SOPT_GET) &&
-	    ((sopt->sopt_name == TCP_FUNCTION_BLK) ||
+	}
+
+	INP_WLOCK(inp);
+	if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
+		INP_WUNLOCK(inp);
+		return (ECONNRESET);
+	}
+	tp = intotcpcb(inp);
+
+	/* Pass in the INP locked, caller must unlock it. */
+	return (tp->t_fb->tfb_tcp_ctloutput(inp->inp_socket, sopt, inp, tp));
+}
+
+static int
+tcp_ctloutput_get(struct inpcb *inp, struct sockopt *sopt)
+{
+	int	error = 0;
+	struct	tcpcb *tp;
+
+	MPASS(sopt->sopt_dir == SOPT_GET);
+
+	if (sopt->sopt_level != IPPROTO_TCP) {
+#ifdef INET6
+		if (inp->inp_vflag & INP_IPV6PROTO)
+			error = ip6_ctloutput(inp->inp_socket, sopt);
+#endif /* INET6 */
+#if defined(INET6) && defined(INET)
+		else
+#endif
+#ifdef INET
+			error = ip_ctloutput(inp->inp_socket, sopt);
+#endif
+		return (error);
+	}
+	INP_WLOCK(inp);
+	if (inp->inp_flags & (INP_TIMEWAIT | INP_DROPPED)) {
+		INP_WUNLOCK(inp);
+		return (ECONNRESET);
+	}
+	tp = intotcpcb(inp);
+	if (((sopt->sopt_name == TCP_FUNCTION_BLK) ||
 	     (sopt->sopt_name == TCP_FUNCTION_ALIAS))) {
+		struct tcp_function_set fsn;
+
 		if (sopt->sopt_name == TCP_FUNCTION_ALIAS) {
 			memset(&fsn, 0, sizeof(fsn));
 			find_tcp_function_alias(tp->t_fb, &fsn);
@@ -1910,8 +1946,27 @@ err_out:
 		error = sooptcopyout(sopt, &fsn, sizeof fsn);
 		return (error);
 	}
-	/* Pass in the INP locked, called must unlock it */
-	return (tp->t_fb->tfb_tcp_ctloutput(so, sopt, inp, tp));
+
+	/* Pass in the INP locked, caller must unlock it. */
+	return (tp->t_fb->tfb_tcp_ctloutput(inp->inp_socket, sopt, inp, tp));
+}
+
+int
+tcp_ctloutput(struct socket *so, struct sockopt *sopt)
+{
+	int	error;
+	struct	inpcb *inp;
+
+	error = 0;
+	inp = sotoinpcb(so);
+	KASSERT(inp != NULL, ("tcp_ctloutput: inp == NULL"));
+
+	if (sopt->sopt_dir == SOPT_SET)
+		return (tcp_ctloutput_set(inp, sopt));
+	else if (sopt->sopt_dir == SOPT_GET)
+		return (tcp_ctloutput_get(inp, sopt));
+	else
+		panic("%s: sopt_dir $%d", __func__, sopt->sopt_dir);
 }
 
 /*