[IPV6]: Consolidate common SNMP code
[powerpc.git] / net / ipv6 / addrconf.c
index 33ccc95..ea86bf4 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>
@@ -246,6 +247,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)
@@ -3438,6 +3470,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)
 {