and changed files
[powerpc.git] / net / ipv6 / addrconf.c
index 9ba9e92..d02685c 100644 (file)
@@ -81,6 +81,7 @@
 #endif
 
 #include <asm/uaccess.h>
+#include <asm/unaligned.h>
 
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
@@ -208,9 +209,7 @@ static struct ipv6_devconf ipv6_devconf_dflt __read_mostly = {
 };
 
 /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
-#if 0
 const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
-#endif
 const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
 
 static void addrconf_del_timer(struct inet6_ifaddr *ifp)
@@ -246,6 +245,37 @@ static void addrconf_mod_timer(struct inet6_ifaddr *ifp,
        add_timer(&ifp->timer);
 }
 
+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)
+               goto err_ip;
+       if (snmp_mib_init((void **)idev->stats.icmpv6,
+                         sizeof(struct icmpv6_mib),
+                         __alignof__(struct icmpv6_mib)) < 0)
+               goto err_icmp;
+
+       return 0;
+
+err_icmp:
+       snmp_mib_free((void **)idev->stats.ipv6);
+err_ip:
+       return err;
+}
+
+static int snmp6_free_dev(struct inet6_dev *idev)
+{
+       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. */
 
 static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
@@ -419,7 +449,7 @@ static void addrconf_forward_change(void)
        struct inet6_dev *idev;
 
        read_lock(&dev_base_lock);
-       for (dev=dev_base; dev; dev=dev->next) {
+       for_each_netdev(dev) {
                rcu_read_lock();
                idev = __in6_dev_get(dev);
                if (idev) {
@@ -881,7 +911,7 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev,
        read_lock(&dev_base_lock);
        rcu_read_lock();
 
-       for (dev = dev_base; dev; dev=dev->next) {
+       for_each_netdev(dev) {
                struct inet6_dev *idev;
                struct inet6_ifaddr *ifa;
 
@@ -2034,7 +2064,7 @@ static void sit_add_v4_addrs(struct inet6_dev *idev)
                return;
        }
 
-       for (dev = dev_base; dev != NULL; dev = dev->next) {
+       for_each_netdev(dev) {
                struct in_device * in_dev = __in_dev_get_rtnl(dev);
                if (in_dev && (dev->flags & IFF_UP)) {
                        struct in_ifaddr * ifa;
@@ -2195,7 +2225,7 @@ static void ip6_tnl_add_linklocal(struct inet6_dev *idev)
                        return;
        }
        /* then try to inherit it from any device */
-       for (link_dev = dev_base; link_dev; link_dev = link_dev->next) {
+       for_each_netdev(link_dev) {
                if (!ipv6_inherit_linklocal(idev, link_dev))
                        return;
        }
@@ -2288,7 +2318,7 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                default:
                        addrconf_dev_config(dev);
                        break;
-               };
+               }
                if (idev) {
                        if (run_pending)
                                addrconf_dad_run(idev);
@@ -2329,8 +2359,9 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                break;
 
        case NETDEV_CHANGENAME:
-#ifdef CONFIG_SYSCTL
                if (idev) {
+                       snmp6_unregister_dev(idev);
+#ifdef CONFIG_SYSCTL
                        addrconf_sysctl_unregister(&idev->cnf);
                        neigh_sysctl_unregister(idev->nd_parms);
                        neigh_sysctl_register(dev, idev->nd_parms,
@@ -2338,10 +2369,11 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                                              &ndisc_ifinfo_sysctl_change,
                                              NULL);
                        addrconf_sysctl_register(idev, &idev->cnf);
-               }
 #endif
+                       snmp6_register_dev(idev);
+               }
                break;
-       };
+       }
 
        return NOTIFY_OK;
 }
@@ -3225,14 +3257,15 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
        s_idx = cb->args[0];
        s_ip_idx = ip_idx = cb->args[1];
 
-       for (dev = dev_base, idx = 0; dev; dev = dev->next, idx++) {
+       idx = 0;
+       for_each_netdev(dev) {
                if (idx < s_idx)
-                       continue;
+                       goto cont;
                if (idx > s_idx)
                        s_ip_idx = 0;
                ip_idx = 0;
                if ((idev = in6_dev_get(dev)) == NULL)
-                       continue;
+                       goto cont;
                read_lock_bh(&idev->lock);
                switch (type) {
                case UNICAST_ADDR:
@@ -3279,6 +3312,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb,
                }
                read_unlock_bh(&idev->lock);
                in6_dev_put(idev);
+cont:
+               idx++;
        }
 done:
        if (err <= 0) {
@@ -3438,6 +3473,34 @@ static inline size_t inet6_if_nlmsg_size(void)
                 );
 }
 
+static inline void __snmp6_fill_stats(u64 *stats, void **mib, int items,
+                                     int bytes)
+{
+       int i;
+       int pad = bytes - sizeof(u64) * items;
+       BUG_ON(pad < 0);
+
+       /* Use put_unaligned() because stats may not be aligned for u64. */
+       put_unaligned(items, &stats[0]);
+       for (i = 1; i < items; i++)
+               put_unaligned(snmp_fold_field(mib, i), &stats[i]);
+
+       memset(&stats[items], 0, pad);
+}
+
+static void snmp6_fill_stats(u64 *stats, struct inet6_dev *idev, int attrtype,
+                            int bytes)
+{
+       switch(attrtype) {
+       case IFLA_INET6_STATS:
+               __snmp6_fill_stats(stats, (void **)idev->stats.ipv6, IPSTATS_MIB_MAX, bytes);
+               break;
+       case IFLA_INET6_ICMP6STATS:
+               __snmp6_fill_stats(stats, (void **)idev->stats.icmpv6, ICMP6_MIB_MAX, bytes);
+               break;
+       }
+}
+
 static int inet6_fill_ifinfo(struct sk_buff *skb, struct inet6_dev *idev,
                             u32 pid, u32 seq, int event, unsigned int flags)
 {
@@ -3515,16 +3578,19 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb)
        struct inet6_dev *idev;
 
        read_lock(&dev_base_lock);
-       for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) {
+       idx = 0;
+       for_each_netdev(dev) {
                if (idx < s_idx)
-                       continue;
+                       goto cont;
                if ((idev = in6_dev_get(dev)) == NULL)
-                       continue;
+                       goto cont;
                err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid,
                                cb->nlh->nlmsg_seq, RTM_NEWLINK, NLM_F_MULTI);
                in6_dev_put(idev);
                if (err <= 0)
                        break;
+cont:
+               idx++;
        }
        read_unlock(&dev_base_lock);
        cb->args[0] = idx;
@@ -4187,7 +4253,7 @@ void __exit addrconf_cleanup(void)
         *      clean dev list.
         */
 
-       for (dev=dev_base; dev; dev=dev->next) {
+       for_each_netdev(dev) {
                if ((idev = __in6_dev_get(dev)) == NULL)
                        continue;
                addrconf_ifdown(dev, 1);