[PATCH Precise SRU] UBUNTU: SAUCE: net/ipv6: don't take interface down when enabling/disabling use_tempaddr
Tim Gardner
tim.gardner at canonical.com
Fri Jun 20 13:32:27 UTC 2014
From: Malcolm Scott <debianpkg at malc.org.uk>
BugLink: http://bugs.launchpad.net/bugs/994931
Altering use_tempaddr drops all IPv6 addresses.
Signed-off-by: Malcolm Scott <debianpkg at malc.org.uk>
Signed-off-by: Tim Gardner <tim.gardner at canonical.com>
---
net/ipv6/addrconf.c | 57 ++++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 43 insertions(+), 14 deletions(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 246a170..6e576c6 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -125,7 +125,8 @@ static inline void addrconf_sysctl_unregister(struct inet6_dev *idev)
#ifdef CONFIG_IPV6_PRIVACY
static int __ipv6_regen_rndid(struct inet6_dev *idev);
static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr);
-static void ipv6_regen_rndid(unsigned long data);
+static void ipv6_regen_rndid(struct inet6_dev *idev);
+static void ipv6_regen_rndid_tick(unsigned long data);
#endif
static int ipv6_generate_eui64(u8 *eui, struct net_device *dev);
@@ -409,7 +410,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
#ifdef CONFIG_IPV6_PRIVACY
INIT_LIST_HEAD(&ndev->tempaddr_list);
- setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev);
+ setup_timer(&ndev->regen_timer, ipv6_regen_rndid_tick, (unsigned long)ndev);
if ((dev->flags&IFF_LOOPBACK) ||
dev->type == ARPHRD_TUNNEL ||
dev->type == ARPHRD_TUNNEL6 ||
@@ -417,8 +418,9 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
dev->type == ARPHRD_NONE) {
ndev->cnf.use_tempaddr = -1;
} else {
- in6_dev_hold(ndev);
- ipv6_regen_rndid((unsigned long) ndev);
+ rcu_read_lock_bh();
+ ipv6_regen_rndid(ndev);
+ rcu_read_unlock_bh();
}
#endif
@@ -1649,12 +1651,21 @@ regen:
return 0;
}
-static void ipv6_regen_rndid(unsigned long data)
+static void ipv6_regen_rndid_tick(unsigned long data)
{
struct inet6_dev *idev = (struct inet6_dev *) data;
- unsigned long expires;
rcu_read_lock_bh();
+ ipv6_regen_rndid(idev);
+ rcu_read_unlock_bh();
+ in6_dev_put(idev);
+}
+
+/* called with rcu_read_lock_bh() */
+static void ipv6_regen_rndid(struct inet6_dev *idev)
+{
+ unsigned long expires;
+
write_lock_bh(&idev->lock);
if (idev->dead)
@@ -1679,8 +1690,6 @@ static void ipv6_regen_rndid(unsigned long data)
out:
write_unlock_bh(&idev->lock);
- rcu_read_unlock_bh();
- in6_dev_put(idev);
}
static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) {
@@ -4390,12 +4399,32 @@ static void dev_tempaddr_change(struct inet6_dev *idev)
if (!idev || !idev->dev)
return;
- if (!idev->cnf.disable_ipv6) {
- /* If ipv6 is enabled, try to bring down and back up the
- * interface to get new temporary addresses created
- */
- addrconf_notify(NULL, NETDEV_DOWN, idev->dev);
- addrconf_notify(NULL, NETDEV_UP, idev->dev);
+ /* Add/remove temporary addresses if necessary */
+ if (!idev->cnf.disable_ipv6 && idev->cnf.autoconf) {
+ if (idev->cnf.use_tempaddr > 0) {
+ struct inet6_ifaddr *ifp, *ifn;
+
+ /*
+ * Create a temporary address for every non-temporary,
+ * non-permanent (i.e. autoconfigured) address
+ */
+
+ ipv6_regen_rndid(idev);
+
+ list_for_each_entry_safe(ifp, ifn, &idev->addr_list, if_list) {
+ if (!(ifp->flags & (IFA_F_TEMPORARY | IFA_F_PERMANENT))) {
+ ipv6_create_tempaddr(ifp, NULL);
+ }
+ }
+ } else {
+ struct inet6_ifaddr *ifa;
+
+ while (!list_empty(&idev->tempaddr_list)) {
+ ifa = list_first_entry(&idev->tempaddr_list,
+ struct inet6_ifaddr, tmp_list);
+ ipv6_del_addr(ifa);
+ }
+ }
}
}
--
2.0.0
More information about the kernel-team
mailing list