diff options
Diffstat (limited to 'net/ipv6/addrconf.c')
| -rw-r--r-- | net/ipv6/addrconf.c | 807 | 
1 files changed, 400 insertions, 407 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 3381b4317c2..7cba8845242 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -53,6 +53,7 @@  #include <linux/route.h>  #include <linux/inetdevice.h>  #include <linux/init.h> +#include <linux/slab.h>  #ifdef CONFIG_SYSCTL  #include <linux/sysctl.h>  #endif @@ -81,7 +82,7 @@  #include <linux/random.h>  #endif -#include <asm/uaccess.h> +#include <linux/uaccess.h>  #include <asm/unaligned.h>  #include <linux/proc_fs.h> @@ -97,7 +98,11 @@  #endif  #define	INFINITY_LIFE_TIME	0xFFFFFFFF -#define TIME_DELTA(a,b) ((unsigned long)((long)(a) - (long)(b))) +#define TIME_DELTA(a, b) ((unsigned long)((long)(a) - (long)(b))) + +#define ADDRCONF_TIMER_FUZZ_MINUS	(HZ > 50 ? HZ/50 : 1) +#define ADDRCONF_TIMER_FUZZ		(HZ / 4) +#define ADDRCONF_TIMER_FUZZ_MAX		(HZ)  #ifdef CONFIG_SYSCTL  static void addrconf_sysctl_register(struct inet6_dev *idev); @@ -126,8 +131,8 @@ static int ipv6_count_addresses(struct inet6_dev *idev);  /*   *	Configured unicast address hash table   */ -static struct inet6_ifaddr		*inet6_addr_lst[IN6_ADDR_HSIZE]; -static DEFINE_RWLOCK(addrconf_hash_lock); +static struct hlist_head inet6_addr_lst[IN6_ADDR_HSIZE]; +static DEFINE_SPINLOCK(addrconf_hash_lock);  static void addrconf_verify(unsigned long); @@ -137,8 +142,8 @@ static DEFINE_SPINLOCK(addrconf_verify_lock);  static void addrconf_join_anycast(struct inet6_ifaddr *ifp);  static void addrconf_leave_anycast(struct inet6_ifaddr *ifp); -static void addrconf_bonding_change(struct net_device *dev, -				    unsigned long event); +static void addrconf_type_change(struct net_device *dev, +				 unsigned long event);  static int addrconf_ifdown(struct net_device *dev, int how);  static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags); @@ -151,8 +156,8 @@ static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifa);  static void inet6_prefix_notify(int event, struct inet6_dev *idev,  				struct prefix_info *pinfo); -static int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, -			      struct net_device *dev); +static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, +			       struct net_device *dev);  static ATOMIC_NOTIFIER_HEAD(inet6addr_chain); @@ -249,8 +254,7 @@ static void addrconf_del_timer(struct inet6_ifaddr *ifp)  		__in6_ifa_put(ifp);  } -enum addrconf_timer_t -{ +enum addrconf_timer_t {  	AC_NONE,  	AC_DAD,  	AC_RS, @@ -270,7 +274,8 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp,  	case AC_RS:  		ifp->timer.function = addrconf_rs_timer;  		break; -	default:; +	default: +		break;  	}  	ifp->timer.expires = jiffies + when;  	add_timer(&ifp->timer); @@ -317,7 +322,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)  {  	struct net_device *dev = idev->dev; -	WARN_ON(idev->addr_list != NULL); +	WARN_ON(!list_empty(&idev->addr_list));  	WARN_ON(idev->mc_list != NULL);  #ifdef NET_REFCNT_DEBUG @@ -325,7 +330,7 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)  #endif  	dev_put(dev);  	if (!idev->dead) { -		printk("Freeing alive inet6 device %p\n", idev); +		pr_warning("Freeing alive inet6 device %p\n", idev);  		return;  	}  	snmp6_free_dev(idev); @@ -350,6 +355,8 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)  	rwlock_init(&ndev->lock);  	ndev->dev = dev; +	INIT_LIST_HEAD(&ndev->addr_list); +  	memcpy(&ndev->cnf, dev_net(dev)->ipv6.devconf_dflt, sizeof(ndev->cnf));  	ndev->cnf.mtu6 = dev->mtu;  	ndev->cnf.sysctl = NULL; @@ -401,6 +408,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)  #endif  #ifdef CONFIG_IPV6_PRIVACY +	INIT_LIST_HEAD(&ndev->tempaddr_list);  	setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev);  	if ((dev->flags&IFF_LOOPBACK) ||  	    dev->type == ARPHRD_TUNNEL || @@ -438,8 +446,10 @@ static struct inet6_dev * ipv6_find_idev(struct net_device *dev)  	ASSERT_RTNL(); -	if ((idev = __in6_dev_get(dev)) == NULL) { -		if ((idev = ipv6_add_dev(dev)) == NULL) +	idev = __in6_dev_get(dev); +	if (!idev) { +		idev = ipv6_add_dev(dev); +		if (!idev)  			return NULL;  	} @@ -465,7 +475,8 @@ static void dev_forward_change(struct inet6_dev *idev)  		else  			ipv6_dev_mc_dec(dev, &in6addr_linklocal_allrouters);  	} -	for (ifa=idev->addr_list; ifa; ifa=ifa->if_next) { + +	list_for_each_entry(ifa, &idev->addr_list, if_list) {  		if (ifa->flags&IFA_F_TENTATIVE)  			continue;  		if (idev->cnf.forwarding) @@ -522,12 +533,16 @@ static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)  }  #endif -/* Nobody refers to this ifaddr, destroy it */ +static void inet6_ifa_finish_destroy_rcu(struct rcu_head *head) +{ +	struct inet6_ifaddr *ifp = container_of(head, struct inet6_ifaddr, rcu); +	kfree(ifp); +} +/* Nobody refers to this ifaddr, destroy it */  void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)  { -	WARN_ON(ifp->if_next != NULL); -	WARN_ON(ifp->lst_next != NULL); +	WARN_ON(!hlist_unhashed(&ifp->addr_lst));  #ifdef NET_REFCNT_DEBUG  	printk(KERN_DEBUG "inet6_ifa_finish_destroy\n"); @@ -536,54 +551,45 @@ void inet6_ifa_finish_destroy(struct inet6_ifaddr *ifp)  	in6_dev_put(ifp->idev);  	if (del_timer(&ifp->timer)) -		printk("Timer is still running, when freeing ifa=%p\n", ifp); +		pr_notice("Timer is still running, when freeing ifa=%p\n", ifp);  	if (!ifp->dead) { -		printk("Freeing alive inet6 address %p\n", ifp); +		pr_warning("Freeing alive inet6 address %p\n", ifp);  		return;  	}  	dst_release(&ifp->rt->u.dst); -	kfree(ifp); +	call_rcu(&ifp->rcu, inet6_ifa_finish_destroy_rcu);  }  static void  ipv6_link_dev_addr(struct inet6_dev *idev, struct inet6_ifaddr *ifp)  { -	struct inet6_ifaddr *ifa, **ifap; +	struct list_head *p;  	int ifp_scope = ipv6_addr_src_scope(&ifp->addr);  	/*  	 * Each device address list is sorted in order of scope -  	 * global before linklocal.  	 */ -	for (ifap = &idev->addr_list; (ifa = *ifap) != NULL; -	     ifap = &ifa->if_next) { +	list_for_each(p, &idev->addr_list) { +		struct inet6_ifaddr *ifa +			= list_entry(p, struct inet6_ifaddr, if_list);  		if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr))  			break;  	} -	ifp->if_next = *ifap; -	*ifap = ifp; +	list_add_tail(&ifp->if_list, p);  } -/* - *	Hash function taken from net_alias.c - */ -static u8 ipv6_addr_hash(const struct in6_addr *addr) +static u32 ipv6_addr_hash(const struct in6_addr *addr)  { -	__u32 word; -  	/*  	 * We perform the hash function over the last 64 bits of the address  	 * This will include the IEEE address token on links that support it.  	 */ - -	word = (__force u32)(addr->s6_addr32[2] ^ addr->s6_addr32[3]); -	word ^= (word >> 16); -	word ^= (word >> 8); - -	return ((word ^ (word >> 4)) & 0x0f); +	return jhash_2words(addr->s6_addr32[2],  addr->s6_addr32[3], 0) +		& (IN6_ADDR_HSIZE - 1);  }  /* On success it returns ifp with increased reference count */ @@ -594,7 +600,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,  {  	struct inet6_ifaddr *ifa = NULL;  	struct rt6_info *rt; -	int hash; +	unsigned int hash;  	int err = 0;  	int addr_type = ipv6_addr_type(addr); @@ -615,7 +621,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,  		goto out2;  	} -	write_lock(&addrconf_hash_lock); +	spin_lock(&addrconf_hash_lock);  	/* Ignore adding duplicate addresses on an interface */  	if (ipv6_chk_same_addr(dev_net(idev->dev), addr, idev->dev)) { @@ -642,6 +648,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,  	spin_lock_init(&ifa->lock);  	init_timer(&ifa->timer); +	INIT_HLIST_NODE(&ifa->addr_lst);  	ifa->timer.data = (unsigned long) ifa;  	ifa->scope = scope;  	ifa->prefix_len = pfxlen; @@ -668,10 +675,8 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,  	/* Add to big hash table */  	hash = ipv6_addr_hash(addr); -	ifa->lst_next = inet6_addr_lst[hash]; -	inet6_addr_lst[hash] = ifa; -	in6_ifa_hold(ifa); -	write_unlock(&addrconf_hash_lock); +	hlist_add_head_rcu(&ifa->addr_lst, &inet6_addr_lst[hash]); +	spin_unlock(&addrconf_hash_lock);  	write_lock(&idev->lock);  	/* Add to inet6_dev unicast addr list. */ @@ -679,8 +684,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,  #ifdef CONFIG_IPV6_PRIVACY  	if (ifa->flags&IFA_F_TEMPORARY) { -		ifa->tmp_next = idev->tempaddr_list; -		idev->tempaddr_list = ifa; +		list_add(&ifa->tmp_list, &idev->tempaddr_list);  		in6_ifa_hold(ifa);  	}  #endif @@ -699,7 +703,7 @@ out2:  	return ifa;  out: -	write_unlock(&addrconf_hash_lock); +	spin_unlock(&addrconf_hash_lock);  	goto out2;  } @@ -707,7 +711,7 @@ out:  static void ipv6_del_addr(struct inet6_ifaddr *ifp)  { -	struct inet6_ifaddr *ifa, **ifap; +	struct inet6_ifaddr *ifa, *ifn;  	struct inet6_dev *idev = ifp->idev;  	int hash;  	int deleted = 0, onlink = 0; @@ -717,42 +721,27 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)  	ifp->dead = 1; -	write_lock_bh(&addrconf_hash_lock); -	for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL; -	     ifap = &ifa->lst_next) { -		if (ifa == ifp) { -			*ifap = ifa->lst_next; -			__in6_ifa_put(ifp); -			ifa->lst_next = NULL; -			break; -		} -	} -	write_unlock_bh(&addrconf_hash_lock); +	spin_lock_bh(&addrconf_hash_lock); +	hlist_del_init_rcu(&ifp->addr_lst); +	spin_unlock_bh(&addrconf_hash_lock);  	write_lock_bh(&idev->lock);  #ifdef CONFIG_IPV6_PRIVACY  	if (ifp->flags&IFA_F_TEMPORARY) { -		for (ifap = &idev->tempaddr_list; (ifa=*ifap) != NULL; -		     ifap = &ifa->tmp_next) { -			if (ifa == ifp) { -				*ifap = ifa->tmp_next; -				if (ifp->ifpub) { -					in6_ifa_put(ifp->ifpub); -					ifp->ifpub = NULL; -				} -				__in6_ifa_put(ifp); -				ifa->tmp_next = NULL; -				break; -			} +		list_del(&ifp->tmp_list); +		if (ifp->ifpub) { +			in6_ifa_put(ifp->ifpub); +			ifp->ifpub = NULL;  		} +		__in6_ifa_put(ifp);  	}  #endif -	for (ifap = &idev->addr_list; (ifa=*ifap) != NULL;) { +	list_for_each_entry_safe(ifa, ifn, &idev->addr_list, if_list) {  		if (ifa == ifp) { -			*ifap = ifa->if_next; +			list_del_init(&ifp->if_list);  			__in6_ifa_put(ifp); -			ifa->if_next = NULL; +  			if (!(ifp->flags & IFA_F_PERMANENT) || onlink > 0)  				break;  			deleted = 1; @@ -785,7 +774,6 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)  				}  			}  		} -		ifap = &ifa->if_next;  	}  	write_unlock_bh(&idev->lock); @@ -1164,7 +1152,7 @@ int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,  			continue;  		read_lock_bh(&idev->lock); -		for (score->ifa = idev->addr_list; score->ifa; score->ifa = score->ifa->if_next) { +		list_for_each_entry(score->ifa, &idev->addr_list, if_list) {  			int i;  			/* @@ -1242,7 +1230,6 @@ try_nextdev:  	in6_ifa_put(hiscore->ifa);  	return 0;  } -  EXPORT_SYMBOL(ipv6_dev_get_saddr);  int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, @@ -1252,12 +1239,14 @@ int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr,  	int err = -EADDRNOTAVAIL;  	rcu_read_lock(); -	if ((idev = __in6_dev_get(dev)) != NULL) { +	idev = __in6_dev_get(dev); +	if (idev) {  		struct inet6_ifaddr *ifp;  		read_lock_bh(&idev->lock); -		for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { -			if (ifp->scope == IFA_LINK && !(ifp->flags & banned_flags)) { +		list_for_each_entry(ifp, &idev->addr_list, if_list) { +			if (ifp->scope == IFA_LINK && +			    !(ifp->flags & banned_flags)) {  				ipv6_addr_copy(addr, &ifp->addr);  				err = 0;  				break; @@ -1275,7 +1264,7 @@ static int ipv6_count_addresses(struct inet6_dev *idev)  	struct inet6_ifaddr *ifp;  	read_lock_bh(&idev->lock); -	for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) +	list_for_each_entry(ifp, &idev->addr_list, if_list)  		cnt++;  	read_unlock_bh(&idev->lock);  	return cnt; @@ -1284,11 +1273,12 @@ static int ipv6_count_addresses(struct inet6_dev *idev)  int ipv6_chk_addr(struct net *net, struct in6_addr *addr,  		  struct net_device *dev, int strict)  { -	struct inet6_ifaddr * ifp; -	u8 hash = ipv6_addr_hash(addr); +	struct inet6_ifaddr *ifp = NULL; +	struct hlist_node *node; +	unsigned int hash = ipv6_addr_hash(addr); -	read_lock_bh(&addrconf_hash_lock); -	for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { +	rcu_read_lock_bh(); +	hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) {  		if (!net_eq(dev_net(ifp->idev->dev), net))  			continue;  		if (ipv6_addr_equal(&ifp->addr, addr) && @@ -1298,27 +1288,28 @@ int ipv6_chk_addr(struct net *net, struct in6_addr *addr,  				break;  		}  	} -	read_unlock_bh(&addrconf_hash_lock); +	rcu_read_unlock_bh(); +  	return ifp != NULL;  }  EXPORT_SYMBOL(ipv6_chk_addr); -static -int ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, -		       struct net_device *dev) +static bool ipv6_chk_same_addr(struct net *net, const struct in6_addr *addr, +			       struct net_device *dev)  { -	struct inet6_ifaddr * ifp; -	u8 hash = ipv6_addr_hash(addr); +	unsigned int hash = ipv6_addr_hash(addr); +	struct inet6_ifaddr *ifp; +	struct hlist_node *node; -	for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { +	hlist_for_each_entry(ifp, node, &inet6_addr_lst[hash], addr_lst) {  		if (!net_eq(dev_net(ifp->idev->dev), net))  			continue;  		if (ipv6_addr_equal(&ifp->addr, addr)) {  			if (dev == NULL || ifp->idev->dev == dev) -				break; +				return true;  		}  	} -	return ifp != NULL; +	return false;  }  int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev) @@ -1332,7 +1323,7 @@ int ipv6_chk_prefix(struct in6_addr *addr, struct net_device *dev)  	idev = __in6_dev_get(dev);  	if (idev) {  		read_lock_bh(&idev->lock); -		for (ifa = idev->addr_list; ifa; ifa = ifa->if_next) { +		list_for_each_entry(ifa, &idev->addr_list, if_list) {  			onlink = ipv6_prefix_equal(addr, &ifa->addr,  						   ifa->prefix_len);  			if (onlink) @@ -1349,24 +1340,26 @@ EXPORT_SYMBOL(ipv6_chk_prefix);  struct inet6_ifaddr *ipv6_get_ifaddr(struct net *net, const struct in6_addr *addr,  				     struct net_device *dev, int strict)  { -	struct inet6_ifaddr * ifp; -	u8 hash = ipv6_addr_hash(addr); +	struct inet6_ifaddr *ifp, *result = NULL; +	unsigned int hash = ipv6_addr_hash(addr); +	struct hlist_node *node; -	read_lock_bh(&addrconf_hash_lock); -	for(ifp = inet6_addr_lst[hash]; ifp; ifp=ifp->lst_next) { +	rcu_read_lock_bh(); +	hlist_for_each_entry_rcu(ifp, node, &inet6_addr_lst[hash], addr_lst) {  		if (!net_eq(dev_net(ifp->idev->dev), net))  			continue;  		if (ipv6_addr_equal(&ifp->addr, addr)) {  			if (dev == NULL || ifp->idev->dev == dev ||  			    !(ifp->scope&(IFA_LINK|IFA_HOST) || strict)) { +				result = ifp;  				in6_ifa_hold(ifp);  				break;  			}  		}  	} -	read_unlock_bh(&addrconf_hash_lock); +	rcu_read_unlock_bh(); -	return ifp; +	return result;  }  /* Gets referenced address, destroys ifaddr */ @@ -1569,7 +1562,7 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)  	struct inet6_ifaddr *ifp;  	read_lock_bh(&idev->lock); -	for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { +	list_for_each_entry(ifp, &idev->addr_list, if_list) {  		if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) {  			memcpy(eui, ifp->addr.s6_addr+8, 8);  			err = 0; @@ -1737,7 +1730,8 @@ static struct inet6_dev *addrconf_add_dev(struct net_device *dev)  	ASSERT_RTNL(); -	if ((idev = ipv6_find_idev(dev)) == NULL) +	idev = ipv6_find_idev(dev); +	if (!idev)  		return NULL;  	/* Add default multicast route */ @@ -1970,7 +1964,7 @@ ok:  #ifdef CONFIG_IPV6_PRIVACY  			read_lock_bh(&in6_dev->lock);  			/* update all temporary addresses in the list */ -			for (ift=in6_dev->tempaddr_list; ift; ift=ift->tmp_next) { +			list_for_each_entry(ift, &in6_dev->tempaddr_list, tmp_list) {  				/*  				 * When adjusting the lifetimes of an existing  				 * temporary address, only lower the lifetimes. @@ -2173,7 +2167,7 @@ static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx,  		return -ENXIO;  	read_lock_bh(&idev->lock); -	for (ifp = idev->addr_list; ifp; ifp=ifp->if_next) { +	list_for_each_entry(ifp, &idev->addr_list, if_list) {  		if (ifp->prefix_len == plen &&  		    ipv6_addr_equal(pfx, &ifp->addr)) {  			in6_ifa_hold(ifp); @@ -2184,7 +2178,7 @@ static int inet6_addr_del(struct net *net, int ifindex, struct in6_addr *pfx,  			/* If the last address is deleted administratively,  			   disable IPv6 on this interface.  			 */ -			if (idev->addr_list == NULL) +			if (list_empty(&idev->addr_list))  				addrconf_ifdown(idev->dev, 1);  			return 0;  		} @@ -2445,7 +2439,8 @@ static void addrconf_ip6_tnl_config(struct net_device *dev)  	ASSERT_RTNL(); -	if ((idev = addrconf_add_dev(dev)) == NULL) { +	idev = addrconf_add_dev(dev); +	if (!idev) {  		printk(KERN_DEBUG "init ip6-ip6: add_dev failed\n");  		return;  	} @@ -2460,7 +2455,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,  	int run_pending = 0;  	int err; -	switch(event) { +	switch (event) {  	case NETDEV_REGISTER:  		if (!idev && dev->mtu >= IPV6_MIN_MTU) {  			idev = ipv6_add_dev(dev); @@ -2468,6 +2463,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,  				return notifier_from_errno(-ENOMEM);  		}  		break; +  	case NETDEV_UP:  	case NETDEV_CHANGE:  		if (dev->flags & IFF_SLAVE) @@ -2497,10 +2493,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,  			}  			if (idev) { -				if (idev->if_flags & IF_READY) { +				if (idev->if_flags & IF_READY)  					/* device is already configured. */  					break; -				}  				idev->if_flags |= IF_READY;  			} @@ -2512,7 +2507,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,  			run_pending = 1;  		} -		switch(dev->type) { +		switch (dev->type) {  #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)  		case ARPHRD_SIT:  			addrconf_sit_config(dev); @@ -2529,25 +2524,30 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,  			addrconf_dev_config(dev);  			break;  		} +  		if (idev) {  			if (run_pending)  				addrconf_dad_run(idev); -			/* If the MTU changed during the interface down, when the -			   interface up, the changed MTU must be reflected in the -			   idev as well as routers. +			/* +			 * If the MTU changed during the interface down, +			 * when the interface up, the changed MTU must be +			 * reflected in the idev as well as routers.  			 */ -			if (idev->cnf.mtu6 != dev->mtu && dev->mtu >= IPV6_MIN_MTU) { +			if (idev->cnf.mtu6 != dev->mtu && +			    dev->mtu >= IPV6_MIN_MTU) {  				rt6_mtu_change(dev, dev->mtu);  				idev->cnf.mtu6 = dev->mtu;  			}  			idev->tstamp = jiffies;  			inet6_ifinfo_notify(RTM_NEWLINK, idev); -			/* If the changed mtu during down is lower than IPV6_MIN_MTU -			   stop IPv6 on this interface. + +			/* +			 * If the changed mtu during down is lower than +			 * IPV6_MIN_MTU stop IPv6 on this interface.  			 */  			if (dev->mtu < IPV6_MIN_MTU) -				addrconf_ifdown(dev, event != NETDEV_DOWN); +				addrconf_ifdown(dev, 1);  		}  		break; @@ -2564,7 +2564,10 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,  				break;  		} -		/* MTU falled under IPV6_MIN_MTU. Stop IPv6 on this interface. */ +		/* +		 * MTU falled under IPV6_MIN_MTU. +		 * Stop IPv6 on this interface. +		 */  	case NETDEV_DOWN:  	case NETDEV_UNREGISTER: @@ -2584,9 +2587,10 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,  				return notifier_from_errno(err);  		}  		break; -	case NETDEV_BONDING_OLDTYPE: -	case NETDEV_BONDING_NEWTYPE: -		addrconf_bonding_change(dev, event); + +	case NETDEV_PRE_TYPE_CHANGE: +	case NETDEV_POST_TYPE_CHANGE: +		addrconf_type_change(dev, event);  		break;  	} @@ -2598,28 +2602,27 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,   */  static struct notifier_block ipv6_dev_notf = {  	.notifier_call = addrconf_notify, -	.priority = 0  }; -static void addrconf_bonding_change(struct net_device *dev, unsigned long event) +static void addrconf_type_change(struct net_device *dev, unsigned long event)  {  	struct inet6_dev *idev;  	ASSERT_RTNL();  	idev = __in6_dev_get(dev); -	if (event == NETDEV_BONDING_NEWTYPE) +	if (event == NETDEV_POST_TYPE_CHANGE)  		ipv6_mc_remap(idev); -	else if (event == NETDEV_BONDING_OLDTYPE) +	else if (event == NETDEV_PRE_TYPE_CHANGE)  		ipv6_mc_unmap(idev);  }  static int addrconf_ifdown(struct net_device *dev, int how)  { -	struct inet6_dev *idev; -	struct inet6_ifaddr *ifa, *keep_list, **bifa;  	struct net *net = dev_net(dev); -	int i; +	struct inet6_dev *idev; +	struct inet6_ifaddr *ifa; +	LIST_HEAD(keep_list);  	ASSERT_RTNL(); @@ -2630,8 +2633,9 @@ static int addrconf_ifdown(struct net_device *dev, int how)  	if (idev == NULL)  		return -ENODEV; -	/* Step 1: remove reference to ipv6 device from parent device. -		   Do not dev_put! +	/* +	 * Step 1: remove reference to ipv6 device from parent device. +	 *	   Do not dev_put!  	 */  	if (how) {  		idev->dead = 1; @@ -2644,40 +2648,21 @@ static int addrconf_ifdown(struct net_device *dev, int how)  	} -	/* Step 2: clear hash table */ -	for (i=0; i<IN6_ADDR_HSIZE; i++) { -		bifa = &inet6_addr_lst[i]; - -		write_lock_bh(&addrconf_hash_lock); -		while ((ifa = *bifa) != NULL) { -			if (ifa->idev == idev && -			    (how || !(ifa->flags&IFA_F_PERMANENT) || -			     ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) { -				*bifa = ifa->lst_next; -				ifa->lst_next = NULL; -				__in6_ifa_put(ifa); -				continue; -			} -			bifa = &ifa->lst_next; -		} -		write_unlock_bh(&addrconf_hash_lock); -	} -  	write_lock_bh(&idev->lock); -	/* Step 3: clear flags for stateless addrconf */ +	/* Step 2: clear flags for stateless addrconf */  	if (!how)  		idev->if_flags &= ~(IF_RS_SENT|IF_RA_RCVD|IF_READY); -	/* Step 4: clear address list */  #ifdef CONFIG_IPV6_PRIVACY  	if (how && del_timer(&idev->regen_timer))  		in6_dev_put(idev); -	/* clear tempaddr list */ -	while ((ifa = idev->tempaddr_list) != NULL) { -		idev->tempaddr_list = ifa->tmp_next; -		ifa->tmp_next = NULL; +	/* Step 3: clear tempaddr list */ +	while (!list_empty(&idev->tempaddr_list)) { +		ifa = list_first_entry(&idev->tempaddr_list, +				       struct inet6_ifaddr, tmp_list); +		list_del(&ifa->tmp_list);  		ifa->dead = 1;  		write_unlock_bh(&idev->lock);  		spin_lock_bh(&ifa->lock); @@ -2691,23 +2676,18 @@ static int addrconf_ifdown(struct net_device *dev, int how)  		write_lock_bh(&idev->lock);  	}  #endif -	keep_list = NULL; -	bifa = &keep_list; -	while ((ifa = idev->addr_list) != NULL) { -		idev->addr_list = ifa->if_next; -		ifa->if_next = NULL; +	while (!list_empty(&idev->addr_list)) { +		ifa = list_first_entry(&idev->addr_list, +				       struct inet6_ifaddr, if_list);  		addrconf_del_timer(ifa);  		/* If just doing link down, and address is permanent  		   and not link-local, then retain it. */ -		if (how == 0 && +		if (!how &&  		    (ifa->flags&IFA_F_PERMANENT) &&  		    !(ipv6_addr_type(&ifa->addr) & IPV6_ADDR_LINKLOCAL)) { - -			/* Move to holding list */ -			*bifa = ifa; -			bifa = &ifa->if_next; +			list_move_tail(&ifa->if_list, &keep_list);  			/* If not doing DAD on this address, just keep it. */  			if ((dev->flags&(IFF_NOARP|IFF_LOOPBACK)) || @@ -2722,24 +2702,32 @@ static int addrconf_ifdown(struct net_device *dev, int how)  			/* Flag it for later restoration when link comes up */  			ifa->flags |= IFA_F_TENTATIVE;  			in6_ifa_hold(ifa); +			write_unlock_bh(&idev->lock);  		} else { +			list_del(&ifa->if_list);  			ifa->dead = 1; +			write_unlock_bh(&idev->lock); + +			/* clear hash table */ +			spin_lock_bh(&addrconf_hash_lock); +			hlist_del_init_rcu(&ifa->addr_lst); +			spin_unlock_bh(&addrconf_hash_lock);  		} -		write_unlock_bh(&idev->lock);  		__ipv6_ifa_notify(RTM_DELADDR, ifa); -		atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa); +		if (ifa->dead) +			atomic_notifier_call_chain(&inet6addr_chain, +						   NETDEV_DOWN, ifa);  		in6_ifa_put(ifa);  		write_lock_bh(&idev->lock);  	} -	idev->addr_list = keep_list; +	list_splice(&keep_list, &idev->addr_list);  	write_unlock_bh(&idev->lock);  	/* Step 5: Discard multicast list */ -  	if (how)  		ipv6_mc_destroy_dev(idev);  	else @@ -2747,8 +2735,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)  	idev->tstamp = jiffies; -	/* Shot the device (if unregistered) */ - +	/* Last: Shot the device (if unregistered) */  	if (how) {  		addrconf_sysctl_unregister(idev);  		neigh_parms_release(&nd_tbl, idev->nd_parms); @@ -2859,7 +2846,7 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp, u32 flags)  	 * Optimistic nodes can start receiving  	 * Frames right away  	 */ -	if(ifp->flags & IFA_F_OPTIMISTIC) +	if (ifp->flags & IFA_F_OPTIMISTIC)  		ip6_ins_rt(ifp->rt);  	addrconf_dad_kick(ifp); @@ -2909,7 +2896,7 @@ out:  static void addrconf_dad_completed(struct inet6_ifaddr *ifp)  { -	struct net_device *	dev = ifp->idev->dev; +	struct net_device *dev = ifp->idev->dev;  	/*  	 *	Configure the address for reception. Now it is valid. @@ -2940,11 +2927,12 @@ static void addrconf_dad_completed(struct inet6_ifaddr *ifp)  	}  } -static void addrconf_dad_run(struct inet6_dev *idev) { +static void addrconf_dad_run(struct inet6_dev *idev) +{  	struct inet6_ifaddr *ifp;  	read_lock_bh(&idev->lock); -	for (ifp = idev->addr_list; ifp; ifp = ifp->if_next) { +	list_for_each_entry(ifp, &idev->addr_list, if_list) {  		spin_lock(&ifp->lock);  		if (!(ifp->flags & IFA_F_TENTATIVE)) {  			spin_unlock(&ifp->lock); @@ -2969,36 +2957,35 @@ static struct inet6_ifaddr *if6_get_first(struct seq_file *seq)  	struct net *net = seq_file_net(seq);  	for (state->bucket = 0; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) { -		ifa = inet6_addr_lst[state->bucket]; - -		while (ifa && !net_eq(dev_net(ifa->idev->dev), net)) -			ifa = ifa->lst_next; -		if (ifa) -			break; +		struct hlist_node *n; +		hlist_for_each_entry_rcu(ifa, n, &inet6_addr_lst[state->bucket], +					 addr_lst) +			if (net_eq(dev_net(ifa->idev->dev), net)) +				return ifa;  	} -	return ifa; +	return NULL;  } -static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, struct inet6_ifaddr *ifa) +static struct inet6_ifaddr *if6_get_next(struct seq_file *seq, +					 struct inet6_ifaddr *ifa)  {  	struct if6_iter_state *state = seq->private;  	struct net *net = seq_file_net(seq); +	struct hlist_node *n = &ifa->addr_lst; -	ifa = ifa->lst_next; -try_again: -	if (ifa) { -		if (!net_eq(dev_net(ifa->idev->dev), net)) { -			ifa = ifa->lst_next; -			goto try_again; -		} -	} +	hlist_for_each_entry_continue_rcu(ifa, n, addr_lst) +		if (net_eq(dev_net(ifa->idev->dev), net)) +			return ifa; -	if (!ifa && ++state->bucket < IN6_ADDR_HSIZE) { -		ifa = inet6_addr_lst[state->bucket]; -		goto try_again; +	while (++state->bucket < IN6_ADDR_HSIZE) { +		hlist_for_each_entry(ifa, n, +				     &inet6_addr_lst[state->bucket], addr_lst) { +			if (net_eq(dev_net(ifa->idev->dev), net)) +				return ifa; +		}  	} -	return ifa; +	return NULL;  }  static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos) @@ -3006,15 +2993,15 @@ static struct inet6_ifaddr *if6_get_idx(struct seq_file *seq, loff_t pos)  	struct inet6_ifaddr *ifa = if6_get_first(seq);  	if (ifa) -		while(pos && (ifa = if6_get_next(seq, ifa)) != NULL) +		while (pos && (ifa = if6_get_next(seq, ifa)) != NULL)  			--pos;  	return pos ? NULL : ifa;  }  static void *if6_seq_start(struct seq_file *seq, loff_t *pos) -	__acquires(addrconf_hash_lock) +	__acquires(rcu)  { -	read_lock_bh(&addrconf_hash_lock); +	rcu_read_lock_bh();  	return if6_get_idx(seq, *pos);  } @@ -3028,9 +3015,9 @@ static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos)  }  static void if6_seq_stop(struct seq_file *seq, void *v) -	__releases(addrconf_hash_lock) +	__releases(rcu)  { -	read_unlock_bh(&addrconf_hash_lock); +	rcu_read_unlock_bh();  }  static int if6_seq_show(struct seq_file *seq, void *v) @@ -3100,10 +3087,12 @@ void if6_proc_exit(void)  int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)  {  	int ret = 0; -	struct inet6_ifaddr * ifp; -	u8 hash = ipv6_addr_hash(addr); -	read_lock_bh(&addrconf_hash_lock); -	for (ifp = inet6_addr_lst[hash]; ifp; ifp = ifp->lst_next) { +	struct inet6_ifaddr *ifp = NULL; +	struct hlist_node *n; +	unsigned int hash = ipv6_addr_hash(addr); + +	rcu_read_lock_bh(); +	hlist_for_each_entry_rcu(ifp, n, &inet6_addr_lst[hash], addr_lst) {  		if (!net_eq(dev_net(ifp->idev->dev), net))  			continue;  		if (ipv6_addr_equal(&ifp->addr, addr) && @@ -3112,7 +3101,7 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)  			break;  		}  	} -	read_unlock_bh(&addrconf_hash_lock); +	rcu_read_unlock_bh();  	return ret;  }  #endif @@ -3123,43 +3112,35 @@ int ipv6_chk_home_addr(struct net *net, struct in6_addr *addr)  static void addrconf_verify(unsigned long foo)  { +	unsigned long now, next, next_sec, next_sched;  	struct inet6_ifaddr *ifp; -	unsigned long now, next; +	struct hlist_node *node;  	int i; -	spin_lock_bh(&addrconf_verify_lock); +	rcu_read_lock_bh(); +	spin_lock(&addrconf_verify_lock);  	now = jiffies; -	next = now + ADDR_CHECK_FREQUENCY; +	next = round_jiffies_up(now + ADDR_CHECK_FREQUENCY);  	del_timer(&addr_chk_timer); -	for (i=0; i < IN6_ADDR_HSIZE; i++) { - +	for (i = 0; i < IN6_ADDR_HSIZE; i++) {  restart: -		read_lock(&addrconf_hash_lock); -		for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) { +		hlist_for_each_entry_rcu(ifp, node, +					 &inet6_addr_lst[i], addr_lst) {  			unsigned long age; -#ifdef CONFIG_IPV6_PRIVACY -			unsigned long regen_advance; -#endif  			if (ifp->flags & IFA_F_PERMANENT)  				continue;  			spin_lock(&ifp->lock); -			age = (now - ifp->tstamp) / HZ; - -#ifdef CONFIG_IPV6_PRIVACY -			regen_advance = ifp->idev->cnf.regen_max_retry * -					ifp->idev->cnf.dad_transmits * -					ifp->idev->nd_parms->retrans_time / HZ; -#endif +			/* We try to batch several events at once. */ +			age = (now - ifp->tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ;  			if (ifp->valid_lft != INFINITY_LIFE_TIME &&  			    age >= ifp->valid_lft) {  				spin_unlock(&ifp->lock);  				in6_ifa_hold(ifp); -				read_unlock(&addrconf_hash_lock);  				ipv6_del_addr(ifp);  				goto restart;  			} else if (ifp->prefered_lft == INFINITY_LIFE_TIME) { @@ -3181,7 +3162,6 @@ restart:  				if (deprecate) {  					in6_ifa_hold(ifp); -					read_unlock(&addrconf_hash_lock);  					ipv6_ifa_notify(0, ifp);  					in6_ifa_put(ifp); @@ -3190,6 +3170,10 @@ restart:  #ifdef CONFIG_IPV6_PRIVACY  			} else if ((ifp->flags&IFA_F_TEMPORARY) &&  				   !(ifp->flags&IFA_F_TENTATIVE)) { +				unsigned long regen_advance = ifp->idev->cnf.regen_max_retry * +					ifp->idev->cnf.dad_transmits * +					ifp->idev->nd_parms->retrans_time / HZ; +  				if (age >= ifp->prefered_lft - regen_advance) {  					struct inet6_ifaddr *ifpub = ifp->ifpub;  					if (time_before(ifp->tstamp + ifp->prefered_lft * HZ, next)) @@ -3199,7 +3183,7 @@ restart:  						in6_ifa_hold(ifp);  						in6_ifa_hold(ifpub);  						spin_unlock(&ifp->lock); -						read_unlock(&addrconf_hash_lock); +  						spin_lock(&ifpub->lock);  						ifpub->regen_count = 0;  						spin_unlock(&ifpub->lock); @@ -3219,12 +3203,26 @@ restart:  				spin_unlock(&ifp->lock);  			}  		} -		read_unlock(&addrconf_hash_lock);  	} -	addr_chk_timer.expires = time_before(next, jiffies + HZ) ? jiffies + HZ : next; +	next_sec = round_jiffies_up(next); +	next_sched = next; + +	/* If rounded timeout is accurate enough, accept it. */ +	if (time_before(next_sec, next + ADDRCONF_TIMER_FUZZ)) +		next_sched = next_sec; + +	/* And minimum interval is ADDRCONF_TIMER_FUZZ_MAX. */ +	if (time_before(next_sched, jiffies + ADDRCONF_TIMER_FUZZ_MAX)) +		next_sched = jiffies + ADDRCONF_TIMER_FUZZ_MAX; + +	ADBG((KERN_DEBUG "now = %lu, schedule = %lu, rounded schedule = %lu => %lu\n", +	      now, next, next_sec, next_sched)); + +	addr_chk_timer.expires = next_sched;  	add_timer(&addr_chk_timer); -	spin_unlock_bh(&addrconf_verify_lock); +	spin_unlock(&addrconf_verify_lock); +	rcu_read_unlock_bh();  }  static struct in6_addr *extract_addr(struct nlattr *addr, struct nlattr *local) @@ -3514,8 +3512,7 @@ static int inet6_fill_ifacaddr(struct sk_buff *skb, struct ifacaddr6 *ifaca,  	return nlmsg_end(skb, nlh);  } -enum addr_type_t -{ +enum addr_type_t {  	UNICAST_ADDR,  	MULTICAST_ADDR,  	ANYCAST_ADDR, @@ -3526,7 +3523,6 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,  			  struct netlink_callback *cb, enum addr_type_t type,  			  int s_ip_idx, int *p_ip_idx)  { -	struct inet6_ifaddr *ifa;  	struct ifmcaddr6 *ifmca;  	struct ifacaddr6 *ifaca;  	int err = 1; @@ -3534,11 +3530,12 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,  	read_lock_bh(&idev->lock);  	switch (type) { -	case UNICAST_ADDR: +	case UNICAST_ADDR: { +		struct inet6_ifaddr *ifa; +  		/* unicast address incl. temp addr */ -		for (ifa = idev->addr_list; ifa; -		     ifa = ifa->if_next, ip_idx++) { -			if (ip_idx < s_ip_idx) +		list_for_each_entry(ifa, &idev->addr_list, if_list) { +			if (++ip_idx < s_ip_idx)  				continue;  			err = inet6_fill_ifaddr(skb, ifa,  						NETLINK_CB(cb->skb).pid, @@ -3549,6 +3546,7 @@ static int in6_dump_addrs(struct inet6_dev *idev, struct sk_buff *skb,  				break;  		}  		break; +	}  	case MULTICAST_ADDR:  		/* multicast address */  		for (ifmca = idev->mc_list; ifmca; @@ -3610,10 +3608,11 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,  		hlist_for_each_entry_rcu(dev, node, head, index_hlist) {  			if (idx < s_idx)  				goto cont; -			if (idx > s_idx) +			if (h > s_h || idx > s_idx)  				s_ip_idx = 0;  			ip_idx = 0; -			if ((idev = __in6_dev_get(dev)) == NULL) +			idev = __in6_dev_get(dev); +			if (!idev)  				goto cont;  			if (in6_dump_addrs(idev, skb, cb, type, @@ -3680,12 +3679,14 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,  	if (ifm->ifa_index)  		dev = __dev_get_by_index(net, ifm->ifa_index); -	if ((ifa = ipv6_get_ifaddr(net, addr, dev, 1)) == NULL) { +	ifa = ipv6_get_ifaddr(net, addr, dev, 1); +	if (!ifa) {  		err = -EADDRNOTAVAIL;  		goto errout;  	} -	if ((skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL)) == NULL) { +	skb = nlmsg_new(inet6_ifaddr_msgsize(), GFP_KERNEL); +	if (!skb) {  		err = -ENOBUFS;  		goto errout_ifa;  	} @@ -3810,7 +3811,7 @@ static inline void __snmp6_fill_stats(u64 *stats, void __percpu **mib,  static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,  			     int bytes)  { -	switch(attrtype) { +	switch (attrtype) {  	case IFLA_INET6_STATS:  		__snmp6_fill_stats(stats, (void __percpu **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);  		break; @@ -4046,7 +4047,8 @@ static void __ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)  			addrconf_leave_anycast(ifp);  		addrconf_leave_solict(ifp->idev, &ifp->addr);  		dst_hold(&ifp->rt->u.dst); -		if (ip6_del_rt(ifp->rt)) + +		if (ifp->dead && ip6_del_rt(ifp->rt))  			dst_free(&ifp->rt->u.dst);  		break;  	} @@ -4162,211 +4164,211 @@ static struct addrconf_sysctl_table  	.sysctl_header = NULL,  	.addrconf_vars = {  		{ -			.procname	=	"forwarding", -			.data		=	&ipv6_devconf.forwarding, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	addrconf_sysctl_forward, +			.procname	= "forwarding", +			.data		= &ipv6_devconf.forwarding, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= addrconf_sysctl_forward,  		},  		{ -			.procname	=	"hop_limit", -			.data		=	&ipv6_devconf.hop_limit, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "hop_limit", +			.data		= &ipv6_devconf.hop_limit, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"mtu", -			.data		=	&ipv6_devconf.mtu6, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "mtu", +			.data		= &ipv6_devconf.mtu6, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"accept_ra", -			.data		=	&ipv6_devconf.accept_ra, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "accept_ra", +			.data		= &ipv6_devconf.accept_ra, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"accept_redirects", -			.data		=	&ipv6_devconf.accept_redirects, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "accept_redirects", +			.data		= &ipv6_devconf.accept_redirects, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"autoconf", -			.data		=	&ipv6_devconf.autoconf, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "autoconf", +			.data		= &ipv6_devconf.autoconf, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"dad_transmits", -			.data		=	&ipv6_devconf.dad_transmits, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "dad_transmits", +			.data		= &ipv6_devconf.dad_transmits, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"router_solicitations", -			.data		=	&ipv6_devconf.rtr_solicits, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "router_solicitations", +			.data		= &ipv6_devconf.rtr_solicits, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"router_solicitation_interval", -			.data		=	&ipv6_devconf.rtr_solicit_interval, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec_jiffies, +			.procname	= "router_solicitation_interval", +			.data		= &ipv6_devconf.rtr_solicit_interval, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec_jiffies,  		},  		{ -			.procname	=	"router_solicitation_delay", -			.data		=	&ipv6_devconf.rtr_solicit_delay, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec_jiffies, +			.procname	= "router_solicitation_delay", +			.data		= &ipv6_devconf.rtr_solicit_delay, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec_jiffies,  		},  		{ -			.procname	=	"force_mld_version", -			.data		=	&ipv6_devconf.force_mld_version, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "force_mld_version", +			.data		= &ipv6_devconf.force_mld_version, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  #ifdef CONFIG_IPV6_PRIVACY  		{ -			.procname	=	"use_tempaddr", -			.data		=	&ipv6_devconf.use_tempaddr, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "use_tempaddr", +			.data		= &ipv6_devconf.use_tempaddr, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"temp_valid_lft", -			.data		=	&ipv6_devconf.temp_valid_lft, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "temp_valid_lft", +			.data		= &ipv6_devconf.temp_valid_lft, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"temp_prefered_lft", -			.data		=	&ipv6_devconf.temp_prefered_lft, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "temp_prefered_lft", +			.data		= &ipv6_devconf.temp_prefered_lft, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"regen_max_retry", -			.data		=	&ipv6_devconf.regen_max_retry, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "regen_max_retry", +			.data		= &ipv6_devconf.regen_max_retry, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"max_desync_factor", -			.data		=	&ipv6_devconf.max_desync_factor, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "max_desync_factor", +			.data		= &ipv6_devconf.max_desync_factor, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  #endif  		{ -			.procname	=	"max_addresses", -			.data		=	&ipv6_devconf.max_addresses, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "max_addresses", +			.data		= &ipv6_devconf.max_addresses, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"accept_ra_defrtr", -			.data		=	&ipv6_devconf.accept_ra_defrtr, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "accept_ra_defrtr", +			.data		= &ipv6_devconf.accept_ra_defrtr, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"accept_ra_pinfo", -			.data		=	&ipv6_devconf.accept_ra_pinfo, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "accept_ra_pinfo", +			.data		= &ipv6_devconf.accept_ra_pinfo, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  #ifdef CONFIG_IPV6_ROUTER_PREF  		{ -			.procname	=	"accept_ra_rtr_pref", -			.data		=	&ipv6_devconf.accept_ra_rtr_pref, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "accept_ra_rtr_pref", +			.data		= &ipv6_devconf.accept_ra_rtr_pref, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"router_probe_interval", -			.data		=	&ipv6_devconf.rtr_probe_interval, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec_jiffies, +			.procname	= "router_probe_interval", +			.data		= &ipv6_devconf.rtr_probe_interval, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec_jiffies,  		},  #ifdef CONFIG_IPV6_ROUTE_INFO  		{ -			.procname	=	"accept_ra_rt_info_max_plen", -			.data		=	&ipv6_devconf.accept_ra_rt_info_max_plen, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "accept_ra_rt_info_max_plen", +			.data		= &ipv6_devconf.accept_ra_rt_info_max_plen, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  #endif  #endif  		{ -			.procname	=	"proxy_ndp", -			.data		=	&ipv6_devconf.proxy_ndp, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "proxy_ndp", +			.data		= &ipv6_devconf.proxy_ndp, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{ -			.procname	=	"accept_source_route", -			.data		=	&ipv6_devconf.accept_source_route, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "accept_source_route", +			.data		= &ipv6_devconf.accept_source_route, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  #ifdef CONFIG_IPV6_OPTIMISTIC_DAD  		{ -			.procname       =       "optimistic_dad", -			.data           =       &ipv6_devconf.optimistic_dad, -			.maxlen         =       sizeof(int), -			.mode           =       0644, -			.proc_handler   =       proc_dointvec, +			.procname       = "optimistic_dad", +			.data           = &ipv6_devconf.optimistic_dad, +			.maxlen         = sizeof(int), +			.mode           = 0644, +			.proc_handler   = proc_dointvec,  		},  #endif  #ifdef CONFIG_IPV6_MROUTE  		{ -			.procname	=	"mc_forwarding", -			.data		=	&ipv6_devconf.mc_forwarding, -			.maxlen		=	sizeof(int), -			.mode		=	0444, -			.proc_handler	=	proc_dointvec, +			.procname	= "mc_forwarding", +			.data		= &ipv6_devconf.mc_forwarding, +			.maxlen		= sizeof(int), +			.mode		= 0444, +			.proc_handler	= proc_dointvec,  		},  #endif  		{ -			.procname	=	"disable_ipv6", -			.data		=	&ipv6_devconf.disable_ipv6, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	addrconf_sysctl_disable, +			.procname	= "disable_ipv6", +			.data		= &ipv6_devconf.disable_ipv6, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= addrconf_sysctl_disable,  		},  		{ -			.procname	=	"accept_dad", -			.data		=	&ipv6_devconf.accept_dad, -			.maxlen		=	sizeof(int), -			.mode		=	0644, -			.proc_handler	=	proc_dointvec, +			.procname	= "accept_dad", +			.data		= &ipv6_devconf.accept_dad, +			.maxlen		= sizeof(int), +			.mode		= 0644, +			.proc_handler	= proc_dointvec,  		},  		{  			.procname       = "force_tllao", @@ -4402,8 +4404,8 @@ static int __addrconf_sysctl_register(struct net *net, char *dev_name,  	if (t == NULL)  		goto out; -	for (i=0; t->addrconf_vars[i].data; i++) { -		t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf; +	for (i = 0; t->addrconf_vars[i].data; i++) { +		t->addrconf_vars[i].data += (char *)p - (char *)&ipv6_devconf;  		t->addrconf_vars[i].extra1 = idev; /* embedded; no ref */  		t->addrconf_vars[i].extra2 = net;  	} @@ -4540,14 +4542,12 @@ int register_inet6addr_notifier(struct notifier_block *nb)  {  	return atomic_notifier_chain_register(&inet6addr_chain, nb);  } -  EXPORT_SYMBOL(register_inet6addr_notifier);  int unregister_inet6addr_notifier(struct notifier_block *nb)  { -	return atomic_notifier_chain_unregister(&inet6addr_chain,nb); +	return atomic_notifier_chain_unregister(&inet6addr_chain, nb);  } -  EXPORT_SYMBOL(unregister_inet6addr_notifier);  /* @@ -4556,11 +4556,12 @@ EXPORT_SYMBOL(unregister_inet6addr_notifier);  int __init addrconf_init(void)  { -	int err; +	int i, err; -	if ((err = ipv6_addr_label_init()) < 0) { -		printk(KERN_CRIT "IPv6 Addrconf: cannot initialize default policy table: %d.\n", -			err); +	err = ipv6_addr_label_init(); +	if (err < 0) { +		printk(KERN_CRIT "IPv6 Addrconf:" +		       " cannot initialize default policy table: %d.\n", err);  		return err;  	} @@ -4591,6 +4592,9 @@ int __init addrconf_init(void)  	if (err)  		goto errlo; +	for (i = 0; i < IN6_ADDR_HSIZE; i++) +		INIT_HLIST_HEAD(&inet6_addr_lst[i]); +  	register_netdevice_notifier(&ipv6_dev_notf);  	addrconf_verify(0); @@ -4619,7 +4623,6 @@ errlo:  void addrconf_cleanup(void)  { -	struct inet6_ifaddr *ifa;  	struct net_device *dev;  	int i; @@ -4639,20 +4642,10 @@ void addrconf_cleanup(void)  	/*  	 *	Check hash table.  	 */ -	write_lock_bh(&addrconf_hash_lock); -	for (i=0; i < IN6_ADDR_HSIZE; i++) { -		for (ifa=inet6_addr_lst[i]; ifa; ) { -			struct inet6_ifaddr *bifa; - -			bifa = ifa; -			ifa = ifa->lst_next; -			printk(KERN_DEBUG "bug: IPv6 address leakage detected: ifa=%p\n", bifa); -			/* Do not free it; something is wrong. -			   Now we can investigate it with debugger. -			 */ -		} -	} -	write_unlock_bh(&addrconf_hash_lock); +	spin_lock_bh(&addrconf_hash_lock); +	for (i = 0; i < IN6_ADDR_HSIZE; i++) +		WARN_ON(!hlist_empty(&inet6_addr_lst[i])); +	spin_unlock_bh(&addrconf_hash_lock);  	del_timer(&addr_chk_timer);  	rtnl_unlock();  |