git: baad45c9c120 - main - inpcb: push multicast case local address selection logic into in_pcbladdr()

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Sat, 22 Mar 2025 23:40:45 UTC
The branch main has been updated by glebius:

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

commit baad45c9c12028964acd0b58096f3aaa0fb22859
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-03-22 23:37:37 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2025-03-22 23:37:37 +0000

    inpcb: push multicast case local address selection logic into in_pcbladdr()
    
    When destination is multicast and inpcb has multicast options configured,
    we use completely different logic than in a normal case.  Before this
    change, in in_pcbconnect() we would run in_pcbladdr() and then just ignore
    its results and run the multicast case block, that would override any
    earlier selection or failure.  Let's embed the case in in_pcbladdr() and
    also check it earlier.
    
    Also, 69c05f428714 switched UDP unconnected sendto(2) to use in_pcbladdr()
    instead of in_pcbconnect_setup() and due to that lost the multicast case.
    
    Reviewed by:            markj
    Differential Revision:  https://reviews.freebsd.org/D49435
    Fixes:                  69c05f42871406b4b2b2dac00a268d1da0cacd3e
---
 sys/netinet/in_pcb.c | 44 +++++++++++++++++++++-----------------------
 1 file changed, 21 insertions(+), 23 deletions(-)

diff --git a/sys/netinet/in_pcb.c b/sys/netinet/in_pcb.c
index 9a49353f1538..3774f73a7a8f 100644
--- a/sys/netinet/in_pcb.c
+++ b/sys/netinet/in_pcb.c
@@ -1127,29 +1127,6 @@ in_pcbconnect(struct inpcb *inp, struct sockaddr_in *sin, struct ucred *cred)
 
 	if (in_nullhost(inp->inp_laddr)) {
 		error = in_pcbladdr(inp, &faddr, &laddr, cred);
-		/*
-		 * If the destination address is multicast and an outgoing
-		 * interface has been set as a multicast option, prefer the
-		 * address of that interface as our source address.
-		 */
-		if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr)) &&
-		    inp->inp_moptions != NULL &&
-		    inp->inp_moptions->imo_multicast_ifp != NULL) {
-			struct ifnet *ifp =
-			    inp->inp_moptions->imo_multicast_ifp;
-			struct in_ifaddr *ia;
-
-			CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
-				if (ia->ia_ifp == ifp &&
-				    prison_check_ip4(cred,
-				    &ia->ia_addr.sin_addr) == 0)
-					break;
-			}
-			if (ia == NULL)
-				return (EADDRNOTAVAIL);
-			laddr = ia->ia_addr.sin_addr;
-			error = 0;
-		}
 		if (error)
 			return (error);
 	} else
@@ -1231,6 +1208,27 @@ in_pcbladdr(const struct inpcb *inp, struct in_addr *faddr,
 	if (!prison_saddrsel_ip4(cred, laddr))
 		return (0);
 
+	/*
+	 * If the destination address is multicast and an outgoing
+	 * interface has been set as a multicast option, prefer the
+	 * address of that interface as our source address.
+	 */
+	if (IN_MULTICAST(ntohl(faddr->s_addr)) && inp->inp_moptions != NULL &&
+	    inp->inp_moptions->imo_multicast_ifp != NULL) {
+		struct ifnet *ifp = inp->inp_moptions->imo_multicast_ifp;
+		struct in_ifaddr *ia;
+
+		CK_STAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) {
+			if (ia->ia_ifp == ifp &&
+			    prison_check_ip4(cred, &ia->ia_addr.sin_addr) == 0)
+				break;
+		}
+		if (ia == NULL)
+			return (EADDRNOTAVAIL);
+		*laddr = ia->ia_addr.sin_addr;
+		return (0);
+	}
+
 	error = 0;
 
 	nh = NULL;