summaryrefslogtreecommitdiffstats
path: root/sys/netinet6/in6_src.c
diff options
context:
space:
mode:
authorbapt <bapt@FreeBSD.org>2015-09-12 12:03:02 +0000
committerbapt <bapt@FreeBSD.org>2015-09-12 12:03:02 +0000
commit934c5c6da6753f906bc4a905e249449fd15b850d (patch)
tree38501bd60c958b3b5474368fc0834fe6d09c307a /sys/netinet6/in6_src.c
parentef64c24c72a0a1e4bc5beba3e1c3d78af363773d (diff)
parentceb1e1488d523eff8fa06828cf0511fc2556c0ef (diff)
downloadFreeBSD-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.c100
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;
}
OpenPOWER on IntegriCloud