aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrconf.c
diff options
context:
space:
mode:
authorBrian Haley <brian.haley@hp.com>2009-03-18 21:22:48 -0400
committerDavid S. Miller <davem@davemloft.net>2009-03-18 21:22:48 -0400
commit9bdd8d40c8c59435664af6049dabe24b7779b203 (patch)
tree9487117b9c98bcab3b0884fffa10dfbb0b01292a /net/ipv6/addrconf.c
parentcedc1dba74f481a632c5d5aedad0068d6ad945d8 (diff)
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 e83852ab4dc8..717584bad02e 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,
590{ 590{
591 struct inet6_ifaddr *ifa = NULL; 591 struct inet6_ifaddr *ifa = NULL;
592 struct rt6_info *rt; 592 struct rt6_info *rt;
593 struct net *net = dev_net(idev->dev);
593 int hash; 594 int hash;
594 int err = 0; 595 int err = 0;
595 int addr_type = ipv6_addr_type(addr); 596 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,
606 goto out2; 607 goto out2;
607 } 608 }
608 609
610 if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) {
611 err = -EACCES;
612 goto out2;
613 }
614
609 write_lock(&addrconf_hash_lock); 615 write_lock(&addrconf_hash_lock);
610 616
611 /* Ignore adding duplicate addresses on an interface */ 617 /* Ignore adding duplicate addresses on an interface */
@@ -1433,6 +1439,11 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
1433void addrconf_dad_failure(struct inet6_ifaddr *ifp) 1439void addrconf_dad_failure(struct inet6_ifaddr *ifp)
1434{ 1440{
1435 struct inet6_dev *idev = ifp->idev; 1441 struct inet6_dev *idev = ifp->idev;
1442
1443 if (net_ratelimit())
1444 printk(KERN_INFO "%s: IPv6 duplicate address detected!\n",
1445 ifp->idev->dev->name);
1446
1436 if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) { 1447 if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
1437 struct in6_addr addr; 1448 struct in6_addr addr;
1438 1449
@@ -1443,11 +1454,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
1443 ipv6_addr_equal(&ifp->addr, &addr)) { 1454 ipv6_addr_equal(&ifp->addr, &addr)) {
1444 /* DAD failed for link-local based on MAC address */ 1455 /* DAD failed for link-local based on MAC address */
1445 idev->cnf.disable_ipv6 = 1; 1456 idev->cnf.disable_ipv6 = 1;
1457
1458 printk(KERN_INFO "%s: IPv6 being disabled!\n",
1459 ifp->idev->dev->name);
1446 } 1460 }
1447 } 1461 }
1448 1462
1449 if (net_ratelimit())
1450 printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
1451 addrconf_dad_stop(ifp); 1463 addrconf_dad_stop(ifp);
1452} 1464}
1453 1465
@@ -2823,11 +2835,6 @@ static void addrconf_dad_timer(unsigned long data)
2823 read_unlock_bh(&idev->lock); 2835 read_unlock_bh(&idev->lock);
2824 goto out; 2836 goto out;
2825 } 2837 }
2826 if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) {
2827 read_unlock_bh(&idev->lock);
2828 addrconf_dad_failure(ifp);
2829 return;
2830 }
2831 spin_lock_bh(&ifp->lock); 2838 spin_lock_bh(&ifp->lock);
2832 if (ifp->probes == 0) { 2839 if (ifp->probes == 0) {
2833 /* 2840 /*