git: 90ea8e89d9b7 - main - netinet6: refactor in6_pcbconnect()

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Thu, 25 Jun 2026 21:35:07 UTC
The branch main has been updated by glebius:

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

commit 90ea8e89d9b751e8b5ae90ef3397883b035788e5
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2026-06-25 21:34:38 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2026-06-25 21:34:38 +0000

    netinet6: refactor in6_pcbconnect()
    
    If the inpcb is already bound to a local address, there is no reason to
    call in6_pcbladdr().  If the inpcb is already bound to a local port, there
    is no reason to call in_pcb_lport_dest().  In the opposite case, if the
    inpcb is not bound, and we are about to choose a non-conflicting local
    addr:port, then there is no reason to call in6_pcblookup_internal().
    
    This change makes in6_pcbconnect() to look much more alike the IPv4
    in_pcbconnect().  I tracked this strange logic all the way down to initial
    KAME import and failed to find any reasoning for it.
    
    Reviewed by:            pouria
    Differential Revision:  https://reviews.freebsd.org/D57534
---
 sys/netinet6/in6_pcb.c | 34 +++++++++++++++++-----------------
 1 file changed, 17 insertions(+), 17 deletions(-)

diff --git a/sys/netinet6/in6_pcb.c b/sys/netinet6/in6_pcb.c
index 0cf6be2f9b33..b8651fd8a2be 100644
--- a/sys/netinet6/in6_pcb.c
+++ b/sys/netinet6/in6_pcb.c
@@ -465,25 +465,18 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred,
 	bzero(&laddr6, sizeof(laddr6));
 	laddr6.sin6_family = AF_INET6;
 
-	/*
-	 * Call inner routine, to assign local interface address.
-	 * in6_pcbladdr() may automatically fill in sin6_scope_id.
-	 */
 	INP_HASH_WLOCK(pcbinfo);
-	if ((error = in6_pcbladdr(inp, sin6, &laddr6.sin6_addr,
-	    sas_required)) != 0) {
-		INP_HASH_WUNLOCK(pcbinfo);
-		return (error);
-	}
-
-	if (in6_pcblookup_internal(pcbinfo, &sin6->sin6_addr, sin6->sin6_port,
-	    IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr) ?
-	    &laddr6.sin6_addr : &inp->in6p_laddr, inp->inp_lport, 0,
-	    M_NODOM, RT_ALL_FIBS) != NULL) {
-		INP_HASH_WUNLOCK(pcbinfo);
-		return (EADDRINUSE);
-	}
 	if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
+		/*
+		 * Call inner routine, to assign local interface address.
+		 * in6_pcbladdr() may automatically fill in sin6_scope_id.
+		 */
+		error = in6_pcbladdr(inp, sin6, &laddr6.sin6_addr,
+		    sas_required);
+		if (__predict_false(error)) {
+			INP_HASH_WUNLOCK(pcbinfo);
+			return (error);
+		}
 		if (inp->inp_lport == 0) {
 			error = in_pcb_lport_dest(inp,
 			    (struct sockaddr *) &laddr6, &inp->inp_lport,
@@ -495,7 +488,14 @@ in6_pcbconnect(struct inpcb *inp, struct sockaddr_in6 *sin6, struct ucred *cred,
 			}
 		}
 		inp->in6p_laddr = laddr6.sin6_addr;
+	} else if (in6_pcblookup_internal(pcbinfo, &sin6->sin6_addr,
+	    sin6->sin6_port, &inp->in6p_laddr, inp->inp_lport, 0,
+	    M_NODOM, RT_ALL_FIBS) != NULL) {
+		INP_HASH_WUNLOCK(pcbinfo);
+		return (EADDRINUSE);
 	}
+	MPASS(inp->inp_lport != 0);
+	MPASS(!IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr));
 	inp->in6p_faddr = sin6->sin6_addr;
 	inp->inp_fport = sin6->sin6_port;
 	/* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */