byebye in6_ifawithscope(). it was a function for old source
address selection. Obtained from: KAME
This commit is contained in:
parent
4dcc0c992a
commit
d2486e878b
@ -1858,288 +1858,6 @@ in6_prefixlen2mask(maskp, len)
|
||||
maskp->s6_addr[bytelen] = maskarray[bitlen - 1];
|
||||
}
|
||||
|
||||
/*
|
||||
* return the best address out of the same scope
|
||||
*/
|
||||
struct in6_ifaddr *
|
||||
in6_ifawithscope(oifp, dst)
|
||||
struct ifnet *oifp;
|
||||
struct in6_addr *dst;
|
||||
{
|
||||
int dst_scope = in6_addrscope(dst), src_scope, best_scope = 0;
|
||||
int blen = -1;
|
||||
struct ifaddr *ifa;
|
||||
struct ifnet *ifp;
|
||||
struct in6_ifaddr *ifa_best = NULL;
|
||||
u_int32_t dstzone, odstzone;
|
||||
|
||||
if (oifp == NULL) {
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
if (in6_addr2zoneid(oifp, dst, &odstzone))
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* We search for all addresses on all interfaces from the beginning.
|
||||
* Comparing an interface with the outgoing interface will be done
|
||||
* only at the final stage of tiebreaking.
|
||||
*/
|
||||
IFNET_RLOCK();
|
||||
for (ifp = TAILQ_FIRST(&ifnet); ifp; ifp = TAILQ_NEXT(ifp, if_list))
|
||||
{
|
||||
/*
|
||||
* We can never take an address that breaks the scope zone
|
||||
* of the destination.
|
||||
*/
|
||||
if (in6_addr2zoneid(ifp, dst, &dstzone) || dstzone != odstzone)
|
||||
continue;
|
||||
|
||||
TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
|
||||
{
|
||||
int tlen = -1, dscopecmp, bscopecmp, matchcmp;
|
||||
|
||||
if (ifa->ifa_addr->sa_family != AF_INET6)
|
||||
continue;
|
||||
|
||||
src_scope = in6_addrscope(IFA_IN6(ifa));
|
||||
|
||||
/*
|
||||
* Don't use an address before completing DAD
|
||||
* nor a duplicated address.
|
||||
*/
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
IN6_IFF_NOTREADY)
|
||||
continue;
|
||||
|
||||
/* XXX: is there any case to allow anycasts? */
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
IN6_IFF_ANYCAST)
|
||||
continue;
|
||||
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
IN6_IFF_DETACHED)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If this is the first address we find,
|
||||
* keep it anyway.
|
||||
*/
|
||||
if (ifa_best == NULL)
|
||||
goto replace;
|
||||
|
||||
/*
|
||||
* ifa_best is never NULL beyond this line except
|
||||
* within the block labeled "replace".
|
||||
*/
|
||||
|
||||
/*
|
||||
* If ifa_best has a smaller scope than dst and
|
||||
* the current address has a larger one than
|
||||
* (or equal to) dst, always replace ifa_best.
|
||||
* Also, if the current address has a smaller scope
|
||||
* than dst, ignore it unless ifa_best also has a
|
||||
* smaller scope.
|
||||
* Consequently, after the two if-clause below,
|
||||
* the followings must be satisfied:
|
||||
* (scope(src) < scope(dst) &&
|
||||
* scope(best) < scope(dst))
|
||||
* OR
|
||||
* (scope(best) >= scope(dst) &&
|
||||
* scope(src) >= scope(dst))
|
||||
*/
|
||||
if (IN6_ARE_SCOPE_CMP(best_scope, dst_scope) < 0 &&
|
||||
IN6_ARE_SCOPE_CMP(src_scope, dst_scope) >= 0)
|
||||
goto replace; /* (A) */
|
||||
if (IN6_ARE_SCOPE_CMP(src_scope, dst_scope) < 0 &&
|
||||
IN6_ARE_SCOPE_CMP(best_scope, dst_scope) >= 0)
|
||||
continue; /* (B) */
|
||||
|
||||
/*
|
||||
* A deprecated address SHOULD NOT be used in new
|
||||
* communications if an alternate (non-deprecated)
|
||||
* address is available and has sufficient scope.
|
||||
* RFC 2462, Section 5.5.4.
|
||||
*/
|
||||
if (((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
IN6_IFF_DEPRECATED) {
|
||||
/*
|
||||
* Ignore any deprecated addresses if
|
||||
* specified by configuration.
|
||||
*/
|
||||
if (!ip6_use_deprecated)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* If we have already found a non-deprecated
|
||||
* candidate, just ignore deprecated addresses.
|
||||
*/
|
||||
if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED)
|
||||
== 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* A non-deprecated address is always preferred
|
||||
* to a deprecated one regardless of scopes and
|
||||
* address matching (Note invariants ensured by the
|
||||
* conditions (A) and (B) above.)
|
||||
*/
|
||||
if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) &&
|
||||
(((struct in6_ifaddr *)ifa)->ia6_flags &
|
||||
IN6_IFF_DEPRECATED) == 0)
|
||||
goto replace;
|
||||
|
||||
/*
|
||||
* When we use temporary addresses described in
|
||||
* RFC 3041, we prefer temporary addresses to
|
||||
* public autoconf addresses. Again, note the
|
||||
* invariants from (A) and (B). Also note that we
|
||||
* don't have any preference between static addresses
|
||||
* and autoconf addresses (despite of whether or not
|
||||
* the latter is temporary or public.)
|
||||
*/
|
||||
if (ip6_use_tempaddr) {
|
||||
struct in6_ifaddr *ifat;
|
||||
|
||||
ifat = (struct in6_ifaddr *)ifa;
|
||||
if ((ifa_best->ia6_flags &
|
||||
(IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY))
|
||||
== IN6_IFF_AUTOCONF &&
|
||||
(ifat->ia6_flags &
|
||||
(IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY))
|
||||
== (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY)) {
|
||||
goto replace;
|
||||
}
|
||||
if ((ifa_best->ia6_flags &
|
||||
(IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY))
|
||||
== (IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY) &&
|
||||
(ifat->ia6_flags &
|
||||
(IN6_IFF_AUTOCONF|IN6_IFF_TEMPORARY))
|
||||
== IN6_IFF_AUTOCONF) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, we have two cases:
|
||||
* 1. we are looking at a non-deprecated address,
|
||||
* and ifa_best is also non-deprecated.
|
||||
* 2. we are looking at a deprecated address,
|
||||
* and ifa_best is also deprecated.
|
||||
* Also, we do not have to consider a case where
|
||||
* the scope of if_best is larger(smaller) than dst and
|
||||
* the scope of the current address is smaller(larger)
|
||||
* than dst. Such a case has already been covered.
|
||||
* Tiebreaking is done according to the following
|
||||
* items:
|
||||
* - the scope comparison between the address and
|
||||
* dst (dscopecmp)
|
||||
* - the scope comparison between the address and
|
||||
* ifa_best (bscopecmp)
|
||||
* - if the address match dst longer than ifa_best
|
||||
* (matchcmp)
|
||||
* - if the address is on the outgoing I/F (outI/F)
|
||||
*
|
||||
* Roughly speaking, the selection policy is
|
||||
* - the most important item is scope. The same scope
|
||||
* is best. Then search for a larger scope.
|
||||
* Smaller scopes are the last resort.
|
||||
* - A deprecated address is chosen only when we have
|
||||
* no address that has an enough scope, but is
|
||||
* prefered to any addresses of smaller scopes
|
||||
* (this must be already done above.)
|
||||
* - addresses on the outgoing I/F are preferred to
|
||||
* ones on other interfaces if none of above
|
||||
* tiebreaks. In the table below, the column "bI"
|
||||
* means if the best_ifa is on the outgoing
|
||||
* interface, and the column "sI" means if the ifa
|
||||
* is on the outgoing interface.
|
||||
* - If there is no other reasons to choose one,
|
||||
* longest address match against dst is considered.
|
||||
*
|
||||
* The precise decision table is as follows:
|
||||
* dscopecmp bscopecmp match bI oI | replace?
|
||||
* N/A equal N/A Y N | No (1)
|
||||
* N/A equal N/A N Y | Yes (2)
|
||||
* N/A equal larger N/A | Yes (3)
|
||||
* N/A equal !larger N/A | No (4)
|
||||
* larger larger N/A N/A | No (5)
|
||||
* larger smaller N/A N/A | Yes (6)
|
||||
* smaller larger N/A N/A | Yes (7)
|
||||
* smaller smaller N/A N/A | No (8)
|
||||
* equal smaller N/A N/A | Yes (9)
|
||||
* equal larger (already done at A above)
|
||||
*/
|
||||
dscopecmp = IN6_ARE_SCOPE_CMP(src_scope, dst_scope);
|
||||
bscopecmp = IN6_ARE_SCOPE_CMP(src_scope, best_scope);
|
||||
|
||||
if (bscopecmp == 0) {
|
||||
struct ifnet *bifp = ifa_best->ia_ifp;
|
||||
|
||||
if (bifp == oifp && ifp != oifp) /* (1) */
|
||||
continue;
|
||||
if (bifp != oifp && ifp == oifp) /* (2) */
|
||||
goto replace;
|
||||
|
||||
/*
|
||||
* Both bifp and ifp are on the outgoing
|
||||
* interface, or both two are on a different
|
||||
* interface from the outgoing I/F.
|
||||
* now we need address matching against dst
|
||||
* for tiebreaking.
|
||||
*/
|
||||
tlen = in6_matchlen(IFA_IN6(ifa), dst);
|
||||
matchcmp = tlen - blen;
|
||||
if (matchcmp > 0) /* (3) */
|
||||
goto replace;
|
||||
continue; /* (4) */
|
||||
}
|
||||
if (dscopecmp > 0) {
|
||||
if (bscopecmp > 0) /* (5) */
|
||||
continue;
|
||||
goto replace; /* (6) */
|
||||
}
|
||||
if (dscopecmp < 0) {
|
||||
if (bscopecmp > 0) /* (7) */
|
||||
goto replace;
|
||||
continue; /* (8) */
|
||||
}
|
||||
|
||||
/* now dscopecmp must be 0 */
|
||||
if (bscopecmp < 0)
|
||||
goto replace; /* (9) */
|
||||
|
||||
replace:
|
||||
ifa_best = (struct in6_ifaddr *)ifa;
|
||||
blen = tlen >= 0 ? tlen :
|
||||
in6_matchlen(IFA_IN6(ifa), dst);
|
||||
best_scope = in6_addrscope(&ifa_best->ia_addr.sin6_addr);
|
||||
}
|
||||
}
|
||||
IFNET_RUNLOCK();
|
||||
|
||||
/* count statistics for future improvements */
|
||||
if (ifa_best == NULL)
|
||||
ip6stat.ip6s_sources_none++;
|
||||
else {
|
||||
if (oifp == ifa_best->ia_ifp)
|
||||
ip6stat.ip6s_sources_sameif[best_scope]++;
|
||||
else
|
||||
ip6stat.ip6s_sources_otherif[best_scope]++;
|
||||
|
||||
if (best_scope == dst_scope)
|
||||
ip6stat.ip6s_sources_samescope[best_scope]++;
|
||||
else
|
||||
ip6stat.ip6s_sources_otherscope[best_scope]++;
|
||||
|
||||
if ((ifa_best->ia6_flags & IN6_IFF_DEPRECATED) != 0)
|
||||
ip6stat.ip6s_sources_deprecated[best_scope]++;
|
||||
}
|
||||
|
||||
return (ifa_best);
|
||||
}
|
||||
|
||||
/*
|
||||
* return the best address out of the same scope. if no address was
|
||||
* found, return the first valid address from designated IF.
|
||||
|
@ -616,7 +616,6 @@ struct cmsghdr;
|
||||
int in6_cksum __P((struct mbuf *, u_int8_t, u_int32_t, u_int32_t));
|
||||
int in6_localaddr __P((struct in6_addr *));
|
||||
int in6_addrscope __P((struct in6_addr *));
|
||||
struct in6_ifaddr *in6_ifawithscope __P((struct ifnet *, struct in6_addr *));
|
||||
struct in6_ifaddr *in6_ifawithifp __P((struct ifnet *, struct in6_addr *));
|
||||
extern void in6_if_up __P((struct ifnet *));
|
||||
struct sockaddr;
|
||||
|
Loading…
Reference in New Issue
Block a user