
/*
 * 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;

}
