Re: Assigning source addresses with IPV6_PKTINFO

2011-08-07 Thread Alexander Bluhm
On Sun, Aug 07, 2011 at 06:05:56PM +0200, Mike Belopuhov wrote:
> updated diff

ok bluhm@

> 
> Index: in6_src.c
> ===
> RCS file: /cvs/src/sys/netinet6/in6_src.c,v
> retrieving revision 1.25
> diff -u -p -u -p -r1.25 in6_src.c
> --- in6_src.c 7 May 2010 13:33:17 -   1.25
> +++ in6_src.c 7 Aug 2011 15:51:30 -
> @@ -86,6 +86,8 @@
>  #include 
>  #include 
>  
> +int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *,
> +struct ip6_moptions *, struct route_in6 *, struct ifnet **);
>  int selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
>  struct ip6_moptions *, struct route_in6 *, struct ifnet **,
>  struct rtentry **, int);
> @@ -110,11 +112,40 @@ in6_selectsrc(struct sockaddr_in6 *dstso
>  
>   /*
>* If the source address is explicitly specified by the caller,
> -  * use it.
> +  * check if the requested source address is indeed a unicast address
> +  * assigned to the node, and can be used as the packet's source
> +  * address.  If everything is okay, use the address as source.
>*/
>   if (opts && (pi = opts->ip6po_pktinfo) &&
> - !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
> + !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
> + struct ifnet *ifp = NULL;
> + struct sockaddr_in6 sa6;
> +
> + /* get the outgoing interface */
> + if ((*errorp = in6_selectif(dstsock, opts, mopts, ro,
> + &ifp)) != 0)
> + return (NULL);
> +
> + bzero(&sa6, sizeof(sa6));
> + sa6.sin6_family = AF_INET6;
> + sa6.sin6_len = sizeof(sa6);
> + sa6.sin6_addr = pi->ipi6_addr;
> +
> + if (ifp && IN6_IS_SCOPE_EMBED(&sa6.sin6_addr))
> + sa6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
> +
> + ia6 = (struct in6_ifaddr *)
> + ifa_ifwithaddr((struct sockaddr *)&sa6, 0);
> + if (ia6 == NULL ||
> + (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
> + *errorp = EADDRNOTAVAIL;
> + return (NULL);
> + }
> +
> + pi->ipi6_addr = sa6.sin6_addr; /* XXX: this overrides pi */
> +
>   return (&pi->ipi6_addr);
> + }
>  
>   /*
>* If the source address is not specified but the socket(if any)
> @@ -480,6 +511,50 @@ selectroute(struct sockaddr_in6 *dstsock
>   *retrt = rt;/* rt may be NULL */
>  
>   return (error);
> +}
> +
> +int
> +in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
> +struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp)
> +{
> + struct rtentry *rt = NULL;
> + int error;
> +
> + if ((error = selectroute(dstsock, opts, mopts, ro, retifp,
> + &rt, 1)) != 0)
> + return (error);
> +
> + /*
> +  * do not use a rejected or black hole route.
> +  * XXX: this check should be done in the L2 output routine.
> +  * However, if we skipped this check here, we'd see the following
> +  * scenario:
> +  * - install a rejected route for a scoped address prefix
> +  *   (like fe80::/10)
> +  * - send a packet to a destination that matches the scoped prefix,
> +  *   with ambiguity about the scope zone.
> +  * - pick the outgoing interface from the route, and disambiguate the
> +  *   scope zone with the interface.
> +  * - ip6_output() would try to get another route with the "new"
> +  *   destination, which may be valid.
> +  * - we'd see no error on output.
> +  * Although this may not be very harmful, it should still be confusing.
> +  * We thus reject the case here.
> +  */
> + if (rt && (rt->rt_flags & (RTF_REJECT | RTF_BLACKHOLE)))
> + return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH);
> +
> + /*
> +  * Adjust the "outgoing" interface.  If we're going to loop the packet
> +  * back to ourselves, the ifp would be the loopback interface.
> +  * However, we'd rather know the interface associated to the
> +  * destination address (which should probably be one of our own
> +  * addresses.)
> +  */
> + if (rt && rt->rt_ifa && rt->rt_ifa->ifa_ifp)
> + *retifp = rt->rt_ifa->ifa_ifp;
> +
> + return (0);
>  }
>  
>  int



