Module Name:    src
Committed By:   ozaki-r
Date:           Mon Oct 31 04:16:25 UTC 2016

Modified Files:
        src/sys/netinet6: icmp6.c in6_pcb.c in6_src.c ip6_var.h nd6_nbr.c
            raw_ip6.c udp6_output.c

Log Message:
Fix race condition of in6_selectsrc

in6_selectsrc returned a pointer to in6_addr that wan't guaranteed to be
safe by pserialize (or psref), which was racy. Let callers pass a pointer
to in6_addr and in6_selectsrc copy a result to it inside pserialize
critical sections.


To generate a diff of this commit:
cvs rdiff -u -r1.199 -r1.200 src/sys/netinet6/icmp6.c
cvs rdiff -u -r1.150 -r1.151 src/sys/netinet6/in6_pcb.c
cvs rdiff -u -r1.71 -r1.72 src/sys/netinet6/in6_src.c
cvs rdiff -u -r1.68 -r1.69 src/sys/netinet6/ip6_var.h
cvs rdiff -u -r1.128 -r1.129 src/sys/netinet6/nd6_nbr.c
cvs rdiff -u -r1.151 -r1.152 src/sys/netinet6/raw_ip6.c
cvs rdiff -u -r1.53 -r1.54 src/sys/netinet6/udp6_output.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/netinet6/icmp6.c
diff -u src/sys/netinet6/icmp6.c:1.199 src/sys/netinet6/icmp6.c:1.200
--- src/sys/netinet6/icmp6.c:1.199	Tue Oct 25 02:45:10 2016
+++ src/sys/netinet6/icmp6.c	Mon Oct 31 04:16:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: icmp6.c,v 1.199 2016/10/25 02:45:10 ozaki-r Exp $	*/
+/*	$NetBSD: icmp6.c,v 1.200 2016/10/31 04:16:25 ozaki-r Exp $	*/
 /*	$KAME: icmp6.c,v 1.217 2001/06/20 15:03:29 jinmei Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.199 2016/10/25 02:45:10 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: icmp6.c,v 1.200 2016/10/31 04:16:25 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -1999,9 +1999,9 @@ icmp6_reflect(struct mbuf *m, size_t off
 	int type, code;
 	struct ifnet *outif = NULL;
 	struct in6_addr origdst;
-	const struct in6_addr *src = NULL;
 	struct ifnet *rcvif;
 	int s;
+	bool ip6_src_filled = false;
 
 	/* too short to reflect */
 	if (off < sizeof(struct ip6_hdr)) {
@@ -2069,8 +2069,10 @@ icmp6_reflect(struct mbuf *m, size_t off
 		;
 	else if ((ip6a = ip6_getdstifaddr(m)) != NULL) {
 		if ((ip6a->ip6a_flags &
-		     (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0)
-			src = &ip6a->ip6a_src;
+		     (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) {
+			ip6->ip6_src = ip6a->ip6a_src;
+			ip6_src_filled = true;
+		}
 	} else {
 		union {
 			struct sockaddr_in6 sin6;
@@ -2087,13 +2089,15 @@ icmp6_reflect(struct mbuf *m, size_t off
 		if (ifa != NULL) {
 			ia = ifatoia6(ifa);
 			if ((ia->ia6_flags &
-				 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0)
-				src = &ia->ia_addr.sin6_addr;
+				 (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)) == 0) {
+				ip6->ip6_src = ia->ia_addr.sin6_addr;
+				ip6_src_filled = true;
+			}
 		}
 		pserialize_read_exit(_s);
 	}
 
-	if (src == NULL) {
+	if (!ip6_src_filled) {
 		int e;
 		struct sockaddr_in6 sin6;
 		struct route ro;
@@ -2107,9 +2111,10 @@ icmp6_reflect(struct mbuf *m, size_t off
 		sockaddr_in6_init(&sin6, &ip6->ip6_dst, 0, 0, 0);
 
 		memset(&ro, 0, sizeof(ro));
-		src = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, NULL, NULL, &e);
+		e = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, NULL, NULL,
+		    &ip6->ip6_src);
 		rtcache_free(&ro);
-		if (src == NULL) {
+		if (e != 0) {
 			nd6log(LOG_DEBUG,
 			    "source can't be determined: "
 			    "dst=%s, error=%d\n",
@@ -2118,7 +2123,6 @@ icmp6_reflect(struct mbuf *m, size_t off
 		}
 	}
 
-	ip6->ip6_src = *src;
 	ip6->ip6_flow = 0;
 	ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
 	ip6->ip6_vfc |= IPV6_VERSION;

Index: src/sys/netinet6/in6_pcb.c
diff -u src/sys/netinet6/in6_pcb.c:1.150 src/sys/netinet6/in6_pcb.c:1.151
--- src/sys/netinet6/in6_pcb.c:1.150	Thu Sep 29 12:19:47 2016
+++ src/sys/netinet6/in6_pcb.c	Mon Oct 31 04:16:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_pcb.c,v 1.150 2016/09/29 12:19:47 roy Exp $	*/
+/*	$NetBSD: in6_pcb.c,v 1.151 2016/10/31 04:16:25 ozaki-r Exp $	*/
 /*	$KAME: in6_pcb.c,v 1.84 2001/02/08 18:02:08 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.150 2016/09/29 12:19:47 roy Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_pcb.c,v 1.151 2016/10/31 04:16:25 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -444,6 +444,7 @@ in6_pcbconnect(void *v, struct sockaddr_
 {
 	struct in6pcb *in6p = v;
 	struct in6_addr *in6a = NULL;
+	struct in6_addr ia6;
 	struct ifnet *ifp = NULL;	/* outgoing interface */
 	int error = 0;
 	int scope_ambiguous = 0;
@@ -530,10 +531,9 @@ in6_pcbconnect(void *v, struct sockaddr_
 		 * with the address specified by setsockopt(IPV6_PKTINFO).
 		 * Is it the intended behavior?
 		 */
-		in6a = in6_selectsrc(sin6, in6p->in6p_outputopts,
-				     in6p->in6p_moptions,
-				     &in6p->in6p_route,
-				     &in6p->in6p_laddr, &ifp, &psref, &error);
+		error = in6_selectsrc(sin6, in6p->in6p_outputopts,
+		    in6p->in6p_moptions, &in6p->in6p_route, &in6p->in6p_laddr,
+		    &ifp, &psref, &ia6);
 		if (ifp && scope_ambiguous &&
 		    (error = in6_setscope(&sin6->sin6_addr, ifp, NULL)) != 0) {
 			if_put(ifp, &psref);
@@ -541,13 +541,14 @@ in6_pcbconnect(void *v, struct sockaddr_
 			return(error);
 		}
 
-		if (in6a == NULL) {
+		if (error != 0) {
 			if_put(ifp, &psref);
 			curlwp_bindx(bound);
 			if (error == 0)
 				error = EADDRNOTAVAIL;
 			return (error);
 		}
+		in6a = &ia6;
 	}
 
 	if (ifp != NULL) {

Index: src/sys/netinet6/in6_src.c
diff -u src/sys/netinet6/in6_src.c:1.71 src/sys/netinet6/in6_src.c:1.72
--- src/sys/netinet6/in6_src.c:1.71	Mon Oct 31 02:50:31 2016
+++ src/sys/netinet6/in6_src.c	Mon Oct 31 04:16:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: in6_src.c,v 1.71 2016/10/31 02:50:31 ozaki-r Exp $	*/
+/*	$NetBSD: in6_src.c,v 1.72 2016/10/31 04:16:25 ozaki-r Exp $	*/
 /*	$KAME: in6_src.c,v 1.159 2005/10/19 01:40:32 t-momose Exp $	*/
 
 /*
@@ -66,7 +66,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: in6_src.c,v 1.71 2016/10/31 02:50:31 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: in6_src.c,v 1.72 2016/10/31 04:16:25 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -171,10 +171,10 @@ static struct in6_addrpolicy *match_addr
 #define BREAK(r) goto out
 #endif
 
-struct in6_addr *
+int
 in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, 
 	struct ip6_moptions *mopts, struct route *ro, struct in6_addr *laddr, 
-	struct ifnet **ifpp, struct psref *psref, int *errorp)
+	struct ifnet **ifpp, struct psref *psref, struct in6_addr *ret_ia6)
 {
 	struct in6_addr dst;
 	struct ifnet *ifp = NULL;
@@ -189,7 +189,6 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 	u_int8_t ip6po_usecoa = 0;
 #endif /* MIP6 && NMIP > 0 */
 	struct psref local_psref;
-	struct in6_addr *ret_ia = NULL;
 	int bound = curlwp_bind();
 #define PSREF (psref == NULL) ? &local_psref : psref
 	int s;
@@ -198,7 +197,6 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 	        (ifpp == NULL && psref == NULL));
 
 	dst = dstsock->sin6_addr; /* make a copy for local operation */
-	*errorp = 0;
 	if (ifpp)
 		*ifpp = NULL;
 
@@ -238,8 +236,8 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 		srcsock.sin6_len = sizeof(srcsock);
 		srcsock.sin6_addr = pi->ipi6_addr;
 		if (ifp) {
-			*errorp = in6_setscope(&srcsock.sin6_addr, ifp, NULL);
-			if (*errorp != 0)
+			error = in6_setscope(&srcsock.sin6_addr, ifp, NULL);
+			if (error != 0)
 				goto exit;
 		}
 
@@ -249,15 +247,14 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 		    ia6->ia6_flags &
 		    (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY)) {
 			pserialize_read_exit(_s);
-			*errorp = EADDRNOTAVAIL;
+			error = EADDRNOTAVAIL;
 			goto exit;
 		}
 		pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */
 		if (ifpp)
 			*ifpp = ifp;
-		ret_ia = &ia6->ia_addr.sin6_addr;
+		*ret_ia6 = ia6->ia_addr.sin6_addr;
 		pserialize_read_exit(_s);
-		/* XXX don't return pointer */
 		goto exit;
 	}
 
@@ -267,7 +264,7 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 	 * though it would eventually cause an error.
 	 */
 	if (laddr && !IN6_IS_ADDR_UNSPECIFIED(laddr)) {
-		ret_ia = laddr;
+		*ret_ia6 = *laddr;
 		goto exit;
 	}
 
@@ -275,10 +272,8 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 	 * The outgoing interface is crucial in the general selection procedure
 	 * below.  If it is not known at this point, we fail.
 	 */
-	if (ifp == NULL) {
-		*errorp = error;
+	if (ifp == NULL)
 		goto exit;
-	}
 
 	/*
 	 * If the address is not yet determined, choose the best one based on
@@ -297,8 +292,8 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 	}
 #endif /* MIP6 && NMIP > 0 */
 
-	*errorp = in6_setscope(&dst, ifp, &odstzone);
-	if (*errorp != 0)
+	error = in6_setscope(&dst, ifp, &odstzone);
+	if (error != 0)
 		goto exit;
 
 	s = pserialize_read_enter();
@@ -560,19 +555,20 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 	  out:
 		break;
 	}
-	pserialize_read_exit(s);
 
 	if ((ia = ia_best) == NULL) {
-		*errorp = EADDRNOTAVAIL;
+		pserialize_read_exit(s);
+		error = EADDRNOTAVAIL;
 		goto exit;
 	}
 
-	ret_ia = &ia->ia_addr.sin6_addr;
+	*ret_ia6 = ia->ia_addr.sin6_addr;
+	pserialize_read_exit(s);
 exit:
 	if (ifpp == NULL)
 		if_put(ifp, PSREF);
 	curlwp_bindx(bound);
-	return ret_ia;
+	return error;
 #undef PSREF
 }
 #undef REPLACE

Index: src/sys/netinet6/ip6_var.h
diff -u src/sys/netinet6/ip6_var.h:1.68 src/sys/netinet6/ip6_var.h:1.69
--- src/sys/netinet6/ip6_var.h:1.68	Tue Aug 23 09:59:20 2016
+++ src/sys/netinet6/ip6_var.h	Mon Oct 31 04:16:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: ip6_var.h,v 1.68 2016/08/23 09:59:20 knakahara Exp $	*/
+/*	$NetBSD: ip6_var.h,v 1.69 2016/10/31 04:16:25 ozaki-r Exp $	*/
 /*	$KAME: ip6_var.h,v 1.33 2000/06/11 14:59:20 jinmei Exp $	*/
 
 /*
@@ -396,9 +396,9 @@ int	none_input(struct mbuf **, int *, in
 
 struct route;
 
-struct 	in6_addr *in6_selectsrc(struct sockaddr_in6 *,
-	struct ip6_pktopts *, struct ip6_moptions *, struct route *,
-	struct in6_addr *, struct ifnet **, struct psref *, int *);
+int	in6_selectsrc(struct sockaddr_in6 *, struct ip6_pktopts *,
+	   struct ip6_moptions *, struct route *, struct in6_addr *,
+	   struct ifnet **, struct psref *, struct in6_addr *);
 int in6_selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
 	struct ip6_moptions *, struct route *, struct ifnet **,
 	struct psref *, struct rtentry **, int);

Index: src/sys/netinet6/nd6_nbr.c
diff -u src/sys/netinet6/nd6_nbr.c:1.128 src/sys/netinet6/nd6_nbr.c:1.129
--- src/sys/netinet6/nd6_nbr.c:1.128	Tue Oct 18 07:30:31 2016
+++ src/sys/netinet6/nd6_nbr.c	Mon Oct 31 04:16:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: nd6_nbr.c,v 1.128 2016/10/18 07:30:31 ozaki-r Exp $	*/
+/*	$NetBSD: nd6_nbr.c,v 1.129 2016/10/31 04:16:25 ozaki-r Exp $	*/
 /*	$KAME: nd6_nbr.c,v 1.61 2001/02/10 16:06:14 jinmei Exp $	*/
 
 /*
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.128 2016/10/18 07:30:31 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nd6_nbr.c,v 1.129 2016/10/31 04:16:25 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -469,15 +469,16 @@ nd6_ns_output(struct ifnet *ifp, const s
 
 			sockaddr_in6_init(&dst_sa, &ip6->ip6_dst, 0, 0, 0);
 
-			src = in6_selectsrc(&dst_sa, NULL,
-			    NULL, &ro, NULL, NULL, NULL, &error);
-			if (src == NULL) {
+			error = in6_selectsrc(&dst_sa, NULL,
+			    NULL, &ro, NULL, NULL, NULL, &src_in);
+			if (error != 0) {
 				nd6log(LOG_DEBUG, "source can't be "
 				    "determined: dst=%s, error=%d\n",
 				    ip6_sprintf(&dst_sa.sin6_addr), error);
 				pserialize_read_exit(s);
 				goto bad;
 			}
+			src = &src_in;
 		}
 		pserialize_read_exit(s);
 	} else {
@@ -894,7 +895,7 @@ nd6_na_output(
 		struct sockaddr		dst;
 		struct sockaddr_in6	dst6;
 	} u;
-	struct in6_addr *src, daddr6;
+	struct in6_addr daddr6;
 	int icmp6len, maxlen, error;
 	const void *mac;
 	struct route ro;
@@ -967,14 +968,14 @@ nd6_na_output(
 	/*
 	 * Select a source whose scope is the same as that of the dest.
 	 */
-	src = in6_selectsrc(satosin6(dst), NULL, NULL, &ro, NULL, NULL, NULL, &error);
-	if (src == NULL) {
+	error = in6_selectsrc(satosin6(dst), NULL, NULL, &ro, NULL, NULL, NULL,
+	    &ip6->ip6_src);
+	if (error != 0) {
 		nd6log(LOG_DEBUG, "source can't be "
 		    "determined: dst=%s, error=%d\n",
 		    ip6_sprintf(&satocsin6(dst)->sin6_addr), error);
 		goto bad;
 	}
-	ip6->ip6_src = *src;
 	nd_na = (struct nd_neighbor_advert *)(ip6 + 1);
 	nd_na->nd_na_type = ND_NEIGHBOR_ADVERT;
 	nd_na->nd_na_code = 0;

Index: src/sys/netinet6/raw_ip6.c
diff -u src/sys/netinet6/raw_ip6.c:1.151 src/sys/netinet6/raw_ip6.c:1.152
--- src/sys/netinet6/raw_ip6.c:1.151	Thu Sep 29 12:19:47 2016
+++ src/sys/netinet6/raw_ip6.c	Mon Oct 31 04:16:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: raw_ip6.c,v 1.151 2016/09/29 12:19:47 roy Exp $	*/
+/*	$NetBSD: raw_ip6.c,v 1.152 2016/10/31 04:16:25 ozaki-r Exp $	*/
 /*	$KAME: raw_ip6.c,v 1.82 2001/07/23 18:57:56 jinmei Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.151 2016/09/29 12:19:47 roy Exp $");
+__KERNEL_RCSID(0, "$NetBSD: raw_ip6.c,v 1.152 2016/10/31 04:16:25 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ipsec.h"
@@ -386,7 +386,6 @@ rip6_output(struct mbuf *m, struct socke
 	struct ifnet *oifp = NULL;
 	int type, code;		/* for ICMPv6 output statistics only */
 	int scope_ambiguous = 0;
-	struct in6_addr *in6a;
 	int bound = curlwp_bind();
 	struct psref psref;
 
@@ -448,13 +447,10 @@ rip6_output(struct mbuf *m, struct socke
 	/*
 	 * Source address selection.
 	 */
-	if ((in6a = in6_selectsrc(dstsock, optp, in6p->in6p_moptions,
-	    &in6p->in6p_route, &in6p->in6p_laddr, &oifp, &psref, &error)) == 0) {
-		if (error == 0)
-			error = EADDRNOTAVAIL;
+	error = in6_selectsrc(dstsock, optp, in6p->in6p_moptions,
+	    &in6p->in6p_route, &in6p->in6p_laddr, &oifp, &psref, &ip6->ip6_src);
+	if (error != 0)
 		goto bad;
-	}
-	ip6->ip6_src = *in6a;
 
 	if (oifp && scope_ambiguous) {
 		/*
@@ -725,7 +721,7 @@ rip6_connect(struct socket *so, struct s
 {
 	struct in6pcb *in6p = sotoin6pcb(so);
 	struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
-	struct in6_addr *in6a = NULL;
+	struct in6_addr in6a;
 	struct ifnet *ifp = NULL;
 	int scope_ambiguous = 0;
 	int error = 0;
@@ -756,20 +752,17 @@ rip6_connect(struct socket *so, struct s
 
 	bound = curlwp_bind();
 	/* Source address selection. XXX: need pcblookup? */
-	in6a = in6_selectsrc(addr, in6p->in6p_outputopts,
+	error = in6_selectsrc(addr, in6p->in6p_outputopts,
 	    in6p->in6p_moptions, &in6p->in6p_route,
-	    &in6p->in6p_laddr, &ifp, &psref, &error);
-	if (in6a == NULL) {
-		if (error == 0)
-			error = EADDRNOTAVAIL;
+	    &in6p->in6p_laddr, &ifp, &psref, &in6a);
+	if (error != 0)
 		goto out;
-	}
 	/* XXX: see above */
 	if (ifp && scope_ambiguous &&
 	    (error = in6_setscope(&addr->sin6_addr, ifp, NULL)) != 0) {
 		goto out;
 	}
-	in6p->in6p_laddr = *in6a;
+	in6p->in6p_laddr = in6a;
 	in6p->in6p_faddr = addr->sin6_addr;
 	soisconnected(so);
 out:

Index: src/sys/netinet6/udp6_output.c
diff -u src/sys/netinet6/udp6_output.c:1.53 src/sys/netinet6/udp6_output.c:1.54
--- src/sys/netinet6/udp6_output.c:1.53	Mon Aug  1 03:15:31 2016
+++ src/sys/netinet6/udp6_output.c	Mon Oct 31 04:16:25 2016
@@ -1,4 +1,4 @@
-/*	$NetBSD: udp6_output.c,v 1.53 2016/08/01 03:15:31 ozaki-r Exp $	*/
+/*	$NetBSD: udp6_output.c,v 1.54 2016/10/31 04:16:25 ozaki-r Exp $	*/
 /*	$KAME: udp6_output.c,v 1.43 2001/10/15 09:19:52 itojun Exp $	*/
 
 /*
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.53 2016/08/01 03:15:31 ozaki-r Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udp6_output.c,v 1.54 2016/10/31 04:16:25 ozaki-r Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_inet.h"
@@ -120,7 +120,7 @@ udp6_output(struct in6pcb * const in6p, 
 	u_int32_t plen = sizeof(struct udphdr) + ulen;
 	struct ip6_hdr *ip6;
 	struct udphdr *udp6;
-	struct in6_addr *laddr, *faddr;
+	struct in6_addr _laddr, *laddr, *faddr;
 	struct in6_addr laddr_mapped; /* XXX ugly */
 	struct sockaddr_in6 *sin6 = NULL;
 	struct ifnet *oifp = NULL;
@@ -229,10 +229,11 @@ udp6_output(struct in6pcb * const in6p, 
 			struct psref psref;
 			int bound = curlwp_bind();
 
-			laddr = in6_selectsrc(sin6, optp,
+			error = in6_selectsrc(sin6, optp,
 			    in6p->in6p_moptions,
 			    &in6p->in6p_route,
-			    &in6p->in6p_laddr, &oifp, &psref, &error);
+			    &in6p->in6p_laddr, &oifp, &psref, &_laddr);
+			/* XXX need error check? */
 			if (oifp && scope_ambiguous &&
 			    (error = in6_setscope(&sin6->sin6_addr,
 			    oifp, NULL))) {
@@ -242,6 +243,7 @@ udp6_output(struct in6pcb * const in6p, 
 			}
 			if_put(oifp, &psref);
 			curlwp_bindx(bound);
+			laddr = &_laddr;
 		} else {
 			/*
 			 * XXX: freebsd[34] does not have in_selectsrc, but

Reply via email to