Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 2780

kernel-2.6.18-238.el5.src.rpm

From: jolsa@redhat.com <jolsa@redhat.com>
Date: Fri, 17 Jul 2009 18:43:44 +0200
Subject: [net] ipv6: fix incorrect disable_ipv6 behavior
Message-id: 1247849024-9640-4-git-send-email-jolsa@redhat.com
O-Subject: [RHEL5 PATCH 3/3] ipv6: Fix incorrect disable_ipv6 behavior
Bugzilla: 512258
RH-Acked-by: David Miller <davem@redhat.com>

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.

wbr,
jirka

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 1f89683..6b99ed5 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -571,6 +571,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_device_extended *ext = (idev == NULL) ? NULL : dev_extended(idev->dev);
 	int hash;
 	int err = 0;
 
@@ -580,6 +581,11 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 		goto out2;
 	}
 
+	if (ext && ext->ipv6_devconf_ext.disable_ipv6) {
+		err = -EACCES;
+		goto out2;
+	}
+
 	write_lock(&addrconf_hash_lock);
 
 	/* Ignore adding duplicate addresses on an interface */
@@ -1335,6 +1341,10 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
 	struct inet6_dev *idev = ifp->idev;
 	struct net_device_extended *ext;
 
+	if (net_ratelimit())
+		printk(KERN_INFO "%s: IPv6 duplicate address detected!\n",
+			ifp->idev->dev->name);
+
 	ext = (idev->dev == NULL) ? NULL : dev_extended(idev->dev);
 
 	if (ext && ext->ipv6_devconf_ext.accept_dad > 1 && 
@@ -1348,11 +1358,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
 		    ipv6_addr_equal(&ifp->addr, &addr)) {
 			/* DAD failed for link-local based on MAC address */
 			ext->ipv6_devconf_ext.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);
 }
 
@@ -2635,7 +2646,6 @@ static void addrconf_dad_timer(unsigned long data)
 	struct inet6_dev *idev = ifp->idev;
 	struct in6_addr unspec;
 	struct in6_addr mcaddr;
-	struct net_device_extended *ext = (idev == NULL) ? NULL : dev_extended(idev->dev);
 
 	read_lock_bh(&idev->lock);
 	if (idev->dead) {
@@ -2643,13 +2653,6 @@ static void addrconf_dad_timer(unsigned long data)
 		goto out;
 	}
 
-	if (ext && ext->ipv6_devconf_ext.accept_dad > 1 &&
-	    ext->ipv6_devconf_ext.disable_ipv6) {
-		read_unlock_bh(&idev->lock);
-		addrconf_dad_failure(ifp);
-		return;
-	}
-
 	spin_lock_bh(&ifp->lock);
 	if (ifp->probes == 0) {
 		/*