Re: Assigning source addresses with IPV6_PKTINFO

2011-08-07 Thread Mike Belopuhov
On Sat, Aug 06, 2011 at 20:05 +0200, Alexander Bluhm wrote:
> On Fri, Aug 05, 2011 at 08:19:21PM +0200, Mike Belopuhov wrote:
> > opinions?
> 
> Although there are other opinions, I think we should not reinvent
> the wheel and use KAME where apropiate.  So we should go this way.
> 
> > +   if (ifp && !(ifp->if_flags & IFF_LOOPBACK))
> > +   sa6.sin6_addr.s6_addr16[1] =
> > +   htons(in6_addr2scopeid(ifp, &sa6.sin6_addr));
> 
> I think this sets the scope id also for global addresses.

no, it sets it only for IPV6_ADDR_SCOPE_INTFACELOCAL and
IPV6_ADDR_SCOPE_LINKLOCAL.

> Should this be more like the code in ip6_input()?
> 
>   if (ifp && IN6_IS_SCOPE_EMBED(&sa6.sin6_addr))
>   sa6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
> 

i think it's essentially the same, except that i don't need
to special case the loopback perhaps...

> > +   pi->ipi6_addr = sa6.sin6_addr; /* XXX: this overrides pi */
> > +
> > return (&pi->ipi6_addr);
> 
> Do you know, why KAME returns &ia6->ia_addr.sin6_addr?
> It is more conservative to keep the code we have, so that is fine.
> 

it doesn't matter what to return, they're equal.

> > +   clone = IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) ? 0 : 1;
> > +   if ((error = selectroute(dstsock, opts, mopts, ro, retifp,
> > +   &rt, clone)) != 0)
> 
> Our selectroute() function is missing the clone paramter, not the
> norouteok.  So you should pass 1 as last argument.
> 

true.

> bluhm

updated diff

Index: in6_src.c
===
RCS file: /cvs/src/sys/netinet6/in6_src.c,v
retrieving revision 1.25
diff -u -p -u -p -r1.25 in6_src.c
--- in6_src.c   7 May 2010 13:33:17 -   1.25
+++ in6_src.c   7 Aug 2011 15:51:30 -
@@ -86,6 +86,8 @@
 #include 
 #include 
 
+int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *,
+struct ip6_moptions *, struct route_in6 *, struct ifnet **);
 int selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
 struct ip6_moptions *, struct route_in6 *, struct ifnet **,
 struct rtentry **, int);
@@ -110,11 +112,40 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 
/*
 * If the source address is explicitly specified by the caller,
-* use it.
+* check if the requested source address is indeed a unicast address
+* assigned to the node, and can be used as the packet's source
+* address.  If everything is okay, use the address as source.
 */
