]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/ipv6/addrconf.c
[NET]: Make device event notification network namespace safe
[net-next-2.6.git] / net / ipv6 / addrconf.c
index 95737ab040ec2ecaebaec044bfae2caa899a8a19..1a6783646520aa341c6d1e6b4d2d552711ed16cd 100644 (file)
@@ -62,6 +62,7 @@
 #include <linux/notifier.h>
 #include <linux/string.h>
 
+#include <net/net_namespace.h>
 #include <net/sock.h>
 #include <net/snmp.h>
 
@@ -1021,7 +1022,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
                                hiscore.rule++;
                        }
                        if (ipv6_saddr_preferred(score.addr_type) ||
-                          (((ifa_result->flags &
+                          (((ifa->flags &
                            (IFA_F_DEPRECATED|IFA_F_OPTIMISTIC)) == 0))) {
                                score.attrs |= IPV6_SADDR_SCORE_PREFERRED;
                                if (!(hiscore.attrs & IPV6_SADDR_SCORE_PREFERRED)) {
@@ -2256,14 +2257,17 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
        struct net_device *dev = (struct net_device *) data;
        struct inet6_dev *idev = __in6_dev_get(dev);
        int run_pending = 0;
+       int err;
+
+       if (dev->nd_net != &init_net)
+               return NOTIFY_DONE;
 
        switch(event) {
        case NETDEV_REGISTER:
                if (!idev && dev->mtu >= IPV6_MIN_MTU) {
                        idev = ipv6_add_dev(dev);
                        if (!idev)
-                               printk(KERN_WARNING "IPv6: add_dev failed for %s\n",
-                                       dev->name);
+                               return notifier_from_errno(-ENOMEM);
                }
                break;
        case NETDEV_UP:
@@ -2373,7 +2377,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                                              NULL);
                        addrconf_sysctl_register(idev, &idev->cnf);
 #endif
-                       snmp6_register_dev(idev);
+                       err = snmp6_register_dev(idev);
+                       if (err)
+                               return notifier_from_errno(err);
                }
                break;
        }
@@ -2475,6 +2481,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
                write_unlock_bh(&idev->lock);
 
                __ipv6_ifa_notify(RTM_DELADDR, ifa);
+               atomic_notifier_call_chain(&inet6addr_chain, NETDEV_DOWN, ifa);
                in6_ifa_put(ifa);
 
                write_lock_bh(&idev->lock);
@@ -2785,7 +2792,7 @@ static int if6_seq_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static struct seq_operations if6_seq_ops = {
+static const struct seq_operations if6_seq_ops = {
        .start  = if6_seq_start,
        .next   = if6_seq_next,
        .show   = if6_seq_show,
@@ -2824,14 +2831,14 @@ static const struct file_operations if6_fops = {
 
 int __init if6_proc_init(void)
 {
-       if (!proc_net_fops_create("if_inet6", S_IRUGO, &if6_fops))
+       if (!proc_net_fops_create(&init_net, "if_inet6", S_IRUGO, &if6_fops))
                return -ENOMEM;
        return 0;
 }
 
 void if6_proc_exit(void)
 {
-       proc_net_remove("if_inet6");
+       proc_net_remove(&init_net, "if_inet6");
 }
 #endif /* CONFIG_PROC_FS */
 
@@ -4290,6 +4297,6 @@ void __exit addrconf_cleanup(void)
        rtnl_unlock();
 
 #ifdef CONFIG_PROC_FS
-       proc_net_remove("if_inet6");
+       proc_net_remove(&init_net, "if_inet6");
 #endif
 }