components/net-snmp/sun/agent/modules/healthMonitor/healthMonitor.c
changeset 252 ee0fb1eabcbf
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/net-snmp/sun/agent/modules/healthMonitor/healthMonitor.c	Fri May 20 12:17:45 2011 +0530
@@ -0,0 +1,3388 @@
+
+/*
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * 
+ * U.S. Government Rights - Commercial software. Government users are subject to
+ * the Sun Microsystems, Inc. standard license agreement and applicable
+ * provisions of the FAR and its supplements.
+ * 
+ * 
+ * This distribution may include materials developed by third parties. Sun, Sun
+ * Microsystems, the Sun logo and Solaris are trademarks or registered
+ * trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
+ * 
+ */
+
+/*
+ * Note: this file originally auto-generated by mib2c using :
+ * mib2c.scalar.conf,v 1.5 2002/07/18 14:18:52 dts12 Exp $
+ */
+
+/*
+ * This Module implements all the nodes in health-monitor-mib.mib.
+ * mib2c.scalar.conf is used to generate template for all nodes except the
+ * hmDiskGroup mib2c.iterate.conf is used to generate template for
+ * hmDiskGroup (which contains a Table) The two templates are merged so that
+ * all the implementation for health-monitor-mib is present as one module.
+ * Template functions are filled and new functions are added to do the
+ * following: 1) Data Acquisition, 2) Automatic refresh, 3) trap generation,
+ * 4) subscribe for thresholds from health_monitor.conf file.
+ */
+
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+#include <net-snmp/agent/net-snmp-agent-includes.h>
+#include "healthMonitor.h"
+#include <netdb.h>
+
+
+/*
+ * DATA: Following are the variables in which data collected for various
+ * nodes is stored. The values are refreshed every "refresh interval"
+ * (default 60 seconds). The value stored in this variable is returned
+ * whenever a "get" request comes.
+ */
+
+/* Data for SWAP node */
+int             swapavail_data, swapresv_data, swapalloc_data, swapused_data,
+                swaptotal_data;
+
+/* Data for Kernel node */
+ulong           sum_smtx = 0;
+int             ncpus;
+
+/* Data for NFS node */
+double          calls;
+int             badcalls, retrans, badxids, timeouts, newcreds, badverfs,
+                timers, nomem, cantsend, interrupts;
+char            callsStr[8];
+
+/* Data for CPU node */
+int            runque, waiting, swapque;
+
+/* Data for RAM node */
+int             handspread, scan;
+
+/*
+ * Data for KMEM node . Only alloc_fail and mem_free are published through
+ * the MIB
+ */
+int    alloc, alloc_fail=0, buf_size, buf_avail, buf_total, buf_max;
+int             mem_avail=0, mem_inuse=0, mem_free=0;
+
+/*
+ * Data for DNLC node . hits, misses, hitrate and refrate are published
+ * through the MIB. Rest of variables are temp data used for processing alarm
+ * conditions.
+ */
+
+int             firsttime = 1;
+int             lasthits = 0;
+int             lastmisses = 0;
+int             prevhits = 0;
+int             prevmisses = 0;
+long            prevtime = 0;
+
+long    hits, misses;
+long    hitrate, refrate;
+
+/*
+ * Data for diskGroup. We maintain the disk table in memory as a linked list
+ * of hmDiskTable objects "head" points to the first memeber of the linked
+ * list
+ */
+
+hmDiskTable    *head;
+int             diskCount;
+
+/*
+ * Following are the variables that hold threshold's used to determine alarm
+ * conditions. The variables are updated with threshold settings in
+ * health_monitor.conf file, when module is initialized.
+ */
+
+/* Thresholds and States for SWAP node */
+int             threshold_swapavail_info = 500000, threshold_swapavail_warning = 100000,
+                threshold_swapavail_error = 40000;
+
+int             prev_SWAP_state = OK;
+int             new_SWAP_state = OK;
+int             SWAP_rule_state = NOTINIT;
+
+/* Thresholds for Kernel node */
+ulong           threshold_mutex_info = 200, threshold_mutex_warning = 500;
+
+int             prev_mutex_state = OK;
+int             new_mutex_state = OK;
+int             Kernel_rule_state = NOTINIT;
+
+/* Thresholds for NFS node */
+float           threshold_mincalls = 0.1, threshold_badxids = 0.0, threshold_timeouts = 5.0;
+
+int             prev_NFS_state = OK;
+int             new_NFS_state = OK;
+int             NFS_rule_state = NOTINIT;
+
+/* Thresholds for CPU node */
+float           threshold_cpuload_info = 1.0, threshold_cpuload_warning = 2.0,
+                threshold_cpuload_error = 3.0;
+
+int             prev_cpuload_state = OK;
+int             new_cpuload_state = OK;
+int             CPU_rule_state = NOTINIT;
+
+/* Thresholds for RAM node */
+int             threshold_restime_long = 600, threshold_restime_ok = 40,
+                threshold_restime_error = 20;
+
+int             prev_restime_state = OK;
+int             new_restime_state = OK;
+int             RAM_rule_state = NOTINIT;
+
+/* Thresholds for KMEM node */
+int             threshold_freemem_low = 1;
+int             firstkmemerrs = 0, lastkmemerrs = 0;	/* These must be Global
+							 * variables and
+							 * preserved across
+							 * invocation of
+							 * check_state_KMEM()
+							 * function */
+
+int             prev_kmem_state = OK;
+int             new_kmem_state = OK;
+int             KMEM_rule_state = NOTINIT;
+
+/* Thresholds for DNLC node */
+
+float           threshold_dnlc_active = 100.0, threshold_dnlc_warning = 80;
+
+int             prev_dnlc_state = OK;
+int             new_dnlc_state = OK;
+int             DNLC_rule_state = NOTINIT;
+
+/* Thresholds for diskGroup */
+
+long            disk_busy_warning = 10.0, disk_busy_problem = 30.0, disk_svc_t_warning = 20.0,
+                disk_svc_t_problem = 30.0;
+
+
+/* COMMON data variables */
+
+u_char          hostName[MAXHOSTNAMELEN], moduleName[15], statusOIDContext[5];
+int             hm_refresh_interval=60;
+time_t          hm_prev_ref_time=1;
+time_t          hm_prev_disk_ref=1;
+
+
+/** Initializes the healthMonitor module */
+void
+init_healthMonitor(void)
+{
+
+    int             retCode;
+
+    static oid      hmSpinsOnMutexes_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 2, 1, 1, 0};
+    static oid      hmTotProcInRunQueue_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 4, 1, 1, 0};
+    static oid      hmTotRPCCalls_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 1, 0};
+    static oid      hmUsedSwapSpace_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 1, 1, 4, 0};
+    static oid      hmDNLCMisses_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 8, 1, 2, 0};
+    static oid      hmReservedSwapSpace_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 1, 1, 2, 0};
+    static oid      hmTotMemAllocFails_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 9, 0};
+    static oid      hmAvailableSwapSpace_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 1, 1, 1, 0};
+    static oid      hmDNLCHitRate_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 8, 1, 3, 0};
+    static oid      hmDNLCHits_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 8, 1, 1, 0};
+    static oid      hmAllocatedSwapSpace_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 1, 1, 3, 0};
+    static oid      hmTotNumOfCPUs_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 2, 1, 2, 0};
+    static oid      hmPageScanRate_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 6, 1, 2, 0};
+    static oid      hmTimers_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 8, 0};
+    static oid      hmTotBadRPCCalls_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 2, 0};
+    static oid      hmDNLCRefRate_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 8, 1, 4, 0};
+    static oid      hmTotSendFails_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 10, 0};
+    static oid      hmTotFailedCallsBV_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 7, 0};
+    static oid      hmTotNumOfAuthRefresh_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 6, 0};
+    static oid      hmHandspread_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 6, 1, 1, 0};
+    static oid      hmTotRPCRetransmissions_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 3, 0};
+    static oid      hmKmemFreeMem_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 7, 1, 2, 0};
+    static oid      hmTotBadRPCReplies_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 4, 0};
+    static oid      hmKmemErrors_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 7, 1, 1, 0};
+    static oid      hmTotProcReadyInSwap_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 4, 1, 3, 0};
+    static oid      hmTotProcBlocked_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 4, 1, 2, 0};
+    static oid      hmTotRPCCallsTimedOut_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1, 5, 0};
+
+    DEBUGMSGTL(("healthMonitor", "Initializing\n"));
+
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmSpinsOnMutexes",
+					 get_hmSpinsOnMutexes,
+					 hmSpinsOnMutexes_oid,
+					 OID_LENGTH(hmSpinsOnMutexes_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotProcInRunQueue",
+					 get_hmTotProcInRunQueue,
+					 hmTotProcInRunQueue_oid,
+					 OID_LENGTH(hmTotProcInRunQueue_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotRPCCalls",
+					 get_hmTotRPCCalls,
+					 hmTotRPCCalls_oid,
+					 OID_LENGTH(hmTotRPCCalls_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmUsedSwapSpace",
+					 get_hmUsedSwapSpace,
+					 hmUsedSwapSpace_oid,
+					 OID_LENGTH(hmUsedSwapSpace_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmDNLCMisses",
+					 get_hmDNLCMisses,
+					 hmDNLCMisses_oid,
+					 OID_LENGTH(hmDNLCMisses_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmReservedSwapSpace",
+					 get_hmReservedSwapSpace,
+					 hmReservedSwapSpace_oid,
+					 OID_LENGTH(hmReservedSwapSpace_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotMemAllocFails",
+					 get_hmTotMemAllocFails,
+					 hmTotMemAllocFails_oid,
+					 OID_LENGTH(hmTotMemAllocFails_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmAvailableSwapSpace",
+					 get_hmAvailableSwapSpace,
+					 hmAvailableSwapSpace_oid,
+				       OID_LENGTH(hmAvailableSwapSpace_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmDNLCHitRate",
+					 get_hmDNLCHitRate,
+					 hmDNLCHitRate_oid,
+					 OID_LENGTH(hmDNLCHitRate_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmDNLCHits",
+					 get_hmDNLCHits,
+					 hmDNLCHits_oid,
+					 OID_LENGTH(hmDNLCHits_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmAllocatedSwapSpace",
+					 get_hmAllocatedSwapSpace,
+					 hmAllocatedSwapSpace_oid,
+				       OID_LENGTH(hmAllocatedSwapSpace_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotNumOfCPUs",
+					 get_hmTotNumOfCPUs,
+					 hmTotNumOfCPUs_oid,
+					 OID_LENGTH(hmTotNumOfCPUs_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmPageScanRate",
+					 get_hmPageScanRate,
+					 hmPageScanRate_oid,
+					 OID_LENGTH(hmPageScanRate_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTimers",
+					 get_hmTimers,
+					 hmTimers_oid,
+					 OID_LENGTH(hmTimers_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotBadRPCCalls",
+					 get_hmTotBadRPCCalls,
+					 hmTotBadRPCCalls_oid,
+					 OID_LENGTH(hmTotBadRPCCalls_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmDNLCRefRate",
+					 get_hmDNLCRefRate,
+					 hmDNLCRefRate_oid,
+					 OID_LENGTH(hmDNLCRefRate_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotSendFails",
+					 get_hmTotSendFails,
+					 hmTotSendFails_oid,
+					 OID_LENGTH(hmTotSendFails_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotFailedCallsBV",
+					 get_hmTotFailedCallsBV,
+					 hmTotFailedCallsBV_oid,
+					 OID_LENGTH(hmTotFailedCallsBV_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotNumOfAuthRefresh",
+					 get_hmTotNumOfAuthRefresh,
+					 hmTotNumOfAuthRefresh_oid,
+				      OID_LENGTH(hmTotNumOfAuthRefresh_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmHandspread",
+					 get_hmHandspread,
+					 hmHandspread_oid,
+					 OID_LENGTH(hmHandspread_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotRPCRetransmissions",
+					 get_hmTotRPCRetransmissions,
+					 hmTotRPCRetransmissions_oid,
+				    OID_LENGTH(hmTotRPCRetransmissions_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmKmemFreeMem",
+					 get_hmKmemFreeMem,
+					 hmKmemFreeMem_oid,
+					 OID_LENGTH(hmKmemFreeMem_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotBadRPCReplies",
+					 get_hmTotBadRPCReplies,
+					 hmTotBadRPCReplies_oid,
+					 OID_LENGTH(hmTotBadRPCReplies_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmKmemErrors",
+					 get_hmKmemErrors,
+					 hmKmemErrors_oid,
+					 OID_LENGTH(hmKmemErrors_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotProcReadyInSwap",
+					 get_hmTotProcReadyInSwap,
+					 hmTotProcReadyInSwap_oid,
+				       OID_LENGTH(hmTotProcReadyInSwap_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotProcBlocked",
+					 get_hmTotProcBlocked,
+					 hmTotProcBlocked_oid,
+					 OID_LENGTH(hmTotProcBlocked_oid),
+					 HANDLER_CAN_RONLY));
+    netsnmp_register_read_only_instance(netsnmp_create_handler_registration
+					("hmTotRPCCallsTimedOut",
+					 get_hmTotRPCCallsTimedOut,
+					 hmTotRPCCallsTimedOut_oid,
+				      OID_LENGTH(hmTotRPCCallsTimedOut_oid),
+					 HANDLER_CAN_RONLY));
+
+
+    /* Initialize Disk stuff */
+
+    /* here we initialize all the tables we're planning on supporting */
+
+    initialize_table_hmDiskTable();
+
+
+    /*
+     * Additions to init function to register callbacks for tokens. Whenever
+     * a token is encountered in health_monitor.conf file, the function
+     * read_health_monitor_thresholds is called by the agent
+     */
+
+    register_config_handler("health_monitor", "hm_refresh_interval",
+                            read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_swapavail_info",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_swapavail_warning",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_swapavail_error",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_mutex_info",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_mutex_warning",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_mincalls",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_badxids",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_timeouts",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_cpuload_info",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_cpuload_warning",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_cpuload_error",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_restime_long",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_restime_ok",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_restime_error",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_freemem_low",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_dnlc_active",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "threshold_dnlc_warning",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "disk_busy_warning",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "disk_busy_problem",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "disk_svc_t_warning",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+    register_config_handler("health_monitor", "disk_svc_t_problem",
+			    read_health_monitor_thresholds, NULL, NULL);
+
+
+
+    /*
+     * Initialize data that's required in the trap - The hostname,
+     * modulenaem, statusOIDContext
+     */
+
+    retCode = gethostname((char *) hostName, MAXHOSTNAMELEN);
+    if (retCode != 0)
+	strcpy((char *) hostName, "null\0");
+
+    strcpy((char *) moduleName, "Health-Monitor\0");
+
+    strcpy((char *) statusOIDContext, "null\0");
+
+
+   snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_POST_READ_CONFIG,
+                          hm_post_read_config, NULL);
+
+
+}
+
+/** Initialize the hmDiskTable table by defining its contents and how it's structured */
+void
+initialize_table_hmDiskTable(void)
+{
+    static oid      hmDiskTable_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 5, 1};
+    netsnmp_table_registration_info *table_info;
+    netsnmp_handler_registration *my_handler;
+    netsnmp_iterator_info *iinfo;
+
+    /* create the table structure itself */
+    table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
+    iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
+
+    /*
+     * if your table is read only, it's easiest to change the
+     * HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY
+     */
+    my_handler = netsnmp_create_handler_registration("hmDiskTable",
+						     hmDiskTable_handler,
+						     hmDiskTable_oid,
+						OID_LENGTH(hmDiskTable_oid),
+						     HANDLER_CAN_RONLY);
+
+    if (!my_handler || !table_info || !iinfo)
+	return;			/* mallocs failed */
+
+    /***************************************************
+     * Setting up the table's definition
+     */
+    netsnmp_table_helper_add_indexes(table_info,
+				     ASN_OCTET_STR,	/* index: hmDiskName */
+				     0);
+
+    table_info->min_column = 1;
+    table_info->max_column = 5;
+
+    /* iterator access routines */
+    iinfo->get_first_data_point = hmDiskTable_get_first_data_point;
+    iinfo->get_next_data_point = hmDiskTable_get_next_data_point;
+
+    iinfo->table_reginfo = table_info;
+
+    /***************************************************
+     * registering the table with the master agent
+     */
+    DEBUGMSGTL(("initialize_table_hmDiskTable",
+		"Registering table hmDiskTable as a table iterator\n"));
+    netsnmp_register_table_iterator(my_handler, iinfo);
+}
+
+int
+get_hmSpinsOnMutexes(netsnmp_mib_handler * handler,
+		     netsnmp_handler_registration * reginfo,
+		     netsnmp_agent_request_info * reqinfo,
+		     netsnmp_request_info * requests)
+{
+
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & sum_smtx, sizeof(sum_smtx));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotProcInRunQueue(netsnmp_mib_handler * handler,
+			netsnmp_handler_registration * reginfo,
+			netsnmp_agent_request_info * reqinfo,
+			netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long runque_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	runque_long = (long) runque;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & runque_long, sizeof(runque_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotRPCCalls(netsnmp_mib_handler * handler,
+		  netsnmp_handler_registration * reginfo,
+		  netsnmp_agent_request_info * reqinfo,
+		  netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+	snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR, (u_char *) callsStr, strlen(callsStr) );
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmUsedSwapSpace(netsnmp_mib_handler * handler,
+		    netsnmp_handler_registration * reginfo,
+		    netsnmp_agent_request_info * reqinfo,
+		    netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long swapused_data_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	swapused_data_long = (long)swapused_data;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & swapused_data_long, sizeof(swapused_data_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmDNLCMisses(netsnmp_mib_handler * handler,
+		 netsnmp_handler_registration * reginfo,
+		 netsnmp_agent_request_info * reqinfo,
+		 netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+	snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) & misses, sizeof(misses));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmReservedSwapSpace(netsnmp_mib_handler * handler,
+			netsnmp_handler_registration * reginfo,
+			netsnmp_agent_request_info * reqinfo,
+			netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long swapresv_data_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+        swapresv_data_long = (long) swapresv_data;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & swapresv_data_long, sizeof(swapresv_data_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotMemAllocFails(netsnmp_mib_handler * handler,
+		       netsnmp_handler_registration * reginfo,
+		       netsnmp_agent_request_info * reqinfo,
+		       netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long nomem_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+	
+	nomem_long = (long) nomem;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & nomem_long, sizeof(nomem_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmAvailableSwapSpace(netsnmp_mib_handler * handler,
+			 netsnmp_handler_registration * reginfo,
+			 netsnmp_agent_request_info * reqinfo,
+			 netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+    switch (reqinfo->mode) {
+
+	long swapavail_data_long;
+
+	case MODE_GET:
+
+	swapavail_data_long = (long) swapavail_data;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & swapavail_data_long, sizeof(swapavail_data_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmDNLCHitRate(netsnmp_mib_handler * handler,
+		  netsnmp_handler_registration * reginfo,
+		  netsnmp_agent_request_info * reqinfo,
+		  netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+	snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) & hitrate, sizeof(hitrate));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmDNLCHits(netsnmp_mib_handler * handler,
+	       netsnmp_handler_registration * reginfo,
+	       netsnmp_agent_request_info * reqinfo,
+	       netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+	snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) & hits, sizeof(hits));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+
+int
+get_hmAllocatedSwapSpace(netsnmp_mib_handler * handler,
+			 netsnmp_handler_registration * reginfo,
+			 netsnmp_agent_request_info * reqinfo,
+			 netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long swapalloc_data_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+        swapalloc_data_long = (long) swapalloc_data;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & swapalloc_data_long, sizeof(swapalloc_data_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotNumOfCPUs(netsnmp_mib_handler * handler,
+		   netsnmp_handler_registration * reginfo,
+		   netsnmp_agent_request_info * reqinfo,
+		   netsnmp_request_info * requests)
+{
+
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long ncpus_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	ncpus_long = (long)ncpus;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & ncpus_long, sizeof(ncpus_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmPageScanRate(netsnmp_mib_handler * handler,
+		   netsnmp_handler_registration * reginfo,
+		   netsnmp_agent_request_info * reqinfo,
+		   netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long scan_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+	
+	scan_long = (long) scan;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & scan_long, sizeof(scan_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTimers(netsnmp_mib_handler * handler,
+	     netsnmp_handler_registration * reginfo,
+	     netsnmp_agent_request_info * reqinfo,
+	     netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long timers_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	timers_long = (long) timers;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & timers_long, sizeof(timers_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotBadRPCCalls(netsnmp_mib_handler * handler,
+		     netsnmp_handler_registration * reginfo,
+		     netsnmp_agent_request_info * reqinfo,
+		     netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long badcalls_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	badcalls_long = (long) badcalls ;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & badcalls_long, sizeof(badcalls_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmDNLCRefRate(netsnmp_mib_handler * handler,
+		  netsnmp_handler_registration * reginfo,
+		  netsnmp_agent_request_info * reqinfo,
+		  netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+	snmp_set_var_typed_value(requests->requestvb, ASN_UNSIGNED, (u_char *) & refrate, sizeof(refrate));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+
+int
+get_hmTotSendFails(netsnmp_mib_handler * handler,
+		   netsnmp_handler_registration * reginfo,
+		   netsnmp_agent_request_info * reqinfo,
+		   netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long cantsend_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	cantsend_long = (long) cantsend;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & cantsend_long, sizeof(cantsend_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotFailedCallsBV(netsnmp_mib_handler * handler,
+		       netsnmp_handler_registration * reginfo,
+		       netsnmp_agent_request_info * reqinfo,
+		       netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long badxids_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	badxids_long = (long) badxids;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & badxids_long, sizeof(badxids_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotNumOfAuthRefresh(netsnmp_mib_handler * handler,
+			  netsnmp_handler_registration * reginfo,
+			  netsnmp_agent_request_info * reqinfo,
+			  netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long newcreds_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	newcreds_long = (long) newcreds;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & newcreds_long, sizeof(newcreds_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmHandspread(netsnmp_mib_handler * handler,
+		 netsnmp_handler_registration * reginfo,
+		 netsnmp_agent_request_info * reqinfo,
+		 netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long handspread_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	handspread_long = (long) handspread;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & handspread_long, sizeof(handspread_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotRPCRetransmissions(netsnmp_mib_handler * handler,
+			    netsnmp_handler_registration * reginfo,
+			    netsnmp_agent_request_info * reqinfo,
+			    netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long interrupts_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+	
+	interrupts_long = (long) interrupts;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & interrupts_long, sizeof(interrupts_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmKmemFreeMem(netsnmp_mib_handler * handler,
+		  netsnmp_handler_registration * reginfo,
+		  netsnmp_agent_request_info * reqinfo,
+		  netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long mem_free_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	mem_free_long = (long) mem_free;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & mem_free_long, sizeof(mem_free_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotBadRPCReplies(netsnmp_mib_handler * handler,
+		       netsnmp_handler_registration * reginfo,
+		       netsnmp_agent_request_info * reqinfo,
+		       netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long badverfs_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	badverfs_long = (long) badverfs;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & badverfs_long, sizeof(badverfs_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmKmemErrors(netsnmp_mib_handler * handler,
+		 netsnmp_handler_registration * reginfo,
+		 netsnmp_agent_request_info * reqinfo,
+		 netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long alloc_fail_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	alloc_fail_long = (long) alloc_fail;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & alloc_fail_long, sizeof(alloc_fail_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotProcReadyInSwap(netsnmp_mib_handler * handler,
+			 netsnmp_handler_registration * reginfo,
+			 netsnmp_agent_request_info * reqinfo,
+			 netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long swapque_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	swapque_long = (long) swapque;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & swapque_long, sizeof(swapque_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotProcBlocked(netsnmp_mib_handler * handler,
+		     netsnmp_handler_registration * reginfo,
+		     netsnmp_agent_request_info * reqinfo,
+		     netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long waiting_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	waiting_long = (long) waiting;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & waiting_long, sizeof(waiting_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+int
+get_hmTotRPCCallsTimedOut(netsnmp_mib_handler * handler,
+			  netsnmp_handler_registration * reginfo,
+			  netsnmp_agent_request_info * reqinfo,
+			  netsnmp_request_info * requests)
+{
+    /*
+     * We are never called for a GETNEXT if it's registered as a "instance",
+     * as it's "magically" handled for us.
+     */
+
+    /*
+     * a instance handler also only hands us one request at a time, so we
+     * don't need to loop over a list of requests; we'll only get one.
+     */
+
+	long timeouts_long;
+    switch (reqinfo->mode) {
+
+	case MODE_GET:
+
+	timeouts_long = (long) timeouts;
+	snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER, (u_char *) & timeouts_long, sizeof(timeouts_long));
+	break;
+
+
+    default:
+	/* we should never get here, so this is a really bad error */
+	return SNMP_ERR_GENERR;
+    }
+
+    return SNMP_ERR_NOERROR;
+}
+
+
+int hm_post_read_config(int a, int b, void *c, void *d)
+{
+
+    /*
+     * Refresh the HealthMonitor module data every 60 seconds. Every 60
+     * seconds, the function refresh_all_HM_data is called automatically by
+     * the agent. Also, load data into nodes now by calling the refresh
+     * function once
+     */
+
+    construct_DISK_table();
+    refresh_all_HM_data(0, NULL);
+
+    snmp_alarm_register(hm_refresh_interval, SA_REPEAT, refresh_DISK_table, NULL);
+    snmp_alarm_register(hm_refresh_interval, SA_REPEAT, refresh_all_HM_data, NULL);
+
+}
+
+
+
+hmDiskTable    *
+get_first_node()
+{
+    return head;
+}
+
+/** returns the first data point within the hmDiskTable table data.
+
+    Set the my_loop_context variable to the first data point structure
+    of your choice (from which you can find the next one).  This could
+    be anything from the first node in a linked list, to an integer
+    pointer containing the beginning of an array variable.
+
+    Set the my_data_context variable to something to be returned to
+    you later that will provide you with the data to return in a given
+    row.  This could be the same pointer as what my_loop_context is
+    set to, or something different.
+
+    The put_index_data variable contains a list of snmp variable
+    bindings, one for each index in your table.  Set the values of
+    each appropriately according to the data matching the first row
+    and return the put_index_data variable at the end of the function.
+*/
+
+netsnmp_variable_list *
+hmDiskTable_get_first_data_point(void **my_loop_context, void **my_data_context,
+				 netsnmp_variable_list * put_index_data,
+				 netsnmp_iterator_info * mydata)
+{
+
+    netsnmp_variable_list *vptr;
+
+    hmDiskTable    *firstNode = get_first_node();
+    if (!firstNode) {
+	return NULL;
+    }
+    *my_loop_context = firstNode;
+    *my_data_context = firstNode;
+
+    vptr = put_index_data;
+
+    snmp_set_var_value(vptr, (u_char *) firstNode->hmDiskName, strlen(firstNode->hmDiskName)	/* XXX: length of
+		           hmDiskName data */ );
+    vptr = vptr->next_variable;
+
+    return put_index_data;
+}
+
+/** functionally the same as hmDiskTable_get_first_data_point, but
+   my_loop_context has already been set to a previous value and should
+   be updated to the next in the list.  For example, if it was a
+   linked list, you might want to cast it and the return
+   my_loop_context->next.  The my_data_context pointer should be set
+   to something you need later and the indexes in put_index_data
+   updated again. */
+
+netsnmp_variable_list *
+hmDiskTable_get_next_data_point(void **my_loop_context, void **my_data_context,
+				netsnmp_variable_list * put_index_data,
+				netsnmp_iterator_info * mydata)
+{
+
+    netsnmp_variable_list *vptr;
+
+    hmDiskTable    *nextNode = (hmDiskTable *) * my_loop_context;
+
+    /* This check is not really required */
+    if(!nextNode) {
+        snmp_log(LOG_DEBUG,"No data returned in get_next\n");
+        return NULL;
+    }
+
+    nextNode = nextNode->pNext;
+
+    if (!nextNode) {
+	snmp_log(LOG_DEBUG,"No data returned in get_next\n");
+	return NULL;
+    }
+    *my_loop_context = nextNode;
+    *my_data_context = nextNode;
+
+    vptr = put_index_data;
+
+    snmp_set_var_value(vptr, (u_char *) nextNode->hmDiskName /* XXX: hmDiskName data */ , strlen(nextNode->hmDiskName)	/* XXX: length of
+		           hmDiskName data */ );
+    vptr = vptr->next_variable;
+
+    return put_index_data;
+}
+
+/** handles requests for the hmDiskTable table, if anything else needs to be done */
+int
+hmDiskTable_handler(
+		    netsnmp_mib_handler * handler,
+		    netsnmp_handler_registration * reginfo,
+		    netsnmp_agent_request_info * reqinfo,
+		    netsnmp_request_info * requests)
+{
+
+    netsnmp_request_info *request;
+    netsnmp_table_request_info *table_info;
+    netsnmp_variable_list *var;
+
+    hmDiskTable    *data;
+
+    for (request = requests; request; request = request->next) {
+	var = request->requestvb;
+	if (request->processed != 0)
+	    continue;
+
+	/*
+	 * perform anything here that you need to do before each request is
+	 * processed.
+	 */
+
+	/*
+	 * the following extracts the my_data_context pointer set in the loop
+	 * functions above.  You can then use the results to help return data
+	 * for the columns of the hmDiskTable table in question
+	 */
+	data = (hmDiskTable *) netsnmp_extract_iterator_context(request);
+	if (data == NULL) {
+	    if (reqinfo->mode == MODE_GET) {
+		netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
+		continue;
+	    }
+	    /*
+	     * XXX: no row existed, if you support creation and this is a
+	     * set, start dealing with it here, else continue
+	     */
+	}
+	/* extracts the information about the table from the request */
+	table_info = netsnmp_extract_table_info(request);
+	/* table_info->colnum contains the column number requested */
+	/*
+	 * table_info->indexes contains a linked list of snmp variable
+	 * bindings for the indexes of the table.  Values in the list have
+	 * been set corresponding to the indexes of the request
+	 */
+	if (table_info == NULL) {
+	    continue;
+	}
+	switch (reqinfo->mode) {
+	    /*
+	     * the table_iterator helper should change all GETNEXTs into GETs
+	     * for you automatically, so you don't have to worry about the
+	     * GETNEXT case.  Only GETs and SETs need to be dealt with here
+	     */
+	case MODE_GET:
+	    switch (table_info->colnum) {
+	    case COLUMN_HMDISKNAME:
+		snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->hmDiskName, strlen(data->hmDiskName));
+		break;
+
+	    case COLUMN_HMDISKALIASNAME:
+		snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->hmDiskAliasName, strlen(data->hmDiskAliasName));
+		break;
+
+	    case COLUMN_HMAVGWAITTRANSACTIONS:
+		snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->hmAvgWaitTransactions, strlen(data->hmAvgWaitTransactions));
+		break;
+
+	    case COLUMN_HMDISKBUSYPCNT:
+		snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->hmDiskBusyPcnt, strlen(data->hmDiskBusyPcnt));
+		break;
+
+	    case COLUMN_HMAVGDISKSVCTIME:
+		snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) data->hmAvgDiskSvcTime, strlen(data->hmAvgDiskSvcTime));
+		break;
+
+	    default:
+		/* We shouldn't get here */
+		snmp_log(LOG_ERR, "problem encountered in hmDiskTable_handler: unknown column\n");
+	    }
+	    break;
+
+	case MODE_SET_RESERVE1:
+	    /* set handling... */
+
+	default:
+	    snmp_log(LOG_ERR, "problem encountered in hmDiskTable_handler: unsupported mode\n");
+	}
+    }
+    return SNMP_ERR_NOERROR;
+}
+
+/*
+ * *****
+ * New Functions that are added to the template generated by mib2c 
+ * *****
+ */
+
+
+/*
+ * The following refresh functions are called every 60 seconds. The data
+ * nodes are updated with latest data
+ */
+
+void 
+refresh_SWAP_data()
+{
+
+    int             code = 0;
+
+    code = krgetswapusage(&swapavail_data, &swapresv_data, &swapalloc_data, &swapused_data, &swaptotal_data);
+
+    /*
+     * code == -1 : Error in swapctl code == 0  : Success Can be verified
+     * using "swap -s" on shell
+     */
+
+    if (code != 0) {
+	snmp_log(LOG_ERR,"Health Monitor Module: errror getting SWAP info\n");
+	swapavail_data = 0;
+	swapresv_data = 0;
+	swapalloc_data = 0;
+	swapused_data = 0;
+    }
+}
+
+void 
+refresh_Kernel_data()
+{
+
+    int             code = 0;
+
+    code = krgetsmtx(&sum_smtx, &ncpus);
+
+    if (code != 0) {
+	snmp_log(LOG_ERR,"Health Monitor Module: errror getting Kernel info\n");
+	sum_smtx = 0;
+	ncpus = 0;
+    }
+}
+
+void 
+refresh_NFS_data()
+{
+
+    int             code = 0;
+
+    code = krgetclientrpcdetail(&calls, &badcalls, &retrans, &badxids, &timeouts, &newcreds, &badverfs, &timers, &nomem, &cantsend);
+
+    if (code != 0) {
+	snmp_log(LOG_ERR,"Health Monitor Module: errror getting NFS info\n");
+	calls = 0;
+	badcalls = 0;
+	retrans = 0;
+	badxids = 0;
+	timeouts = 0;
+	newcreds = 0;
+	badverfs = 0;
+	timers = 0;
+	nomem = 0;
+	cantsend = 0;
+    }
+
+    /* "calls" is defined as a "DisplayString" in the MIB. So, converting
+     * it to String
+     */
+
+    sprintf(callsStr, "%3.1f\0", calls);
+}
+
+void 
+refresh_CPU_data()
+{
+
+    int             code = 0;
+
+    code = krgetprocdetail(&runque, &waiting, &swapque);
+
+    if (code != 0) {
+
+	snmp_log(LOG_ERR,"Health Monitor Module: errror getting CPU info\n");
+	runque = 0;
+	waiting = 0;
+	swapque = 0;
+    }
+}
+
+void 
+refresh_RAM_data()
+{
+
+    int             code = 0;
+
+    code = krgetramdetail(&handspread, &scan);
+
+    if (code != 0) {
+
+	snmp_log(LOG_ERR,"Health Monitor Module: errror getting RAM info\n");
+	handspread = 0;
+	scan = 0;
+
+    }
+}
+
+void 
+refresh_KMEM_data()
+{
+
+    int             code = 0;
+    char            char_name[2] = "*\n";
+
+    /* char char_name='*'; */
+
+    /* The first argument of "*" requests sum of statistics of all caches */
+
+    code = krgetkmemdetail(char_name, &alloc, &alloc_fail, &buf_size, &buf_avail, &buf_total, &buf_max);
+
+    if (code >= 0)
+	code = krgetmemusage(&mem_avail, &mem_inuse, &mem_free);
+
+    if (code != 0) {
+
+	snmp_log(LOG_ERR,"Health Monitor Module: errror getting KMEM info\n");
+	alloc_fail = 0;
+	mem_free = 0;
+
+    }
+}
+
+void 
+refresh_DNLC_data()
+{
+
+    int             code = 0;
+    long            curtime;
+
+    curtime = time(&curtime);
+    if (prevtime != curtime) {
+
+	code = krgetncstatdetail(&hits, &misses);
+
+	if (code != 0) {
+
+	    snmp_log(LOG_ERR,"Health Monitor Module: errror getting DNLC info\n");
+	    hits = 0;
+	    misses = 0;
+
+	}			/* NOTE : Should we do below even if
+				 * hits=0,misses=0 ? Yes, according to SunMC
+				 * rule */
+	if (firsttime == 1) {
+	    firsttime = 0;
+	    lasthits = hits;
+	    lastmisses = misses;
+	} else {
+	    lasthits = prevhits;
+	    lastmisses = prevmisses;
+	}
+
+	prevhits = hits;
+	prevmisses = misses;
+
+	refrate = (hits - lasthits) + (misses - lastmisses);
+	if (refrate == 0) {
+	    hitrate = 100;
+	} else {
+	    hitrate = 100 * (hits - lasthits) / refrate;
+	    refrate = refrate / (curtime - prevtime);
+	}
+
+	prevtime = curtime;
+    }
+}
+
+void 
+construct_DISK_table()
+{
+
+    hmDiskTable    *prevPtr = NULL;
+
+    char            name[MAXNAMELEN];
+    char            alias[MAXNAMELEN];
+    double          rps, wps, tps, krps, kwps, kps, avw, avr;
+    double          w_pct, r_pct, wserv, rserv, serv;
+    int             code = 0;
+
+
+    /* set to 0 so that we can block any other refresh's */
+    hm_prev_disk_ref = 0;
+
+    /* Keeps track of number of disks */
+    diskCount = 0;
+
+    do {
+
+	hmDiskTable    *ptr = (hmDiskTable *) malloc(sizeof(hmDiskTable));
+	
+	if ( ptr == NULL) {
+		snmp_log(LOG_DEBUG,"malloc failed when constructing DISK table in health monitor module \n");
+		return;
+	}
+
+	code = krgetdiskdetail(name, alias, &rps, &wps, &tps, &krps, &kwps, &kps, &avw, &avr);
+
+	if (code < 0) {
+	    /* Error occured during kstat read */
+	    snmp_log(LOG_ERR,"Health Monitor Module: errror getting disk info\n");
+	    return;
+	}
+	code = krgetdisksrv(name, alias, &w_pct, &r_pct, &wserv, &rserv, &serv);
+
+	if (code < 0) {
+	    /* Error occured during kstat read */
+	    snmp_log(LOG_ERR,"Health Monitor Module: errror getting disk info\n");
+	    return;
+	}
+	/* Allocate required memory to hold each disk data. */
+
+	ptr->hmDiskName = (char *) malloc(strlen(name) + 1);
+	ptr->hmDiskAliasName = (char *) malloc(strlen(alias) + 1);
+	ptr->hmAvgWaitTransactions = (char *) malloc(DISK_DATA_LEN);
+	ptr->hmDiskBusyPcnt = (char *) malloc(DISK_DATA_LEN);
+	ptr->hmAvgDiskSvcTime = (char *) malloc(DISK_DATA_LEN);
+
+        if ( ptr->hmAvgDiskSvcTime == NULL) {
+                snmp_log(LOG_DEBUG,"malloc failed when constructing DISK table in health monitor module \n");
+                return;
+        }
+
+	strcpy(ptr->hmDiskName,name);
+
+	strcpy(ptr->hmDiskAliasName,alias);
+
+	sprintf(ptr->hmAvgWaitTransactions, "%3.1f\0", w_pct);
+
+	sprintf(ptr->hmDiskBusyPcnt, "%3.1f\0", r_pct);
+
+	sprintf(ptr->hmAvgDiskSvcTime, "%3.1f\0", serv);
+
+	/* Set the state of Disk to OK. */
+
+	ptr->hmDiskState = OK;
+
+	diskCount++;
+	ptr->pNext = NULL;
+	if (prevPtr == NULL) {
+	    head = prevPtr = ptr;
+	} else {
+
+	    prevPtr->pNext = ptr;
+	    prevPtr = ptr;
+	}
+	/* code is set to value 0 if there is more disk information */
+    } while (code == 0);
+
+    check_state_DISK();
+
+    /* set the time of first refresh */
+
+    time(&hm_prev_disk_ref);
+
+}
+
+
+void 
+refresh_DISK_table(unsigned int clientreg, void *clientarg)
+{
+
+    char            name[MAXNAMELEN];
+    char            alias[MAXNAMELEN];
+    double          rps, wps, tps, krps, kwps, kps, avw, avr;
+    double          w_pct, r_pct, wserv, rserv, serv;
+    int             code = 0;
+    hmDiskTable    *headPtr;
+    hmDiskTable    *ptr;
+    hmDiskTable    *tailPtr, *p1, *p2;
+
+
+    time_t hm_current_time;
+
+    /* Did the previous refresh really finish ??
+     * This means that previous refresh is still in progress */
+    if (hm_prev_disk_ref == 0) return;
+
+    time(&hm_current_time);
+
+    /* Did the previous refresh finish too close to start another refresh ???
+     * This means that the previous refresh finished relatively closer to current time
+     * so, another refresh is not necessary. hm_prev_disk_ref is initialized to 1
+     * during variable declaration. so, the first time refresh is called, it will always
+     * proceed.
+     */
+
+    if ( (hm_current_time - hm_prev_disk_ref) < (hm_refresh_interval / 4) ) return;
+
+    /* set to 0 so that we can block any other refresh's */
+    hm_prev_disk_ref = 0;
+
+    diskCount=0;
+
+    /* Set tailPtr to the last structure
+     * set "hmTraversed" to 0 for all disks
+     */
+
+    tailPtr = head;
+    while (tailPtr->pNext != NULL) {
+	tailPtr->hmTraversed=0;
+	tailPtr = tailPtr->pNext;
+    }
+    if(tailPtr != NULL) tailPtr->hmTraversed=0;
+
+    do {
+
+	int             hit = 0;
+	code = krgetdiskdetail(name, alias, &rps, &wps, &tps, &krps, &kwps, &kps, &avw, &avr);
+
+	if (code < 0) {
+	    /* Error occured during kstat read */
+	    snmp_log(LOG_ERR,"Health Monitor Module: errror getting disk info\n");
+	    return;
+	}
+	code = krgetdisksrv(name, alias, &w_pct, &r_pct, &wserv, &rserv, &serv);
+
+	if (code < 0) {
+	    /* Error occured during kstat read */
+	    snmp_log(LOG_ERR,"Health Monitor Module: errror getting disk info\n");
+	    return;
+	}
+
+	/* For each row in the table, refresh the data  */
+
+	headPtr = head;
+	while ((headPtr != NULL) && (hit == 0)) {
+
+	    if (strncmp(headPtr->hmDiskName, name, strlen(name)) == 0) {
+
+		/*
+		 * This Disk is already part of the list. Just update the
+		 * data
+		 */
+
+		hit = 1;
+
+		strcpy(headPtr->hmDiskAliasName,alias);
+		sprintf(headPtr->hmAvgWaitTransactions, "%3.1f\0", w_pct);
+		sprintf(headPtr->hmDiskBusyPcnt, "%3.1f\0", r_pct);
+		sprintf(headPtr->hmAvgDiskSvcTime, "%3.1f\0", serv);
+
+		/*
+		 * Don't change the hmDiskState here because existing
+		 * diskState should be maintained
+		 */
+
+                headPtr->hmTraversed=1;
+
+	    }
+	    headPtr = headPtr->pNext;
+
+	}			/* End of while loop around each row */
+
+	if (hit != 1) {
+
+
+	    /* A new Disk is found in this refresh cycle . How likely ? */
+
+	    ptr = (hmDiskTable *) malloc(sizeof(hmDiskTable));
+
+	    ptr->hmDiskName = (char *) malloc(strlen(name) + 1);
+	    ptr->hmDiskAliasName = (char *) malloc(strlen(alias) + 1);
+	    ptr->hmAvgWaitTransactions = (char *) malloc(DISK_DATA_LEN);
+	    ptr->hmDiskBusyPcnt = (char *) malloc(DISK_DATA_LEN);
+	    ptr->hmAvgDiskSvcTime = (char *) malloc(DISK_DATA_LEN);
+
+            if ( ptr->hmAvgDiskSvcTime == NULL) {
+                snmp_log(LOG_DEBUG,"malloc failed when refreshing DISK table in health monitor module \n");
+                return;
+            }
+
+	    strcpy(ptr->hmDiskName,name);
+
+	    strcpy(ptr->hmDiskAliasName,alias);
+
+	    sprintf(ptr->hmAvgWaitTransactions, "%3.1f\0", w_pct);
+
+	    sprintf(ptr->hmDiskBusyPcnt, "%3.1f\0", r_pct);
+
+	    sprintf(ptr->hmAvgDiskSvcTime, "%3.1f\0", serv);
+
+	    /* Set the state of Disk to OK. */
+
+	    ptr->hmDiskState = OK;
+
+	    /* Set Traversed to 1 */
+
+	    ptr->hmTraversed=1;
+
+
+	    ptr->pNext = NULL;
+
+	    if (tailPtr == NULL) {
+		head = tailPtr = ptr;
+	    } else {
+
+		tailPtr->pNext = ptr;
+		tailPtr = ptr;
+	    }
+
+	}
+	diskCount++;
+
+    } while (code == 0);
+
+    /* Any disk that is not "touched" previously (i.e, has 
+     * hmTraversal value of 0, means that it's a removed disk.
+     * Traverse through the whole list again and remove those
+     * entries from the list.
+     */
+
+    p1=head;
+    p2=head;
+
+    while( p2 != NULL) {
+
+	if (p2->hmTraversed == 0) {
+		
+		/* Take care of removing this disk */
+
+		if(p2->pNext != NULL) {
+			p1->pNext = p2->pNext;
+			free(p2);
+			p2=p1->pNext;
+		} else {
+			p1->pNext=NULL;
+			free(p2);
+			p2=NULL;
+		}
+	} else {
+
+		/* Extend pointers  by 1 step */
+
+		if(p2->pNext != NULL) {
+	
+			p1=p2;
+			p2=p2->pNext;
+		} else {
+			
+			p2=p2->pNext;
+		}
+	}
+    }
+
+
+    check_state_DISK();
+
+    time(&hm_prev_disk_ref);
+
+}
+
+/*
+ * Function: refresh_all_HM_data. This function collects the data for all
+ * nodes in the module and stores the data in the data variables. The
+ * function is called every "refresh-interval" automatically. After the data
+ * is refreshed, the alarm condition is checked and a trap is sent if the
+ * conditions are met.
+ */
+
+void
+refresh_all_HM_data(unsigned int clientreg, void *clientarg)
+{
+
+    time_t hm_current_time;
+
+    /* Did the previous refresh really finish ??
+     * This means that previous refresh is still in progress */
+    if (hm_prev_ref_time == 0) return;
+
+    time(&hm_current_time);
+
+    /* Did the previous refresh finish too close to start another refresh ???
+     * This means that the previous refresh finished relatively closer to current time 
+     * so, another refresh is not necessary. hm_prev_ref_time is initialized to 1
+     * during variable declaration. so, the first time refresh is called, it will always 
+     * proceed.
+     */
+
+    /* printf("%u	%u	%u\n",hm_current_time, hm_prev_ref_time, hm_refresh_interval/4);*/
+    if ( (hm_current_time - hm_prev_ref_time) < (hm_refresh_interval / 4) ) return;
+
+    /* set to 0 so that we can block any other refresh's */
+    hm_prev_ref_time = 0;
+
+    /* refresh data for SWAP nodes and check alarm condition */
+
+    refresh_SWAP_data();
+    hm_handle_rule(&SWAP_rule_state, &SWAP_rule);
+
+    /* Acquire data for Kernel nodes */
+
+    refresh_Kernel_data();
+    hm_handle_rule(&Kernel_rule_state, &Kernel_rule);
+
+    /* Acquire data for NFS nodes */
+
+    refresh_NFS_data();
+    hm_handle_rule(&NFS_rule_state, &NFS_rule);
+
+    /* Acquire data for CPU nodes */
+
+    refresh_CPU_data();
+    hm_handle_rule(&CPU_rule_state, &CPU_rule);
+
+    /* Acquire data for RAM nodes */
+
+    refresh_RAM_data();
+    hm_handle_rule(&RAM_rule_state, &RAM_rule);
+
+    /* Acquire data for KMEM nodes */
+
+    refresh_KMEM_data();
+    hm_handle_rule(&KMEM_rule_state, &KMEM_rule);
+
+    /* Acquire data for DNLC nodes */
+
+    refresh_DNLC_data();
+    hm_handle_rule(&DNLC_rule_state, &DNLC_rule);
+
+    /* End of Data acquisition for HM module */
+
+    time(&hm_prev_ref_time);
+
+    return;
+
+}
+
+/*
+ * Function: read_health_monitor_thresholds: This function is called whenever
+ * a registered token is encountered in health_monitor.conf file. The
+ * function simply stores the token's value in the appropriate threshold
+ * variable.
+ */
+
+void
+read_health_monitor_thresholds(const char *token, char *cptr)
+{
+
+    if (strcmp(token, "hm_refresh_interval") == 0) {
+        hm_refresh_interval = atoi(cptr);
+    } else if (strcmp(token, "threshold_swapavail_info") == 0) {
+	threshold_swapavail_info = atoi(cptr);
+    } else if (strcmp(token, "threshold_swapavail_warning") == 0) {
+	threshold_swapavail_warning = atoi(cptr);
+    } else if (strcmp(token, "threshold_swapavail_error") == 0) {
+	threshold_swapavail_error = atoi(cptr);
+    } else if (strcmp(token, "threshold_mutex_info") == 0) {
+	threshold_mutex_info = atol(cptr);
+    } else if (strcmp(token, "threshold_mutex_warning") == 0) {
+	threshold_mutex_warning = atol(cptr);
+    } else if (strcmp(token, "threshold_mincalls") == 0) {
+	threshold_mincalls = atof(cptr);
+    } else if (strcmp(token, "threshold_badxids") == 0) {
+	threshold_badxids = atof(cptr);
+    } else if (strcmp(token, "threshold_timeouts") == 0) {
+	threshold_timeouts = atof(cptr);
+    } else if (strcmp(token, "threshold_cpuload_info") == 0) {
+	threshold_cpuload_info = atof(cptr);
+    } else if (strcmp(token, "threshold_cpuload_warning") == 0) {
+	threshold_cpuload_warning = atof(cptr);
+    } else if (strcmp(token, "threshold_cpuload_error") == 0) {
+	threshold_cpuload_error = atof(cptr);
+    } else if (strcmp(token, "threshold_restime_long") == 0) {
+	threshold_restime_long = atoi(cptr);
+    } else if (strcmp(token, "threshold_restime_ok") == 0) {
+	threshold_restime_ok = atoi(cptr);
+    } else if (strcmp(token, "threshold_restime_error") == 0) {
+	threshold_restime_error = atoi(cptr);
+    } else if (strcmp(token, "threshold_freemem_low") == 0) {
+	threshold_freemem_low = atoi(cptr);
+    } else if (strcmp(token, "threshold_dnlc_active") == 0) {
+	threshold_dnlc_active = atof(cptr);
+    } else if (strcmp(token, "threshold_dnlc_warning") == 0) {
+	threshold_dnlc_warning = atof(cptr);
+    } else if (strcmp(token, "disk_busy_warning") == 0) {
+	disk_busy_warning = atol(cptr);
+    } else if (strcmp(token, "disk_busy_problem") == 0) {
+	disk_busy_problem = atol(cptr);
+    } else if (strcmp(token, "disk_svc_t_warning") == 0) {
+	disk_svc_t_warning = atol(cptr);
+    } else if (strcmp(token, "disk_svc_t_problem") == 0) {
+	disk_svc_t_problem = atol(cptr);
+    } else {
+	/* Do nothing */
+    }
+
+
+    return;
+}
+
+/*
+ * hm_handle_rule:
+ * 
+ * arguments: rule_state = previous state of the rule rule       = Function
+ * pointer to the actual rule
+ * 
+ * This function first determines the new state of the rule by calling
+ * rule(CONDITION).
+ * 
+ * In the switch loop, depending on the previous rule state (the rule_state) and
+ * new state, the rule function is again called appropriately. For example,
+ * if the previous state is INIT and the new state is > OK, then rule(OPEN)
+ * is called.
+ * 
+ */
+
+
+void 
+hm_handle_rule(int *rule_state, int (*rule) (int))
+{
+
+    int             new_alarm_state;
+
+    if (*rule_state == NOTINIT) {
+	*rule_state = INIT;
+	rule(INIT);
+    }
+    new_alarm_state = rule(CONDITION);
+
+    switch (*rule_state) {
+
+    case INIT:
+	if (new_alarm_state > OK) {
+	    *rule_state = OPEN;
+	    rule(OPEN);
+	}
+	return;
+    case OPEN:
+	if (new_alarm_state == OK) {
+	    *rule_state = CLOSE;
+	    rule(CLOSE);
+	} else {
+	    *rule_state = CONTINUE;
+	    rule(CONTINUE);
+	}
+	return;
+    case CONTINUE:
+	if (new_alarm_state == OK) {
+	    *rule_state = CLOSE;
+	    rule(CLOSE);
+	} else {
+	    *rule_state = CONTINUE;
+	    rule(CONTINUE);
+	}
+	return;
+    case CLOSE:
+	if (new_alarm_state > OK) {
+	    *rule_state = OPEN;
+	    rule(OPEN);
+	}
+	return;
+    }
+
+}
+
+
+/*
+ * Function: send_trap : This function sends a *statusChange* trap with
+ * appropriate varbind's see SMA trap mib for detailed trap notification
+ * definition.
+ * 
+ * hostname - Name of host on which alarm occured ; modulename - Name of the
+ * module generating the trap ; moduleContext - The context of the module, if
+ * any; statusOID - The trapoid; size - The size of trapoid (not included in
+ * the trap); status - status of the node; description - description of the
+ * trap; dvalue - value of the node on which trap occured; dtype - data type of
+ * the value
+ */
+
+void
+send_trap(u_char * hostname, u_char * modulename, u_char * moduleContext, oid * trapoid, int size, u_char * status, u_char * description, u_char * dvalue, int dtype)
+{
+
+    /* This is the notification type itself. This is statusChange trap */
+
+    oid             notification_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 0, 1};
+
+    size_t          notification_oid_len = OID_LENGTH(notification_oid);
+
+    /*
+     * In the notification, we have to assign our notification OID to the
+     * snmpTrapOID.0 object. Here is it's definition.
+     */
+
+    oid             objid_snmptrap[] = {1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0};
+    size_t          objid_snmptrap_len = OID_LENGTH(objid_snmptrap);
+
+    /*
+     * here is where we store the variables to be sent in the trap
+     */
+
+    netsnmp_variable_list *notification_vars = NULL;
+
+    oid             hostname_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 1, 0};
+
+    size_t          hostname_oid_len = OID_LENGTH(hostname_oid);
+
+
+    oid             modulename_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 2, 0};
+
+    size_t          modulename_oid_len = OID_LENGTH(modulename_oid);
+
+
+    oid             nodeoid_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 3, 0};
+
+    size_t          nodeoid_oid_len = OID_LENGTH(nodeoid_oid);
+
+
+    oid             moduleContext_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 4, 0};
+
+    size_t          moduleContext_oid_len = OID_LENGTH(moduleContext_oid);
+
+
+    oid             status_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 5, 0};
+
+    size_t          status_oid_len = OID_LENGTH(status_oid);
+
+
+    oid             description_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 6, 0};
+
+    size_t          description_oid_len = OID_LENGTH(description_oid);
+
+    oid             dvalue_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 7, 0};
+
+    size_t          dvalue_oid_len = OID_LENGTH(dvalue_oid);
+
+    oid             dtype_oid[] = {1, 3, 6, 1, 4, 1, 42, 2, 2, 4, 3, 1, 8, 0};
+
+    size_t          dtype_oid_len = OID_LENGTH(dtype_oid);
+
+
+    /*
+     * add in the trap definition object
+     */
+
+    snmp_varlist_add_variable(&notification_vars,
+    /*
+     * the snmpTrapOID.0 variable
+     */
+			      objid_snmptrap, objid_snmptrap_len,
+    /*
+     * value type is an OID
+     */
+			      ASN_OBJECT_ID,
+    /*
+     * value contents is our notification OID
+     */
+			      (u_char *) notification_oid,
+    /*
+     * size in bytes = oid length * sizeof(oid)
+     */
+			      notification_oid_len * sizeof(oid));
+
+
+    /*
+     * if we wanted to insert additional objects, we'd do it here
+     */
+
+
+    snmp_varlist_add_variable(&notification_vars,
+			      hostname_oid, hostname_oid_len,
+    /*
+     * value type is an OID
+     */
+			      ASN_OCTET_STR,
+    /*
+     * value contents is our notification OID
+     */
+			      (u_char *) hostname,
+    /*
+     * size in bytes = oid length * sizeof(oid)
+     */
+			      strlen((char *) hostname));
+
+
+    snmp_varlist_add_variable(&notification_vars,
+			      modulename_oid, modulename_oid_len,
+    /*
+     * value type is an OID
+     */
+			      ASN_OCTET_STR,
+    /*
+     * value contents is our notification OID
+     */
+			      (u_char *) modulename,
+    /*
+     * size in bytes = oid length * sizeof(oid)
+     */
+			      strlen((char *) modulename));
+
+
+    snmp_varlist_add_variable(&notification_vars,
+			      nodeoid_oid, nodeoid_oid_len,
+    /*
+     * value type is an OID
+     */
+			      ASN_OBJECT_ID,
+    /*
+     * value contents is our notification OID
+     */
+			      (u_char *) trapoid,
+    /*
+     * size in bytes = oid length * sizeof(oid)
+     */
+			      size * sizeof(oid));
+
+
+    snmp_varlist_add_variable(&notification_vars,
+			      moduleContext_oid, moduleContext_oid_len,
+    /*
+     * value type is an OID
+     */
+			      ASN_OCTET_STR,
+    /*
+     * value contents is our notification OID
+     */
+			      (u_char *) moduleContext,
+    /*
+     * size in bytes = oid length * sizeof(oid)
+     */
+			      strlen((char *) moduleContext));
+
+
+    snmp_varlist_add_variable(&notification_vars,
+			      status_oid, status_oid_len,
+    /*
+     * value type is an OID
+     */
+			      ASN_OCTET_STR,
+    /*
+     * value contents is our notification OID
+     */
+			      (u_char *) status,
+    /*
+     * size in bytes = oid length * sizeof(oid)
+     */
+			      strlen((char *) status));
+
+
+    snmp_varlist_add_variable(&notification_vars,
+			      description_oid, description_oid_len,
+    /*
+     * value type is an OID
+     */
+			      ASN_OCTET_STR,
+    /*
+     * value contents is our notification OID
+     */
+			      (u_char *) description,
+    /*
+     * size in bytes = oid length * sizeof(oid)
+     */
+			      strlen((char *) description));
+
+
+    snmp_varlist_add_variable(&notification_vars,
+			      dvalue_oid, dvalue_oid_len,
+    /*
+     * value type is an OID
+     */
+			      ASN_OCTET_STR,
+    /*
+     * value contents is our notification OID
+     */
+			      (u_char *) dvalue,
+    /*
+     * size in bytes = oid length * sizeof(oid)
+     */
+			      strlen((char *) dvalue));
+
+
+
+    snmp_varlist_add_variable(&notification_vars,
+			      dtype_oid, dtype_oid_len,
+    /*
+     * value type is an OID
+     */
+			      ASN_INTEGER,
+    /*
+     * value contents is our notification OID
+     */
+			      (u_char *) & dtype,
+    /*
+     * size in bytes = oid length * sizeof(oid)
+     */
+			      sizeof(dtype));
+
+
+    /* SEND THE TRAP !!!! */
+
+    send_v2trap(notification_vars);
+
+    /*
+     * free the created notification variable list
+     */
+
+    DEBUGMSGTL(("example_notification", "cleaning up\n"));
+    snmp_free_varbind(notification_vars);
+
+    return;
+
+}
+
+/*
+ * Function: conv_alarm_state : This function returns appropriate charecter
+ * string for each integer alarm type
+ */
+
+char           *
+conv_alarm_state(int state)
+{
+    switch (state) {
+	case OK:
+	return "OK\0";
+    case INFO:
+	return "INFO\0";
+    case WARNING:
+	return "WARNING\0";
+    case ERROR:
+	return "ERROR\0";
+    default:
+	return "INVALID\0";
+    }
+}
+
+
+
+/*
+ * Function: SWAP_rule : This function checks the state of SWAP nodes and
+ * issues trap if necessary
+ */
+
+int 
+SWAP_rule(int action)
+{
+
+    /* This is the OID of hmAvailableSwapSpace */
+    oid             trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 1, 1, 1, 0};
+    u_char          status[8];
+    u_char          description[] = "Available Swap space on the system is low";
+    int             size;
+    u_char          dvalue[15];
+    /* The value of dtype is 1 here becuase swapavail_data is of "int" type */
+    int             dtype = 1;
+
+    sprintf((char *) dvalue, "%d\0", swapavail_data);
+    size = sizeof(trapoid) / sizeof(oid);
+
+    switch (action) {
+
+    case CONDITION:
+
+	/*
+	 * Quite straightforward. Depending on the threshold that is crossed,
+	 * assign the new state
+	 */
+
+	if ((swapavail_data <= threshold_swapavail_info) && (swapavail_data > threshold_swapavail_warning)) {
+	    new_SWAP_state = INFO;
+	    return INFO;
+	} else if ((swapavail_data <= threshold_swapavail_warning) && (swapavail_data > threshold_swapavail_error)) {
+	    new_SWAP_state = WARNING;
+	    return WARNING;
+	} else if (swapavail_data <= threshold_swapavail_error) {
+	    new_SWAP_state = ERROR;
+	    return ERROR;
+	}
+	new_SWAP_state = OK;
+	return OK;
+
+    case OPEN:
+
+	strcpy((char *) status, conv_alarm_state(new_SWAP_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    case INIT:
+
+	return 0;
+
+    case CONTINUE:
+
+	strcpy((char *) status, conv_alarm_state(new_SWAP_state));
+	if (new_SWAP_state > prev_SWAP_state) {
+
+	    /* Send trap */
+	    send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	    prev_SWAP_state = new_SWAP_state;
+
+	}
+	return 0;
+
+    case CLOSE:
+
+	strcpy((char *) status, conv_alarm_state(new_SWAP_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    default:
+
+	return 0;
+    }
+
+}
+
+/*
+ * Function: Kernel_rule : This function checks the state of Kernel nodes and
+ * issues trap if necessary
+ */
+
+int 
+Kernel_rule(int action)
+{
+
+    int             mutexrate;
+
+    /* This is the OID of hmSpinsOnMutexes */
+    oid             trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 2, 1, 1, 0};
+    u_char          status[8];
+    u_char          description[] = "Mutex contention rate is high , kernel overload \0";
+    int             size;
+    u_char          dvalue[15];
+    /*
+     * dtype is set to 1 because the hmSpinsOnMutexes node is defined as
+     * Integer32 in the mib
+     */
+    int             dtype = 1;
+
+    sprintf((char *) dvalue, "%lu\0", sum_smtx);
+    size = sizeof(trapoid) / sizeof(oid);
+
+    switch (action) {
+
+    case CONDITION:
+
+	if (ncpus == 0) {
+	    /* this happens only during initialization */
+	    new_mutex_state = OK;
+	    return OK;
+	}
+	mutexrate = sum_smtx / ncpus;
+
+	/* Determine if there is a new Alarm state */
+
+	if (mutexrate < threshold_mutex_info) {
+	    if (mutexrate == 0) {
+
+		/*
+		 * This is a change from existing rule. It makes more sense
+		 * that if mutexrate is 0, then the state should be OK. i.e,
+		 * no problems
+		 */
+
+		new_mutex_state = OK;
+		return OK;
+
+	    } else {
+		new_mutex_state = INFO;
+		return INFO;
+	    }
+	} else if (mutexrate < threshold_mutex_warning) {
+	    new_mutex_state = WARNING;
+	    return WARNING;
+	} else {
+	    new_mutex_state = ERROR;
+	    return WARNING;
+	}
+
+    case OPEN:
+
+	strcpy((char *) status, conv_alarm_state(new_mutex_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    case INIT:
+
+	return 0;
+
+    case CONTINUE:
+
+	strcpy((char *) status, conv_alarm_state(new_mutex_state));
+
+	if (new_mutex_state > prev_mutex_state) {
+
+	    /* Send trap */
+	    send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	    prev_mutex_state = new_mutex_state;
+
+	}
+	return 0;
+
+    case CLOSE:
+
+	strcpy((char *) status, conv_alarm_state(new_mutex_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    default:
+
+	return 0;
+    }
+
+}
+
+/*
+ * Function: NFS_rule : This function checks the state of NFS nodes and
+ * issues trap if necessary
+ */
+
+int 
+NFS_rule(int action)
+{
+
+    float           maxtimeout, maxbadxid;
+
+    /*
+     * This is the OID of hmNFSClientRPCGroup. Note that this rule uses data
+     * from more than one node to determine the alarm state
+     */
+    oid             trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 3, 1};
+    u_char          status[8];
+    u_char          description[] = "Bad Network or Server is slow. May need to increase timeout \0 ";
+    int             size;
+    u_char          dvalue[15];
+    int             dtype = 1;
+
+    /*
+     * It's tricky which "value" should be put in dvalue field. More than one
+     * node's data is looked at to determine alarm state.
+     */
+    sprintf((char *) dvalue, "%d\0", timeouts);
+    size = sizeof(trapoid) / sizeof(oid);
+
+    switch (action) {
+
+    case CONDITION:
+
+	if (calls <= threshold_mincalls) {
+	    /*
+	     * This is a change from existing rule (which has INFO). It makes
+	     * sense that no trap is sent when calls is < threshold_mincalls.
+	     */
+
+	    new_NFS_state = OK;
+	    return OK;
+	} else {
+	    maxtimeout = threshold_timeouts * calls / 100.0;
+
+	    if (timeouts < maxtimeout) {
+
+		/*
+		 * This is a change from existing rule (which has INFO). It
+		 * makes sense that no trap is sent when timeouts is <
+		 * maxtimeout
+		 */
+
+		new_NFS_state = OK;
+		return OK;
+
+	    } else {
+		maxbadxid = threshold_badxids * timeouts / 100.0;
+		if ((maxtimeout <= timeouts) && (badxids <= maxbadxid)) {
+		    new_NFS_state = WARNING;
+		    return WARNING;
+		} else {
+		    /*
+		     * This will be the case when timeout >= maxtimeout AND
+		     * badxids > maxbadxid
+		     */
+		    new_NFS_state = ERROR;
+		    return ERROR;
+		}
+	    }
+	}
+
+    case OPEN:
+
+	strcpy((char *) status, conv_alarm_state(new_NFS_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    case INIT:
+
+	return 0;
+
+    case CONTINUE:
+
+	strcpy((char *) status, conv_alarm_state(new_NFS_state));
+	if (new_NFS_state > prev_NFS_state) {
+
+	    /* Send trap */
+	    send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	    prev_NFS_state = new_NFS_state;
+
+	}
+	return 0;
+
+    case CLOSE:
+
+	strcpy((char *) status, conv_alarm_state(new_NFS_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    default:
+
+	return 0;
+    }
+
+}
+
+/*
+ * Function: CPU_rule : This function checks the state of CPU nodes and
+ * issues trap if necessary
+ */
+
+int 
+CPU_rule(int action)
+{
+
+    /* This is the OID for hmTotProcInRunQueue */
+    oid             trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 4, 1, 1, 0};
+    u_char          status[8];
+    u_char          description[] = "CPU overloaded \0";
+    int             size;
+    u_char          dvalue[15];
+    /* dtype is given a value of 1 because runque is of "int" type */
+    int             dtype = 1;
+
+    float           cpuload;
+
+    sprintf((char *) dvalue, "%d\0", runque);
+    size = sizeof(trapoid) / sizeof(oid);
+
+    switch (action) {
+
+    case CONDITION:
+
+	/*
+	 * Added this If statement to existing rule. From Kernel_rule, it
+	 * looks like ncpus may be 0 during initialization
+	 */
+	if (ncpus == 0) {
+	    /* this happens only during initialization */
+	    new_cpuload_state = OK;
+	    return OK;
+	}
+	cpuload = runque / ncpus;
+
+	/*
+	 * Quite straightforward. If the threshold is crossed, set the state
+	 * accordingly
+	 */
+
+	if (cpuload < threshold_cpuload_info) {
+	    new_cpuload_state = OK;
+	    return OK;
+	} else if (cpuload < threshold_cpuload_warning) {
+	    new_cpuload_state = INFO;
+	    return INFO;
+	} else if (cpuload < threshold_cpuload_error) {
+	    new_cpuload_state = WARNING;
+	    return WARNING;
+	} else {
+	    new_cpuload_state = ERROR;
+	    return ERROR;
+	}
+
+    case OPEN:
+
+	strcpy((char *) status, conv_alarm_state(new_cpuload_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    case INIT:
+
+	return 0;
+
+    case CONTINUE:
+
+	strcpy((char *) status, conv_alarm_state(new_cpuload_state));
+	if (new_cpuload_state > prev_cpuload_state) {
+
+	    /* Send trap */
+	    send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	    prev_cpuload_state = new_cpuload_state;
+
+	}
+	return 0;
+
+    case CLOSE:
+
+	strcpy((char *) status, conv_alarm_state(new_cpuload_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    default:
+
+	return 0;
+    }
+
+}
+
+/*
+ * Function: RAM_rule : This function checks the state of RAM nodes and
+ * issues trap if necessary
+ */
+
+int 
+RAM_rule(int action)
+{
+
+    /*
+     * This is the OID of hmRamMemoryPagingGroup. Note that this rule uses
+     * data from more than one node to determine the alarm state
+     */
+    oid             trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 6, 1};
+    u_char          status[8];
+    u_char          description[] = "RAM shortage \0";
+    int             size;
+    u_char          dvalue[15];
+
+    /* dtype is given a value of 1 because scan is of "int" type */
+    int             dtype = 1;
+
+    float           restime;
+
+    /*
+     * It's tricky which "value" should be put in dvalue field. More than one
+     * node's data is looked at to determine alarm state.
+     */
+    sprintf((char *) dvalue, "%d\0", scan);
+
+    size = sizeof(trapoid) / sizeof(oid);
+
+    switch (action) {
+
+    case CONDITION:
+
+	if (scan == 0) {
+	    restime = threshold_restime_long;
+	} else {
+	    restime = handspread / scan;
+	}
+
+	if (restime > threshold_restime_long) {
+	    restime = threshold_restime_long;
+	}
+	if (restime >= threshold_restime_long) {
+	    /* This is a change from existing rule (which has INFO). */
+
+	    new_restime_state = OK;
+	    return OK;
+	} else {
+	    if (restime > threshold_restime_ok) {
+		new_restime_state = INFO;
+		return INFO;
+	    } else {
+		if (restime > threshold_restime_error) {
+		    new_restime_state = WARNING;
+		    return WARNING;
+		} else {
+		    new_restime_state = ERROR;
+		    return ERROR;
+		}
+	    }
+	}
+
+    case OPEN:
+
+	strcpy((char *) status, conv_alarm_state(new_restime_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    case INIT:
+
+	return 0;
+
+    case CONTINUE:
+
+	strcpy((char *) status, conv_alarm_state(new_restime_state));
+	if (new_restime_state > prev_restime_state) {
+
+	    /* Send trap */
+	    send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	    prev_restime_state = new_restime_state;
+
+	}
+	return 0;
+
+    case CLOSE:
+
+	strcpy((char *) status, conv_alarm_state(new_restime_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    default:
+
+	return 0;
+    }
+
+}
+
+/*
+ * Function: KMEM_rule : This function checks the state of KMEM nodes and
+ * issues trap if necessary
+ */
+
+int 
+KMEM_rule(int action)
+{
+
+    /*
+     * This is the OID of hmKmemStatisticsGroup. Note that this rule uses
+     * data from more than one node to determine the alarm state
+     */
+    oid             trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 7, 1};
+    u_char          status[8];
+    u_char          description[] = "Kernel Memory allocation errors \0";
+    int             size;
+    u_char          dvalue[15];
+    /* dtype is given a value of 1 because alloc_fail is of "int" type */
+    int             dtype = 1;
+
+    int             firsterrs, lasterrs;
+
+    /*
+     * It's tricky which "value" should be put in dvalue field. More than one
+     * node's data is looked at to determine alarm state.
+     */
+    sprintf((char *) dvalue, "%d\0", alloc_fail);
+
+    size = sizeof(trapoid) / sizeof(oid);
+
+    switch (action) {
+
+    case CONDITION:
+
+	/* This is a slightly confusing rule  */
+
+	firsterrs = firstkmemerrs;
+	lasterrs = lastkmemerrs;
+
+	if (alloc_fail == firsterrs) {
+	    if (alloc_fail == 0) {
+		/*
+		 * This is a change from existing rule (which has INFO). It
+		 * makes sense that an OK state should be returned when
+		 * alloc_fail is 0
+		 */
+		new_kmem_state = OK;
+		return OK;
+	    } else {
+		new_kmem_state = INFO;
+		return INFO;
+	    }
+	} else {
+	    if (alloc_fail == lasterrs) {
+		new_kmem_state = WARNING;
+		return WARNING;
+	    } else {
+		new_kmem_state = ERROR;
+		lastkmemerrs = alloc_fail;
+		if (mem_free > threshold_freemem_low) {
+		    /*
+		     * Kernel memory allocation problem. The state is already
+		     * set to ERROR.
+		     */
+		} else {
+		    /*
+		     * Kernel memory allocation problem. The state is already
+		     * set to ERROR.
+		     */
+		}
+		return ERROR;
+	    }
+	}
+
+    case OPEN:
+
+	firstkmemerrs = alloc_fail;
+	lastkmemerrs = alloc_fail;
+	strcpy((char *) status, conv_alarm_state(new_kmem_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    case INIT:
+
+	firstkmemerrs = 0;
+	lastkmemerrs = 0;
+	return 0;
+
+    case CONTINUE:
+
+	strcpy((char *) status, conv_alarm_state(new_kmem_state));
+	if (new_kmem_state > prev_kmem_state) {
+
+	    /* Send trap */
+	    send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	    prev_kmem_state = new_kmem_state;
+
+	}
+	return 0;
+
+    case CLOSE:
+
+	strcpy((char *) status, conv_alarm_state(new_kmem_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    default:
+
+	return 0;
+    }
+
+}
+
+/*
+ * Function: DNLC_rule : This function checks the state of DNLC nodes and
+ * issues trap if necessary
+ */
+
+int 
+DNLC_rule(int action)
+{
+
+    /* This is the OID for hmDNLCStatGroup */
+    oid             trapoid[] = {1, 3, 6, 1, 4, 1, 42, 2, 12, 2, 2, 11, 8, 1};
+    u_char          status[8];
+    u_char          description[] = "Poor DNLC Hit rate \0";
+    int             size;
+    u_char          dvalue[15];
+    /* dtype is given a value of 1 because hitrate is of "int" type */
+    int             dtype = 1;
+
+    /*
+     * It's tricky which "value" should be put in dvalue field. More than one
+     * node's data is looked at to determine alarm state.
+     */
+    sprintf((char *) dvalue, "%d\0", hitrate);
+
+    size = sizeof(trapoid) / sizeof(oid);
+
+    switch (action) {
+
+    case CONDITION:
+
+	/*
+	 * Changed the rule from existing rule. Used OK instead of INFO when
+	 * there is no problem
+	 */
+
+	if (refrate < threshold_dnlc_active) {
+	    new_dnlc_state = OK;
+	    return OK;
+	} else {
+	    if (hitrate > threshold_dnlc_warning) {
+		new_dnlc_state = OK;
+		return OK;
+	    } else {
+		new_dnlc_state = WARNING;
+		return WARNING;
+	    }
+	}
+
+
+    case OPEN:
+
+	strcpy((char *) status, conv_alarm_state(new_dnlc_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    case INIT:
+
+	return 0;
+
+    case CONTINUE:
+
+	strcpy((char *) status, conv_alarm_state(new_dnlc_state));
+	if (new_dnlc_state > prev_dnlc_state) {
+
+	    /* Send trap */
+	    send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	    prev_dnlc_state = new_dnlc_state;
+
+	}
+	return 0;
+
+    case CLOSE:
+
+	strcpy((char *) status, conv_alarm_state(new_dnlc_state));
+	send_trap(hostName, moduleName, statusOIDContext, trapoid, size, status, description, dvalue, dtype);
+	return 0;
+
+    default:
+
+	return 0;
+    }
+
+}
+
+void
+check_state_DISK()
+{
+
+    /* TRAP STUFF */
+
+    oid            *trapoid;
+    u_char          status[8];
+    u_char          description[] = "Disk Loaded \0";
+
+    /*
+     * A value of 12 is given to dtype because the diskName is of
+     * "DisplayString" type. Disk Name is used for dvalue because multiple
+     * values are used to determine trap state. No single value can be used
+     */
+
+    int             dtype = 12;
+
+    /* Maintain a pointer to diskTable called headPtr */
+
+    hmDiskTable    *headPtr;
+    int             nameSize;
+    headPtr = head;
+
+    /* For each row in the table, determine if there is a new Alarm Condition */
+
+    while (headPtr != NULL) {
+
+	/* For each disk, set the new state back to OK again */
+	int             new_disk_state = OK;
+	int             i;
+
+	long            wait = atol(headPtr->hmAvgWaitTransactions);
+	long            svcTime = atol(headPtr->hmAvgDiskSvcTime);
+	long            busyTime = atol(headPtr->hmDiskBusyPcnt);
+
+        /* For cases where busyTime < disk_busy_warning, svcTime < disk_svc_t_warning,
+           state is set to OK instead of INFO (as in existing rule);
+	*/
+
+	if (busyTime < disk_busy_warning) {
+	    new_disk_state = OK;
+	} else {
+	    if (svcTime < disk_svc_t_warning) {
+		new_disk_state = OK;
+	    } else {
+		if (disk_busy_problem <= busyTime) {
+		    if ((disk_svc_t_warning <= svcTime) && (svcTime < disk_svc_t_problem)) {
+			new_disk_state = WARNING;
+		    } else {
+			if (disk_svc_t_problem <= svcTime) {
+			    new_disk_state = ERROR;
+			}
+		    }
+		} else {
+		    new_disk_state = WARNING;
+		}
+	    }
+
+	}
+
+	nameSize = strlen(headPtr->hmDiskName);
+
+	/*
+	 * Compose the trap OID here. It is:
+	 * 1.3.6.1.4.1.42.2.12.2.2.11.5.1.1.1.<size-of-index>.index
+	 */
+
+	trapoid = malloc((16 * sizeof(oid)) + sizeof(oid) + (nameSize * sizeof(oid)));
+
+        if ( trapoid == NULL) {
+                snmp_log(LOG_DEBUG,"malloc failed when constructing trapoid in health monitor module \n");
+                return;
+        }
+
+	trapoid[0] = 1;
+	trapoid[1] = 3;
+	trapoid[2] = 6;
+	trapoid[3] = 1;
+	trapoid[4] = 4;
+	trapoid[5] = 1;
+	trapoid[6] = 42;
+	trapoid[7] = 2;
+	trapoid[8] = 12;
+	trapoid[9] = 2;
+	trapoid[10] = 2;
+	trapoid[11] = 11;
+	trapoid[12] = 5;
+	trapoid[13] = 1;
+	trapoid[14] = 1;
+	trapoid[15] = 1;
+
+	trapoid[16] = nameSize;
+
+	for (i = 1; i <= nameSize; i++) {
+	    trapoid[16 + i] = headPtr->hmDiskName[i - 1];
+	}
+
+	/* Depending on the new state, send trap if necessary */
+
+	if (new_disk_state > headPtr->hmDiskState) {
+
+	    /* Send trap */
+	    strcpy((char *) status, conv_alarm_state(new_disk_state));
+	    send_trap(hostName, moduleName, statusOIDContext, trapoid, 17 + nameSize, status, description, (u_char *) headPtr->hmDiskName, dtype);
+	    headPtr->hmDiskState = new_disk_state;
+
+	} else if (new_disk_state == headPtr->hmDiskState) {
+
+	    /* No Change in state .. Do nothing */
+
+	} else if (new_disk_state < headPtr->hmDiskState) {
+
+	    if (new_disk_state == OK) {
+
+		/* Send OK trap */
+		strcpy((char *) status, conv_alarm_state(new_disk_state));
+		send_trap(hostName, moduleName, statusOIDContext, trapoid, 17 + nameSize, status, description, (u_char *) headPtr->hmDiskName, dtype);
+		headPtr->hmDiskState = OK;
+
+	    }
+	}
+
+	headPtr = headPtr->pNext;
+
+    }				/* End of while loop that traverses each row */
+
+
+    return;
+
+}