if (opts && (pi = opts->ip6po_pktinfo) &&
-   !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
+   !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
+   struct ifnet *ifp = NULL;
+   struct sockaddr_in6 sa6;
+
+   /* get the outgoing interface */
+   if ((*errorp = in6_selectif(dstsock, opts, mopts, ro,
+   &ifp)) != 0)
+   return (NULL);
+
+   bzero(&sa6, sizeof(sa6));
+   sa6.sin6_family = AF_INET6;
+   sa6.sin6_len = sizeof(sa6);
+   sa6.sin6_addr = pi->ipi6_addr;
+
+   if (ifp && IN6_IS_SCOPE_EMBED(&sa6.sin6_addr))
+   sa6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
+
+   ia6 = (struct in6_ifaddr *)
+   ifa_ifwithaddr((struct sockaddr *)&sa6, 0);
+   if (ia6 == NULL ||
+   (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
+   *errorp = EADDRNOTAVAIL;
+   return (NULL);
+   }
+
+   pi->ipi6_addr = sa6.sin6_addr; /* XXX: this overrides pi */
+
return (&pi->ipi6_addr);
+   }
 
/*
 * If the source address is not specified but the socket(if any)
@@ -480,6 +511,50 @@ selectroute(struct sockaddr_in6 *dstsock
*retrt = rt;/* rt may be NULL */
 
return (error);
+}
+
+int
+in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
+struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp)
+{
+   struct rtentry *rt = NULL;
+   int error;
+
+   if ((error = selectroute(dstsock, opts, mopts, ro, retifp,
+   &rt, 1)) != 0)
+   return (error);
+
+   /*
+* do not use a rejected or black hole route.
+* XXX: this check should be done in the L2 output routine.
+* However, if we skipped this check here, we'd see the following
+* scenario:
+* - install a rejected route for a scoped address prefix
+*   (like fe80::/10)
+* - send a packet to a destination that matches the scoped prefix,
+*   with ambiguity about the scope zone.
+* - pick the outgoing interface from the route, and disambiguate the
+*   scope zone with the interface.
+* - ip6_output() would try to get another route with the "new"
+*

Re: Assigning source addresses with IPV6_PKTINFO

2011-08-06 Thread Alexander Bluhm
On Fri, Aug 05, 2011 at 08:19:21PM +0200, Mike Belopuhov wrote:
> opinions?

Although there are other opinions, I think we should not reinvent
the wheel and use KAME where apropiate.  So we should go this way.

> + if (ifp && !(ifp->if_flags & IFF_LOOPBACK))
> + sa6.sin6_addr.s6_addr16[1] =
> + htons(in6_addr2scopeid(ifp, &sa6.sin6_addr));

I think this sets the scope id also for global addresses.  Should
this be more like the code in ip6_input()?

if (ifp && IN6_IS_SCOPE_EMBED(&sa6.sin6_addr))
sa6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);

> + pi->ipi6_addr = sa6.sin6_addr; /* XXX: this overrides pi */
> +
>   return (&pi->ipi6_addr);

Do you know, why KAME returns &ia6->ia_addr.sin6_addr?
It is more conservative to keep the code we have, so that is fine.

> + clone = IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) ? 0 : 1;
> + if ((error = selectroute(dstsock, opts, mopts, ro, retifp,
> + &rt, clone)) != 0)

Our selectroute() function is missing the clone paramter, not the
norouteok.  So you should pass 1 as last argument.

bluhm



Re: Assigning source addresses with IPV6_PKTINFO

2011-08-05 Thread Mike Belopuhov
i've looked at it again and although it's a bit more involved,
it's better (it calles selectroute) than what i was going to
do by calling rtalloc in place in the other solution.

so just everyone understands, it works by figuring out the
destination interface (by looking at ipi6_ifindex or doing
an route lookup) and looking up the provided address in the
interface address tree.  if needed it embeds the scope from
the outgoing interface.  while doing that it does several
additional checks (route is available, address is unicast,
etc).

this fixes jeremy's test case and solves a bunch of problems
with assigning addresses that don't belong us.

opinions?

On Thu, Aug 04, 2011 at 23:29 +0200, Mike Belopuhov wrote:
> i saw what kame did.  be my guest and try to port that.
> 
> On Thu, Aug 4, 2011 at 11:23 PM, Alexander Bluhm
>  wrote:
> > On Thu, Aug 04, 2011 at 05:06:24PM +0200, Mike Belopuhov wrote:
> >> I'm not sure it's a desired behavior and afaik it's not possible
> >> to achieve this with IPv4 sockets without the need to be a root.
> >> Do we want to change that?
> >
> > Yes.  KAME fixed that, too.
> >
> >> The following change restricts it to the locally configured
> >> addresses.  Is it a way to go?
> >
> > I would prefer to take as much as possible from the KAME solution.
> > No need to introduce more differently implemented code.
> >
> > bluhm
> >

Index: in6_src.c
===
RCS file: /home/cvs/src/sys/netinet6/in6_src.c,v
retrieving revision 1.25
diff -u -p -u -p -r1.25 in6_src.c
--- in6_src.c   7 May 2010 13:33:17 -   1.25
+++ in6_src.c   5 Aug 2011 18:00:00 -
@@ -86,6 +86,8 @@
 #include 
 #include 
 
