diff --git a/debian.master/changelog b/debian.master/changelog index 0a41d31..c4fcfd8 100644 --- a/debian.master/changelog +++ b/debian.master/changelog @@ -1,3 +1,9 @@ +linux (3.2.0-24.38retrosnub1) precise; urgency=low + + * net/ipv6: don't take interface down when enabling/disabling use_tempaddr + + -- Malcolm Scott Tue, 08 May 2012 15:57:20 +0100 + linux (3.2.0-24.38) precise-proposed; urgency=low [ Luis Henriques ] diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 98bb9ae..da889fe 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 @@ -1642,12 +1644,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) @@ -1672,8 +1683,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) { @@ -4351,12 +4360,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); + } + } } }