diff options
author | bapt <bapt@FreeBSD.org> | 2015-09-12 12:03:02 +0000 |
---|---|---|
committer | bapt <bapt@FreeBSD.org> | 2015-09-12 12:03:02 +0000 |
commit | 934c5c6da6753f906bc4a905e249449fd15b850d (patch) | |
tree | 38501bd60c958b3b5474368fc0834fe6d09c307a /sys/netinet6/in6_src.c | |
parent | ef64c24c72a0a1e4bc5beba3e1c3d78af363773d (diff) | |
parent | ceb1e1488d523eff8fa06828cf0511fc2556c0ef (diff) | |
download | FreeBSD-src-934c5c6da6753f906bc4a905e249449fd15b850d.zip FreeBSD-src-934c5c6da6753f906bc4a905e249449fd15b850d.tar.gz |
Finish merging from head, messed up in previous attempt
Diffstat (limited to 'sys/netinet6/in6_src.c')
-rw-r--r-- | sys/netinet6/in6_src.c | 100 |
1 files changed, 29 insertions, 71 deletions
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index 227f234..020c5cf 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -82,6 +82,7 @@ __FBSDID("$FreeBSD$"); #include <sys/time.h> #include <sys/jail.h> #include <sys/kernel.h> +#include <sys/rmlock.h> #include <sys/sx.h> #include <net/if.h> @@ -178,6 +179,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, struct inpcb *inp, struct route_in6 *ro, struct ucred *cred, struct ifnet **ifpp, struct in6_addr *srcp) { + struct rm_priotracker in6_ifa_tracker; struct in6_addr dst, tmp; struct ifnet *ifp = NULL, *oifp = NULL; struct in6_ifaddr *ia = NULL, *ia_best = NULL; @@ -303,7 +305,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, return (error); rule = 0; - IN6_IFADDR_RLOCK(); + IN6_IFADDR_RLOCK(&in6_ifa_tracker); TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { int new_scope = -1, new_matchlen = -1; struct in6_addrpolicy *new_policy = NULL; @@ -501,7 +503,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, } if ((ia = ia_best) == NULL) { - IN6_IFADDR_RUNLOCK(); + IN6_IFADDR_RUNLOCK(&in6_ifa_tracker); IP6STAT_INC(ip6s_sources_none); return (EADDRNOTAVAIL); } @@ -518,7 +520,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, tmp = ia->ia_addr.sin6_addr; if (cred != NULL && prison_local_ip6(cred, &tmp, (inp != NULL && (inp->inp_flags & IN6P_IPV6_V6ONLY) != 0)) != 0) { - IN6_IFADDR_RUNLOCK(); + IN6_IFADDR_RUNLOCK(&in6_ifa_tracker); IP6STAT_INC(ip6s_sources_none); return (EADDRNOTAVAIL); } @@ -537,7 +539,7 @@ in6_selectsrc(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, IP6STAT_INC(ip6s_sources_otherscope[best_scope]); if (IFA6_IS_DEPRECATED(ia)) IP6STAT_INC(ip6s_sources_deprecated[best_scope]); - IN6_IFADDR_RUNLOCK(); + IN6_IFADDR_RUNLOCK(&in6_ifa_tracker); return (0); } @@ -614,82 +616,38 @@ selectroute(struct sockaddr_in6 *dstsock, struct ip6_pktopts *opts, */ 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) { - /* XXX-BZ WT.? */ - if (ron->ro_rt) { - RTFREE(ron->ro_rt); - 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; } |