--- linux-2.6.9/include/net/ipv6.h.orig 2004-10-18 22:54:55.000000000 +0100 +++ linux-2.6.9/include/net/ipv6.h 2005-03-23 14:34:31.923039991 +0000 @@ -149,6 +149,8 @@ extern atomic_t inet6_sock_nr; int snmp6_register_dev(struct inet6_dev *idev); int snmp6_unregister_dev(struct inet6_dev *idev); +int snmp6_alloc_dev(struct inet6_dev *idev); +int snmp6_free_dev(struct inet6_dev *idev); int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign); void snmp6_mib_free(void *ptr[2]); --- linux-2.6.9/net/ipv6/addrconf.c.orig 2004-10-18 22:55:24.000000000 +0100 +++ linux-2.6.9/net/ipv6/addrconf.c 2005-03-23 14:34:31.920040461 +0000 @@ -307,7 +307,7 @@ void in6_dev_finish_destroy(struct inet6 printk("Freeing alive inet6 device %p\n", idev); return; } - snmp6_unregister_dev(idev); + snmp6_free_dev(idev); inet6_dev_count--; kfree(idev); } @@ -340,6 +340,16 @@ static struct inet6_dev * ipv6_add_dev(s /* We refer to the device */ dev_hold(dev); + if (snmp6_alloc_dev(ndev) < 0) { + ADBG((KERN_WARNING + "%s(): cannot allocate memory for statistics; dev=%s.\n", + __FUNCTION__, dev->name)); + neigh_parms_release(&nd_tbl, ndev->nd_parms); + ndev->dead = 1; + in6_dev_finish_destroy(ndev); + return NULL; + } + if (snmp6_register_dev(ndev) < 0) { ADBG((KERN_WARNING "%s(): cannot create /proc/net/dev_snmp6/%s\n", @@ -2006,6 +2016,10 @@ static int addrconf_ifdown(struct net_de dev->ip6_ptr = NULL; idev->dead = 1; write_unlock_bh(&addrconf_lock); + + /* Step 1.5: remove snmp6 entry */ + snmp6_unregister_dev(idev); + } /* Step 2: clear hash table */ --- linux-2.6.9/net/ipv6/af_inet6.c.orig 2004-10-18 22:54:32.000000000 +0100 +++ linux-2.6.9/net/ipv6/af_inet6.c 2005-03-23 14:34:31.922040148 +0000 @@ -632,8 +632,10 @@ snmp6_mib_free(void *ptr[2]) { if (ptr == NULL) return; - free_percpu(ptr[0]); - free_percpu(ptr[1]); + if (ptr[0]) + free_percpu(ptr[0]); + if (ptr[1]) + free_percpu(ptr[1]); ptr[0] = ptr[1] = NULL; } --- linux-2.6.9/net/ipv6/proc.c.orig 2004-10-18 22:53:51.000000000 +0100 +++ linux-2.6.9/net/ipv6/proc.c 2005-03-23 14:34:31.916041087 +0000 @@ -201,33 +201,23 @@ static struct file_operations snmp6_seq_ int snmp6_register_dev(struct inet6_dev *idev) { - int err = -ENOMEM; struct proc_dir_entry *p; if (!idev || !idev->dev) return -EINVAL; - if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib), - __alignof__(struct icmpv6_mib)) < 0) - goto err_icmp; + if (!proc_net_devsnmp6) + return -ENOENT; - if (!proc_net_devsnmp6) { - err = -ENOENT; - goto err_proc; - } p = create_proc_entry(idev->dev->name, S_IRUGO, proc_net_devsnmp6); if (!p) - goto err_proc; + return -ENOMEM; + p->data = idev; p->proc_fops = &snmp6_seq_fops; idev->stats.proc_dir_entry = p; return 0; - -err_proc: - snmp6_mib_free((void **)idev->stats.icmpv6); -err_icmp: - return err; } int snmp6_unregister_dev(struct inet6_dev *idev) @@ -238,8 +228,6 @@ int snmp6_unregister_dev(struct inet6_de return -EINVAL; remove_proc_entry(idev->stats.proc_dir_entry->name, proc_net_devsnmp6); - snmp6_mib_free((void **)idev->stats.icmpv6); - return 0; } @@ -280,6 +268,17 @@ void ipv6_misc_proc_exit(void) int snmp6_register_dev(struct inet6_dev *idev) { + return 0; +} + +int snmp6_unregister_dev(struct inet6_dev *idev) +{ + return 0; +} +#endif /* CONFIG_PROC_FS */ + +int snmp6_alloc_dev(struct inet6_dev *idev) +{ int err = -ENOMEM; if (!idev || !idev->dev) @@ -295,11 +294,10 @@ err_icmp: return err; } -int snmp6_unregister_dev(struct inet6_dev *idev) +int snmp6_free_dev(struct inet6_dev *idev) { snmp6_mib_free((void **)idev->stats.icmpv6); return 0; } -#endif