summaryrefslogtreecommitdiff
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
authorBrian Haley <brian.haley@hp.com>2009-03-18 18:22:48 -0700
committerDavid S. Miller <davem@davemloft.net>2009-03-18 18:22:48 -0700
commit9bdd8d40c8c59435664af6049dabe24b7779b203 (patch)
tree9487117b9c98bcab3b0884fffa10dfbb0b01292a /net/ipv6/addrconf.c
parentcedc1dba74f481a632c5d5aedad0068d6ad945d8 (diff)
downloadlinux-3.10-9bdd8d40c8c59435664af6049dabe24b7779b203.tar.gz
linux-3.10-9bdd8d40c8c59435664af6049dabe24b7779b203.tar.bz2
linux-3.10-9bdd8d40c8c59435664af6049dabe24b7779b203.zip
ipv6: Fix incorrect disable_ipv6 behavior
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>
Diffstat (limited to 'net/ipv6/addrconf.c')
-rw-r--r--net/ipv6/addrconf.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index e83852ab4dc..717584bad02 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -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);
@@ -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 */
@@ -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;
@@ -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);
}
@@ -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) {
/*