Author: ae
Date: Sun Aug  2 12:40:56 2015
New Revision: 286195
URL: https://svnweb.freebsd.org/changeset/base/286195

Log:
  Properly handle IPV6_NEXTHOP socket option in selectroute().
  
   o remove disabled code;
   o if nexthop address is link-local, use embedded scope zone id to
     determine outgoing interface;
   o properly fill ro_dst before doing route lookup;
   o remove LLE lookup, instead check rt_flags for RTF_GATEWAY bit.
  
  Sponsored by: Yandex LLC

Modified:
  head/sys/netinet6/in6_src.c

Modified: head/sys/netinet6/in6_src.c
==============================================================================
--- head/sys/netinet6/in6_src.c Sun Aug  2 11:58:24 2015        (r286194)
+++ head/sys/netinet6/in6_src.c Sun Aug  2 12:40:56 2015        (r286195)
@@ -616,77 +616,38 @@ selectroute(struct sockaddr_in6 *dstsock
         */
        if (opts && opts->ip6po_nexthop) {
                struct route_in6 *ron;
-               struct llentry *la;
-           
-               sin6_next = satosin6(opts->ip6po_nexthop);
-               
-               /* at this moment, we only support AF_INET6 next hops */
-               if (sin6_next->sin6_family != AF_INET6) {
-                       error = EAFNOSUPPORT; /* or should we proceed? */
-                       goto done;
-               }
-
-               /*
-                * If the next hop is an IPv6 address, then the node identified
-                * by that address must be a neighbor of the sending host.
-                */
-               ron = &opts->ip6po_nextroute;
-               /*
-                * XXX what do we do here?
-                * PLZ to be fixing
-                */
 
-
-               if (ron->ro_rt == NULL) {
-                       in6_rtalloc(ron, fibnum); /* multi path case? */
-                       if (ron->ro_rt == NULL) {
-                               error = EHOSTUNREACH;
+               sin6_next = satosin6(opts->ip6po_nexthop);
+               if (IN6_IS_ADDR_LINKLOCAL(&sin6_next->sin6_addr)) {
+                       /*
+                        * Next hop is LLA, thus it should be neighbor.
+                        * Determine outgoing interface by zone index.
+                        */
+                       zoneid = ntohs(in6_getscope(&sin6_next->sin6_addr));
+                       if (zoneid > 0) {
+                               ifp = in6_getlinkifnet(zoneid);
                                goto done;
                        }
                }
-
-               rt = ron->ro_rt;
-               ifp = rt->rt_ifp;
-               IF_AFDATA_RLOCK(ifp);
-               la = lla_lookup(LLTABLE6(ifp), 0, (struct sockaddr *)sin6_next);
-               IF_AFDATA_RUNLOCK(ifp);
-               if (la != NULL) 
-                       LLE_RUNLOCK(la);
-               else {
-                       error = EHOSTUNREACH;
-                       goto done;
-               }
-#if 0
-               if ((ron->ro_rt &&
-                    (ron->ro_rt->rt_flags & (RTF_UP | RTF_LLINFO)) !=
-                    (RTF_UP | RTF_LLINFO)) ||
-                   !IN6_ARE_ADDR_EQUAL(&satosin6(&ron->ro_dst)->sin6_addr,
-                   &sin6_next->sin6_addr)) {
-                       if (ron->ro_rt) {
-                               RTFREE(ron->ro_rt);
-                               ron->ro_rt = NULL;
-                       }
-                       *satosin6(&ron->ro_dst) = *sin6_next;
-               }
+               ron = &opts->ip6po_nextroute;
+               /* Use a cached route if it exists and is valid. */
+               if (ron->ro_rt != NULL && (
+                   (ron->ro_rt->rt_flags & RTF_UP) == 0 ||
+                   ron->ro_dst.sin6_family != AF_INET6 ||
+                   !IN6_ARE_ADDR_EQUAL(&ron->ro_dst.sin6_addr,
+                       &sin6_next->sin6_addr)))
+                       RO_RTFREE(ron);
                if (ron->ro_rt == NULL) {
+                       ron->ro_dst = *sin6_next;
                        in6_rtalloc(ron, fibnum); /* multi path case? */
-                       if (ron->ro_rt == NULL ||
-                           !(ron->ro_rt->rt_flags & RTF_LLINFO)) {
-                               if (ron->ro_rt) {
-                                       RTFREE(ron->ro_rt);
-                                       ron->ro_rt = NULL;
-                               }
-                               error = EHOSTUNREACH;
-                               goto done;
-                       }
                }
-#endif
-
                /*
-                * When cloning is required, try to allocate a route to the
-                * destination so that the caller can store path MTU
-                * information.
+                * The node identified by that address must be a
+                * neighbor of the sending host.
                 */
+               if (ron->ro_rt == NULL ||
+                   (ron->ro_rt->rt_flags & RTF_GATEWAY) != 0)
+                       error = EHOSTUNREACH;
                goto done;
        }
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to