aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorErik Kline <ek@google.com>2015-02-04 06:01:23 -0500
committerDavid S. Miller <davem@davemloft.net>2015-02-05 18:37:41 -0500
commitc58da4c659803ac12eca5275c8a7064222adb4c7 (patch)
tree2be9074469ec18c9b99ba52065fe0b69d2bf3789
parent233c96fc077d310772375d47522fb444ff546905 (diff)
net: ipv6: allow explicitly choosing optimistic addresses
RFC 4429 ("Optimistic DAD") states that optimistic addresses should be treated as deprecated addresses. From section 2.1: Unless noted otherwise, components of the IPv6 protocol stack should treat addresses in the Optimistic state equivalently to those in the Deprecated state, indicating that the address is available for use but should not be used if another suitable address is available. Optimistic addresses are indeed avoided when other addresses are available (i.e. at source address selection time), but they have not heretofore been available for things like explicit bind() and sendmsg() with struct in6_pktinfo, etc. This change makes optimistic addresses treated more like deprecated addresses than tentative ones. Signed-off-by: Erik Kline <ek@google.com> Acked-by: Lorenzo Colitti <lorenzo@google.com> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/addrconf.h3
-rw-r--r--net/ipv6/addrconf.c19
-rw-r--r--net/ipv6/ndisc.c4
3 files changed, 23 insertions, 3 deletions
diff --git a/include/net/addrconf.h b/include/net/addrconf.h
index d13573bb879e..80456f72d70a 100644
--- a/include/net/addrconf.h
+++ b/include/net/addrconf.h
@@ -62,6 +62,9 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg);
62 62
63int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, 63int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
64 const struct net_device *dev, int strict); 64 const struct net_device *dev, int strict);
65int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr,
66 const struct net_device *dev, int strict,
67 u32 banned_flags);
65 68
66#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) 69#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
67int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr); 70int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr);
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index f7c8bbeb27b7..62900aee4c58 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1519,15 +1519,30 @@ static int ipv6_count_addresses(struct inet6_dev *idev)
1519int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, 1519int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
1520 const struct net_device *dev, int strict) 1520 const struct net_device *dev, int strict)
1521{ 1521{
1522 return ipv6_chk_addr_and_flags(net, addr, dev, strict, IFA_F_TENTATIVE);
1523}
1524EXPORT_SYMBOL(ipv6_chk_addr);
1525
1526int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr,
1527 const struct net_device *dev, int strict,
1528 u32 banned_flags)
1529{
1522 struct inet6_ifaddr *ifp; 1530 struct inet6_ifaddr *ifp;
1523 unsigned int hash = inet6_addr_hash(addr); 1531 unsigned int hash = inet6_addr_hash(addr);
1532 u32 ifp_flags;
1524 1533
1525 rcu_read_lock_bh(); 1534 rcu_read_lock_bh();
1526 hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { 1535 hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) {
1527 if (!net_eq(dev_net(ifp->idev->dev), net)) 1536 if (!net_eq(dev_net(ifp->idev->dev), net))
1528 continue; 1537 continue;
1538 /* Decouple optimistic from tentative for evaluation here.
1539 * Ban optimistic addresses explicitly, when required.
1540 */
1541 ifp_flags = (ifp->flags&IFA_F_OPTIMISTIC)
1542 ? (ifp->flags&~IFA_F_TENTATIVE)
1543 : ifp->flags;
1529 if (ipv6_addr_equal(&ifp->addr, addr) && 1544 if (ipv6_addr_equal(&ifp->addr, addr) &&
1530 !(ifp->flags&IFA_F_TENTATIVE) && 1545 !(ifp_flags&banned_flags) &&
1531 (dev == NULL || ifp->idev->dev == dev || 1546 (dev == NULL || ifp->idev->dev == dev ||
1532 !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { 1547 !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) {
1533 rcu_read_unlock_bh(); 1548 rcu_read_unlock_bh();
@@ -1538,7 +1553,7 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
1538 rcu_read_unlock_bh(); 1553 rcu_read_unlock_bh();
1539 return 0; 1554 return 0;
1540} 1555}
1541EXPORT_SYMBOL(ipv6_chk_addr); 1556EXPORT_SYMBOL(ipv6_chk_addr_and_flags);
1542 1557
1543static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, 1558static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
1544 struct net_device *dev) 1559 struct net_device *dev)
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 682866777d53..113fc6cd5a0c 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -655,7 +655,9 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
655 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; 655 struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
656 int probes = atomic_read(&neigh->probes); 656 int probes = atomic_read(&neigh->probes);
657 657
658 if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) 658 if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr,
659 dev, 1,
660 IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))
659 saddr = &ipv6_hdr(skb)->saddr; 661 saddr = &ipv6_hdr(skb)->saddr;
660 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); 662 probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
661 if (probes < 0) { 663 if (probes < 0) {