]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv6/addrconf.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
[linux-2.6-omap-h63xx.git] / net / ipv6 / addrconf.c
index 24424c3b7dc0e5918bb0b35295db8f73d0ee7591..52d10d213217c0bb8c7be5bbda65d9e31ad45e3d 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>
 
@@ -73,6 +74,7 @@
 #include <net/tcp.h>
 #include <net/ip.h>
 #include <net/netlink.h>
+#include <net/pkt_sched.h>
 #include <linux/if_tunnel.h>
 #include <linux/rtnetlink.h>
 
@@ -212,6 +214,12 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
 
+/* Check if a valid qdisc is available */
+static inline int addrconf_qdisc_ok(struct net_device *dev)
+{
+       return (dev->qdisc != &noop_qdisc);
+}
+
 static void addrconf_del_timer(struct inet6_ifaddr *ifp)
 {
        if (del_timer(&ifp->timer))
@@ -260,9 +268,15 @@ static int snmp6_alloc_dev(struct inet6_dev *idev)
                          sizeof(struct icmpv6_mib),
                          __alignof__(struct icmpv6_mib)) < 0)
                goto err_icmp;
+       if (snmp_mib_init((void **)idev->stats.icmpv6msg,
+                         sizeof(struct icmpv6msg_mib),
+                         __alignof__(struct icmpv6msg_mib)) < 0)
+               goto err_icmpmsg;
 
        return 0;
 
+err_icmpmsg:
+       snmp_mib_free((void **)idev->stats.icmpv6);
 err_icmp:
        snmp_mib_free((void **)idev->stats.ipv6);
 err_ip:
@@ -271,6 +285,7 @@ err_ip:
 
 static int snmp6_free_dev(struct inet6_dev *idev)
 {
+       snmp_mib_free((void **)idev->stats.icmpv6msg);
        snmp_mib_free((void **)idev->stats.icmpv6);
        snmp_mib_free((void **)idev->stats.ipv6);
        return 0;
@@ -376,7 +391,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
        }
 #endif
 
-       if (netif_running(dev) && netif_carrier_ok(dev))
+       if (netif_running(dev) && addrconf_qdisc_ok(dev))
                ndev->if_flags |= IF_READY;
 
        ipv6_mc_init_dev(ndev);
@@ -449,7 +464,7 @@ static void addrconf_forward_change(void)
        struct inet6_dev *idev;
 
        read_lock(&dev_base_lock);
