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 -0000       1.25
> +++ in6_src.c 7 Aug 2011 15:51:30 -0000
> @@ -86,6 +86,8 @@
>  #include <netinet6/ip6_var.h>
>  #include <netinet6/nd6.h>
>  
> +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

Reply via email to