+int in6_selectif(struct sockaddr_in6 *, struct ip6_pktopts *,
+struct ip6_moptions *, struct route_in6 *, struct ifnet **);
 int selectroute(struct sockaddr_in6 *, struct ip6_pktopts *,
 struct ip6_moptions *, struct route_in6 *, struct ifnet **,
 struct rtentry **, int);
@@ -110,11 +112,41 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 
/*
 * If the source address is explicitly specified by the caller,
-* use it.
+* check if the requested source address is indeed a unicast address
+* assigned to the node, and can be used as the packet's source
+* address.  If everything is okay, use the address as source.
 */
if (opts && (pi = opts->ip6po_pktinfo) &&
-   !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
+   !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
+   struct ifnet *ifp = NULL;
+   struct sockaddr_in6 sa6;
+
+   /* get the outgoing interface */
+   if ((*errorp = in6_selectif(dstsock, opts, mopts, ro,
+   &ifp)) != 0)
+   return (NULL);
+
+   bzero(&sa6, sizeof(sa6));
+   sa6.sin6_family = AF_INET6;
+   sa6.sin6_len = sizeof(sa6);
+   sa6.sin6_addr = pi->ipi6_addr;
+
+   if (ifp && !(ifp->if_flags & IFF_LOOPBACK))
+   sa6.sin6_addr.s6_addr16[1] =
+   htons(in6_addr2scopeid(ifp, &sa6.sin6_addr));
+
+   ia6 = (struct in6_ifaddr *)
+   ifa_ifwithaddr((struct sockaddr *)&sa6, 0);
+   if (ia6 == NULL ||
+   (ia6->ia6_flags & (IN6_IFF_ANYCAST | IN6_IFF_NOTREADY))) {
+   *errorp = EADDRNOTAVAIL;
+   return (NULL);
+   }
+
+   pi->ipi6_addr = sa6.sin6_addr; /* XXX: this overrides pi */
+
return (&pi->ipi6_addr);
+   }
 
/*
 * If the source address is not specified but the socket(if any)
@@ -480,6 +512,51 @@ selectroute(struct sockaddr_in6 *dstsock
*retrt = rt;/* rt may be NULL */
 
