File Add-ICMP-Statistics-Tables-support.patch of Package net-snmp

From f691d90915f55027107270245494e1d25e340e20 Mon Sep 17 00:00:00 2001
From: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
Date: Mon, 20 Oct 2008 16:43:13 +0900
Subject: [PATCH] Add ICMP Statistics Tables support

From net-snmp patch tracker:
[ 1702361 ] Add ability to retrieve /proc/net/snmp6 under linux
http://sourceforge.net/tracker/index.php?func=detail&aid=1702361&group_id=12694&atid=312694

[ 1702366 ] add support for icmpStatsTable oid under linux
http://sourceforge.net/tracker/index.php?func=detail&aid=1702366&group_id=12694&atid=312694

[ 1703004 ] consolidate snmp6 caching in mibII read for linux
http://sourceforge.net/tracker/index.php?func=detail&aid=1703004&group_id=12694&atid=312694

[ 1715395 ] Fix the output form of icmpStatsTable on Linux
http://sourceforge.net/tracker/index.php?func=detail&aid=1715395&group_id=12694&atid=312694

[ 1721096 ] [Linux] Reply icmpStatsTable with old kernel
http://sourceforge.net/tracker/index.php?func=detail&aid=1721096&group_id=12694&atid=312694

[ 1823465 ] fix icmp registration and caches
http://sourceforge.net/tracker/index.php?func=detail&aid=1823465&group_id=12694&atid=312694

[ 1927751 ] Update icmpMsgStatsTable, Take IV
http://sourceforge.net/tracker/index.php?func=detail&aid=1927751&group_id=12694&atid=312694

Signed-off-by: Mitsuru Chinen <mitch@linux.vnet.ibm.com>
---
 agent/mibgroup/mibII/icmp.c           |  578 +++++++++++++++++++++++++++++++++
 agent/mibgroup/mibII/icmp.h           |   15 +
 agent/mibgroup/mibII/ipv6.c           |    2 +-
 agent/mibgroup/mibII/kernel_linux.c   |  483 +++++++++++++++++++++++++---
 agent/mibgroup/mibII/kernel_linux.h   |   86 +++++
 configure                             |    5 +-
 configure.in                          |    5 +-
 include/net-snmp/net-snmp-config.h.in |    3 +
 win32/net-snmp/net-snmp-config.h.in   |    3 +
 9 files changed, 1138 insertions(+), 42 deletions(-)

diff --git a/agent/mibgroup/mibII/icmp.c b/agent/mibgroup/mibII/icmp.c
index f3fbb82..50daac1 100644
--- a/agent/mibgroup/mibII/icmp.c
+++ b/agent/mibgroup/mibII/icmp.c
@@ -9,6 +9,13 @@
 #if HAVE_NETINET_IP_ICMP_H
 #include <netinet/ip_icmp.h>
 #endif
+
+#ifdef NETSNMP_ENABLE_IPV6
+#if HAVE_NETINET_ICMP6_H
+#include <netinet/icmp6.h>
+#endif
+#endif /* NETSNMP_ENABLE_IPV6 */
+
 #if HAVE_NETINET_ICMP_VAR_H
 #include <netinet/icmp_var.h>
 #endif
@@ -60,16 +67,388 @@ perfstat_id_t ps_name;
  * registering underneath 
  */
 oid             icmp_oid[] = { SNMP_OID_MIB2, 5 };
+oid             icmp_stats_tbl_oid[] = { SNMP_OID_MIB2, 5, 29 };
+oid             icmp_msg_stats_tbl_oid[] = { SNMP_OID_MIB2, 5, 30 };
 #ifdef USING_MIBII_IP_MODULE
 extern oid      ip_module_oid[];
 extern int      ip_module_oid_len;
 extern int      ip_module_count;
 #endif
 
