|
@@ -877,20 +877,39 @@ out:
|
|
/*
|
|
/*
|
|
* Choose an appropriate source address (RFC3484)
|
|
* Choose an appropriate source address (RFC3484)
|
|
*/
|
|
*/
|
|
|
|
+enum {
|
|
|
|
+ IPV6_SADDR_RULE_INIT = 0,
|
|
|
|
+ IPV6_SADDR_RULE_LOCAL,
|
|
|
|
+ IPV6_SADDR_RULE_SCOPE,
|
|
|
|
+ IPV6_SADDR_RULE_PREFERRED,
|
|
|
|
+#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
|
|
|
|
+};
|
|
|
|
+
|
|
struct ipv6_saddr_score {
|
|
struct ipv6_saddr_score {
|
|
- int addr_type;
|
|
|
|
- unsigned int attrs;
|
|
|
|
- int matchlen;
|
|
|
|
- int scope;
|
|
|
|
- unsigned int rule;
|
|
|
|
|
|
+ int rule;
|
|
|
|
+ int addr_type;
|
|
|
|
+ struct inet6_ifaddr *ifa;
|
|
|
|
+ DECLARE_BITMAP(scorebits, IPV6_SADDR_RULE_MAX);
|
|
|
|
+ int scopedist;
|
|
|
|
+ int matchlen;
|
|
};
|
|
};
|
|
|
|
|
|
-#define IPV6_SADDR_SCORE_LOCAL 0x0001
|
|
|
|
-#define IPV6_SADDR_SCORE_PREFERRED 0x0004
|
|
|
|
-#define IPV6_SADDR_SCORE_HOA 0x0008
|
|
|
|
-#define IPV6_SADDR_SCORE_OIF 0x0010
|
|
|
|
-#define IPV6_SADDR_SCORE_LABEL 0x0020
|
|
|
|
-#define IPV6_SADDR_SCORE_PRIVACY 0x0040
|
|
|
|
|
|
+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 inet6_ifaddr *ifa_result = NULL;
|
|
|
|
- struct net *net = daddr_dev->nd_net;
|
|
|
|
- int daddr_type = __ipv6_addr_type(daddr);
|
|
|
|
- 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 ipv6_saddr_score scores[2],
|
|
|
|
+ *score = &scores[0], *hiscore = &scores[1];
|
|
|
|
+ struct net *net = dst_dev->nd_net;
|
|
|
|
+ struct ipv6_saddr_dst dst;
|
|
struct net_device *dev;
|
|
struct net_device *dev;
|
|
|
|
+ int dst_type;
|
|
|
|
+
|
|
|
|
+ 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);
|
|
|
|
|
|
- memset(&hiscore, 0, sizeof(hiscore));
|
|
|
|
|
|
+ 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 ||
|
|
|
|
- daddr_scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
|
|
|
|
- daddr_dev && dev != daddr_dev)
|
|
|
|
|
|
+ if (((dst_type & IPV6_ADDR_MULTICAST) ||
|
|
|
|
+ dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL) &&
|
|
|
|
+ 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) {
|
|
|
|
- struct ipv6_saddr_score score;
|
|
|
|
|
|
+ for (score->ifa = idev->addr_list; score->ifa; score->ifa = score->ifa->if_next) {
|
|
|
|
+ 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) &&
|
|
|
|
- (!(ifa->flags & IFA_F_OPTIMISTIC)))
|
|
|
|
|
|
+ if ((score->ifa->flags & IFA_F_TENTATIVE) &&
|
|
|
|
+ (!(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.matchlen = 0;
|
|
|
|
- score.scope = 0;
|
|
|
|
- score.rule = 0;
|
|
|
|
-
|
|
|
|
- if (ifa_result == NULL) {
|
|
|
|
- /* record it if the first available entry */
|
|
|
|
- goto record_it;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /* Rule 1: Prefer same address */
|
|
|
|
- if (hiscore.rule < 1) {
|
|
|
|
- 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;
|
|
|
|
- }
|
|
|
|
|
|
+ score->rule = -1;
|
|
|
|
+ bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX);
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) {
|
|
|
|
+ int minihiscore, miniscore;
|
|
|
|
+
|
|
|
|
+ minihiscore = ipv6_get_saddr_eval(hiscore, &dst, i);
|
|
|
|
+ miniscore = ipv6_get_saddr_eval(score, &dst, i);
|
|
|
|
+
|
|
|
|
+ if (minihiscore > miniscore) {
|
|
|
|
+ if (i == IPV6_SADDR_RULE_SCOPE &&
|
|
|
|
+ score->scopedist > 0) {
|
|
|
|
+ /*
|
|
|
|
+ * special case:
|
|
|
|
+ * each remaining entry
|
|
|
|
+ * has too small (not enough)
|
|
|
|
+ * scope, because ifa entries
|
|
|
|
+ * are sorted by their scope
|
|
|
|
+ * values.
|
|
|
|
+ */
|
|
|
|
+ goto try_nextdev;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
+ } else if (minihiscore < miniscore) {
|
|
|
|
+ struct ipv6_saddr_score *tmp;
|
|
|
|
|
|
- /* Rule 2: Prefer appropriate scope */
|
|
|
|
- if (hiscore.rule < 2) {
|
|
|
|
- hiscore.scope = __ipv6_addr_src_scope(hiscore.addr_type);
|
|
|
|
- hiscore.rule++;
|
|
|
|
- }
|
|
|
|
- score.scope = __ipv6_addr_src_scope(score.addr_type);
|
|
|
|
- if (hiscore.scope < score.scope) {
|
|
|
|
- if (hiscore.scope < daddr_scope) {
|
|
|
|
- score.rule = 2;
|
|
|
|
- goto record_it;
|
|
|
|
- } else
|
|
|
|
- continue;
|
|
|
|
- } else if (score.scope < hiscore.scope) {
|
|
|
|
- if (score.scope < daddr_scope)
|
|
|
|
- break; /* addresses sorted by scope */
|
|
|
|
- else {
|
|
|
|
- score.rule = 2;
|
|
|
|
- goto record_it;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if (hiscore->ifa)
|
|
|
|
+ in6_ifa_put(hiscore->ifa);
|
|
|
|
|
|
- /* 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;
|
|
|
|
- }
|
|
|
|
|
|
+ in6_ifa_hold(score->ifa);
|
|
|
|
|
|
- /* 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
|
|
|
|
|
|
+ tmp = hiscore;
|
|
|
|
+ hiscore = score;
|
|
|
|
+ score = tmp;
|
|
|
|
|
|
- /* 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;
|
|
|
|
- }
|
|
|
|
|
|
+ /* restore our iterator */
|
|
|
|
+ score->ifa = hiscore->ifa;
|
|
|
|
|
|
-#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;
|
|
|
|
|
|
+ break;
|
|
}
|
|
}
|
|
- } 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);
|
|
|
|
- in6_ifa_put(ifa_result);
|
|
|
|
|
|
+ ipv6_addr_copy(saddr, &hiscore->ifa->addr);
|
|
|
|
+ in6_ifa_put(hiscore->ifa);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|