mirror of
https://github.com/opnsense/src.git
synced 2026-06-09 00:32:25 -04:00
Make callers to in6_selectsrc() and in6_pcbladdr() pass in memory
to save the selected source address rather than returning an unreferenced copy to a pointer that might long be gone by the time we use the pointer for anything meaningful. Asked for by: rwatson Reviewed by: rwatson
This commit is contained in:
parent
9e9be26906
commit
88d166bf19
9 changed files with 87 additions and 92 deletions
|
|
@ -1137,7 +1137,7 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
|||
struct socket *so = inp->inp_socket;
|
||||
INIT_VNET_INET(so->so_vnet);
|
||||
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
|
||||
struct in6_addr *addr6;
|
||||
struct in6_addr addr6;
|
||||
int error;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(&V_tcbinfo);
|
||||
|
|
@ -1161,13 +1161,13 @@ tcp6_connect(struct tcpcb *tp, struct sockaddr *nam, struct thread *td)
|
|||
oinp = in6_pcblookup_hash(inp->inp_pcbinfo,
|
||||
&sin6->sin6_addr, sin6->sin6_port,
|
||||
IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
|
||||
? addr6
|
||||
? &addr6
|
||||
: &inp->in6p_laddr,
|
||||
inp->inp_lport, 0, NULL);
|
||||
if (oinp)
|
||||
return EADDRINUSE;
|
||||
if (IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr))
|
||||
inp->in6p_laddr = *addr6;
|
||||
inp->in6p_laddr = addr6;
|
||||
inp->in6p_faddr = sin6->sin6_addr;
|
||||
inp->inp_fport = sin6->sin6_port;
|
||||
/* update flowinfo - draft-itojun-ipv6-flowlabel-api-00 */
|
||||
|
|
|
|||
|
|
@ -2080,7 +2080,7 @@ icmp6_reflect(struct mbuf *m, size_t off)
|
|||
int plen;
|
||||
int type, code;
|
||||
struct ifnet *outif = NULL;
|
||||
struct in6_addr origdst, *src = NULL;
|
||||
struct in6_addr origdst, src, *srcp = NULL;
|
||||
|
||||
/* too short to reflect */
|
||||
if (off < sizeof(struct ip6_hdr)) {
|
||||
|
|
@ -2148,7 +2148,7 @@ icmp6_reflect(struct mbuf *m, size_t off)
|
|||
if ((ia = ip6_getdstifaddr(m))) {
|
||||
if (!(ia->ia6_flags &
|
||||
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY)))
|
||||
src = &ia->ia_addr.sin6_addr;
|
||||
srcp = &ia->ia_addr.sin6_addr;
|
||||
} else {
|
||||
struct sockaddr_in6 d;
|
||||
|
||||
|
|
@ -2161,12 +2161,12 @@ icmp6_reflect(struct mbuf *m, size_t off)
|
|||
if (ia &&
|
||||
!(ia->ia6_flags &
|
||||
(IN6_IFF_ANYCAST|IN6_IFF_NOTREADY))) {
|
||||
src = &ia->ia_addr.sin6_addr;
|
||||
srcp = &ia->ia_addr.sin6_addr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (src == NULL) {
|
||||
if (srcp == NULL) {
|
||||
int e;
|
||||
struct sockaddr_in6 sin6;
|
||||
struct route_in6 ro;
|
||||
|
|
@ -2182,10 +2182,10 @@ icmp6_reflect(struct mbuf *m, size_t off)
|
|||
sin6.sin6_addr = ip6->ip6_dst; /* zone ID should be embedded */
|
||||
|
||||
bzero(&ro, sizeof(ro));
|
||||
src = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, &outif, &e);
|
||||
e = in6_selectsrc(&sin6, NULL, NULL, &ro, NULL, &outif, &src);
|
||||
if (ro.ro_rt)
|
||||
RTFREE(ro.ro_rt); /* XXX: we could use this */
|
||||
if (src == NULL) {
|
||||
if (e) {
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
nd6log((LOG_DEBUG,
|
||||
"icmp6_reflect: source can't be determined: "
|
||||
|
|
@ -2193,9 +2193,10 @@ icmp6_reflect(struct mbuf *m, size_t off)
|
|||
ip6_sprintf(ip6buf, &sin6.sin6_addr), e));
|
||||
goto bad;
|
||||
}
|
||||
srcp = &src;
|
||||
}
|
||||
|
||||
ip6->ip6_src = *src;
|
||||
ip6->ip6_src = *srcp;
|
||||
ip6->ip6_flow = 0;
|
||||
ip6->ip6_vfc &= ~IPV6_VERSION_MASK;
|
||||
ip6->ip6_vfc |= IPV6_VERSION;
|
||||
|
|
|
|||
|
|
@ -289,13 +289,14 @@ in6_pcbbind(register struct inpcb *inp, struct sockaddr *nam,
|
|||
*/
|
||||
int
|
||||
in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
|
||||
struct in6_addr **plocal_addr6)
|
||||
struct in6_addr *plocal_addr6)
|
||||
{
|
||||
INIT_VNET_INET6(inp->inp_vnet);
|
||||
register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
|
||||
int error = 0;
|
||||
struct ifnet *ifp = NULL;
|
||||
int scope_ambiguous = 0;
|
||||
struct in6_addr in6a;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
INP_WLOCK_ASSERT(inp);
|
||||
|
|
@ -323,25 +324,25 @@ in6_pcbladdr(register struct inpcb *inp, struct sockaddr *nam,
|
|||
if ((error = prison_remote_ip6(inp->inp_cred, &sin6->sin6_addr)) != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* XXX: in6_selectsrc might replace the bound local address
|
||||
* with the address specified by setsockopt(IPV6_PKTINFO).
|
||||
* Is it the intended behavior?
|
||||
*/
|
||||
*plocal_addr6 = in6_selectsrc(sin6, inp->in6p_outputopts,
|
||||
inp, NULL,
|
||||
inp->inp_cred,
|
||||
&ifp, &error);
|
||||
error = in6_selectsrc(sin6, inp->in6p_outputopts,
|
||||
inp, NULL, inp->inp_cred, &ifp, &in6a);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
if (ifp && scope_ambiguous &&
|
||||
(error = in6_setscope(&sin6->sin6_addr, ifp, NULL)) != 0) {
|
||||
return(error);
|
||||
}
|
||||
|
||||
if (*plocal_addr6 == NULL) {
|
||||
if (error == 0)
|
||||
error = EADDRNOTAVAIL;
|
||||
return (error);
|
||||
}
|
||||
/*
|
||||
* Do not update this earlier, in case we return with an error.
|
||||
*
|
||||
* XXX: this in6_selectsrc result might replace the bound local
|
||||
* aaddress with the address specified by setsockopt(IPV6_PKTINFO).
|
||||
* Is it the intended behavior?
|
||||
*/
|
||||
*plocal_addr6 = in6a;
|
||||
|
||||
/*
|
||||
* Don't do pcblookup call here; return interface in
|
||||
* plocal_addr6
|
||||
|
|
@ -362,8 +363,8 @@ int
|
|||
in6_pcbconnect(register struct inpcb *inp, struct sockaddr *nam,
|
||||
struct ucred *cred)
|
||||
{
|
||||
struct in6_addr *addr6;
|
||||
register struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)nam;
|
||||
struct in6_addr addr6;
|
||||
int error;
|
||||
|
||||
INP_INFO_WLOCK_ASSERT(inp->inp_pcbinfo);
|
||||
|
|
@ -379,7 +380,7 @@ in6_pcbconnect(register struct inpcb *inp, struct sockaddr *nam,
|
|||
if (in6_pcblookup_hash(inp->inp_pcbinfo, &sin6->sin6_addr,
|
||||
sin6->sin6_port,
|
||||
IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)
|
||||
? addr6 : &inp->in6p_laddr,
|
||||
? &addr6 : &inp->in6p_laddr,
|
||||
inp->inp_lport, 0, NULL) != NULL) {
|
||||
return (EADDRINUSE);
|
||||
}
|
||||
|
|
@ -389,7 +390,7 @@ in6_pcbconnect(register struct inpcb *inp, struct sockaddr *nam,
|
|||
if (error)
|
||||
return (error);
|
||||
}
|
||||
inp->in6p_laddr = *addr6;
|
||||
inp->in6p_laddr = addr6;
|
||||
}
|
||||
inp->in6p_faddr = sin6->sin6_addr;
|
||||
inp->inp_fport = sin6->sin6_port;
|
||||
|
|
|
|||
|
|
@ -74,8 +74,7 @@ void in6_losing __P((struct inpcb *));
|
|||
int in6_pcbbind __P((struct inpcb *, struct sockaddr *, struct ucred *));
|
||||
int in6_pcbconnect __P((struct inpcb *, struct sockaddr *, struct ucred *));
|
||||
void in6_pcbdisconnect __P((struct inpcb *));
|
||||
int in6_pcbladdr __P((struct inpcb *, struct sockaddr *,
|
||||
struct in6_addr **));
|
||||
int in6_pcbladdr(struct inpcb *, struct sockaddr *, struct in6_addr *);
|
||||
struct inpcb *
|
||||
in6_pcblookup_local __P((struct inpcbinfo *,
|
||||
struct in6_addr *, u_short, int,
|
||||
|
|
|
|||
|
|
@ -179,10 +179,10 @@ static struct in6_addrpolicy *match_addrsel_policy(struct sockaddr_in6 *);
|
|||
goto out; /* XXX: we can't use 'break' here */ \
|
||||
} while(0)
|
||||
|
||||
struct in6_addr *
|
||||
int
|
||||
in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
||||
struct inpcb *inp, struct route_in6 *ro, struct ucred *cred,
|
||||
struct ifnet **ifpp, int *errorp)
|
||||
struct ifnet **ifpp, struct in6_addr *srcp)
|
||||
{
|
||||
INIT_VNET_INET6(curvnet);
|
||||
struct in6_addr dst;
|
||||
|
|
@ -193,10 +193,12 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
|||
struct in6_addrpolicy *dst_policy = NULL, *best_policy = NULL;
|
||||
u_int32_t odstzone;
|
||||
int prefer_tempaddr;
|
||||
int error;
|
||||
struct ip6_moptions *mopts;
|
||||
|
||||
KASSERT(srcp != NULL, ("%s: srcp is NULL", __func__));
|
||||
|
||||
dst = dstsock->sin6_addr; /* make a copy for local operation */
|
||||
*errorp = 0;
|
||||
if (ifpp)
|
||||
*ifpp = NULL;
|
||||
|
||||
|
|
@ -219,10 +221,8 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
|||
struct in6_ifaddr *ia6;
|
||||
|
||||
/* get the outgoing interface */
|
||||
if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp))
|
||||
!= 0) {
|
||||
return (NULL);
|
||||
}
|
||||
if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* determine the appropriate zone id of the source based on
|
||||
|
|
@ -236,14 +236,14 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
|||
srcsock.sin6_len = sizeof(srcsock);
|
||||
srcsock.sin6_addr = pi->ipi6_addr;
|
||||
if (ifp) {
|
||||
*errorp = in6_setscope(&srcsock.sin6_addr, ifp, NULL);
|
||||
if (*errorp != 0)
|
||||
return (NULL);
|
||||
error = in6_setscope(&srcsock.sin6_addr, ifp, NULL);
|
||||
if (error)
|
||||
return (error);
|
||||
}
|
||||
if (cred != NULL && (*errorp = prison_local_ip6(cred,
|
||||
if (cred != NULL && (error = prison_local_ip6(cred,
|
||||
&srcsock.sin6_addr, (inp != NULL &&
|
||||
(inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0)
|
||||
return (NULL);
|
||||
return (error);
|
||||
|
||||
ia6 = (struct in6_ifaddr *)ifa_ifwithaddr(
|
||||
(struct sockaddr *)&srcsock);
|
||||
|
|
@ -251,21 +251,14 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
|||
(ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
|
||||
if (ia6 != NULL)
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
*errorp = EADDRNOTAVAIL;
|
||||
return (NULL);
|
||||
return (EADDRNOTAVAIL);
|
||||
}
|
||||
pi->ipi6_addr = srcsock.sin6_addr; /* XXX: this overrides pi */
|
||||
if (ifpp)
|
||||
*ifpp = ifp;
|
||||
|
||||
/*
|
||||
* XXXRW: This returns a pointer into a structure with no
|
||||
* refcount. in6_selectsrc() should return it to caller-
|
||||
* provided memory using call-by-reference rather than
|
||||
* returning pointers into other memory.
|
||||
*/
|
||||
bcopy(&ia6->ia_addr.sin6_addr, srcp, sizeof(*srcp));
|
||||
ifa_free(&ia6->ia_ifa);
|
||||
return (&ia6->ia_addr.sin6_addr);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -273,10 +266,11 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
|||
*/
|
||||
if (inp != NULL && !IN6_IS_ADDR_UNSPECIFIED(&inp->in6p_laddr)) {
|
||||
if (cred != NULL &&
|
||||
(*errorp = prison_local_ip6(cred, &inp->in6p_laddr,
|
||||
(error = prison_local_ip6(cred, &inp->in6p_laddr,
|
||||
((inp->inp_flags & IN6P_IPV6_V6ONLY) != 0))) != 0)
|
||||
return (NULL);
|
||||
return (&inp->in6p_laddr);
|
||||
return (error);
|
||||
bcopy(&inp->in6p_laddr, srcp, sizeof(*srcp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -284,16 +278,16 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
|||
* the outgoing interface and the destination address.
|
||||
*/
|
||||
/* get the outgoing interface */
|
||||
if ((*errorp = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
|
||||
return (NULL);
|
||||
if ((error = in6_selectif(dstsock, opts, mopts, ro, &ifp)) != 0)
|
||||
return (error);
|
||||
|
||||
#ifdef DIAGNOSTIC
|
||||
if (ifp == NULL) /* this should not happen */
|
||||
panic("in6_selectsrc: NULL ifp");
|
||||
#endif
|
||||
*errorp = in6_setscope(&dst, ifp, &odstzone);
|
||||
if (*errorp != 0)
|
||||
return (NULL);
|
||||
error = in6_setscope(&dst, ifp, &odstzone);
|
||||
if (error)
|
||||
return (error);
|
||||
|
||||
for (ia = V_in6_ifaddr; ia; ia = ia->ia_next) {
|
||||
int new_scope = -1, new_matchlen = -1;
|
||||
|
|
@ -472,15 +466,14 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
|
|||
break;
|
||||
}
|
||||
|
||||
if ((ia = ia_best) == NULL) {
|
||||
*errorp = EADDRNOTAVAIL;
|
||||
return (NULL);
|
||||
}
|
||||
if ((ia = ia_best) == NULL)
|
||||
return (EADDRNOTAVAIL);
|
||||
|
||||
if (ifpp)
|
||||
*ifpp = ifp;
|
||||
|
||||
return (&ia->ia_addr.sin6_addr);
|
||||
bcopy(&ia->ia_addr.sin6_addr, srcp, sizeof(*srcp));
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -402,9 +402,9 @@ int rip6_usrreq __P((struct socket *,
|
|||
int dest6_input __P((struct mbuf **, int *, int));
|
||||
int none_input __P((struct mbuf **, int *, int));
|
||||
|
||||
struct in6_addr *in6_selectsrc __P((struct sockaddr_in6 *, struct ip6_pktopts *,
|
||||
int in6_selectsrc(struct sockaddr_in6 *, struct ip6_pktopts *,
|
||||
struct inpcb *inp, struct route_in6 *, struct ucred *cred,
|
||||
struct ifnet **, int *));
|
||||
struct ifnet **, struct in6_addr *);
|
||||
int in6_selectroute __P((struct sockaddr_in6 *, struct ip6_pktopts *,
|
||||
struct ip6_moptions *, struct route_in6 *, struct ifnet **,
|
||||
struct rtentry **));
|
||||
|
|
|
|||
|
|
@ -505,9 +505,9 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
|
|||
dst_sa.sin6_len = sizeof(dst_sa);
|
||||
dst_sa.sin6_addr = ip6->ip6_dst;
|
||||
|
||||
src = in6_selectsrc(&dst_sa, NULL,
|
||||
NULL, &ro, NULL, NULL, &error);
|
||||
if (src == NULL) {
|
||||
error = in6_selectsrc(&dst_sa, NULL,
|
||||
NULL, &ro, NULL, NULL, &src_in);
|
||||
if (error) {
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
nd6log((LOG_DEBUG,
|
||||
"nd6_ns_output: source can't be "
|
||||
|
|
@ -516,6 +516,7 @@ nd6_ns_output(struct ifnet *ifp, const struct in6_addr *daddr6,
|
|||
error));
|
||||
goto bad;
|
||||
}
|
||||
src = &src_in;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
|
@ -933,7 +934,7 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
|
|||
struct ip6_hdr *ip6;
|
||||
struct nd_neighbor_advert *nd_na;
|
||||
struct ip6_moptions im6o;
|
||||
struct in6_addr *src, daddr6;
|
||||
struct in6_addr src, daddr6;
|
||||
struct sockaddr_in6 dst_sa;
|
||||
int icmp6len, maxlen, error;
|
||||
caddr_t mac = NULL;
|
||||
|
|
@ -1006,15 +1007,15 @@ nd6_na_output(struct ifnet *ifp, const struct in6_addr *daddr6_0,
|
|||
* Select a source whose scope is the same as that of the dest.
|
||||
*/
|
||||
bcopy(&dst_sa, &ro.ro_dst, sizeof(dst_sa));
|
||||
src = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, NULL, &error);
|
||||
if (src == NULL) {
|
||||
error = in6_selectsrc(&dst_sa, NULL, NULL, &ro, NULL, NULL, &src);
|
||||
if (error) {
|
||||
char ip6buf[INET6_ADDRSTRLEN];
|
||||
nd6log((LOG_DEBUG, "nd6_na_output: source can't be "
|
||||
"determined: dst=%s, error=%d\n",
|
||||
ip6_sprintf(ip6buf, &dst_sa.sin6_addr), error));
|
||||
goto bad;
|
||||
}
|
||||
ip6->ip6_src = *src;
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -389,7 +389,7 @@ rip6_output(m, va_alist)
|
|||
struct ifnet *oifp = NULL;
|
||||
int type = 0, code = 0; /* for ICMPv6 output statistics only */
|
||||
int scope_ambiguous = 0;
|
||||
struct in6_addr *in6a;
|
||||
struct in6_addr in6a;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, m);
|
||||
|
|
@ -450,16 +450,14 @@ rip6_output(m, va_alist)
|
|||
/*
|
||||
* Source address selection.
|
||||
*/
|
||||
if ((in6a = in6_selectsrc(dstsock, optp, in6p, NULL, so->so_cred,
|
||||
&oifp, &error)) == NULL) {
|
||||
if (error == 0)
|
||||
error = EADDRNOTAVAIL;
|
||||
error = in6_selectsrc(dstsock, optp, in6p, NULL, so->so_cred,
|
||||
&oifp, &in6a);
|
||||
if (error)
|
||||
goto bad;
|
||||
}
|
||||
error = prison_get_ip6(in6p->inp_cred, in6a);
|
||||
error = prison_get_ip6(in6p->inp_cred, &in6a);
|
||||
if (error != 0)
|
||||
goto bad;
|
||||
ip6->ip6_src = *in6a;
|
||||
ip6->ip6_src = in6a;
|
||||
|
||||
if (oifp && scope_ambiguous) {
|
||||
/*
|
||||
|
|
@ -757,7 +755,7 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
|||
INIT_VNET_INET6(so->so_vnet);
|
||||
struct inpcb *inp;
|
||||
struct sockaddr_in6 *addr = (struct sockaddr_in6 *)nam;
|
||||
struct in6_addr *in6a = NULL;
|
||||
struct in6_addr in6a;
|
||||
struct ifnet *ifp = NULL;
|
||||
int error = 0, scope_ambiguous = 0;
|
||||
|
||||
|
|
@ -787,13 +785,12 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
|||
INP_INFO_WLOCK(&V_ripcbinfo);
|
||||
INP_WLOCK(inp);
|
||||
/* Source address selection. XXX: need pcblookup? */
|
||||
in6a = in6_selectsrc(addr, inp->in6p_outputopts,
|
||||
inp, NULL, so->so_cred,
|
||||
&ifp, &error);
|
||||
if (in6a == NULL) {
|
||||
error = in6_selectsrc(addr, inp->in6p_outputopts,
|
||||
inp, NULL, so->so_cred, &ifp, &in6a);
|
||||
if (error) {
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_ripcbinfo);
|
||||
return (error ? error : EADDRNOTAVAIL);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/* XXX: see above */
|
||||
|
|
@ -804,7 +801,7 @@ rip6_connect(struct socket *so, struct sockaddr *nam, struct thread *td)
|
|||
return (error);
|
||||
}
|
||||
inp->in6p_faddr = addr->sin6_addr;
|
||||
inp->in6p_laddr = *in6a;
|
||||
inp->in6p_laddr = in6a;
|
||||
soisconnected(so);
|
||||
INP_WUNLOCK(inp);
|
||||
INP_INFO_WUNLOCK(&V_ripcbinfo);
|
||||
|
|
|
|||
|
|
@ -552,7 +552,7 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
|
|||
u_int32_t plen = sizeof(struct udphdr) + ulen;
|
||||
struct ip6_hdr *ip6;
|
||||
struct udphdr *udp6;
|
||||
struct in6_addr *laddr, *faddr;
|
||||
struct in6_addr *laddr, *faddr, in6a;
|
||||
struct sockaddr_in6 *sin6 = NULL;
|
||||
struct ifnet *oifp = NULL;
|
||||
int scope_ambiguous = 0;
|
||||
|
|
@ -650,13 +650,16 @@ udp6_output(struct inpcb *inp, struct mbuf *m, struct sockaddr *addr6,
|
|||
}
|
||||
|
||||
if (!IN6_IS_ADDR_V4MAPPED(faddr)) {
|
||||
laddr = in6_selectsrc(sin6, optp, inp, NULL,
|
||||
td->td_ucred, &oifp, &error);
|
||||
error = in6_selectsrc(sin6, optp, inp, NULL,
|
||||
td->td_ucred, &oifp, &in6a);
|
||||
if (error)
|
||||
goto release;
|
||||
if (oifp && scope_ambiguous &&
|
||||
(error = in6_setscope(&sin6->sin6_addr,
|
||||
oifp, NULL))) {
|
||||
goto release;
|
||||
}
|
||||
laddr = &in6a;
|
||||
} else
|
||||
laddr = &inp->in6p_laddr; /* XXX */
|
||||
if (laddr == NULL) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue