Commit c58da4c6 authored by Erik Kline's avatar Erik Kline Committed by David S. Miller

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: default avatarErik Kline <ek@google.com>
Acked-by: default avatarLorenzo Colitti <lorenzo@google.com>
Acked-by: default avatarHannes Frederic Sowa <hannes@stressinduktion.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 233c96fc
...@@ -62,6 +62,9 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg); ...@@ -62,6 +62,9 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg);
int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
const struct net_device *dev, int strict); const struct net_device *dev, int strict);
int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr,
const struct net_device *dev, int strict,
u32 banned_flags);
#if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE)
int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr); int ipv6_chk_home_addr(struct net *net, const struct in6_addr *addr);
......
...@@ -1518,16 +1518,31 @@ static int ipv6_count_addresses(struct inet6_dev *idev) ...@@ -1518,16 +1518,31 @@ static int ipv6_count_addresses(struct inet6_dev *idev)
int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
const struct net_device *dev, int strict) const struct net_device *dev, int strict)
{
return ipv6_chk_addr_and_flags(net, addr, dev, strict, IFA_F_TENTATIVE);
}
EXPORT_SYMBOL(ipv6_chk_addr);
int ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr,
const struct net_device *dev, int strict,
u32 banned_flags)
{ {
struct inet6_ifaddr *ifp; struct inet6_ifaddr *ifp;
unsigned int hash = inet6_addr_hash(addr); unsigned int hash = inet6_addr_hash(addr);
u32 ifp_flags;
rcu_read_lock_bh(); rcu_read_lock_bh();
hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) { hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) {
if (!net_eq(dev_net(ifp->idev->dev), net)) if (!net_eq(dev_net(ifp->idev->dev), net))
continue; continue;
/* Decouple optimistic from tentative for evaluation here.
* Ban optimistic addresses explicitly, when required.
*/
ifp_flags = (ifp->flags&IFA_F_OPTIMISTIC)
? (ifp->flags&~IFA_F_TENTATIVE)
: ifp->flags;
if (ipv6_addr_equal(&ifp->addr, addr) && if (ipv6_addr_equal(&ifp->addr, addr) &&
!(ifp->flags&IFA_F_TENTATIVE) && !(ifp_flags&banned_flags) &&
(dev == NULL || ifp->idev->dev == dev || (dev == NULL || ifp->idev->dev == dev ||
!(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) { !(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) {
rcu_read_unlock_bh(); rcu_read_unlock_bh();
...@@ -1538,7 +1553,7 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr, ...@@ -1538,7 +1553,7 @@ int ipv6_chk_addr(struct net *net, const struct in6_addr *addr,
rcu_read_unlock_bh(); rcu_read_unlock_bh();
return 0; return 0;
} }
EXPORT_SYMBOL(ipv6_chk_addr); EXPORT_SYMBOL(ipv6_chk_addr_and_flags);
static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr,
struct net_device *dev) struct net_device *dev)
......
...@@ -655,7 +655,9 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) ...@@ -655,7 +655,9 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
struct in6_addr *target = (struct in6_addr *)&neigh->primary_key; struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;
int probes = atomic_read(&neigh->probes); int probes = atomic_read(&neigh->probes);
if (skb && ipv6_chk_addr(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, 1)) if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr,
dev, 1,
IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))
saddr = &ipv6_hdr(skb)->saddr; saddr = &ipv6_hdr(skb)->saddr;
probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES); probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);
if (probes < 0) { if (probes < 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment