Skip to content

Commit

Permalink
ipv6: Fix incorrect disable_ipv6 behavior
Browse files Browse the repository at this point in the history
Fix the behavior of allowing both sysctl and addrconf_dad_failure()
to set the disable_ipv6 parameter without any bad side-effects.
If DAD fails and accept_dad > 1, we will still set disable_ipv6=1,
but then instead of allowing an RA to add an address then
immediately fail DAD, we simply don't allow the address to be
added in the first place.  This also lets the user set this flag
and disable all IPv6 addresses on the interface, or on the entire
system.

Signed-off-by: Brian Haley <brian.haley@hp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Brian Haley authored and David S. Miller committed Mar 19, 2009
1 parent cedc1db commit 9bdd8d4
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 8 deletions.
4 changes: 3 additions & 1 deletion Documentation/networking/ip-sysctl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,9 @@ max_addresses - INTEGER
Default: 16

disable_ipv6 - BOOLEAN
Disable IPv6 operation.
Disable IPv6 operation. If accept_dad is set to 2, this value
will be dynamically set to TRUE if DAD fails for the link-local
address.
Default: FALSE (enable IPv6 operation)

accept_dad - INTEGER
Expand Down
21 changes: 14 additions & 7 deletions net/ipv6/addrconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
{
struct inet6_ifaddr *ifa = NULL;
struct rt6_info *rt;
struct net *net = dev_net(idev->dev);
int hash;
int err = 0;
int addr_type = ipv6_addr_type(addr);
Expand All @@ -606,6 +607,11 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
goto out2;
}

if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) {
err = -EACCES;
goto out2;
}

write_lock(&addrconf_hash_lock);

/* Ignore adding duplicate addresses on an interface */
Expand Down Expand Up @@ -1433,6 +1439,11 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
void addrconf_dad_failure(struct inet6_ifaddr *ifp)
{
struct inet6_dev *idev = ifp->idev;

if (net_ratelimit())
printk(KERN_INFO "%s: IPv6 duplicate address detected!\n",
ifp->idev->dev->name);

if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
struct in6_addr addr;

Expand All @@ -1443,11 +1454,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
ipv6_addr_equal(&ifp->addr, &addr)) {
/* DAD failed for link-local based on MAC address */
idev->cnf.disable_ipv6 = 1;

printk(KERN_INFO "%s: IPv6 being disabled!\n",
ifp->idev->dev->name);
}
}

if (net_ratelimit())
printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
addrconf_dad_stop(ifp);
}

Expand Down Expand Up @@ -2823,11 +2835,6 @@ static void addrconf_dad_timer(unsigned long data)
read_unlock_bh(&idev->lock);
goto out;
}
if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) {
read_unlock_bh(&idev->lock);
addrconf_dad_failure(ifp);
return;
}
spin_lock_bh(&ifp->lock);
if (ifp->probes == 0) {
/*
Expand Down

0 comments on commit 9bdd8d4

Please sign in to comment.