]> err.no Git - linux-2.6/blobdiff - net/ipv6/addrconf.c
[IPSEC]: Separate inner/outer mode processing on output
[linux-2.6] / net / ipv6 / addrconf.c
index cd2db728d183d031dd9cfa3232d3555950908c8b..c0720e4659bcc91dfa29d06245383a407ed0d5eb 100644 (file)
@@ -74,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>
 
@@ -213,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))
@@ -248,11 +255,6 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp,
 
 static int snmp6_alloc_dev(struct inet6_dev *idev)
 {
-       int err = -ENOMEM;
-
-       if (!idev || !idev->dev)
-               return -EINVAL;
-
        if (snmp_mib_init((void **)idev->stats.ipv6,
                          sizeof(struct ipstats_mib),
                          __alignof__(struct ipstats_mib)) < 0)
@@ -261,20 +263,26 @@ 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:
-       return err;
+       return -ENOMEM;
 }
 
-static int snmp6_free_dev(struct inet6_dev *idev)
+static void 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;
 }
 
 /* Nobody refers to this device, we may destroy it. */
@@ -358,9 +366,7 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
        in6_dev_hold(ndev);
 
 #ifdef CONFIG_IPV6_PRIVACY
-       init_timer(&ndev->regen_timer);
-       ndev->regen_timer.function = ipv6_regen_rndid;
-       ndev->regen_timer.data = (unsigned long) ndev;
+       setup_timer(&ndev->regen_timer, ipv6_regen_rndid, (unsigned long)ndev);
        if ((dev->flags&IFF_LOOPBACK) ||
            dev->type == ARPHRD_TUNNEL ||
 #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE)
@@ -377,7 +383,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);
@@ -450,7 +456,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) {
@@ -912,7 +918,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;
 
@@ -959,7 +965,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
                        if (unlikely(score.addr_type == IPV6_ADDR_ANY ||
                                     score.addr_type & IPV6_ADDR_MULTICAST)) {
                                LIMIT_NETDEBUG(KERN_DEBUG
-                                              "ADDRCONF: unspecified / multicast address"
+                                              "ADDRCONF: unspecified / multicast address "
                                               "assigned as unicast address on %s",
                                               dev->name);
                                continue;
@@ -1858,7 +1864,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)
@@ -1889,7 +1895,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);
                }
@@ -1919,7 +1925,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)
@@ -1970,7 +1976,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)
@@ -2065,7 +2071,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;
@@ -2221,12 +2227,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;
        }
@@ -2259,6 +2265,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
        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) {
@@ -2273,7 +2282,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: "
@@ -2282,10 +2291,13 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                                break;
                        }
 
+                       if (!idev && dev->mtu >= IPV6_MIN_MTU)
+                               idev = ipv6_add_dev(dev);
+
                        if (idev)
                                idev->if_flags |= IF_READY;
                } else {
-                       if (!netif_carrier_ok(dev)) {
+                       if (!addrconf_qdisc_ok(dev)) {
                                /* device is still not ready. */
                                break;
                        }
@@ -2346,12 +2358,18 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                break;
 
        case NETDEV_CHANGEMTU:
-               if ( idev && dev->mtu >= IPV6_MIN_MTU) {
+               if (idev && dev->mtu >= IPV6_MIN_MTU) {
                        rt6_mtu_change(dev, dev->mtu);
                        idev->cnf.mtu6 = dev->mtu;
                        break;
                }
 
+               if (!idev && dev->mtu >= IPV6_MIN_MTU) {
+                       idev = ipv6_add_dev(dev);
+                       if (idev)
+                               break;
+               }
+
                /* MTU falled under IPV6_MIN_MTU. Stop IPv6 on this interface. */
 
        case NETDEV_DOWN:
@@ -2400,7 +2418,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);
@@ -2492,9 +2510,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) */
 
@@ -2798,24 +2814,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 = {
@@ -3081,7 +3081,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;
 
@@ -3265,7 +3265,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)
@@ -3374,7 +3374,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;
@@ -3586,7 +3586,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)
@@ -4204,16 +4204,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);
@@ -4263,12 +4266,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.
@@ -4292,8 +4295,4 @@ void __exit addrconf_cleanup(void)
        del_timer(&addr_chk_timer);
 
        rtnl_unlock();
-
-#ifdef CONFIG_PROC_FS
-       proc_net_remove(&init_net, "if_inet6");
-#endif
 }