[IPV6] ADDRCONF: Clean-up ipv6_dev_get_saddr().
old: | text data bss dec hex filename | 28599 1416 96 30111 759f net/ipv6/addrconf.o new: | text data bss dec hex filename | 28007 1416 96 29519 734f net/ipv6/addrconf.o Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
This commit is contained in:
parent
9bb182a700
commit
a9b05723ff
|
@ -877,20 +877,39 @@ out:
|
||||||
/*
|
/*
|
||||||
* Choose an appropriate source address (RFC3484)
|
* Choose an appropriate source address (RFC3484)
|
||||||
*/
|
*/
|
||||||
struct ipv6_saddr_score {
|
enum {
|
||||||
int addr_type;
|
IPV6_SADDR_RULE_INIT = 0,
|
||||||
unsigned int attrs;
|
IPV6_SADDR_RULE_LOCAL,
|
||||||
int matchlen;
|
IPV6_SADDR_RULE_SCOPE,
|
||||||
int scope;
|
IPV6_SADDR_RULE_PREFERRED,
|
||||||
unsigned int rule;
|
#ifdef CONFIG_IPV6_MIP6
|
||||||
|
IPV6_SADDR_RULE_HOA,
|
||||||
|
#endif
|
||||||
|
IPV6_SADDR_RULE_OIF,
|
||||||
|
IPV6_SADDR_RULE_LABEL,
|
||||||
|
#ifdef CONFIG_IPV6_PRIVACY
|
||||||
|
IPV6_SADDR_RULE_PRIVACY,
|
||||||
|
#endif
|
||||||
|
IPV6_SADDR_RULE_ORCHID,
|
||||||
|
IPV6_SADDR_RULE_PREFIX,
|
||||||
|
IPV6_SADDR_RULE_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
#define IPV6_SADDR_SCORE_LOCAL 0x0001
|
struct ipv6_saddr_score {
|
||||||
#define IPV6_SADDR_SCORE_PREFERRED 0x0004
|
int rule;
|
||||||
#define IPV6_SADDR_SCORE_HOA 0x0008
|
int addr_type;
|
||||||
#define IPV6_SADDR_SCORE_OIF 0x0010
|
struct inet6_ifaddr *ifa;
|
||||||
#define IPV6_SADDR_SCORE_LABEL 0x0020
|
DECLARE_BITMAP(scorebits, IPV6_SADDR_RULE_MAX);
|
||||||
#define IPV6_SADDR_SCORE_PRIVACY 0x0040
|
int scopedist;
|
||||||
|
int matchlen;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ipv6_saddr_dst {
|
||||||
|
struct in6_addr *addr;
|
||||||
|
int ifindex;
|
||||||
|
int scope;
|
||||||
|
int label;
|
||||||
|
};
|
||||||
|
|
||||||
static inline int ipv6_saddr_preferred(int type)
|
static inline int ipv6_saddr_preferred(int type)
|
||||||
{
|
{
|
||||||
|
@ -900,28 +919,142 @@ static inline int ipv6_saddr_preferred(int type)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ipv6_dev_get_saddr(struct net_device *daddr_dev,
|
static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score,
|
||||||
|
struct ipv6_saddr_dst *dst,
|
||||||
|
int i)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (i <= score->rule) {
|
||||||
|
switch (i) {
|
||||||
|
case IPV6_SADDR_RULE_SCOPE:
|
||||||
|
ret = score->scopedist;
|
||||||
|
break;
|
||||||
|
case IPV6_SADDR_RULE_PREFIX:
|
||||||
|
ret = score->matchlen;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = !!test_bit(i, score->scorebits);
|
||||||
|
}
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (i) {
|
||||||
|
case IPV6_SADDR_RULE_INIT:
|
||||||
|
/* Rule 0: remember if hiscore is not ready yet */
|
||||||
|
ret = !!score->ifa;
|
||||||
|
break;
|
||||||
|
case IPV6_SADDR_RULE_LOCAL:
|
||||||
|
/* Rule 1: Prefer same address */
|
||||||
|
ret = ipv6_addr_equal(&score->ifa->addr, dst->addr);
|
||||||
|
break;
|
||||||
|
case IPV6_SADDR_RULE_SCOPE:
|
||||||
|
/* Rule 2: Prefer appropriate scope
|
||||||
|
*
|
||||||
|
* ret
|
||||||
|
* ^
|
||||||
|
* -1 | d 15
|
||||||
|
* ---+--+-+---> scope
|
||||||
|
* |
|
||||||
|
* | d is scope of the destination.
|
||||||
|
* B-d | \
|
||||||
|
* | \ <- smaller scope is better if
|
||||||
|
* B-15 | \ if scope is enough for destinaion.
|
||||||
|
* | ret = B - scope (-1 <= scope >= d <= 15).
|
||||||
|
* d-C-1 | /
|
||||||
|
* |/ <- greater is better
|
||||||
|
* -C / if scope is not enough for destination.
|
||||||
|
* /| ret = scope - C (-1 <= d < scope <= 15).
|
||||||
|
*
|
||||||
|
* d - C - 1 < B -15 (for all -1 <= d <= 15).
|
||||||
|
* C > d + 14 - B >= 15 + 14 - B = 29 - B.
|
||||||
|
* Assume B = 0 and we get C > 29.
|
||||||
|
*/
|
||||||
|
ret = __ipv6_addr_src_scope(score->addr_type);
|
||||||
|
if (ret >= dst->scope)
|
||||||
|
ret = -ret;
|
||||||
|
else
|
||||||
|
ret -= 128; /* 30 is enough */
|
||||||
|
score->scopedist = ret;
|
||||||
|
break;
|
||||||
|
case IPV6_SADDR_RULE_PREFERRED:
|
||||||
|
/* Rule 3: Avoid deprecated and optimistic addresses */
|
||||||
|
ret = ipv6_saddr_preferred(score->addr_type) ||
|
||||||
|
!(score->ifa->flags & (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC));
|
||||||
|
break;
|
||||||
|
#ifdef CONFIG_IPV6_MIP6
|
||||||
|
case IPV6_SADDR_RULE_HOA:
|
||||||
|
/* Rule 4: Prefer home address */
|
||||||
|
ret = !!(score->ifa->flags & IFA_F_HOMEADDRESS);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case IPV6_SADDR_RULE_OIF:
|
||||||
|
/* Rule 5: Prefer outgoing interface */
|
||||||
|
ret = (!dst->ifindex ||
|
||||||
|
dst->ifindex == score->ifa->idev->dev->ifindex);
|
||||||
|
break;
|
||||||
|
case IPV6_SADDR_RULE_LABEL:
|
||||||
|
/* Rule 6: Prefer matching label */
|
||||||
|
ret = ipv6_addr_label(&score->ifa->addr, score->addr_type,
|
||||||
|
score->ifa->idev->dev->ifindex) == dst->label;
|
||||||
|
break;
|
||||||
|
#ifdef CONFIG_IPV6_PRIVACY
|
||||||
|
case IPV6_SADDR_RULE_PRIVACY:
|
||||||
|
/* Rule 7: Prefer public address
|
||||||
|
* Note: prefer temprary address if use_tempaddr >= 2
|
||||||
|
*/
|
||||||
|
ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ (score->ifa->idev->cnf.use_tempaddr >= 2);
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case IPV6_SADDR_RULE_ORCHID:
|
||||||
|
/* Rule 8-: Prefer ORCHID vs ORCHID or
|
||||||
|
* non-ORCHID vs non-ORCHID
|
||||||
|
*/
|
||||||
|
ret = !(ipv6_addr_orchid(&score->ifa->addr) ^
|
||||||
|
ipv6_addr_orchid(dst->addr));
|
||||||
|
break;
|
||||||
|
case IPV6_SADDR_RULE_PREFIX:
|
||||||
|
/* Rule 8: Use longest matching prefix */
|
||||||
|
score->matchlen = ret = ipv6_addr_diff(&score->ifa->addr,
|
||||||
|
dst->addr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret)
|
||||||
|
__set_bit(i, score->scorebits);
|
||||||
|
score->rule = i;
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ipv6_dev_get_saddr(struct net_device *dst_dev,
|
||||||
struct in6_addr *daddr, struct in6_addr *saddr)
|
struct in6_addr *daddr, struct in6_addr *saddr)
|
||||||
{
|
{
|
||||||
struct ipv6_saddr_score hiscore;
|
struct ipv6_saddr_score scores[2],
|
||||||
struct inet6_ifaddr *ifa_result = NULL;
|
*score = &scores[0], *hiscore = &scores[1];
|
||||||
struct net *net = daddr_dev->nd_net;
|
struct net *net = dst_dev->nd_net;
|
||||||
int daddr_type = __ipv6_addr_type(daddr);
|
struct ipv6_saddr_dst dst;
|
||||||
int daddr_scope = __ipv6_addr_src_scope(daddr_type);
|
|
||||||
int daddr_ifindex = daddr_dev ? daddr_dev->ifindex : 0;
|
|
||||||
u32 daddr_label = ipv6_addr_label(daddr, daddr_type, daddr_ifindex);
|
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
|
int dst_type;
|
||||||
|
|
||||||
memset(&hiscore, 0, sizeof(hiscore));
|
dst_type = __ipv6_addr_type(daddr);
|
||||||
|
dst.addr = daddr;
|
||||||
|
dst.ifindex = dst_dev ? dst_dev->ifindex : 0;
|
||||||
|
dst.scope = __ipv6_addr_src_scope(dst_type);
|
||||||
|
dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex);
|
||||||
|
|
||||||
|
hiscore->rule = -1;
|
||||||
|
hiscore->ifa = NULL;
|
||||||
|
|
||||||
read_lock(&dev_base_lock);
|
read_lock(&dev_base_lock);
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
|
|
||||||
for_each_netdev(net, dev) {
|
for_each_netdev(net, dev) {
|
||||||
struct inet6_dev *idev;
|
struct inet6_dev *idev;
|
||||||
struct inet6_ifaddr *ifa;
|
|
||||||
|
|
||||||
/* Rule 0: Candidate Source Address (section 4)
|
/* Candidate Source Address (section 4)
|
||||||
* - multicast and link-local destination address,
|
* - multicast and link-local destination address,
|
||||||
* the set of candidate source address MUST only
|
* the set of candidate source address MUST only
|
||||||
* include addresses assigned to interfaces
|
* include addresses assigned to interfaces
|
||||||
|
@ -933,9 +1066,9 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
|
||||||
* belonging to the same site as the outgoing
|
* belonging to the same site as the outgoing
|
||||||
* interface.)
|
* interface.)
|
||||||
*/
|
*/
|
||||||
if ((daddr_type & IPV6_ADDR_MULTICAST ||
|
if (((dst_type & IPV6_ADDR_MULTICAST) ||
|
||||||
daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
|
dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
|
||||||
daddr_dev && dev != daddr_dev)
|
dst.ifindex && dev->ifindex != dst.ifindex)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
idev = __in6_dev_get(dev);
|
idev = __in6_dev_get(dev);
|
||||||
|
@ -943,12 +1076,10 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
read_lock_bh(&idev->lock);
|
read_lock_bh(&idev->lock);
|
||||||
for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) {
|
for (score->ifa = idev->addr_list; score->ifa; score->ifa = score->ifa->if_next) {
|
||||||
struct ipv6_saddr_score score;
|
int i;
|
||||||
|
|
||||||
score.addr_type = __ipv6_addr_type(&ifa->addr);
|
/*
|
||||||
|
|
||||||
/* Rule 0:
|
|
||||||
* - Tentative Address (RFC2462 section 5.4)
|
* - Tentative Address (RFC2462 section 5.4)
|
||||||
* - A tentative address is not considered
|
* - A tentative address is not considered
|
||||||
* "assigned to an interface" in the traditional
|
* "assigned to an interface" in the traditional
|
||||||
|
@ -958,11 +1089,14 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
|
||||||
* addresses, and the unspecified address MUST
|
* addresses, and the unspecified address MUST
|
||||||
* NOT be included in a candidate set.
|
* NOT be included in a candidate set.
|
||||||
*/
|
*/
|
||||||
if ((ifa->flags & IFA_F_TENTATIVE) &&
|
if ((score->ifa->flags & IFA_F_TENTATIVE) &&
|
||||||
(!(ifa->flags & IFA_F_OPTIMISTIC)))
|
(!(score->ifa->flags & IFA_F_OPTIMISTIC)))
|
||||||
continue;
|
continue;
|
||||||
if (unlikely(score.addr_type == IPV6_ADDR_ANY ||
|
|
||||||
score.addr_type & IPV6_ADDR_MULTICAST)) {
|
score->addr_type = __ipv6_addr_type(&score->ifa->addr);
|
||||||
|
|
||||||
|
if (unlikely(score->addr_type == IPV6_ADDR_ANY ||
|
||||||
|
score->addr_type & IPV6_ADDR_MULTICAST)) {
|
||||||
LIMIT_NETDEBUG(KERN_DEBUG
|
LIMIT_NETDEBUG(KERN_DEBUG
|
||||||
"ADDRCONF: unspecified / multicast address "
|
"ADDRCONF: unspecified / multicast address "
|
||||||
"assigned as unicast address on %s",
|
"assigned as unicast address on %s",
|
||||||
|
@ -970,201 +1104,59 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
score.attrs = 0;
|
score->rule = -1;
|
||||||
score.matchlen = 0;
|
bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX);
|
||||||
score.scope = 0;
|
|
||||||
score.rule = 0;
|
|
||||||
|
|
||||||
if (ifa_result == NULL) {
|
for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) {
|
||||||
/* record it if the first available entry */
|
int minihiscore, miniscore;
|
||||||
goto record_it;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Rule 1: Prefer same address */
|
minihiscore = ipv6_get_saddr_eval(hiscore, &dst, i);
|
||||||
if (hiscore.rule < 1) {
|
miniscore = ipv6_get_saddr_eval(score, &dst, i);
|
||||||
if (ipv6_addr_equal(&ifa_result->addr, daddr))
|
|
||||||
hiscore.attrs |= IPV6_SADDR_SCORE_LOCAL;
|
|
||||||
hiscore.rule++;
|
|
||||||
}
|
|
||||||
if (ipv6_addr_equal(&ifa->addr, daddr)) {
|
|
||||||
score.attrs |= IPV6_SADDR_SCORE_LOCAL;
|
|
||||||
if (!(hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)) {
|
|
||||||
score.rule = 1;
|
|
||||||
goto record_it;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (hiscore.attrs & IPV6_SADDR_SCORE_LOCAL)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Rule 2: Prefer appropriate scope */
|
if (minihiscore > miniscore) {
|
||||||
if (hiscore.rule < 2) {
|
if (i == IPV6_SADDR_RULE_SCOPE &&
|
||||||
hiscore.scope = __ipv6_addr_src_scope(hiscore.addr_type);
|
score->scopedist > 0) {
|
||||||
hiscore.rule++;
|
/*
|
||||||
}
|
* special case:
|
||||||
score.scope = __ipv6_addr_src_scope(score.addr_type);
|
* each remaining entry
|
||||||
if (hiscore.scope < score.scope) {
|
* has too small (not enough)
|
||||||
if (hiscore.scope < daddr_scope) {
|
* scope, because ifa entries
|
||||||
score.rule = 2;
|
* are sorted by their scope
|
||||||
goto record_it;
|
* values.
|
||||||
} else
|
*/
|
||||||
continue;
|
goto try_nextdev;
|
||||||
} else if (score.scope < hiscore.scope) {
|
}
|
||||||
if (score.scope < daddr_scope)
|
break;
|
||||||
break; /* addresses sorted by scope */
|
} else if (minihiscore < miniscore) {
|
||||||
else {
|
struct ipv6_saddr_score *tmp;
|
||||||
score.rule = 2;
|
|
||||||
goto record_it;
|
if (hiscore->ifa)
|
||||||
|
in6_ifa_put(hiscore->ifa);
|
||||||
|
|
||||||
|
in6_ifa_hold(score->ifa);
|
||||||
|
|
||||||
|
tmp = hiscore;
|
||||||
|
hiscore = score;
|
||||||
|
score = tmp;
|
||||||
|
|
||||||
|
/* restore our iterator */
|
||||||
|
score->ifa = hiscore->ifa;
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Rule 3: Avoid deprecated and optimistic addresses */
|
|
||||||
if (hiscore.rule < 3) {
|
|
||||||
if (ipv6_saddr_preferred(hiscore.addr_type) ||
|
|
||||||
(((ifa_result->flags &
|
|
||||||
(IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0)))
|
|
||||||
hiscore.attrs |= IPV6_SADDR_SCORE_PREFERRED;
|
|
||||||
hiscore.rule++;
|
|
||||||
}
|
|
||||||
if (ipv6_saddr_preferred(score.addr_type) ||
|
|
||||||
(((ifa->flags &
|
|
||||||
(IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) {
|
|
||||||
score.attrs |= IPV6_SADDR_SCORE_PREFERRED;
|
|
||||||
if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {
|
|
||||||
score.rule = 3;
|
|
||||||
goto record_it;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Rule 4: Prefer home address */
|
|
||||||
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
|
|
||||||
if (hiscore.rule < 4) {
|
|
||||||
if (ifa_result->flags & IFA_F_HOMEADDRESS)
|
|
||||||
hiscore.attrs |= IPV6_SADDR_SCORE_HOA;
|
|
||||||
hiscore.rule++;
|
|
||||||
}
|
|
||||||
if (ifa->flags & IFA_F_HOMEADDRESS) {
|
|
||||||
score.attrs |= IPV6_SADDR_SCORE_HOA;
|
|
||||||
if (!(ifa_result->flags & IFA_F_HOMEADDRESS)) {
|
|
||||||
score.rule = 4;
|
|
||||||
goto record_it;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (hiscore.attrs & IPV6_SADDR_SCORE_HOA)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (hiscore.rule < 4)
|
|
||||||
hiscore.rule++;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Rule 5: Prefer outgoing interface */
|
|
||||||
if (hiscore.rule < 5) {
|
|
||||||
if (daddr_dev == NULL ||
|
|
||||||
daddr_dev == ifa_result->idev->dev)
|
|
||||||
hiscore.attrs |= IPV6_SADDR_SCORE_OIF;
|
|
||||||
hiscore.rule++;
|
|
||||||
}
|
|
||||||
if (daddr_dev == NULL ||
|
|
||||||
daddr_dev == ifa->idev->dev) {
|
|
||||||
score.attrs |= IPV6_SADDR_SCORE_OIF;
|
|
||||||
if (!(hiscore.attrs & IPV6_SADDR_SCORE_OIF)) {
|
|
||||||
score.rule = 5;
|
|
||||||
goto record_it;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (hiscore.attrs & IPV6_SADDR_SCORE_OIF)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Rule 6: Prefer matching label */
|
|
||||||
if (hiscore.rule < 6) {
|
|
||||||
if (ipv6_addr_label(&ifa_result->addr,
|
|
||||||
hiscore.addr_type,
|
|
||||||
ifa_result->idev->dev->ifindex) == daddr_label)
|
|
||||||
hiscore.attrs |= IPV6_SADDR_SCORE_LABEL;
|
|
||||||
hiscore.rule++;
|
|
||||||
}
|
|
||||||
if (ipv6_addr_label(&ifa->addr,
|
|
||||||
score.addr_type,
|
|
||||||
ifa->idev->dev->ifindex) == daddr_label) {
|
|
||||||
score.attrs |= IPV6_SADDR_SCORE_LABEL;
|
|
||||||
if (!(hiscore.attrs & IPV6_SADDR_SCORE_LABEL)) {
|
|
||||||
score.rule = 6;
|
|
||||||
goto record_it;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (hiscore.attrs & IPV6_SADDR_SCORE_LABEL)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CONFIG_IPV6_PRIVACY
|
|
||||||
/* Rule 7: Prefer public address
|
|
||||||
* Note: prefer temprary address if use_tempaddr >= 2
|
|
||||||
*/
|
|
||||||
if (hiscore.rule < 7) {
|
|
||||||
if ((!(ifa_result->flags & IFA_F_TEMPORARY)) ^
|
|
||||||
(ifa_result->idev->cnf.use_tempaddr >= 2))
|
|
||||||
hiscore.attrs |= IPV6_SADDR_SCORE_PRIVACY;
|
|
||||||
hiscore.rule++;
|
|
||||||
}
|
|
||||||
if ((!(ifa->flags & IFA_F_TEMPORARY)) ^
|
|
||||||
(ifa->idev->cnf.use_tempaddr >= 2)) {
|
|
||||||
score.attrs |= IPV6_SADDR_SCORE_PRIVACY;
|
|
||||||
if (!(hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)) {
|
|
||||||
score.rule = 7;
|
|
||||||
goto record_it;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (hiscore.attrs & IPV6_SADDR_SCORE_PRIVACY)
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
if (hiscore.rule < 7)
|
|
||||||
hiscore.rule++;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Skip rule 8 for orchid -> non-orchid address pairs. */
|
|
||||||
if (ipv6_addr_orchid(&ifa->addr) && !ipv6_addr_orchid(daddr))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* Rule 8: Use longest matching prefix */
|
|
||||||
if (hiscore.rule < 8) {
|
|
||||||
hiscore.matchlen = ipv6_addr_diff(&ifa_result->addr, daddr);
|
|
||||||
hiscore.rule++;
|
|
||||||
}
|
|
||||||
score.matchlen = ipv6_addr_diff(&ifa->addr, daddr);
|
|
||||||
if (score.matchlen > hiscore.matchlen) {
|
|
||||||
score.rule = 8;
|
|
||||||
goto record_it;
|
|
||||||
}
|
|
||||||
#if 0
|
|
||||||
else if (score.matchlen < hiscore.matchlen)
|
|
||||||
continue;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Final Rule: choose first available one */
|
|
||||||
continue;
|
|
||||||
record_it:
|
|
||||||
if (ifa_result)
|
|
||||||
in6_ifa_put(ifa_result);
|
|
||||||
in6_ifa_hold(ifa);
|
|
||||||
ifa_result = ifa;
|
|
||||||
hiscore = score;
|
|
||||||
}
|
}
|
||||||
|
try_nextdev:
|
||||||
read_unlock_bh(&idev->lock);
|
read_unlock_bh(&idev->lock);
|
||||||
}
|
}
|
||||||
rcu_read_unlock();
|
rcu_read_unlock();
|
||||||
read_unlock(&dev_base_lock);
|
read_unlock(&dev_base_lock);
|
||||||
|
|
||||||
if (!ifa_result)
|
if (!hiscore->ifa)
|
||||||
return -EADDRNOTAVAIL;
|
return -EADDRNOTAVAIL;
|
||||||
|
|
||||||
ipv6_addr_copy(saddr, &ifa_result->addr);
|
ipv6_addr_copy(saddr, &hiscore->ifa->addr);
|
||||||
in6_ifa_put(ifa_result);
|
in6_ifa_put(hiscore->ifa);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue