diff options
Diffstat (limited to 'sys/netinet6/in6_src.c')
| -rw-r--r-- | sys/netinet6/in6_src.c | 45 |
1 files changed, 37 insertions, 8 deletions
diff --git a/sys/netinet6/in6_src.c b/sys/netinet6/in6_src.c index d5849569fddd..88ace1cc6cac 100644 --- a/sys/netinet6/in6_src.c +++ b/sys/netinet6/in6_src.c @@ -211,7 +211,6 @@ in6_selectsrc(dstsock, opts, mopts, ro, laddr, errorp) != 0) { return (NULL); } - /* * determine the appropriate zone id of the source based on * the zone of the destination and the outgoing interface. @@ -449,12 +448,19 @@ in6_selectif(dstsock, opts, mopts, ro, retifp) struct route_in6 *ro; struct ifnet **retifp; { - int error, clone; + int error; + struct route_in6 sro; struct rtentry *rt = NULL; - clone = IN6_IS_ADDR_MULTICAST(&dstsock->sin6_addr) ? 0 : 1; + if (ro == NULL) { + bzero(&sro, sizeof(sro)); + ro = &sro; + } + if ((error = in6_selectroute(dstsock, opts, mopts, ro, retifp, - &rt, clone)) != 0) { + &rt, 0)) != 0) { + if (rt && rt == sro.ro_rt) + RTFREE(rt); return (error); } @@ -476,7 +482,11 @@ in6_selectif(dstsock, opts, mopts, ro, retifp) * We thus reject the case here. */ if (rt && (rt->rt_flags & (RTF_REJECT | RTF_BLACKHOLE))) { - return (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); + int flags = (rt->rt_flags & RTF_HOST ? EHOSTUNREACH : ENETUNREACH); + + if (rt && rt == sro.ro_rt) + RTFREE(rt); + return (flags); } /* @@ -489,6 +499,8 @@ in6_selectif(dstsock, opts, mopts, ro, retifp) if (rt && rt->rt_ifa && rt->rt_ifa->ifa_ifp) *retifp = rt->rt_ifa->ifa_ifp; + if (rt && rt == sro.ro_rt) + RTFREE(rt); return (0); } @@ -623,6 +635,7 @@ in6_selectroute(dstsock, opts, mopts, ro, retifp, retrt, clone) sa6 = (struct sockaddr_in6 *)&ro->ro_dst; *sa6 = *dstsock; sa6->sin6_scope_id = 0; + if (clone) { rtalloc((struct route *)ro); } else { @@ -695,7 +708,7 @@ in6_selectroute(dstsock, opts, mopts, ro, retifp, retrt, clone) * 2. (If the outgoing interface is detected) the current * hop limit of the interface specified by router advertisement. * 3. The system default hoplimit. -*/ + */ int in6_selecthlim(in6p, ifp) struct in6pcb *in6p; @@ -705,8 +718,24 @@ in6_selecthlim(in6p, ifp) return (in6p->in6p_hops); else if (ifp) return (ND_IFINFO(ifp)->chlim); - else - return (ip6_defhlim); + else if (in6p && !IN6_IS_ADDR_UNSPECIFIED(&in6p->in6p_faddr)) { + struct route_in6 ro6; + struct ifnet *lifp; + + bzero(&ro6, sizeof(ro6)); + ro6.ro_dst.sin6_family = AF_INET6; + ro6.ro_dst.sin6_len = sizeof(struct sockaddr_in6); + ro6.ro_dst.sin6_addr = in6p->in6p_faddr; + rtalloc((struct route *)&ro6); + if (ro6.ro_rt) { + lifp = ro6.ro_rt->rt_ifp; + RTFREE(ro6.ro_rt); + if (lifp) + return (ND_IFINFO(lifp)->chlim); + } else + return (ip6_defhlim); + } + return (ip6_defhlim); } /* |