-       for_each_netdev(dev) {
+       for_each_netdev(&init_net, dev) {
                rcu_read_lock();
                idev = __in6_dev_get(dev);
                if (idev) {
@@ -911,7 +926,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
        read_lock(&dev_base_lock);
        rcu_read_lock();
 
-       for_each_netdev(dev) {
+       for_each_netdev(&init_net, dev) {
                struct inet6_dev *idev;
                struct inet6_ifaddr *ifa;
 
@@ -1021,7 +1036,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)) {
@@ -1857,7 +1872,7 @@ int addrconf_set_dstaddr(void __user *arg)
        if (copy_from_user(&ireq, arg, sizeof(struct in6_ifreq)))
                goto err_exit;
 
-       dev = __dev_get_by_index(ireq.ifr6_ifindex);
+       dev = __dev_get_by_index(&init_net, ireq.ifr6_ifindex);
 
        err = -ENODEV;
        if (dev == NULL)
@@ -1888,7 +1903,7 @@ int addrconf_set_dstaddr(void __user *arg)
 
                if (err == 0) {
                        err = -ENOBUFS;
-                       if ((dev = __dev_get_by_name(p.name)) == NULL)
+                       if ((dev = __dev_get_by_name(&init_net, p.name)) == NULL)
                                goto err_exit;
                        err = dev_open(dev);
                }
@@ -1918,7 +1933,7 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen,
        if (!valid_lft || prefered_lft > valid_lft)
                return -EINVAL;
 
-       if ((dev = __dev_get_by_index(ifindex)) == NULL)
+       if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL)
                return -ENODEV;
 
        if ((idev = addrconf_add_dev(dev)) == NULL)
@@ -1969,7 +1984,7 @@ static int inet6_addr_del(int ifindex, struct in6_addr *pfx, int plen)
        struct inet6_dev *idev;
        struct net_device *dev;
 
-       if ((dev = __dev_get_by_index(ifindex)) == NULL)
+       if ((dev = __dev_get_by_index(&init_net, ifindex)) == NULL)
                return -ENODEV;
 
        if ((idev = __in6_dev_get(dev)) == NULL)
@@ -2064,7 +2079,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
                return;
        }
 
-       for_each_netdev(dev) {
+       for_each_netdev(&init_net, dev) {
                struct in_device * in_dev = __in_dev_get_rtnl(dev);
                if (in_dev && (dev->flags & IFF_UP)) {
                        struct in_ifaddr * ifa;
@@ -2220,12 +2235,12 @@ static void ip6_tnl_add_linklocal(struct inet6_dev *idev)
 
        /* first try to inherit the link-local address from the link device */
        if (idev->dev->iflink &&
-           (link_dev = __dev_get_by_index(idev->dev->iflink))) {
+           (link_dev = __dev_get_by_index(&init_net, idev->dev->iflink))) {
                if (!ipv6_inherit_linklocal(idev, link_dev))
                        return;
        }
        /* then try to inherit it from any device */
-       for_each_netdev(link_dev) {
+       for_each_netdev(&init_net, link_dev) {
                if (!ipv6_inherit_linklocal(idev, link_dev))
                        return;
        }
@@ -2256,14 +2271,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:
@@ -2272,7 +2290,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                        break;
 
                if (event == NETDEV_UP) {
-                       if (!netif_carrier_ok(dev)) {
+                       if (!addrconf_qdisc_ok(dev)) {
                                /* device is not ready yet. */
                                printk(KERN_INFO
                                        "ADDRCONF(NETDEV_UP): %s: "
@@ -2284,7 +2302,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                        if (idev)
                                idev->if_flags |= IF_READY;
                } else {
-                       if (!netif_carrier_ok(dev)) {
+                       if (!addrconf_qdisc_ok(dev)) {
                                /* device is still not ready. */
                                break;
                        }
@@ -2373,7 +2391,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;
        }
@@ -2397,7 +2417,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
        ASSERT_RTNL();
 
-       if (dev == &loopback_dev && how == 1)
+       if (dev == init_net.loopback_dev && how == 1)
                how = 0;
 
        rt6_ifdown(dev);
@@ -2475,6 +2495,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);
@@ -2488,9 +2509,7 @@ static int addrconf_ifdown(struct net_device *dev, int how)
        else
                ipv6_mc_down(idev);
 
-       /* Step 5: netlink notification of this interface */
        idev->tstamp = jiffies;
-       inet6_ifinfo_notify(RTM_DELLINK, idev);
 
        /* Shot the device (if unregistered) */
 
@@ -2794,24 +2813,8 @@ static const struct seq_operations if6_seq_ops = {
 
 static int if6_seq_open(struct inode *inode, struct file *file)
 {
-       struct seq_file *seq;
-       int rc = -ENOMEM;
-       struct if6_iter_state *s = kzalloc(sizeof(*s), GFP_KERNEL);
-
-       if (!s)
-               goto out;
-
-       rc = seq_open(file, &if6_seq_ops);
-       if (rc)
-               goto out_kfree;
-
-       seq = file->private_data;
-       seq->private = s;
-out:
-       return rc;
-out_kfree:
-       kfree(s);
-       goto out;
+       return seq_open_private(file, &if6_seq_ops,
+                       sizeof(struct if6_iter_state));
 }
 
 static const struct file_operations if6_fops = {
@@ -2824,14 +2827,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 */
 
@@ -3077,7 +3080,7 @@ inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                valid_lft = INFINITY_LIFE_TIME;
        }
 
-       dev =  __dev_get_by_index(ifm->ifa_index);
+       dev =  __dev_get_by_index(&init_net, ifm->ifa_index);
        if (dev == NULL)
                return -ENODEV;
 
@@ -3261,7 +3264,7 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
        s_ip_idx = ip_idx = cb->args[1];
 
        idx = 0;
-       for_each_netdev(dev) {
+       for_each_netdev(&init_net, dev) {
                if (idx < s_idx)
                        goto cont;
                if (idx > s_idx)
@@ -3370,7 +3373,7 @@ static int inet6_rtm_getaddr(struct sk_buff *in_skb, struct nlmsghdr* nlh,
 
        ifm = nlmsg_data(nlh);
        if (ifm->ifa_index)
-               dev = __dev_get_by_index(ifm->ifa_index);
+               dev = __dev_get_by_index(&init_net, ifm->ifa_index);
 
        if ((ifa = ipv6_get_ifaddr(addr, dev, 1)) == NULL) {
                err = -EADDRNOTAVAIL;
@@ -3582,7 +3585,7 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
 
        read_lock(&dev_base_lock);
        idx = 0;
-       for_each_netdev(dev) {
+       for_each_netdev(&init_net, dev) {
                if (idx < s_idx)
                        goto cont;
                if ((idev = in6_dev_get(dev)) == NULL)
@@ -4200,16 +4203,19 @@ int __init addrconf_init(void)
         * device and it being up should be removed.
         */
        rtnl_lock();
-       if (!ipv6_add_dev(&loopback_dev))
+       if (!ipv6_add_dev(init_net.loopback_dev))
                err = -ENOMEM;
        rtnl_unlock();
        if (err)
                return err;
 
-       ip6_null_entry.rt6i_idev = in6_dev_get(&loopback_dev);
+       ip6_null_entry.u.dst.dev = init_net.loopback_dev;
+       ip6_null_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
-       ip6_prohibit_entry.rt6i_idev = in6_dev_get(&loopback_dev);
-       ip6_blk_hole_entry.rt6i_idev = in6_dev_get(&loopback_dev);
+       ip6_prohibit_entry.u.dst.dev = init_net.loopback_dev;
+       ip6_prohibit_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
+       ip6_blk_hole_entry.u.dst.dev = init_net.loopback_dev;
+       ip6_blk_hole_entry.rt6i_idev = in6_dev_get(init_net.loopback_dev);
 #endif
 
        register_netdevice_notifier(&ipv6_dev_notf);
@@ -4259,12 +4265,12 @@ void __exit addrconf_cleanup(void)
         *      clean dev list.
         */
 
-       for_each_netdev(dev) {
+       for_each_netdev(&init_net, dev) {
                if (__in6_dev_get(dev) == NULL)
                        continue;
                addrconf_ifdown(dev, 1);
        }
-       addrconf_ifdown(&loopback_dev, 2);
+       addrconf_ifdown(init_net.loopback_dev, 2);
 
        /*
         *      Check hash table.
@@ -4290,6 +4296,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
 }