+#ifdef linux
+struct icmp_stats_table_entry {
+	__uint32_t ipVer;
+        __uint32_t icmpStatsInMsgs;
+        __uint32_t icmpStatsInErrors;
+        __uint32_t icmpStatsOutMsgs;
+        __uint32_t icmpStatsOutErrors;
+};
+
+struct icmp_stats_table_entry icmp_stats_table[2];
+ 
+#define ICMP_MSG_STATS_HAS_IN 1
+#define ICMP_MSG_STATS_HAS_OUT 2
+
+struct icmp_msg_stats_table_entry {
+	uint32_t ipVer;
+	uint32_t icmpMsgStatsType;
+	uint32_t icmpMsgStatsInPkts;
+	uint32_t icmpMsgStatsOutPkts;
+	int flags;
+};
+
+#define ICMP_MSG_STATS_IPV4_COUNT 11
+
+#ifdef NETSNMP_ENABLE_IPV6
+#define ICMP_MSG_STATS_IPV6_COUNT 14
+#else
+#define ICMP_MSG_STATS_IPV6_COUNT 0
+#endif /* NETSNMP_ENABLE_IPV6 */
+
+struct icmp_msg_stats_table_entry icmp_msg_stats_table[ICMP_MSG_STATS_IPV4_COUNT + ICMP_MSG_STATS_IPV6_COUNT];
+
+int
+icmp_stats_load(netsnmp_cache *cache, void *vmagic)
+{
+
+	/*
+         * note don't bother using the passed in cache
+	 * and vmagic pointers.  They are useless as they 
+	 * currently point to the icmp system stats cache	
+	 * since I see little point in registering another
+	 * cache for this table.  Its not really needed
+	 */
+
+	int i;
+	struct icmp_mib v4icmp;
+	struct icmp6_mib v6icmp;
+	for(i=0;i<2;i++) {
+		switch(i) {
+			case 0:
+				linux_read_icmp_stat(&v4icmp);
+				icmp_stats_table[i].icmpStatsInMsgs = v4icmp.icmpInMsgs;
+				icmp_stats_table[i].icmpStatsInErrors = v4icmp.icmpInErrors;
+				icmp_stats_table[i].icmpStatsOutMsgs = v4icmp.icmpOutMsgs;
+				icmp_stats_table[i].icmpStatsOutErrors = v4icmp.icmpOutErrors;
+				break;
+			default:
+				memset(&icmp_stats_table[i],0,
+					sizeof(struct icmp_stats_table_entry));
+				linux_read_icmp6_stat(&v6icmp);
+				icmp_stats_table[i].icmpStatsInMsgs = v6icmp.icmp6InMsgs;
+				icmp_stats_table[i].icmpStatsInErrors = v6icmp.icmp6InErrors;
+				icmp_stats_table[i].icmpStatsOutMsgs = v6icmp.icmp6OutMsgs;
+				icmp_stats_table[i].icmpStatsOutErrors = v6icmp.icmp6OutDestUnreachs +
+					v6icmp.icmp6OutPktTooBigs +  v6icmp.icmp6OutTimeExcds +
+					v6icmp.icmp6OutParmProblems;
+				break;
+		}
+		icmp_stats_table[i].ipVer=i+1;
+	}
+
+	return 0;
+}
+
+int
+icmp_msg_stats_load(netsnmp_cache *cache, void *vmagic)
+{
+    struct icmp_mib v4icmp;
+    struct icmp4_msg_mib v4icmpmsg;
+    struct icmp6_mib v6icmp;
+    struct icmp6_msg_mib v6icmpmsg;
+    int i, j, k, flag, inc;
+
+    memset(&icmp_msg_stats_table, 0, sizeof(icmp_msg_stats_table));
+
+    i = 0;
+    flag = 0;
+    k = 0;
+    inc = 0;
+    linux_read_icmp_msg_stat(&v4icmp, &v4icmpmsg, &flag);
+    if (flag) {
+        while (254 != k) {
+            if (v4icmpmsg.vals[k].InType) {
+                icmp_msg_stats_table[i].ipVer = 1;
+                icmp_msg_stats_table[i].icmpMsgStatsType = k;
+                icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmpmsg.vals[k].InType;
+                icmp_msg_stats_table[i].flags = icmp_msg_stats_table[i].flags | ICMP_MSG_STATS_HAS_IN;
+                inc = 1; /* Set this if we found a valid entry */
+            }
+            if (v4icmpmsg.vals[k].OutType) {
+                icmp_msg_stats_table[i].ipVer = 1;
+                icmp_msg_stats_table[i].icmpMsgStatsType = k;
+                icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmpmsg.vals[k].OutType;
+                icmp_msg_stats_table[i].flags = icmp_msg_stats_table[i].flags | ICMP_MSG_STATS_HAS_OUT;
+                inc = 1; /* Set this if we found a valid entry */
+            }
+            if (inc) {
+                i++;
+                inc = 0;
+            }
+            k++;
+        }
+    } else {
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP_ECHOREPLY;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmp.icmpInEchoReps;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmp.icmpOutEchoReps;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP_DEST_UNREACH;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmp.icmpInDestUnreachs;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmp.icmpOutDestUnreachs;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP_SOURCE_QUENCH;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmp.icmpInSrcQuenchs;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmp.icmpOutSrcQuenchs;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP_REDIRECT;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmp.icmpInRedirects;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmp.icmpOutRedirects;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP_ECHO;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmp.icmpInEchos;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmp.icmpOutEchos;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP_TIME_EXCEEDED;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmp.icmpInTimeExcds;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmp.icmpOutTimeExcds;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP_PARAMETERPROB;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmp.icmpInParmProbs;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmp.icmpOutParmProbs;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP_TIMESTAMP;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmp.icmpInTimestamps;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmp.icmpOutTimestamps;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP_TIMESTAMPREPLY;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmp.icmpInTimestampReps;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmp.icmpOutTimestampReps;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP_ADDRESS;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmp.icmpInAddrMasks;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmp.icmpOutAddrMasks;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP_ADDRESSREPLY;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v4icmp.icmpInAddrMaskReps;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v4icmp.icmpOutAddrMaskReps;
+        i++;
+
+        /* set the IP version and default flags */
+        for (j = 0; j < ICMP_MSG_STATS_IPV4_COUNT; j++) {
+            icmp_msg_stats_table[j].ipVer = 1;
+            icmp_msg_stats_table[j].flags = ICMP_MSG_STATS_HAS_IN | ICMP_MSG_STATS_HAS_OUT;
+        }
+    }
+
+#ifdef NETSNMP_ENABLE_IPV6
+    flag = 0;
+    k = 0;
+    inc = 0;
+    linux_read_icmp6_msg_stat(&v6icmp, &v6icmpmsg, &flag);
+    if (flag) {
+        while (254 != k) {
+            if (v6icmpmsg.vals[k].InType) {
+                icmp_msg_stats_table[i].ipVer = 2;
+                icmp_msg_stats_table[i].icmpMsgStatsType = k;
+                icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmpmsg.vals[k].InType;
+                icmp_msg_stats_table[i].flags = icmp_msg_stats_table[i].flags | ICMP_MSG_STATS_HAS_IN;
+                inc = 1; /* Set this if we found a valid entry */
+            }
+            if (v6icmpmsg.vals[k].OutType) {
+                icmp_msg_stats_table[i].ipVer = 2;
+                icmp_msg_stats_table[i].icmpMsgStatsType = k;
+                icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmpmsg.vals[k].OutType;
+                icmp_msg_stats_table[i].flags = icmp_msg_stats_table[i].flags | ICMP_MSG_STATS_HAS_OUT;
+                inc = 1; /* Set this if we found a valid entry */
+            }
+            if (inc) {
+                i++;
+                inc = 0;
+            }
+            k++;
+        }
+    } else {
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP6_DST_UNREACH;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InDestUnreachs;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmp.icmp6OutDestUnreachs;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP6_PACKET_TOO_BIG;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InPktTooBigs;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmp.icmp6OutPktTooBigs;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP6_TIME_EXCEEDED;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InTimeExcds;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmp.icmp6OutTimeExcds;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP6_PARAM_PROB;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InParmProblems;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmp.icmp6OutParmProblems;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP6_ECHO_REQUEST;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InEchos;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = 0;
+        icmp_msg_stats_table[i].flags = ICMP_MSG_STATS_HAS_IN;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ICMP6_ECHO_REPLY;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InEchoReplies;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmp.icmp6OutEchoReplies;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = MLD_LISTENER_QUERY;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InGroupMembQueries;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = 0;
+        icmp_msg_stats_table[i].flags = ICMP_MSG_STATS_HAS_IN;
+        i++;
+        icmp_msg_stats_table[i].icmpMsgStatsType = MLD_LISTENER_REPORT;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InGroupMembResponses;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmp.icmp6OutGroupMembResponses;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = MLD_LISTENER_REDUCTION;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InGroupMembReductions;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmp.icmp6OutGroupMembReductions;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ND_ROUTER_SOLICIT;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InRouterSolicits;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmp.icmp6OutRouterSolicits;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ND_ROUTER_ADVERT;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InRouterAdvertisements;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = 0;
+        icmp_msg_stats_table[i].flags = ICMP_MSG_STATS_HAS_IN;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ND_NEIGHBOR_SOLICIT;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InNeighborSolicits;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmp.icmp6OutNeighborSolicits;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ND_NEIGHBOR_ADVERT;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InNeighborAdvertisements;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmp.icmp6OutNeighborAdvertisements;
+        i++;
+
+        icmp_msg_stats_table[i].icmpMsgStatsType = ND_REDIRECT;
+        icmp_msg_stats_table[i].icmpMsgStatsInPkts = v6icmp.icmp6InRedirects;
+        icmp_msg_stats_table[i].icmpMsgStatsOutPkts = v6icmp.icmp6OutRedirects;
+
+        for (j = 0; j < ICMP_MSG_STATS_IPV6_COUNT; j++) {
+            icmp_msg_stats_table[ICMP_MSG_STATS_IPV4_COUNT + j].ipVer = 2;
+            icmp_msg_stats_table[ICMP_MSG_STATS_IPV4_COUNT + j].flags = ICMP_MSG_STATS_HAS_IN | ICMP_MSG_STATS_HAS_OUT;
+        }
+#endif /* NETSNMP_ENABLE_IPV6 */
+    }
+    return 0;
+}
+
+netsnmp_variable_list *
+icmp_stats_next_entry( void **loop_context,
+                     void **data_context,
+                     netsnmp_variable_list *index,
+                     netsnmp_iterator_info *data)
+{
+	int i = (int)(*loop_context);
+	netsnmp_variable_list *idx = index;
+
+	if(i > 1)
+		return NULL;
+
+
+	/*
+	 *set IP version
+	 */
+	snmp_set_var_typed_value(idx, ASN_INTEGER, (u_char *)&icmp_stats_table[i].ipVer,
+                                sizeof(__uint32_t));
+	idx = idx->next_variable;
+
+	*data_context = &icmp_stats_table[i];
+
+	*loop_context = (void *)(++i);
+	
+	return index;
+}
+
+
+netsnmp_variable_list *
+icmp_stats_first_entry( void **loop_context,
+                     void **data_context,
+                     netsnmp_variable_list *index,
+                     netsnmp_iterator_info *data)
+{
+
+        *loop_context = 0;
+        *data_context = NULL;
+        return icmp_stats_next_entry(loop_context, data_context, index, data);
+}
+
+netsnmp_variable_list *
+icmp_msg_stats_next_entry(void **loop_context,
+                          void **data_context,
+                          netsnmp_variable_list *index,
+                          netsnmp_iterator_info *data)
+{
+    int i = (int)(*loop_context);
+    netsnmp_variable_list *idx = index;
+
+    if(i >= ICMP_MSG_STATS_IPV4_COUNT + ICMP_MSG_STATS_IPV6_COUNT)
+        return NULL;
+
+    /* set IP version */
+    snmp_set_var_typed_value(idx, ASN_INTEGER,
+            (u_char *)&icmp_msg_stats_table[i].ipVer,
+            sizeof(uint32_t));
+
+    /* set packet type */
+    idx = idx->next_variable;
+    snmp_set_var_typed_value(idx, ASN_INTEGER,
+            (u_char *)&icmp_msg_stats_table[i].icmpMsgStatsType,
+            sizeof(uint32_t));
+
+    *data_context = &icmp_msg_stats_table[i];
+    *loop_context = (void *)(++i);
+
+    return index;
+}
+
+
+netsnmp_variable_list *
+icmp_msg_stats_first_entry(void **loop_context,
+                           void **data_context,
+                           netsnmp_variable_list *index,
+                           netsnmp_iterator_info *data)
+{
+    *loop_context = 0;
+    *data_context = NULL;
+    return icmp_msg_stats_next_entry(loop_context, data_context, index, data);
+}
+#endif
+
 void
 init_icmp(void)
 {
     netsnmp_handler_registration *reginfo;
+    netsnmp_handler_registration *msg_stats_reginfo;
+    netsnmp_iterator_info *iinfo;
+    netsnmp_iterator_info *msg_stats_iinfo;
+    netsnmp_table_registration_info *table_info;
+    netsnmp_table_registration_info *msg_stats_table_info;
 
     /*
      * register ourselves with the agent as a group of scalars...
@@ -89,6 +468,68 @@ init_icmp(void)
 					icmp_oid, OID_LENGTH(icmp_oid)));
 #endif
 
+#ifdef linux
+
+    /* register icmpStatsTable */
+    reginfo = netsnmp_create_handler_registration("icmpStatsTable",
+		icmp_stats_table_handler, icmp_stats_tbl_oid,
+		OID_LENGTH(icmp_stats_tbl_oid), HANDLER_CAN_RONLY);
+
+    table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
+    if (!table_info) {
+        return;
+    }
+
+    netsnmp_table_helper_add_indexes(table_info, ASN_INTEGER, 0);
+    table_info->min_column = ICMP_STAT_INMSG;
+    table_info->max_column = ICMP_STAT_OUTERR;
+
+
+    iinfo      = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
+    if (!iinfo) {
+        return;
+    }
+    iinfo->get_first_data_point = icmp_stats_first_entry;
+    iinfo->get_next_data_point  = icmp_stats_next_entry;
+    iinfo->table_reginfo        = table_info;
+
+    netsnmp_register_table_iterator(reginfo, iinfo);
+
+    /* register icmpMsgStatsTable */
+    msg_stats_reginfo = netsnmp_create_handler_registration("icmpMsgStatsTable",
+            icmp_msg_stats_table_handler, icmp_msg_stats_tbl_oid,
+            OID_LENGTH(icmp_msg_stats_tbl_oid), HANDLER_CAN_RONLY);
+
+    msg_stats_table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
+    if (!msg_stats_table_info) {
+        return;
+    }
+
+    netsnmp_table_helper_add_indexes(msg_stats_table_info, ASN_INTEGER, ASN_INTEGER, 0);
+    msg_stats_table_info->min_column = ICMP_MSG_STAT_IN_PKTS;
+    msg_stats_table_info->max_column = ICMP_MSG_STAT_OUT_PKTS;
+
+    msg_stats_iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
+    if (!msg_stats_iinfo) {
+        return;
+    }
+    msg_stats_iinfo->get_first_data_point = icmp_msg_stats_first_entry;
+    msg_stats_iinfo->get_next_data_point  = icmp_msg_stats_next_entry;
+    msg_stats_iinfo->table_reginfo        = msg_stats_table_info;
+
+    netsnmp_register_table_iterator(msg_stats_reginfo, msg_stats_iinfo);
+    netsnmp_inject_handler( msg_stats_reginfo,
+            netsnmp_get_cache_handler(ICMP_STATS_CACHE_TIMEOUT,
+                icmp_load, icmp_free,
+                icmp_msg_stats_tbl_oid, OID_LENGTH(icmp_msg_stats_tbl_oid)));
+#ifndef hpux11
+    netsnmp_inject_handler( reginfo,
+		    netsnmp_get_cache_handler(ICMP_STATS_CACHE_TIMEOUT,
+					icmp_load, icmp_free,
+					icmp_stats_tbl_oid, OID_LENGTH(icmp_stats_tbl_oid)));
+#endif /* ! hpux11 */
+#endif /* linux */
+
 #ifdef USING_MIBII_IP_MODULE
     if (++ip_module_count == 2)
         REGISTER_SYSOR_TABLE(ip_module_oid, ip_module_oid_len,
@@ -550,6 +991,141 @@ icmp_handler(netsnmp_mib_handler          *handler,
     return SNMP_ERR_NOERROR;
 }
 
+int
+icmp_msg_stats_table_handler(netsnmp_mib_handler          *handler,
+                             netsnmp_handler_registration *reginfo,
+                             netsnmp_agent_request_info   *reqinfo,
+                             netsnmp_request_info         *requests)
+{
+    netsnmp_request_info *request;
+    netsnmp_variable_list *requestvb;
+    netsnmp_table_request_info *table_info;
+    struct icmp_msg_stats_table_entry *entry;
+    oid subid;
+
+    switch (reqinfo->mode) {
+	case MODE_GET:
+	    for (request = requests; request; request = request->next) {
+		requestvb = request->requestvb;
+		entry = (struct icmp_msg_stats_table_entry *)netsnmp_extract_iterator_context(request);
+		if (!entry)
+		    continue;
+		table_info = netsnmp_extract_table_info(request);
+		subid = table_info->colnum;
+
+		switch (subid) {
+		    case ICMP_MSG_STAT_IN_PKTS:
+			if (entry->flags & ICMP_MSG_STATS_HAS_IN) {
+			    snmp_set_var_typed_value(requestvb, ASN_COUNTER,
+				    (u_char *)&entry->icmpMsgStatsInPkts, sizeof(uint32_t));
+			} else {
+			    requestvb->type = SNMP_NOSUCHINSTANCE;
+			}
+			break;
+		    case ICMP_MSG_STAT_OUT_PKTS:
+			if (entry->flags & ICMP_MSG_STATS_HAS_OUT) {
+			    snmp_set_var_typed_value(requestvb, ASN_COUNTER,
+				    (u_char *)&entry->icmpMsgStatsOutPkts, sizeof(uint32_t));
+			} else {
+			    requestvb->type = SNMP_NOSUCHINSTANCE;
+			}
+			break;
+		    default:
+			snmp_log(LOG_WARNING, "mibII/icmpMsgStatsTable: Unrecognised column (%d)\n",(int)subid);
+		}
+	    }
+	    break;
+	case MODE_GETNEXT:
+	case MODE_GETBULK:
+	case MODE_SET_RESERVE1:
+	case MODE_SET_RESERVE2:
+	case MODE_SET_ACTION:
+	case MODE_SET_COMMIT:
+	case MODE_SET_FREE:
+	case MODE_SET_UNDO:
+	    snmp_log(LOG_WARNING, "mibII/icmpStatsTable: Unsupported mode (%d)\n",
+		    reqinfo->mode);
+	    break;
+	default:
+	    snmp_log(LOG_WARNING, "mibII/icmpStatsTable: Unrecognised mode (%d)\n",
+		    reqinfo->mode);
+	    break;
+
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+icmp_stats_table_handler(netsnmp_mib_handler  *handler,
+                 netsnmp_handler_registration *reginfo,
+                 netsnmp_agent_request_info   *reqinfo,
+                 netsnmp_request_info         *requests)
+{
+	netsnmp_request_info  *request;
+	netsnmp_variable_list *requestvb;
+	netsnmp_table_request_info *table_info;
+	struct icmp_stats_table_entry   *entry;
+	oid      subid;
+#ifndef hpux11
+	if (!netsnmp_cache_is_valid(reqinfo, reginfo->handlerName)) {
+		netsnmp_assert(!"cache == valid"); /* always false */
+		icmp_load( NULL, NULL );	/* XXX - check for failure */
+	}
+#endif
+
+	switch (reqinfo->mode) {
+		case MODE_GET:
+			for (request=requests; request; request=request->next) {
+				requestvb = request->requestvb;
+				entry = (struct icmp_stats_table_entry *)netsnmp_extract_iterator_context(request);
+				if (!entry)
+					continue;
+				table_info = netsnmp_extract_table_info(request);
+				subid      = table_info->colnum;
+
+				switch (subid) {
+					case ICMP_STAT_INMSG:
+						snmp_set_var_typed_value(requestvb, ASN_COUNTER,
+							(u_char *)&entry->icmpStatsInMsgs, sizeof(__uint32_t));
+						break;	
+					case ICMP_STAT_INERR:
+						snmp_set_var_typed_value(requestvb, ASN_COUNTER,
+							(u_char *)&entry->icmpStatsInErrors, sizeof(__uint32_t));
+						break;
+					case ICMP_STAT_OUTMSG:
+						snmp_set_var_typed_value(requestvb, ASN_COUNTER,
+							(u_char *)&entry->icmpStatsOutMsgs, sizeof(__uint32_t));
+						break;
+					case ICMP_STAT_OUTERR:
+						snmp_set_var_typed_value(requestvb, ASN_COUNTER,
+							(u_char *)&entry->icmpStatsOutErrors, sizeof(__uint32_t));
+						break;
+					default:
+						snmp_log(LOG_WARNING, "mibII/icmpStatsTable: Unrecognised column (%d)\n",(int)subid);
+				}
+			}
+			break;
+		case MODE_GETNEXT:
+		case MODE_GETBULK:
+		case MODE_SET_RESERVE1:
+		case MODE_SET_RESERVE2:
+		case MODE_SET_ACTION:
+		case MODE_SET_COMMIT:
+		case MODE_SET_FREE:
+		case MODE_SET_UNDO:
+			snmp_log(LOG_WARNING, "mibII/icmpStatsTable: Unsupported mode (%d)\n",
+				reqinfo->mode);
+			break;
+		default:
+			snmp_log(LOG_WARNING, "mibII/icmpStatsTable: Unrecognised mode (%d)\n",
+				reqinfo->mode);
+			break;
+
+	}
+
+	return SNMP_ERR_NOERROR;
+}
 
         /*********************
 	 *
@@ -680,6 +1256,8 @@ icmp_load(netsnmp_cache *cache, void *vmagic)
     } else {
         DEBUGMSGTL(("mibII/icmp", "Loaded ICMP Group (linux)\n"));
     }
+    icmp_stats_load(cache, vmagic);
+    icmp_msg_stats_load(cache, vmagic);
     return ret_value;
 }
 #elif defined(solaris2)
diff --git a/agent/mibgroup/mibII/icmp.h b/agent/mibgroup/mibII/icmp.h
index 7417639..4a780ac 100644
--- a/agent/mibgroup/mibII/icmp.h
+++ b/agent/mibgroup/mibII/icmp.h
@@ -12,6 +12,8 @@ config_arch_require(linux, mibII/kernel_linux)
 
 extern void     init_icmp(void);
 extern Netsnmp_Node_Handler icmp_handler;
+extern Netsnmp_Node_Handler icmp_stats_table_handler;
+extern Netsnmp_Node_Handler icmp_msg_stats_table_handler;
 extern NetsnmpCacheLoad icmp_load;
 extern NetsnmpCacheFree icmp_free;
 
@@ -42,4 +44,17 @@ extern NetsnmpCacheFree icmp_free;
 #define ICMPOUTADDRMASKS     25
 #define ICMPOUTADDRMASKREPS  26
 
+#define ICMPSTATSTABLE       29
+#define ICMP_STAT_IPVER       1
+#define ICMP_STAT_INMSG       2 
+#define ICMP_STAT_INERR       3 
+#define ICMP_STAT_OUTMSG      4 
+#define ICMP_STAT_OUTERR      5 
+
+#define ICMPMSGSTATSTABLE     30
+#define ICMP_MSG_STAT_IPVER    1
+#define ICMP_MSG_STAT_TYPE     2
+#define ICMP_MSG_STAT_IN_PKTS  3
+#define ICMP_MSG_STAT_OUT_PKTS 4
+
 #endif                          /* _MIBGROUP_ICMP_H */
diff --git a/agent/mibgroup/mibII/ipv6.c b/agent/mibgroup/mibII/ipv6.c
index 1e24989..ac64ad5 100644
--- a/agent/mibgroup/mibII/ipv6.c
+++ b/agent/mibgroup/mibII/ipv6.c
@@ -1851,7 +1851,7 @@ linux_read_ip6_stat_ulong(const char *file)
     return value;
 }
 
-void
+static void
 linux_read_ip6_stat(struct ip6_mib *ip6stat)
 {
     if (!ip6stat)
diff --git a/agent/mibgroup/mibII/kernel_linux.c b/agent/mibgroup/mibII/kernel_linux.c
index bb6f867..7b47d9c 100644
--- a/agent/mibgroup/mibII/kernel_linux.c
+++ b/agent/mibgroup/mibII/kernel_linux.c
@@ -16,43 +16,109 @@
 #if HAVE_SYS_PARAM_H
 #include <sys/param.h>
 #endif
+#include <errno.h>
 
 #include "kernel_linux.h"
 
 struct ip_mib   cached_ip_mib;
+struct ip6_mib   cached_ip6_mib;
 struct icmp_mib cached_icmp_mib;
+struct icmp6_mib cached_icmp6_mib;
+struct icmp4_msg_mib cached_icmp4_msg_mib;
+struct tcp_mib  cached_tcp_mib;
 struct tcp_mib  cached_tcp_mib;
 struct udp_mib  cached_udp_mib;
+struct udp6_mib  cached_udp6_mib;
 
 #define IP_STATS_LINE	"Ip: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu"
 #define ICMP_STATS_LINE	"Icmp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu"
+#define ICMP_MSG_STATS_LINE "IcmpMsg: "
 #define TCP_STATS_LINE	"Tcp: %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu %lu"
 #define UDP_STATS_LINE	"Udp: %lu %lu %lu %lu"
+#define IP6_STATS_LINE	"Ip6"
+#define ICMP6_STATS_LINE    "Icmp6"
 #define UDP6_STATS_LINE "Udp6"
 
 #define IP_STATS_PREFIX_LEN	4
 #define ICMP_STATS_PREFIX_LEN	6
+#define ICMP_MSG_STATS_PREFIX_LEN 9
 #define TCP_STATS_PREFIX_LEN	5
 #define UDP_STATS_PREFIX_LEN	5
+#define IP6_STATS_PREFIX_LEN	3
+#define ICMP6_STATS_PREFIX_LEN	5
 #define UDP6_STATS_PREFIX_LEN   4
 
+int
+decode_icmp_msg(char *line, char *data, struct icmp4_msg_mib *msg)
+{
+    char *token, *saveptr, *lineptr, *saveptr1, *dataptr, *delim = NULL;
+    char line_cpy[1024];
+    char data_cpy[1024];
+    long index;
+
+    if(data == NULL)
+	return -1;
+
+    /*
+     * Since we are using strtok, there is a possiblity of the orginal data
+     * getting modified. So we take a local copy for this purpose even though
+     * its expensive.
+     */
+    strncpy(line_cpy, line, sizeof(line_cpy));
+    strncpy(data_cpy, data, sizeof(data_cpy));
+
+    lineptr = line_cpy;
+    dataptr = data_cpy;
+    saveptr1 = NULL;
+    while (1) {
+	if(NULL == (token = strtok_r(lineptr, " ", &saveptr)))
+	    break;
+	lineptr = NULL;
+	errno = 0;
+	if (0 == strncmp(strsep(&token, "e"), "OutTyp", 6)) {
+	    index = strtol(token, &delim, 0);
+	    if (ERANGE == errno) {
+		continue;
+	    } else if (index > LONG_MAX) {
+		continue;
+	    } else if (index < LONG_MIN) {
+		continue;
+	    }
+	    if (NULL == (token = strtok_r(dataptr, " ", &saveptr1)))
+		break;
+	    dataptr = NULL;
+	    msg->vals[index].OutType = atoi(token);
+	} else {
+	    index = strtol(token, &delim, 0);
+	    if (ERANGE == errno) {
+		continue;
+	    } else if (index > LONG_MAX) {
+		continue;
+	    } else if (index < LONG_MIN) {
+		continue;
+	    }
+	    if(NULL == (token = strtok_r(dataptr, " ", &saveptr1)))
+		break;
+	    dataptr = NULL;
+	    msg->vals[index].InType = atoi(token);
+	}
+    }
+    return 0;
+}
 
 int
 linux_read_mibII_stats(void)
 {
     FILE           *in = fopen("/proc/net/snmp", "r");
-#ifdef NETSNMP_ENABLE_IPV6
-    FILE           *in6;
-    unsigned long   value;
-#endif
-    char            line[1024];
-
+    char	    line[1024], data[1024];
+    int ret = 0;
     if (!in) {
         DEBUGMSGTL(("mibII/kernel_linux","Unable to open /proc/net/snmp"));
         return -1;
     }
 
-
+    memset(line, '\0', sizeof(line));
+    memset(data, '\0', sizeof(data));
     while (line == fgets(line, sizeof(line), in)) {
         if (!strncmp(line, IP_STATS_LINE, IP_STATS_PREFIX_LEN)) {
             sscanf(line, IP_STATS_LINE,
@@ -104,6 +170,19 @@ linux_read_mibII_stats(void)
                    &cached_icmp_mib.icmpOutTimestampReps,
                    &cached_icmp_mib.icmpOutAddrMasks,
                    &cached_icmp_mib.icmpOutAddrMaskReps);
+        } else if (!strncmp(line, ICMP_MSG_STATS_LINE, ICMP_MSG_STATS_PREFIX_LEN)) {
+            /*
+             * Note: We have to do this differently from other stats as the
+             * counters to this stats are dynamic. So we will not know the
+             * number of counters at a given time.
+             */
+            fgets(data, sizeof(data), in);
+            if(decode_icmp_msg(line + ICMP_MSG_STATS_PREFIX_LEN,
+                        data + ICMP_MSG_STATS_PREFIX_LEN,
+                        &cached_icmp4_msg_mib) < 0) {
+                continue;
+            }
+            ret = 1;
         } else if (!strncmp(line, TCP_STATS_LINE, TCP_STATS_PREFIX_LEN)) {
             int             ret = sscanf(line, TCP_STATS_LINE,
                                          &cached_tcp_mib.tcpRtoAlgorithm,
@@ -132,35 +211,6 @@ linux_read_mibII_stats(void)
     }
     fclose(in);
 
-#ifdef NETSNMP_ENABLE_IPV6
-    in6 = fopen("/proc/net/snmp6", "r");
-    if (in6) {
-      
-        while (line == fgets(line, sizeof(line), in6)) {
-
-            if (('U' != line[0]) ||
-                (0 != strncmp(line, UDP6_STATS_LINE, UDP6_STATS_PREFIX_LEN)))
-                continue;
-
-            sscanf(line, "%*s %lu" , &value);
-                 
-            if ('O' == line[4]) /* Udp6OutDatagrams */
-                cached_udp_mib.udpOutDatagrams += value;
-            else if ('N' == line[4]) /* Udp6NoPorts */
-                cached_udp_mib.udpNoPorts += value;
-            else if ('D' == line[6]) /* Udp6InDatagrams */
-                cached_udp_mib.udpInDatagrams += value;
-            else if ('E' == line[6]) /* Udp6InErrors */
-                cached_udp_mib.udpInErrors += value;
-
-        }
-        fclose(in6);
-    } else {
-        DEBUGMSGTL(("mibII/kernel_linux","Unable to open /proc/net/snmp6"));
-    }
-
-#endif
-
     /*
      * Tweak illegal values:
      *
@@ -176,7 +226,8 @@ linux_read_mibII_stats(void)
      */
     if (!cached_tcp_mib.tcpRtoAlgorithm)
         cached_tcp_mib.tcpRtoAlgorithm = 1;
-    return 0;
+ 
+    return ret;
 }
 
 int
@@ -189,18 +240,305 @@ linux_read_ip_stat(struct ip_mib *ipstat)
     return 0;
 }
 
+int linux_read_ip6_stat( struct ip6_mib *ip6stat)
+{
+#ifdef NETSNMP_ENABLE_IPV6
+    FILE	   *in;
+    char	    line[1024];
+    unsigned long   stats;
+    char	   *endp;
+    int		    match;
+#endif
+
+    memset((char *) ip6stat, (0), sizeof(*ip6stat));
+
+#ifdef NETSNMP_ENABLE_IPV6
+    DEBUGMSGTL(("mibII/kernel_linux/ip6stats",
+		"Reading /proc/net/snmp6 stats\n"));
+    if (NULL == (in = fopen("/proc/net/snmp6", "r"))) {
+	DEBUGMSGTL(("mibII/kernel_linux/ip6stats",
+		    "Failed to open /proc/net/snmp6\n"));
+	return -1;
+    }
+
+    while (NULL != fgets(line, sizeof(line), in)) {
+	if (0 != strncmp(line, IP6_STATS_LINE, IP6_STATS_PREFIX_LEN))
+	    continue;
+
+	if (1 != sscanf(line, "%*s %lu", &stats))
+	    continue;
+
+	endp = strchr(line, ' ');
+	*endp = '\0';
+	DEBUGMSGTL(("mibII/kernel_linux/ip6stats", "Find tag: %s\n", line));
+
+	match = 1;
+	if (0 == strncmp(line + 3, "In", 2)) {  /* In */
+	    if (0 == strcmp(line + 5, "AddrErrors")) {
+		cached_ip6_mib.ip6InAddrErrors = stats;
+	    } else if (0 == strcmp(line + 5, "Delivers")) {
+		cached_ip6_mib.ip6InDelivers = stats;
+	    } else if (0 == strcmp(line + 5, "Discards")) {
+		cached_ip6_mib.ip6InDiscards = stats;
+	    } else if (0 == strcmp(line + 5, "HdrErrors")) {
+		cached_ip6_mib.ip6InHdrErrors = stats;
+	    } else if (0 == strcmp(line + 5, "McastPkts")) {
+		cached_ip6_mib.ip6InMcastPkts = stats;
+	    } else if (0 == strcmp(line + 5, "NoRoutes")) {
+		cached_ip6_mib.ip6InNoRoutes = stats;
+	    } else if (0 == strcmp(line + 5, "Receives")) {
+		cached_ip6_mib.ip6InReceives = stats;
+	    } else if (0 == strcmp(line + 5, "TruncatedPkts")) {
+		cached_ip6_mib.ip6InTruncatedPkts = stats;
+	    } else if (0 == strcmp(line + 5, "TooBigErrors")) {
+		cached_ip6_mib.ip6InTooBigErrors = stats;
+	    } else if (0 == strcmp(line + 5, "UnknownProtos")) {
+		cached_ip6_mib.ip6InUnknownProtos = stats;
+	    } else {
+		match = 0;
+	    }
+	} else if (0 == strncmp(line + 3, "Out", 3)) {  /* Out */
+	    if (0 == strcmp(line + 6, "Discards")) {
+		cached_ip6_mib.ip6OutDiscards = stats;
+	    } else if (0 == strcmp(line + 6, "ForwDatagrams")) {
+		cached_ip6_mib.ip6OutForwDatagrams = stats;
+	    } else if (0 == strcmp(line + 6, "McastPkts")) {
+		cached_ip6_mib.ip6OutMcastPkts = stats;
+	    } else if (0 == strcmp(line + 6, "NoRoutes")) {
+		cached_ip6_mib.ip6OutNoRoutes = stats;
+	    } else if (0 == strcmp(line + 6, "Requests")) {
+		cached_ip6_mib.ip6OutRequests = stats;
+	    } else {
+		match = 0;
+	    }
+	} else if (0 == strncmp(line + 3, "Reasm", 5)) {  /* Reasm */
+	    if (0 == strcmp(line + 8, "Fails")) {
+		cached_ip6_mib.ip6ReasmFails = stats;
+	    } else if (0 == strcmp(line + 8, "OKs")) {
+		cached_ip6_mib.ip6ReasmOKs = stats;
+	    } else if (0 == strcmp(line + 8, "Reqds")) {
+		cached_ip6_mib.ip6ReasmReqds = stats;
+	    } else if (0 == strcmp(line + 8, "Timeout")) {
+		cached_ip6_mib.ip6ReasmTimeout = stats;
+	    } else {
+		match = 0;
+	    }
+	} else if (0 == strncmp(line + 3, "Frag", 4)) {  /* Frag */
+	    if (0 == strcmp(line + 7, "Creates")) {
+		cached_ip6_mib.ip6FragCreates = stats;
+	    } else if (0 == strcmp(line + 7, "Fails")) {
+		cached_ip6_mib.ip6FragFails = stats;
+	    } else if (0 == strcmp(line + 7, "OKs")) {
+		cached_ip6_mib.ip6FragOKs = stats;
+	    } else {
+		match = 0;
+	    }
+	} else {
+	    match = 0;
+	}
+
+	if(!match)
+	    DEBUGMSGTL(("mibII/kernel_linux/ip6stats",
+			"%s is an unknown tag\n", line));
+    }
+
+    fclose(in);
+#endif
+
+    memcpy((char *) ip6stat, (char *) &cached_ip6_mib, sizeof(*ip6stat));
+    return 0;
+}
+
+int
+linux_read_icmp_msg_stat(struct icmp_mib *icmpstat,
+	struct icmp4_msg_mib *icmpmsgstat,
+	int *flag)
+{
+    int ret;
+
+    memset(icmpstat, 0, sizeof(*icmpstat));
+    memset(icmpmsgstat, 0, sizeof(*icmpmsgstat));
+
+    if ((ret = linux_read_mibII_stats()) == -1) {
+	return -1;
+    } else if (ret) {
+	memcpy(icmpmsgstat, &cached_icmp4_msg_mib, sizeof(*icmpmsgstat));
+	*flag = 1; /* We have a valid icmpmsg */
+    }
+
+    memcpy(icmpstat, &cached_icmp_mib, sizeof(*icmpstat));
+    return 0;
+}
+
+
+
+int
+linux_read_icmp6_parse(struct icmp6_mib *icmp6stat,
+                       struct icmp6_msg_mib *icmp6msgstat,
+                       int *support)
+{
+#ifdef NETSNMP_ENABLE_IPV6
+    FILE           *in;
+    char            line[1024];
+    char            name[255];
+    unsigned long   stats;
+    char           *endp ,*token, *vals;
+    int             match;
+#endif
+
+    memset(icmp6stat, 0, sizeof(*icmp6stat));
+    if (NULL != icmp6msgstat)
+        memset(icmp6msgstat, 0, sizeof(*icmp6msgstat));
+
+#ifdef NETSNMP_ENABLE_IPV6
+    DEBUGMSGTL(("mibII/kernel_linux/icmp6stats",
+                "Reading /proc/net/snmp6 stats\n"));
+    if (NULL == (in = fopen("/proc/net/snmp6", "r"))) {
+        DEBUGMSGTL(("mibII/kernel_linux/icmp6stats",
+                    "Failed to open /proc/net/snmp6\n"));
+        return -1;
+    }
+
+    while (NULL != fgets(line, sizeof(line), in)) {
+        if (0 != strncmp(line, ICMP6_STATS_LINE, ICMP6_STATS_PREFIX_LEN))
+            continue;
+
+        if (2 != sscanf(line, "%s %lu", name, &stats))
+            continue;
+
+        endp = strchr(line, ' ');
+        *endp = '\0';
+        DEBUGMSGTL(("mibII/kernel_linux/icmp6stats", "Find tag: %s\n", line));
+
+        vals = name;
+        if (NULL != icmp6msgstat) {
+            if (0 == strncmp(name, "Icmp6OutType", 12)) {
+                token = strsep(&vals, "e");
+                icmp6msgstat->vals[atoi(vals)].OutType = stats;
+                *support = 1;
+                continue;
+            } else if (0 == strncmp(name, "Icmp6InType", 11)) {
+                token = strsep(&vals, "e");
+                icmp6msgstat->vals[atoi(vals)].InType = stats;
+                *support = 1;
+                continue;
+            }
+        }
+
+        match = 1;
+        if (0 == strncmp(line + 5, "In", 2)) {  /* In */
+            if (0 == strcmp(line + 7, "DestUnreachs")) {
+                cached_icmp6_mib.icmp6InDestUnreachs = stats;
+            } else if (0 == strcmp(line + 7, "Echos")) {
+                cached_icmp6_mib.icmp6InEchos = stats;
+            } else if (0 == strcmp(line + 7, "EchoReplies")) {
+                cached_icmp6_mib.icmp6InEchoReplies = stats;
+            } else if (0 == strcmp(line + 7, "Errors")) {
+                cached_icmp6_mib.icmp6InErrors = stats;
+            } else if (0 == strcmp(line + 7, "GroupMembQueries")) {
+                cached_icmp6_mib.icmp6InGroupMembQueries = stats;
+            } else if (0 == strcmp(line + 7, "GroupMembReductions")) {
+                cached_icmp6_mib.icmp6InGroupMembReductions = stats;
+            } else if (0 == strcmp(line + 7, "GroupMembResponses")) {
+                cached_icmp6_mib.icmp6InGroupMembResponses = stats;
+            } else if (0 == strcmp(line + 7, "Msgs")) {
+                cached_icmp6_mib.icmp6InMsgs = stats;
+            } else if (0 == strcmp(line + 7, "NeighborAdvertisements")) {
+                cached_icmp6_mib.icmp6InNeighborAdvertisements = stats;
+            } else if (0 == strcmp(line + 7, "NeighborSolicits")) {
+                cached_icmp6_mib.icmp6InNeighborSolicits = stats;
+            } else if (0 == strcmp(line + 7, "PktTooBigs")) {
+                cached_icmp6_mib.icmp6InPktTooBigs = stats;
+            } else if (0 == strcmp(line + 7, "ParmProblems")) {
+                cached_icmp6_mib.icmp6InParmProblems = stats;
+            } else if (0 == strcmp(line + 7, "Redirects")) {
+                cached_icmp6_mib.icmp6InRedirects = stats;
+            } else if (0 == strcmp(line + 7, "RouterAdvertisements")) {
+                cached_icmp6_mib.icmp6InRouterAdvertisements = stats;
+            } else if (0 == strcmp(line + 7, "RouterSolicits")) {
+                cached_icmp6_mib.icmp6InRouterSolicits = stats;
+            } else if (0 == strcmp(line + 7, "TimeExcds")) {
+                cached_icmp6_mib.icmp6InTimeExcds = stats;
+            } else {
+                match = 0;
+            }
+        } else if (0 == strncmp(line + 5, "Out", 3)) {  /* Out */
+            if (0 == strcmp(line + 8, "DestUnreachs")) {
+                cached_icmp6_mib.icmp6OutDestUnreachs = stats;
+            } else if (0 == strcmp(line + 8, "EchoReplies")) {
+                cached_icmp6_mib.icmp6OutEchoReplies = stats;
+            } else if (0 == strcmp(line + 8, "GroupMembReductions")) {
+                cached_icmp6_mib.icmp6OutGroupMembReductions = stats;
+            } else if (0 == strcmp(line + 8, "GroupMembResponses")) {
+                cached_icmp6_mib.icmp6OutGroupMembResponses = stats;
+            } else if (0 == strcmp(line + 8, "Msgs")) {
+                cached_icmp6_mib.icmp6OutMsgs = stats;
+            } else if (0 == strcmp(line + 8, "NeighborAdvertisements")) {
+                cached_icmp6_mib.icmp6OutNeighborAdvertisements = stats;
+            } else if (0 == strcmp(line + 8, "NeighborSolicits")) {
+                cached_icmp6_mib.icmp6OutNeighborSolicits = stats;
+            } else if (0 == strcmp(line + 8, "PktTooBigs")) {
+                cached_icmp6_mib.icmp6OutPktTooBigs = stats;
+            } else if (0 == strcmp(line + 8, "ParmProblems")) {
+                cached_icmp6_mib.icmp6OutParmProblems = stats;
+            } else if (0 == strcmp(line + 8, "Redirects")) {
+                cached_icmp6_mib.icmp6OutRedirects = stats;
+            } else if (0 == strcmp(line + 8, "RouterSolicits")) {
+                cached_icmp6_mib.icmp6OutRouterSolicits = stats;
+            } else if (0 == strcmp(line + 8, "TimeExcds")) {
+                cached_icmp6_mib.icmp6OutTimeExcds = stats;
+            } else {
+                match = 0;
+            }
+        } else {
+            match = 0;
+        }
+        if(!match)
+            DEBUGMSGTL(("mibII/kernel_linux/icmp6stats",
+                        "%s is an unknown tag\n", line));
+    }
+
+    fclose(in);
+#endif
+
+    memcpy((char *) icmp6stat, (char *) &cached_icmp6_mib,
+           sizeof(*icmp6stat));
+    return 0;
+}
+
+int
+linux_read_icmp6_msg_stat(struct icmp6_mib *icmp6stat,
+                          struct icmp6_msg_mib *icmp6msgstat,
+                          int *support)
+{
+     if (linux_read_icmp6_parse(icmp6stat, icmp6msgstat, support) < 0)
+         return -1;
+     else
+         return 0;
+}
+
 int
 linux_read_icmp_stat(struct icmp_mib *icmpstat)
 {
     memset((char *) icmpstat, (0), sizeof(*icmpstat));
     if (linux_read_mibII_stats() == -1)
-        return -1;
+	return -1;
+
     memcpy((char *) icmpstat, (char *) &cached_icmp_mib,
-           sizeof(*icmpstat));
+	    sizeof(*icmpstat));
     return 0;
 }
 
 int
+linux_read_icmp6_stat(struct icmp6_mib *icmp6stat)
+{
+   if (linux_read_icmp6_parse(icmp6stat, NULL, NULL) < 0)
+       return -1;
+   else
+       return 0;
+}
+
+int
 linux_read_tcp_stat(struct tcp_mib *tcpstat)
 {
     memset((char *) tcpstat, (0), sizeof(*tcpstat));
@@ -216,6 +554,73 @@ linux_read_udp_stat(struct udp_mib *udpstat)
     memset((char *) udpstat, (0), sizeof(*udpstat));
     if (linux_read_mibII_stats() == -1)
         return -1;
+
+#ifdef NETSNMP_ENABLE_IPV6
+    {
+        struct udp6_mib udp6stat;
+        memset(&udp6stat, 0, sizeof(udp6stat));
+
+        if (linux_read_udp6_stat(&udp6stat) == 0) {
+            cached_udp_mib.udpOutDatagrams += udp6stat.udp6OutDatagrams;
+            cached_udp_mib.udpNoPorts      += udp6stat.udp6NoPorts;
+            cached_udp_mib.udpInDatagrams  += udp6stat.udp6InDatagrams;
+            cached_udp_mib.udpInErrors     += udp6stat.udp6InErrors;
+        }
+    }
+#endif
     memcpy((char *) udpstat, (char *) &cached_udp_mib, sizeof(*udpstat));
     return 0;
 }
+
+int
+linux_read_udp6_stat(struct udp6_mib *udp6stat)
+{
+#ifdef NETSNMP_ENABLE_IPV6
+    FILE           *in;
+    char            line[1024];
+    unsigned long   stats;
+    char           *endp;
+#endif
+
+    memset(udp6stat, 0, sizeof(*udp6stat));
+
+#ifdef NETSNMP_ENABLE_IPV6
+    DEBUGMSGTL(("mibII/kernel_linux/udp6stats",
+                "Reading /proc/net/snmp6 stats\n"));
+    if (NULL == (in = fopen("/proc/net/snmp6", "r"))) {
+        DEBUGMSGTL(("mibII/kernel_linux/udp6stats",
+                    "Failed to open /proc/net/snmp6\n"));
+       return -1;
+    }
+
+    while (NULL != fgets(line, sizeof(line), in)) {
+        if (0 != strncmp(line, UDP6_STATS_LINE, UDP6_STATS_PREFIX_LEN))
+            continue;
+
+        if (1 != sscanf(line, "%*s %lu", &stats))
+            continue;
+
+        endp = strchr(line, ' ');
+        *endp = '\0';
+        DEBUGMSGTL(("mibII/kernel_linux/udp6stats", "Find tag: %s\n", line));
+
+        if (0 == strcmp(line + 4, "OutDatagrams")) {
+            cached_udp6_mib.udp6OutDatagrams = stats;
+        } else if (0 == strcmp(line + 4, "NoPorts")) {
+            cached_udp6_mib.udp6NoPorts = stats;
+        } else if (0 == strcmp(line + 4, "InDatagrams")) {
+            cached_udp6_mib.udp6InDatagrams = stats;
+        } else if (0 == strcmp(line + 4, "InErrors")) {
+            cached_udp6_mib.udp6InErrors = stats;
+        } else {
+            DEBUGMSGTL(("mibII/kernel_linux/udp6stats",
+                        "%s is an unknown tag\n", line));
+        }
+    }
+
+    fclose(in);
+#endif
+
+    memcpy((char *) udp6stat, (char *) &cached_udp6_mib, sizeof(*udp6stat));
+    return 0;
+}
diff --git a/agent/mibgroup/mibII/kernel_linux.h b/agent/mibgroup/mibII/kernel_linux.h
index fb7db96..6bf5d47 100644
--- a/agent/mibgroup/mibII/kernel_linux.h
+++ b/agent/mibgroup/mibII/kernel_linux.h
@@ -29,6 +29,31 @@ struct ip_mib {
     unsigned long   ipRoutingDiscards;
 };
 
+struct ip6_mib {
+    unsigned long ip6InReceives;
+    unsigned long ip6InHdrErrors;
+    unsigned long ip6InTooBigErrors;
+    unsigned long ip6InNoRoutes;
+    unsigned long ip6InAddrErrors;
+    unsigned long ip6InUnknownProtos;
+    unsigned long ip6InTruncatedPkts;
+    unsigned long ip6InDiscards;
+    unsigned long ip6InDelivers;
+    unsigned long ip6OutForwDatagrams;
+    unsigned long ip6OutRequests;
+    unsigned long ip6OutDiscards;
+    unsigned long ip6OutNoRoutes;
+    unsigned long ip6ReasmTimeout;
+    unsigned long ip6ReasmReqds;
+    unsigned long ip6ReasmOKs;
+    unsigned long ip6ReasmFails;
+    unsigned long ip6FragOKs;
+    unsigned long ip6FragFails;
+    unsigned long ip6FragCreates;
+    unsigned long ip6InMcastPkts;
+    unsigned long ip6OutMcastPkts;
+};
+
 struct icmp_mib {
     unsigned long   icmpInMsgs;
     unsigned long   icmpInErrors;
@@ -58,6 +83,51 @@ struct icmp_mib {
     unsigned long   icmpOutAddrMaskReps;
 };
 
+struct icmp6_mib {
+    unsigned long icmp6InMsgs;
+    unsigned long icmp6InErrors;
+    unsigned long icmp6InDestUnreachs;
+    unsigned long icmp6InPktTooBigs;
+    unsigned long icmp6InTimeExcds;
+    unsigned long icmp6InParmProblems;
+    unsigned long icmp6InEchos;
+    unsigned long icmp6InEchoReplies;
+    unsigned long icmp6InGroupMembQueries;
+    unsigned long icmp6InGroupMembResponses;
+    unsigned long icmp6InGroupMembReductions;
+    unsigned long icmp6InRouterSolicits;
+    unsigned long icmp6InRouterAdvertisements;
+    unsigned long icmp6InNeighborSolicits;
+    unsigned long icmp6InNeighborAdvertisements;
+    unsigned long icmp6InRedirects;
+    unsigned long icmp6OutMsgs;
+    unsigned long icmp6OutDestUnreachs;
+    unsigned long icmp6OutPktTooBigs;
+    unsigned long icmp6OutTimeExcds;
+    unsigned long icmp6OutParmProblems;
+    unsigned long icmp6OutEchoReplies;
+    unsigned long icmp6OutRouterSolicits;
+    unsigned long icmp6OutNeighborSolicits;
+    unsigned long icmp6OutNeighborAdvertisements;
+    unsigned long icmp6OutRedirects;
+    unsigned long icmp6OutGroupMembResponses;
+    unsigned long icmp6OutGroupMembReductions;
+};
+
+struct icmp_msg_mib {
+    unsigned long InType;
+    unsigned long OutType;
+};
+
+/* Lets use wrapper structures for future expansion */
+struct icmp4_msg_mib {
+    struct icmp_msg_mib vals[255];
+};
+
+struct icmp6_msg_mib {
+    struct icmp_msg_mib vals[255];
+};
+
 struct udp_mib {
     unsigned long   udpInDatagrams;
     unsigned long   udpNoPorts;
@@ -65,6 +135,13 @@ struct udp_mib {
     unsigned long   udpOutDatagrams;
 };
 
+struct udp6_mib {
+    unsigned long udp6InDatagrams;
+    unsigned long udp6NoPorts;
+    unsigned long udp6InErrors;
+    unsigned long udp6OutDatagrams;
+};
+
 struct tcp_mib {
     unsigned long   tcpRtoAlgorithm;
     unsigned long   tcpRtoMin;
@@ -86,8 +163,17 @@ struct tcp_mib {
 
 
 int             linux_read_ip_stat(struct ip_mib *);
+int             linux_read_ip6_stat(struct ip6_mib *);
 int             linux_read_icmp_stat(struct icmp_mib *);
+int             linux_read_icmp6_stat(struct icmp6_mib *);
 int             linux_read_udp_stat(struct udp_mib *);
+int             linux_read_udp6_stat(struct udp6_mib *);
 int             linux_read_tcp_stat(struct tcp_mib *);
+int             linux_read_icmp_msg_stat(struct icmp_mib *,
+                                         struct icmp4_msg_mib *,
+                                         int *flag);
+int             linux_read_icmp6_msg_stat(struct icmp6_mib *,
+                                          struct icmp6_msg_mib *,
+                                          int *support);
 
 #endif                          /* _MIBGROUP_KERNEL_LINUX_H */
diff --git a/configure b/configure
index 322d5ac..1b062bf 100755
--- a/configure
+++ b/configure
@@ -33746,7 +33746,7 @@ done
 
 
 
-for ac_header in arpa/inet.h netinet/in_systm.h netinet/in.h netinet/ip_var.h netinet/tcp.h netinet/tcpip.h netinet/udp.h net/if.h netinet/in_var.h netinet/ip.h netinet/ip_icmp.h net/if_arp.h net/if_mib.h net/if_var.h netinet/if_ether.h netinet/tcp_timer.h netinet/tcp_var.h netinet/udp_var.h netinet/icmp_var.h netdb.h net/route.h
+for ac_header in arpa/inet.h netinet/in_systm.h netinet/in.h netinet/ip_var.h netinet/tcp.h netinet/tcpip.h netinet/udp.h net/if.h netinet/in_var.h netinet/ip.h netinet/ip_icmp.h netinet/icmp6.h net/if_arp.h net/if_mib.h net/if_var.h netinet/if_ether.h netinet/tcp_timer.h netinet/tcp_var.h netinet/udp_var.h netinet/icmp_var.h netdb.h net/route.h
 do
 as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh`
 echo "$as_me:$LINENO: checking for $ac_header" >&5
@@ -33794,6 +33794,9 @@ cat >>conftest.$ac_ext <<_ACEOF
 #if HAVE_NETINET_IP_ICMP_H
 #include <netinet/ip_icmp.h>
 #endif
+#if HAVE_NETINET_ICMP6_H
+#include <netinet/icmp6.h>
+#endif
 #if HAVE_NETINET_TCP_H
 #include <netinet/tcp.h>
 #endif
diff --git a/configure.in b/configure.in
index 82c22b8..3ad7955 100644
--- a/configure.in
+++ b/configure.in
@@ -3247,7 +3247,7 @@ AC_INCLUDES_DEFAULT([])
 ])
 AC_CHECK_HEADERS(sys/timeout.h sys/un.h fstab.h sys/fs.h mtab.h ufs/fs.h sys/fixpoint.h machine/param.h sys/vm.h vm/vm.h sys/vmmeter.h sys/vmparam.h sys/vmmac.h sys/vmsystm.h sys/time.h sys/times.h sys/statvfs.h sys/vfs.h sys/mnttab.h sys/select.h mntent.h sys/mntent.h kstat.h utsname.h sys/utsname.h sys/cdefs.h getopt.h locale.h pthread.h sys/loadavg.h regex.h linux/tasks.h pwd.h grp.h utmpx.h)
 # Network headers
-AC_CHECK_HEADERS(arpa/inet.h netinet/in_systm.h netinet/in.h netinet/ip_var.h netinet/tcp.h netinet/tcpip.h netinet/udp.h net/if.h netinet/in_var.h netinet/ip.h netinet/ip_icmp.h net/if_arp.h net/if_mib.h net/if_var.h netinet/if_ether.h netinet/tcp_timer.h netinet/tcp_var.h netinet/udp_var.h netinet/icmp_var.h netdb.h net/route.h,,,
+AC_CHECK_HEADERS(arpa/inet.h netinet/in_systm.h netinet/in.h netinet/ip_var.h netinet/tcp.h netinet/tcpip.h netinet/udp.h net/if.h netinet/in_var.h netinet/ip.h netinet/ip_icmp.h netinet/icmp6.h net/if_arp.h net/if_mib.h net/if_var.h netinet/if_ether.h netinet/tcp_timer.h netinet/tcp_var.h netinet/udp_var.h netinet/icmp_var.h netdb.h net/route.h,,,
 [[
 #if HAVE_SYS_TYPES_H
 #include <sys/types.h>
@@ -3282,6 +3282,9 @@ AC_CHECK_HEADERS(arpa/inet.h netinet/in_systm.h netinet/in.h netinet/ip_var.h ne
 #if HAVE_NETINET_IP_ICMP_H
 #include <netinet/ip_icmp.h>
 #endif
+#if HAVE_NETINET_ICMP6_H
+#include <netinet/icmp6.h>
+#endif
 #if HAVE_NETINET_TCP_H
 #include <netinet/tcp.h>
 #endif
diff --git a/include/net-snmp/net-snmp-config.h.in b/include/net-snmp/net-snmp-config.h.in
index 1be4ca4..2c93d11 100644
--- a/include/net-snmp/net-snmp-config.h.in
+++ b/include/net-snmp/net-snmp-config.h.in
@@ -588,6 +588,9 @@
 /* Define to 1 if you have the <netinet/ip_icmp.h> header file. */
 #undef HAVE_NETINET_IP_ICMP_H
 
+/* Define to 1 if you have the <netinet/icmp6.h> header file. */
+#undef HAVE_NETINET_ICMP6_H
+
 /* Define to 1 if you have the <netinet/ip_var.h> header file. */
 #undef HAVE_NETINET_IP_VAR_H
 
diff --git a/win32/net-snmp/net-snmp-config.h.in b/win32/net-snmp/net-snmp-config.h.in
index bf2d2dc..1654562 100644
--- a/win32/net-snmp/net-snmp-config.h.in
+++ b/win32/net-snmp/net-snmp-config.h.in
@@ -486,6 +486,9 @@
 /* Define to 1 if you have the <netinet/ip_icmp.h> header file. */
 /* #undef HAVE_NETINET_IP_ICMP_H */
 
+/* Define to 1 if you have the <netinet/icmp6.h> header file. */
+/* #undef HAVE_NETINET_ICMP6_H */
+
 /* Define to 1 if you have the <netinet/ip_var.h> header file. */
 /* #undef HAVE_NETINET_IP_VAR_H */
 
-- 
1.6.0.2

openSUSE Build Service is sponsored by