return (error);
+}
+
+int
+in6_selectif(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts,
+struct ip6_moptions *mopts, struct route_in6 *ro, struct ifnet **retifp)
+{
+   int error, clone;
+   struct rtentry *rt = NULL;
+
+   clone = IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) ? 0 : 1;
+   if ((error = selectroute(dstsock, opts, mopts, ro, retifp,
+   &rt, clone)) != 0)
+   return (error);
+
+   /*
+* do not use a rejected or black hole route.
+* XXX: this check should be done in the L2 output routine.
+* However, if we skipped this check here, we'd see the following
+* scenario:
+* - install a rejected route for a scoped address prefix
+*   (like fe80::/10)
+* - send a packet to a destination that matches the scoped prefix,
+*   with ambiguity about the scope zone.
+* - pick the outgoing interface from the route, and disambiguate the
+*   scope zone with the interface.
+* - ip6_output() would try to get another route with the "new"
+*   destination, which may be valid.
+

Re: Assigning source addresses with IPV6_PKTINFO

2011-08-05 Thread Henning Brauer
* Claudio Jeker  [2011-08-05 08:46]:
> On Thu, Aug 04, 2011 at 11:23:44PM +0200, Alexander Bluhm wrote:
> > On Thu, Aug 04, 2011 at 05:06:24PM +0200, Mike Belopuhov wrote:
> > > I'm not sure it's a desired behavior and afaik it's not possible
> > > to achieve this with IPv4 sockets without the need to be a root.
> > > Do we want to change that?
> > 
> > Yes.  KAME fixed that, too.
> > 
> > > The following change restricts it to the locally configured
> > > addresses.  Is it a way to go?
> > 
> > I would prefer to take as much as possible from the KAME solution.
> > No need to introduce more differently implemented code.
> 
> Ugh, you want to take the zone crap from KAME? It is just yet another
> layer of steaming bullshit added on top of an already huge dunghill.

and, seriously, "don't diverge from KAME" is bullshit anyways, given
how much we diverged already.

-- 
Henning Brauer, h...@bsws.de, henn...@openbsd.org
BS Web Services, http://bsws.de
Full-Service ISP - Secure Hosting, Mail and DNS Services
Dedicated Servers, Rootservers, Application Hosting



Re: Assigning source addresses with IPV6_PKTINFO

2011-08-04 Thread Claudio Jeker
On Thu, Aug 04, 2011 at 11:23:44PM +0200, Alexander Bluhm wrote:
> On Thu, Aug 04, 2011 at 05:06:24PM +0200, Mike Belopuhov wrote:
> > I'm not sure it's a desired behavior and afaik it's not possible
> > to achieve this with IPv4 sockets without the need to be a root.
> > Do we want to change that?
> 
> Yes.  KAME fixed that, too.
> 
> > The following change restricts it to the locally configured
> > addresses.  Is it a way to go?
> 
> I would prefer to take as much as possible from the KAME solution.
> No need to introduce more differently implemented code.

Ugh, you want to take the zone crap from KAME? It is just yet another
layer of steaming bullshit added on top of an already huge dunghill.

-- 
:wq Claudio



Re: Assigning source addresses with IPV6_PKTINFO

2011-08-04 Thread Mike Belopuhov
On Thu, Aug 4, 2011 at 11:23 PM, Alexander Bluhm
 wrote:
> On Thu, Aug 04, 2011 at 05:06:24PM +0200, Mike Belopuhov wrote:
>> I'm not sure it's a desired behavior and afaik it's not possible
>> to achieve this with IPv4 sockets without the need to be a root.
>> Do we want to change that?
>
> Yes.  KAME fixed that, too.
>

and kame didn't fix all the problems.  it's still possible to inject
packets afaiu.

>> The following change restricts it to the locally configured
>> addresses.  Is it a way to go?
>
> I would prefer to take as much as possible from the KAME solution.
> No need to introduce more differently implemented code.
>
> bluhm



Re: Assigning source addresses with IPV6_PKTINFO

2011-08-04 Thread Mike Belopuhov
i saw what kame did.  be my guest and try to port that.

On Thu, Aug 4, 2011 at 11:23 PM, Alexander Bluhm
 wrote:
> On Thu, Aug 04, 2011 at 05:06:24PM +0200, Mike Belopuhov wrote:
>> I'm not sure it's a desired behavior and afaik it's not possible
>> to achieve this with IPv4 sockets without the need to be a root.
>> Do we want to change that?
>
> Yes.  KAME fixed that, too.
>
>> The following change restricts it to the locally configured
>> addresses.  Is it a way to go?
>
> I would prefer to take as much as possible from the KAME solution.
> No need to introduce more differently implemented code.
>
> bluhm



Re: Assigning source addresses with IPV6_PKTINFO

2011-08-04 Thread Alexander Bluhm
On Thu, Aug 04, 2011 at 05:06:24PM +0200, Mike Belopuhov wrote:
> I'm not sure it's a desired behavior and afaik it's not possible
> to achieve this with IPv4 sockets without the need to be a root.
> Do we want to change that?

Yes.  KAME fixed that, too.

> The following change restricts it to the locally configured
> addresses.  Is it a way to go?

I would prefer to take as much as possible from the KAME solution.
No need to introduce more differently implemented code.

bluhm



Re: Assigning source addresses with IPV6_PKTINFO

2011-08-04 Thread Mike Belopuhov
On Thu, Aug 04, 2011 at 17:06 +0200, Mike Belopuhov wrote:
> Hi,
> 
> Currently it's possible to assign *any* IPv6 source address to
> the datagram sent out by the unprivileged process by supplying
> a IPV6_PKTINFO control message to the sendmsg(2).
> 
> I'm not sure it's a desired behavior and afaik it's not possible
> to achieve this with IPv4 sockets without the need to be a root.
> Do we want to change that?
> 
> The following change restricts it to the locally configured
> addresses.  Is it a way to go?
> 
> Cheers!
> 

Considering all the pros and cons and what other operating systems
are doing this approach should be good enough for us at least at
this point.

OK? (with a s/IN6_IS_SCOPE_EMBED/IN6_IS_ADDR_LINKLOCAL/ fix)

> 
> Index: in6_src.c
> ===
> RCS file: /home/cvs/src/sys/netinet6/in6_src.c,v
> retrieving revision 1.25
> diff -u -p -u -p -r1.25 in6_src.c
> --- in6_src.c 7 May 2010 13:33:17 -   1.25
> +++ in6_src.c 4 Aug 2011 14:19:54 -
> @@ -113,8 +113,29 @@ in6_selectsrc(struct sockaddr_in6 *dstso
>* use it.
>*/
>   if (opts && (pi = opts->ip6po_pktinfo) &&
> - !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
> + !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
> + struct ifnet *ifp;
> +
> + if (IN6_IS_SCOPE_EMBED(&pi->ipi6_addr)) {

This has to be IN6_IS_ADDR_LINKLOCAL because multicast addresses
are prohibited by the RFC.

> + pi->ipi6_addr.s6_addr16[1] = htons(pi->ipi6_ifindex);
> + if (in6ifa_ifpwithaddr(ifindex2ifnet[pi->ipi6_ifindex],
> + &pi->ipi6_addr) == NULL) {
> + *errorp = EADDRNOTAVAIL;
> + return (NULL);
> + }
> + } else {
> + TAILQ_FOREACH(ifp, &ifnet, if_list) {
> + if ((ia6 = in6ifa_ifpwithaddr(ifp,
> + &pi->ipi6_addr)) != NULL)
> + break;
> + }
> + if (!ia6) {
> + *errorp = EADDRNOTAVAIL;
> + return (NULL);
> + }
> + }
>   return (&pi->ipi6_addr);
> + }
>  
>   /*
>* If the source address is not specified but the socket(if any)



Assigning source addresses with IPV6_PKTINFO

2011-08-04 Thread Mike Belopuhov
Hi,

Currently it's possible to assign *any* IPv6 source address to
the datagram sent out by the unprivileged process by supplying
a IPV6_PKTINFO control message to the sendmsg(2).

I'm not sure it's a desired behavior and afaik it's not possible
to achieve this with IPv4 sockets without the need to be a root.
Do we want to change that?

The following change restricts it to the locally configured
addresses.  Is it a way to go?

Cheers!


Index: in6_src.c
===
RCS file: /home/cvs/src/sys/netinet6/in6_src.c,v
retrieving revision 1.25
diff -u -p -u -p -r1.25 in6_src.c
--- in6_src.c   7 May 2010 13:33:17 -   1.25
+++ in6_src.c   4 Aug 2011 14:19:54 -
@@ -113,8 +113,29 @@ in6_selectsrc(struct sockaddr_in6 *dstso
 * use it.
 */
if (opts && (pi = opts->ip6po_pktinfo) &&
-   !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr))
+   !IN6_IS_ADDR_UNSPECIFIED(&pi->ipi6_addr)) {
+   struct ifnet *ifp;
+
+   if (IN6_IS_SCOPE_EMBED(&pi->ipi6_addr)) {
+   pi->ipi6_addr.s6_addr16[1] = htons(pi->ipi6_ifindex);
+   if (in6ifa_ifpwithaddr(ifindex2ifnet[pi->ipi6_ifindex],
+   &pi->ipi6_addr) == NULL) {
+   *errorp = EADDRNOTAVAIL;
+   return (NULL);
+   }
+   } else {
+   TAILQ_FOREACH(ifp, &ifnet, if_list) {
+   if ((ia6 = in6ifa_ifpwithaddr(ifp,
+   &pi->ipi6_addr)) != NULL)
+   break;
+   }
+   if (!ia6) {
+   *errorp = EADDRNOTAVAIL;
+   return (NULL);
+   }
+   }
return (&pi->ipi6_addr);
+   }
 
/*
 * If the source address is not specified but the socket(if any)