/*
 * 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.iterate.conf,v 5.5 2002/12/16 22:50:18 hardaker Exp $
 */

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "stdhdr.h"
#include "entPhysicalTable.h"
#include "entPhysicalContainsTable.h"
#include "entLastChangeTime.h"
#include "entAliasMappingTable.h"
#include "entLPMappingTable.h"

entPhysicalEntry_t *gPhysicalTableTail, *gPhysicalTableHead;
int gPhysicalTableSize;
#define ENTPHYSICALSERIALNUM_CACHE "entphyserialnum_cache"
/* Fix for 4915824 */
#define ENTPHYSICALALIAS_CACHE "entphyalias_cache"
#define ENTPHYSICALASSETID_CACHE "entphyassetid_cache"
/* End of Fix for 4915824 */

static int AddToPhysicalTable(entPhysicalEntry_t *);
static int FreePhysicalEntry(entPhysicalEntry_t *);

/** Initialize the entPhysicalTable table by defining its contents and how it's structured */
void
initialize_table_entPhysicalTable(void)
{
    static oid entPhysicalTable_oid[] = {1,3,6,1,2,1,47,1,1,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 */
    /* Fix for 4921485: Temporarily disabling write access, until we */
    /*                  actually need to re-enable it */
    my_handler = netsnmp_create_handler_registration("entPhysicalTable",
                                                     entPhysicalTable_handler,
                                                     entPhysicalTable_oid,
                                                     OID_LENGTH(entPhysicalTable_oid),
                                                     HANDLER_CAN_RONLY);
    /* End of Fix for 4921485 */

    /* Future Fix for 4922782: When we re-enable write access, we will also */
    /*                         look into 4914919 - persistency.  Of course */
    /*                         we need to remove 4921485 and enable the */
    /*                         CAN_RWRITE.   Treat the write handling code */
    /*                         in entPhysicalTable_handlerNeeds as hostile: */
    /*                         everything should be tested and properly */
    /*                         reviewed.  Pay special attention to when */
    /*                         to return error codes */
/*
    my_handler = netsnmp_create_handler_registration("entPhysicalTable",
                                                     entPhysicalTable_handler,
                                                     entPhysicalTable_oid,
                                                     OID_LENGTH(entPhysicalTable_oid),
                                                     HANDLER_CAN_RWRITE);
*/
    /* End of Future Fix for 4922782 */
            
    if (!my_handler || !table_info || !iinfo)
        return; /* mallocs failed */

    /***************************************************
     * Setting up the table's definition
     */
    netsnmp_table_helper_add_indexes(table_info,
                                     ASN_INTEGER, /* index: entPhysicalIndex */
                                     0);

    table_info->min_column = 2;
    table_info->max_column = 16;

    /* iterator access routines */
    iinfo->get_first_data_point = entPhysicalTable_get_first_data_point;
    iinfo->get_next_data_point = entPhysicalTable_get_next_data_point;

    iinfo->table_reginfo = table_info;

    /***************************************************
     * registering the table with the master agent
     */
    DEBUGMSGTL(("initialize_table_entPhysicalTable",
                "Registering table entPhysicalTable as a table iterator\n"));		 
    netsnmp_register_table_iterator(my_handler, iinfo);
}

/** Initializes the entPhysicalTable module */
void
init_entPhysicalTable(void)
{

    /* here we initialize all the tables we're planning on supporting */
    initialize_table_entPhysicalTable();
    gPhysicalTableTail = gPhysicalTableHead = NULL;
    gPhysicalTableSize = 0;
}

/** returns the first data point within the entPhysicalTable 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 *
entPhysicalTable_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;
    entPhysicalEntry_t *zRunner;
    zRunner = gPhysicalTableHead;

    while (zRunner) {
        if (zRunner->entPhysicalIndex > 0)
            break;
        zRunner = zRunner->pNextEntry;
    }

    if (zRunner == NULL) return NULL;

    *my_loop_context = (void *)zRunner;
    *my_data_context = (void *)zRunner;

    vptr = put_index_data;
    
    snmp_set_var_value(vptr, (u_char *)&zRunner->entPhysicalIndex, sizeof(zRunner->entPhysicalIndex));
    vptr = vptr->next_variable;

    return put_index_data;
}

/** functionally the same as entPhysicalTable_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 *
entPhysicalTable_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;
    entPhysicalEntry_t *zRunner;

    zRunner = (entPhysicalEntry_t *) *my_loop_context;

    while (zRunner) {
        zRunner = zRunner->pNextEntry;
        if (zRunner && zRunner->entPhysicalIndex > 0)
            break;
    }

    if (zRunner == NULL) return NULL;

    *my_loop_context = (void *)zRunner;
    *my_data_context = (void *)zRunner;

    vptr = put_index_data;
    
    snmp_set_var_value(vptr, (u_char *)&zRunner->entPhysicalIndex, sizeof(zRunner->entPhysicalIndex));
    vptr = vptr->next_variable;

    return put_index_data;
}

/** handles requests for the entPhysicalTable table, if anything else needs to be done */
int
entPhysicalTable_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;
    entPhysicalEntry_t *zPhysicalEntry;
    static char *zentPhySerialNum, *zentPhyAlias, *zentPhyAssetId;
    static char *zOldentPhySerialNum, *zOldentPhyAlias, *zOldentPhyAssetId;
    
    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 entPhysicalTable table in question */
        zPhysicalEntry = (entPhysicalEntry_t *) netsnmp_extract_iterator_context(request);
        if ((zPhysicalEntry==NULL)||(zPhysicalEntry->entPhysicalIndex <= 0) ) {
            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_ENTPHYSICALDESCR:
                snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) zPhysicalEntry->entPhysicalDescr, strlen(zPhysicalEntry->entPhysicalDescr));
                break;

            case COLUMN_ENTPHYSICALVENDORTYPE:
                snmp_set_var_typed_value(var, ASN_OBJECT_ID, (u_char *) zPhysicalEntry->entPhysicalVendorType, zPhysicalEntry->entPhysicalVendorTypeSize);
                break;

            case COLUMN_ENTPHYSICALCONTAINEDIN:
                snmp_set_var_typed_value(var, ASN_INTEGER, (u_char *)&zPhysicalEntry->entPhysicalContainedIn, sizeof(zPhysicalEntry->entPhysicalContainedIn));
                break;

            case COLUMN_ENTPHYSICALCLASS:
                snmp_set_var_typed_value(var, ASN_INTEGER, (u_char *)&zPhysicalEntry->entPhysicalClass, sizeof(zPhysicalEntry->entPhysicalClass));
                break;

            case COLUMN_ENTPHYSICALPARENTRELPOS:
                snmp_set_var_typed_value(var, ASN_INTEGER, (u_char *)&zPhysicalEntry->entPhysicalParentRelPos, sizeof(zPhysicalEntry->entPhysicalParentRelPos));
                break;

            case COLUMN_ENTPHYSICALNAME:
                snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) zPhysicalEntry->entPhysicalName, strlen(zPhysicalEntry->entPhysicalName));
                break;

            case COLUMN_ENTPHYSICALHARDWAREREV:
                snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) zPhysicalEntry->entPhysicalHardwareRev, strlen(zPhysicalEntry->entPhysicalHardwareRev));
                break;

            case COLUMN_ENTPHYSICALFIRMWAREREV:
                snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) zPhysicalEntry->entPhysicalFirmwareRev, strlen(zPhysicalEntry->entPhysicalFirmwareRev));
                break;

            case COLUMN_ENTPHYSICALSOFTWAREREV:
                snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) zPhysicalEntry->entPhysicalSoftwareRev, strlen(zPhysicalEntry->entPhysicalSoftwareRev));
                break;

            case COLUMN_ENTPHYSICALSERIALNUM:
                snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) zPhysicalEntry->entPhysicalSerialNum, strlen(zPhysicalEntry->entPhysicalSerialNum));
                break;

            case COLUMN_ENTPHYSICALMFGNAME:
                snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) zPhysicalEntry->entPhysicalMfgName, strlen(zPhysicalEntry->entPhysicalMfgName));
                break;

            case COLUMN_ENTPHYSICALMODELNAME:
                snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) zPhysicalEntry->entPhysicalModelName, strlen(zPhysicalEntry->entPhysicalModelName));
                break;

            case COLUMN_ENTPHYSICALALIAS:
                snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) zPhysicalEntry->entPhysicalAlias, strlen(zPhysicalEntry->entPhysicalAlias));
                break;

            case COLUMN_ENTPHYSICALASSETID:
                snmp_set_var_typed_value(var, ASN_OCTET_STR, (u_char *) zPhysicalEntry->entPhysicalAssetID, strlen(zPhysicalEntry->entPhysicalAssetID));
                break;

            case COLUMN_ENTPHYSICALISFRU:
                snmp_set_var_typed_value(var, ASN_INTEGER, (u_char *) &zPhysicalEntry->entPhysicalIsFRU, sizeof(zPhysicalEntry->entPhysicalIsFRU));
                break;

            default:
                /* We shouldn't get here */
                snmp_log(LOG_ERR, "problem encountered in entPhysicalTable_handler: unknown column\n");
            }
            break;

        /* Fix for 4915824: We have rewritten much of the section here, and */
        /*                  we have also improved the way the boundary */
        /*                  checking and return code is handled */
        case MODE_SET_RESERVE1:
            switch(table_info->colnum) {
            case COLUMN_ENTPHYSICALSERIALNUM:
                if (var->type != ASN_OCTET_STR) {
                    netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
                    return SNMP_ERR_WRONGTYPE;
                }
                /* Fix for 4911817: Check for size and boundary limits */
                else if ((const char*)var->val.string != NULL) {
                    if (var->val_len > 32) {
                        netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGLENGTH);
                        return SNMP_ERR_WRONGLENGTH;
                    }
                }
                /* End of Fix for 4911817 */
                break;
            case COLUMN_ENTPHYSICALALIAS:
                if (var->type != ASN_OCTET_STR) {
                    netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
                    return SNMP_ERR_WRONGTYPE;
                }
                /* Fix for 4911817: Check for size and boundary limits */
                else if ((const char*)var->val.string != NULL) {
                    if (var->val_len > 32) {
                        netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGLENGTH);
                        return SNMP_ERR_WRONGLENGTH;
                    }
                }
                /* End of Fix for 4911817 */
                break;
            case COLUMN_ENTPHYSICALASSETID:
                if (var->type != ASN_OCTET_STR) {
                    netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE);
                    return SNMP_ERR_WRONGTYPE;
                }
                /* Fix for 4911817: Check for size and boundary limits */
                else if ((const char*)var->val.string != NULL) {
                    if (var->val_len > 32) {
                        netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGLENGTH);
                        return SNMP_ERR_WRONGLENGTH;
                    }
                }
                /* End of Fix for 4911817 */
                break;
            default:
                netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE);
            }
            break;
        case MODE_SET_RESERVE2:
            switch(table_info->colnum) {
            case COLUMN_ENTPHYSICALSERIALNUM:
                zOldentPhySerialNum = strdup(zPhysicalEntry->entPhysicalSerialNum);
                if (zOldentPhySerialNum == NULL)
                    netsnmp_set_request_error(reqinfo, request, SNMP_ERR_RESOURCEUNAVAILABLE);
                netsnmp_request_add_list_data (request, 
                                               netsnmp_create_data_list(ENTPHYSICALSERIALNUM_CACHE,
                                                                        zOldentPhySerialNum,
                                                                        free));
                break;
            case COLUMN_ENTPHYSICALALIAS:
                zOldentPhyAlias = strdup(zPhysicalEntry->entPhysicalAlias);
                if (zOldentPhyAlias == NULL)
                    netsnmp_set_request_error(reqinfo, request, SNMP_ERR_RESOURCEUNAVAILABLE);
                netsnmp_request_add_list_data (request,
                                               netsnmp_create_data_list(ENTPHYSICALALIAS_CACHE,
                                                                        zOldentPhyAlias,
                                                                        free));
                break;
            case COLUMN_ENTPHYSICALASSETID:
                zOldentPhyAssetId = strdup(zPhysicalEntry->entPhysicalAssetID);
                if (zOldentPhyAssetId == NULL)
                    netsnmp_set_request_error(reqinfo, request, SNMP_ERR_RESOURCEUNAVAILABLE);
                netsnmp_request_add_list_data (request,
                                               netsnmp_create_data_list(ENTPHYSICALASSETID_CACHE,
                                                                        zOldentPhyAssetId,
                                                                        free));
                break;
            default:
                netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE);
            }
            break;
        case MODE_SET_FREE:
            switch(table_info->colnum) {
            /* We do not need to free anything, because the zOld* will be */
            /* freed as part of the request */
            case COLUMN_ENTPHYSICALSERIALNUM:
                break;
            case COLUMN_ENTPHYSICALALIAS:
                break;
            case COLUMN_ENTPHYSICALASSETID:
                break;

            default:
                netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE);
            }
            break;
        case MODE_SET_ACTION:
            switch(table_info->colnum) {
            case COLUMN_ENTPHYSICALSERIALNUM:
                /* As part of the 4915824 fix, we have improved */
                /* the way we are doing the string copying. Using */
                /* var->val_len will guarantee that we are not copying junk, */
                /* since var->val.string is not NULL terminated*/
                free (zPhysicalEntry->entPhysicalSerialNum);
                zPhysicalEntry->entPhysicalSerialNum = (char *)malloc(sizeof(char) * (var->val_len + 1));
                if (zPhysicalEntry->entPhysicalSerialNum == NULL)
                    netsnmp_set_request_error(reqinfo, request, SNMP_ERR_RESOURCEUNAVAILABLE);
                else {
                    strncpy(zPhysicalEntry->entPhysicalSerialNum, (const char *)var->val.string, var->val_len);
                    zPhysicalEntry->entPhysicalSerialNum[var->val_len] = 0;
                }
                break;		
            case COLUMN_ENTPHYSICALALIAS:
                free (zPhysicalEntry->entPhysicalAlias);
                zPhysicalEntry->entPhysicalAlias = (char *)malloc(sizeof(char) * (var->val_len + 1));
                if (zPhysicalEntry->entPhysicalAlias == NULL)
                    netsnmp_set_request_error(reqinfo, request, SNMP_ERR_RESOURCEUNAVAILABLE);
                else {
                    strncpy(zPhysicalEntry->entPhysicalAlias, (const char *)var->val.string, var->val_len);
                    zPhysicalEntry->entPhysicalAlias[var->val_len] = 0;
                }
                break;
            case COLUMN_ENTPHYSICALASSETID:
                free (zPhysicalEntry->entPhysicalAssetID);
                zPhysicalEntry->entPhysicalAssetID = (char *)malloc(sizeof(char) * (var->val_len + 1));
                if (zPhysicalEntry->entPhysicalAssetID == NULL)
                    netsnmp_set_request_error(reqinfo, request, SNMP_ERR_RESOURCEUNAVAILABLE);
                else {
                    strncpy(zPhysicalEntry->entPhysicalAssetID, (const char *)var->val.string, var->val_len);
                    zPhysicalEntry->entPhysicalAssetID[var->val_len] = 0;
                }
                break;
            default:
                netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE);
            }
            break;
        case MODE_SET_COMMIT:
            switch(table_info->colnum) {
            case COLUMN_ENTPHYSICALSERIALNUM:
                /* Fix for 4910657: There is no need to free the data set, */
                /*                  as it is handled by the agent */
                /*                  infrastructure.  However, Purify should */
                /*                  be run to make sure that there is no */
                /*                  memory leak */
                /* End of Fix 4910657 */
                break;
            case COLUMN_ENTPHYSICALALIAS:
                break;
            case COLUMN_ENTPHYSICALASSETID:
                break;
            default:
                netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE);
            }
            break;
        case MODE_SET_UNDO:
            switch(table_info->colnum) {
            case COLUMN_ENTPHYSICALSERIALNUM:
                free(zPhysicalEntry->entPhysicalSerialNum);
                zentPhySerialNum = strdup((char *)netsnmp_request_get_list_data(request, ENTPHYSICALSERIALNUM_CACHE));
                zPhysicalEntry->entPhysicalSerialNum = zentPhySerialNum;
                break;
            case COLUMN_ENTPHYSICALALIAS:
                free(zPhysicalEntry->entPhysicalAlias);
                zentPhyAlias = strdup((char *)netsnmp_request_get_list_data(request, ENTPHYSICALALIAS_CACHE));
                zPhysicalEntry->entPhysicalAlias = zentPhyAlias;
                break;
            case COLUMN_ENTPHYSICALASSETID:
                free(zPhysicalEntry->entPhysicalAssetID);
                zentPhyAssetId = strdup((char *)netsnmp_request_get_list_data(request, ENTPHYSICALASSETID_CACHE));
                zPhysicalEntry->entPhysicalAssetID = zentPhyAssetId;
                break;
            default:
                netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE);
            }
            break;
        /* End of Fix for 4915824 */           
        default:
            snmp_log(LOG_ERR, "problem encountered in entPhysicalTable_handler: unsupported mode\n");
        }
    }
    return SNMP_ERR_NOERROR;
}



/*
 * Allocates a physical entry. if physidx >0 attempts to reuse an
 * existing entry
 */
int
allocPhysicalEntry(int physidx, entPhysicalEntry_t * newPhysEntry)
{
    entPhysicalEntry_t *physent;
    int index;
    /* Fix for 4927388 */
    oid zerooid[] = { 0, 0 };
    /* End of Fix for 4927388 */
    /* Fix for 4927412 */
    char emptystring[1] = "";
    /* End of Fix for 4927412 */

    /* Fix for 4927412: according to RFC 2737, entPhysicalDescr has to be */
    /*                  unique - NULL should be rejected. */
    /*                  entPhysicalVendorType will default to { 0, 0 } for */
    /*                  NULL.  For the rest, we will force NULL = "" */
    /*                  (zero-length string) */
    if (newPhysEntry->entPhysicalDescr == NULL)
        return -1;
    /* Fix for 4927388 */
    if (newPhysEntry->entPhysicalVendorType == NULL) {
        newPhysEntry->entPhysicalVendorType = zerooid;
        newPhysEntry->entPhysicalVendorTypeSize = sizeof(zerooid);
    }
    /* End of Fix for 4927388 */
    if (newPhysEntry->entPhysicalName == NULL)
        newPhysEntry->entPhysicalName = emptystring;
    if (newPhysEntry->entPhysicalHardwareRev == NULL)
        newPhysEntry->entPhysicalHardwareRev = emptystring;
    if (newPhysEntry->entPhysicalFirmwareRev == NULL)
        newPhysEntry->entPhysicalFirmwareRev = emptystring;
    if (newPhysEntry->entPhysicalSoftwareRev == NULL)
        newPhysEntry->entPhysicalSoftwareRev = emptystring;
    if (newPhysEntry->entPhysicalSerialNum == NULL)
        newPhysEntry->entPhysicalSerialNum = emptystring;
    if (newPhysEntry->entPhysicalMfgName == NULL)
        newPhysEntry->entPhysicalMfgName = emptystring;
    if (newPhysEntry->entPhysicalModelName == NULL)
        newPhysEntry->entPhysicalModelName = emptystring;
    if (newPhysEntry->entPhysicalAlias == NULL)
        newPhysEntry->entPhysicalAlias = emptystring;
    if (newPhysEntry->entPhysicalAssetID == NULL)
        newPhysEntry->entPhysicalAssetID = emptystring;
    /* End of Fix for 4927412 */

    /* Fix for 4921309 */
    if (physidx < 0 || physidx > MAX_ENTITY_INDEX)
        return NULL;
    /* End of Fix for 4921309 */

    /* Fix for 4884681: Check entPhysicalClass and make sure that it
       is between 1 and 11 - read the Entity MIB RFC
       for details */
    if (newPhysEntry->entPhysicalClass < ENTPHYSICAL_CLASS_OTHER || newPhysEntry->entPhysicalClass > ENTPHYSICAL_CLASS_STACK) {
        return (-1);
    }
    /* End of Fix for 4884681 */

    /* Fix for 4884702: */
    /* Make sure when entPhysicalContainedIn is 0 that */
    /* entPhysicalParentRelPos is -1.  Also check for boundary */
    if (newPhysEntry->entPhysicalParentRelPos < -1 || newPhysEntry->entPhysicalParentRelPos > MAX_ENTITY_INDEX)
        return -1;
    if (newPhysEntry->entPhysicalContainedIn == 0 && newPhysEntry->entPhysicalParentRelPos != -1)
        return -1;
    /* End of Fix for 4884702 */

    /* Fix for 4929711 */
    /* Make sure when entPhysicalRelPos is -1 that */
    /* entPhysicalParentContainedIn is 0.  */
    if (newPhysEntry->entPhysicalParentRelPos == -1
        && newPhysEntry->entPhysicalContainedIn != 0)
        return -1;
    /* End of Fix for 4929711 */

    /* Fix for 4893121: */
    /* check for invalid entries: negative number or greater than allowed */
    /* range, stale, or non-existing entry. */
    if ((newPhysEntry->entPhysicalContainedIn < 0 || newPhysEntry->entPhysicalContainedIn > MAX_ENTITY_INDEX)) {
        /* reject because it is beyond the valid physical index range */
        return (-1);
    } else if (newPhysEntry->entPhysicalContainedIn != 0 && getPhysicalTableEntry(newPhysEntry->entPhysicalContainedIn) == NULL) {
        /* If the intended parent (newPhysEntry->entPhysicalContainedIn) is */
        /* a possible index (0 - 2^31-1), but it is stale or does not exist, */
        /* then we will reject the entry */
        return (-1);
    }

    /* End of Fix for 4893121 */

    /* Fix for 4911817: Check for size and boundary limits */
    /* entPhysicalDescr 0..255 */
    if (strlen(newPhysEntry->entPhysicalDescr) > 255)
        return -1;

    /* entPhysicalName 0..255 */
    if (strlen(newPhysEntry->entPhysicalName) > 255)
        return -1;

    /* entPhysicalHardwareRev 0..255 */
    if (strlen(newPhysEntry->entPhysicalHardwareRev) > 255)
        return -1;

    /* entPhysicalFirmwareRev 0..255 */
    if (strlen(newPhysEntry->entPhysicalFirmwareRev) > 255)
        return -1;

    /* entPhysicalSoftwareRev 0..255 */
    if (strlen(newPhysEntry->entPhysicalSoftwareRev) > 255)
        return -1;

    /* entPhysicalSerialNum 0..32 */
    if (strlen(newPhysEntry->entPhysicalSerialNum) > 32)
        return -1;

    /* entPhysicalMfgName 0..255 */
    if (strlen(newPhysEntry->entPhysicalMfgName) > 255)
        return -1;

    /* entPhysicalModelName 0..255 */
    if (strlen(newPhysEntry->entPhysicalModelName) > 255)
        return -1;

    /* entPhysicalAlias 0..32 */
    if (strlen(newPhysEntry->entPhysicalAlias) > 32)
        return -1;

    /* entPhysicalAssetID 0..32 */
    if (strlen(newPhysEntry->entPhysicalAssetID) > 32)
        return -1;

    /* entPhysicalIsFRU only MIB_TRUE and MIB_FALSE */
    if (newPhysEntry->entPhysicalIsFRU < MIB_TRUE || newPhysEntry->entPhysicalIsFRU > MIB_FALSE)
        return (-1);
    /* End of Fix for 4911817 */

    physent = malloc(sizeof (entPhysicalEntry_t));
    if (physent == NULL) {
        /* sent a message to log file */
        return (-1);
    }

    physent->entPhysicalIndex = physidx;

    physent->entPhysicalDescr = strdup(newPhysEntry->entPhysicalDescr);
    /* Fix for 4884526 */
    if (physent->entPhysicalDescr == NULL) {
        free(physent);
        return (-1);
    }
    /* End of Fix for 4884526 */

    physent->entPhysicalVendorType =
        malloc(newPhysEntry->entPhysicalVendorTypeSize);

    /* Fix for 4884526 */
    if (physent->entPhysicalVendorType == NULL) {
        free(physent->entPhysicalDescr);
        free(physent);
        return (-1);
    }
    /* End of Fix for 4884526 */

    memcpy(physent->entPhysicalVendorType,
           newPhysEntry->entPhysicalVendorType,
           newPhysEntry->entPhysicalVendorTypeSize);
    physent->entPhysicalVendorTypeSize =
        newPhysEntry->entPhysicalVendorTypeSize;

    physent->entPhysicalContainedIn = newPhysEntry->entPhysicalContainedIn;
    physent->entPhysicalClass = newPhysEntry->entPhysicalClass;
    physent->entPhysicalParentRelPos =
        newPhysEntry->entPhysicalParentRelPos;
    physent->entPhysicalName = strdup(newPhysEntry->entPhysicalName);
    /* Fix for 4884526 */
    if (physent->entPhysicalName == NULL) {
        free(physent->entPhysicalVendorType);
        free(physent->entPhysicalDescr);
        free(physent);
        return (-1);
    }
    /* End of Fix for 4884526 */
    physent->entPhysicalHardwareRev = 
        strdup(newPhysEntry->entPhysicalHardwareRev);
    /* Fix for 4884526 */
    if (physent->entPhysicalHardwareRev == NULL) {
        free(physent->entPhysicalName);
        free(physent->entPhysicalVendorType);
        free(physent->entPhysicalDescr);
        free(physent);
        return (-1);
    }
    /* End of Fix for 4884526 */
    physent->entPhysicalFirmwareRev =
        strdup(newPhysEntry->entPhysicalFirmwareRev);
    /* Fix for 4884526 */
    if (physent->entPhysicalFirmwareRev == NULL) {
        free(physent->entPhysicalHardwareRev);
        free(physent->entPhysicalName);
        free(physent->entPhysicalVendorType);
        free(physent->entPhysicalDescr);
        free(physent);
        return (-1);
    }
    /* End of Fix for 4884526 */
    physent->entPhysicalSoftwareRev =
        strdup(newPhysEntry->entPhysicalSoftwareRev);
    /* Fix for 4884526 */
    if (physent->entPhysicalSoftwareRev == NULL) {
        free(physent->entPhysicalFirmwareRev);
        free(physent->entPhysicalHardwareRev);
        free(physent->entPhysicalName);
        free(physent->entPhysicalVendorType);
        free(physent->entPhysicalDescr);
        free(physent);
        return (-1);
    }
    /* End of Fix for 4884526 */
    physent->entPhysicalSerialNum =
        strdup(newPhysEntry->entPhysicalSerialNum);
    /* Fix for 4884526 */
    if (physent->entPhysicalSerialNum == NULL) {
        free(physent->entPhysicalSoftwareRev);
        free(physent->entPhysicalFirmwareRev);
        free(physent->entPhysicalHardwareRev);
        free(physent->entPhysicalName);
        free(physent->entPhysicalVendorType);
        free(physent->entPhysicalDescr);
        free(physent);
        return (-1);
    }
    /* End of Fix for 4884526 */
    physent->entPhysicalMfgName =
        strdup(newPhysEntry->entPhysicalMfgName);
    /* Fix for 4884526 */
    if (physent->entPhysicalMfgName == NULL) {
        free(physent->entPhysicalSerialNum);
        free(physent->entPhysicalSoftwareRev);
        free(physent->entPhysicalFirmwareRev);
        free(physent->entPhysicalHardwareRev);
        free(physent->entPhysicalName);
        free(physent->entPhysicalVendorType);
        free(physent->entPhysicalDescr);
        free(physent);
        return (-1);
    }
    /* End of Fix for 4884526 */
    physent->entPhysicalModelName =
        strdup(newPhysEntry->entPhysicalModelName);
    /* Fix for 4884526 */
    if (physent->entPhysicalModelName == NULL) {
        free(physent->entPhysicalMfgName);
        free(physent->entPhysicalSerialNum);
        free(physent->entPhysicalSoftwareRev);
        free(physent->entPhysicalFirmwareRev);
        free(physent->entPhysicalHardwareRev);
        free(physent->entPhysicalName);
        free(physent->entPhysicalVendorType);
        free(physent->entPhysicalDescr);
        free(physent);
        return (-1);
    }
    /* End of Fix for 4884526 */
    physent->entPhysicalAlias =
        strdup(newPhysEntry->entPhysicalAlias);
    /* Fix for 4884526 */
    if (physent->entPhysicalAlias == NULL) {
        free(physent->entPhysicalModelName);
        free(physent->entPhysicalMfgName);
        free(physent->entPhysicalSerialNum);
        free(physent->entPhysicalSoftwareRev);
        free(physent->entPhysicalFirmwareRev);
        free(physent->entPhysicalHardwareRev);
        free(physent->entPhysicalName);
        free(physent->entPhysicalVendorType);
        free(physent->entPhysicalDescr);
        free(physent);
        return (-1);
    }
    /* End of Fix for 4884526 */
    physent->entPhysicalAssetID =
        strdup(newPhysEntry->entPhysicalAssetID);
    /* Fix for 4884526 */
    if (physent->entPhysicalAssetID == NULL) /* Memory allocation failed */
    {
        free(physent->entPhysicalAlias);
        free(physent->entPhysicalModelName);
        free(physent->entPhysicalMfgName);
        free(physent->entPhysicalSerialNum);
        free(physent->entPhysicalSoftwareRev);
        free(physent->entPhysicalFirmwareRev);
        free(physent->entPhysicalHardwareRev);
        free(physent->entPhysicalName);
        free(physent->entPhysicalVendorType);
        free(physent->entPhysicalDescr);
        free(physent);
        return (-1);
    }
    /* End of Fix for 4884526 */

    physent->entPhysicalIsFRU = newPhysEntry->entPhysicalIsFRU;

    index = AddToPhysicalTable(physent);
    return (index);
}

static int
AddToPhysicalTable(entPhysicalEntry_t * xnewPhysicalEntry)
{
    entPhysicalEntry_t *zRunner, *temp;
    int placeFound; /* Fix for 4921309 */
    int zIndex;
    zRunner = gPhysicalTableHead;

    if (xnewPhysicalEntry == NULL) return (-1);
    xnewPhysicalEntry->pNextEntry = NULL;

    /* Fix for 4921309 */
    /* If index > 0, attempt to insert in appropriate place. */
    if (xnewPhysicalEntry->entPhysicalIndex > 0) {
	placeFound = 0;
	temp = zRunner;
	while (zRunner != NULL) {
	    if (xnewPhysicalEntry->entPhysicalIndex >
		abs(zRunner->entPhysicalIndex)) {
		temp = zRunner;
		zRunner = zRunner->pNextEntry;
	    } else {
		break;
	    }
	}

	/* If the indexes don't match, we can use the specified index */
	if (temp == NULL) {
            /* List is empty, make this the first/last entry */
	    gPhysicalTableHead = xnewPhysicalEntry;
            gPhysicalTableTail = xnewPhysicalEntry;
	    placeFound = 1;
	} else if (zRunner == NULL) {
            /* Index > last value, make this the last entry */
	    temp->pNextEntry = xnewPhysicalEntry;
            gPhysicalTableTail = xnewPhysicalEntry;
	    placeFound = 1;
	} else if (xnewPhysicalEntry->entPhysicalIndex != 
		   abs(zRunner->entPhysicalIndex)) {
            /* Index < zRunner, insert entry before it */
	    xnewPhysicalEntry->pNextEntry = zRunner;
            if (zRunner == gPhysicalTableHead) {
                /* Index fits before list head, insert entry */
                gPhysicalTableHead = xnewPhysicalEntry;
            } else {
                /* Index fits between two entries, insert entry */
	        temp->pNextEntry = xnewPhysicalEntry;
            }
	    placeFound = 1;
	}

	if (placeFound) {
	    gPhysicalTableSize++;
	    configChanged();
	    return (xnewPhysicalEntry->entPhysicalIndex);
	} else {
            /* Re-initialize for code that follows */
            zRunner = gPhysicalTableHead;
	}
    }

    /* Either index was zero or specified index is already taken */
    /* End of Fix for 4921309 */

    if (gPhysicalTableSize > LARGE_TABLE) {
        gPhysicalTableTail->pNextEntry = xnewPhysicalEntry;
        zIndex = abs(gPhysicalTableTail->entPhysicalIndex) + 1;
        xnewPhysicalEntry->entPhysicalIndex = zIndex;
        gPhysicalTableTail = xnewPhysicalEntry;
        gPhysicalTableSize++;
        configChanged();
        return (zIndex);
    }

    if (gPhysicalTableHead) { /* A slightly slower way to add into the list */
        while (zRunner->pNextEntry != NULL) {
            if ((abs(zRunner->pNextEntry->entPhysicalIndex)
                 - abs(zRunner->entPhysicalIndex)) > 1) {
                temp = zRunner->pNextEntry;
                zRunner->pNextEntry = xnewPhysicalEntry;
                zIndex = abs(zRunner->entPhysicalIndex) + 1;
                xnewPhysicalEntry->entPhysicalIndex = zIndex;
                xnewPhysicalEntry->pNextEntry = temp;
                gPhysicalTableSize++;
                configChanged();
                return (zIndex);
            }
            zRunner = zRunner->pNextEntry;
        }
        zIndex = abs(zRunner->entPhysicalIndex) + 1;
        xnewPhysicalEntry->entPhysicalIndex = zIndex;
        zRunner->pNextEntry = xnewPhysicalEntry;
    }  else {
        zIndex = xnewPhysicalEntry->entPhysicalIndex = 1;
        gPhysicalTableHead = xnewPhysicalEntry;
    }
    gPhysicalTableTail = xnewPhysicalEntry;
    gPhysicalTableSize++;
    configChanged();
    return (zIndex);
}

entPhysicalEntry_t*
getPhysicalTableEntry(int xPhysicalIndex)
{
    entPhysicalEntry_t *zRunner;
    int zPhysicalIndex;

    /* Fix for 4888088 */
    if (xPhysicalIndex <= 0 || xPhysicalIndex > MAX_ENTITY_INDEX)
        return NULL;
    /* End of Fix for 4888088 */

    zRunner = gPhysicalTableHead;
    while (zRunner) {
        zPhysicalIndex = zRunner->entPhysicalIndex;
        if (zPhysicalIndex > 0) {
            if (zPhysicalIndex == xPhysicalIndex)
                return zRunner;
        }
        if (zPhysicalIndex == -(xPhysicalIndex)) {
            return NULL; /* The stale entry exist, we can stop the search*/
        }
        zRunner = zRunner->pNextEntry;
    }
    return NULL;
}

entPhysicalEntry_t*
getPhysicalTableStaleEntry(int xPhysicalIndex)
{
    entPhysicalEntry_t *zRunner;
    int zPhysicalIndex;

    /* Fix for 4888088 */
    if (xPhysicalIndex <= 0 || xPhysicalIndex > MAX_ENTITY_INDEX)
        return NULL;
    /* End of Fix for 4888088 */

    zRunner = gPhysicalTableHead;
    while (zRunner) {
        zPhysicalIndex = zRunner->entPhysicalIndex;
        if (zPhysicalIndex < 0) {
            if (zPhysicalIndex == -(xPhysicalIndex))
                return zRunner;
        }
        if (zPhysicalIndex == xPhysicalIndex) {
            return NULL; /* The live entry exist, we can stop the search*/
        }
        zRunner = zRunner->pNextEntry;
    }
    return NULL;
}


void populate_entPhysicalEntry(entPhysicalEntry_t *phyStatic,
                               char *entPhysicalDescr,
                               oid *entPhysicalVendorType,
                               int entPhysicalVendorTypeSize,
                               int entPhysicalContainedIn,
                               int entPhysicalClass,
                               int entPhysicalParentRelPos,
                               char *entPhysicalName,
                               char *entPhysicalHardwareRev,
                               char *entPhysicalFirmwareRev,
                               char *entPhysicalSoftwareRev,
                               char *entPhysicalSerialNum,
                               char *entPhysicalMfgName,
                               char *entPhysicalModelName,
                               char *entPhysicalAlias,
                               char *entPhysicalAssetID,
                               int entPhysicalIsFRU)
{
    phyStatic->entPhysicalDescr = entPhysicalDescr;
    phyStatic->entPhysicalVendorType = entPhysicalVendorType;
    phyStatic->entPhysicalVendorTypeSize = entPhysicalVendorTypeSize;
    phyStatic->entPhysicalContainedIn = entPhysicalContainedIn;
    phyStatic->entPhysicalClass = entPhysicalClass;
    phyStatic->entPhysicalParentRelPos = entPhysicalParentRelPos;
    phyStatic->entPhysicalName = entPhysicalName;
    phyStatic->entPhysicalHardwareRev = entPhysicalHardwareRev;
    phyStatic->entPhysicalFirmwareRev = entPhysicalFirmwareRev;
    phyStatic->entPhysicalSoftwareRev = entPhysicalSoftwareRev;
    phyStatic->entPhysicalSerialNum = entPhysicalSerialNum;
    phyStatic->entPhysicalMfgName = entPhysicalMfgName;
    phyStatic->entPhysicalModelName = entPhysicalModelName;
    phyStatic->entPhysicalAlias = entPhysicalAlias;
    phyStatic->entPhysicalAssetID = entPhysicalAssetID;
    phyStatic->entPhysicalIsFRU = entPhysicalIsFRU;
}

int
deletePhysicalTableEntry(int xPhysicalIndex)
{
    entPhysicalEntry_t *zRunner, *temp, *prevEntry;
    int zPhysicalIndex;

    /* Fix for 4888088 */
    if (xPhysicalIndex <= 0 || xPhysicalIndex > MAX_ENTITY_INDEX)
        return (-1);
    /* End of Fix for 4888088 */

    zRunner = gPhysicalTableHead;
    prevEntry = NULL;
    while (zRunner) {
        zPhysicalIndex = zRunner->entPhysicalIndex;
        if (zPhysicalIndex > 0) {
            if (zPhysicalIndex == xPhysicalIndex) {
                /* Fix for 4918876: We need to delete the related entries */
                /* first */
/*
   Delete all instances of this physical index in all other
   tables to maintain table integrity. Should we roll-back if a
   deletion fails, perhaps not ?
*/
                deleteAliasMappingPhysicalIndex(xPhysicalIndex); /*Alias mapping*/
                deleteLPMappingPhysicalIndex(xPhysicalIndex); /* LPTable */
                /* Fix for 4891869 */
                deletePhysicalContainsParentIndex(xPhysicalIndex);
                deletePhysicalContainsChildIndex(xPhysicalIndex);
                /* End of Fix for 4891869 */
                /* End of Fix for 4918876 */

                temp = zRunner->pNextEntry;
                zRunner->pNextEntry = NULL;
                if (prevEntry)
                    prevEntry->pNextEntry = temp;
                else
                    gPhysicalTableHead =  temp;
                FreePhysicalEntry(zRunner);
                gPhysicalTableSize--;

                configChanged();
                return (0);
            }
        }
        if (zPhysicalIndex == -(xPhysicalIndex)) {
            return (-2); /* The stale entry exist, we can stop the search*/
        }
        prevEntry = zRunner;
        zRunner = zRunner->pNextEntry;
    }
    return (-1);
}

static int
FreePhysicalEntry(entPhysicalEntry_t *xEntry)
{
    if (xEntry == NULL) return (-1);
    free(xEntry->entPhysicalDescr);
    free(xEntry->entPhysicalVendorType);
    free(xEntry->entPhysicalName);
    free(xEntry->entPhysicalHardwareRev);
    free(xEntry->entPhysicalFirmwareRev);
    free(xEntry->entPhysicalSoftwareRev);
    free(xEntry->entPhysicalSerialNum);
    free(xEntry->entPhysicalMfgName);
    free(xEntry->entPhysicalModelName);
    free(xEntry->entPhysicalAlias);
    free(xEntry->entPhysicalAssetID);
    free(xEntry);
    xEntry = NULL;
    return (1);
}

int
makePhysicalTableEntryStale(int xPhysicalIndex)
{

    entPhysicalEntry_t *zRunner;
    int zPhysicalIndex;

    /* Fix for 4888088 */
    if (xPhysicalIndex <= 0 || xPhysicalIndex > MAX_ENTITY_INDEX)
        return (-1);
    /* End of Fix for 4888088 */

    zRunner = gPhysicalTableHead;

    while (zRunner) {
        zPhysicalIndex = zRunner->entPhysicalIndex;
        if (zPhysicalIndex < 0) {
            if (zPhysicalIndex == -(xPhysicalIndex))
                return (-2); /* Entry is already stale */
        }
        if (zPhysicalIndex == xPhysicalIndex) {
            /* Fix for 4918876: We need to delete the related entries first */
/*
  Delete all instances of this physical index in all other
  tables to maintain table integrity. Should we roll-back if a
  deletion fails, perhaps not ?
*/
            deleteAliasMappingPhysicalIndex(xPhysicalIndex); /*Alias mapping*/
            deleteLPMappingPhysicalIndex(xPhysicalIndex); /* LPTable */
            /* Fix for 4891869 */
            deletePhysicalContainsParentIndex(xPhysicalIndex);
            deletePhysicalContainsChildIndex(xPhysicalIndex);
            /* End of Fix for 4891869 */
            /* End of Fix for 4918876 */

            zRunner->entPhysicalIndex = -zPhysicalIndex;

            configChanged();

            return (0);
        }
        zRunner = zRunner->pNextEntry;
    }
    return (-1);
}

int
makePhysicalTableEntryLive(int xPhysicalIndex)
{
    entPhysicalEntry_t *zRunner;
    int zPhysicalIndex;

    /* Fix for 4888088 */
    if (xPhysicalIndex <= 0 || xPhysicalIndex > MAX_ENTITY_INDEX)
        return (-1);
    /* End of Fix for 4888088 */

    zRunner = gPhysicalTableHead;

    while (zRunner) {
        zPhysicalIndex = zRunner->entPhysicalIndex;
        if (zPhysicalIndex > 0) {
            if (zPhysicalIndex == xPhysicalIndex)
                return (-2); /* Entry is already live */
        }
        if (zPhysicalIndex == -(xPhysicalIndex)) {
            zRunner->entPhysicalIndex = xPhysicalIndex;
            configChanged();
            return (0);
        }
        zRunner = zRunner->pNextEntry;
    }
    return (-1);
}

/* Fix for 4915080 */
/* Given a parent, find all its children based on the relationship defined */
/* in entPhysicalContainedIn.  Needs to free the memory after */
int *getAllChildrenFromPhysicalContainedIn(int parentIdx)
{
    int *child_list, *temp, i;
    entPhysicalEntry_t *zRunner;

    child_list = NULL;
    i = 0;
    /* Fix for 4888088 */
    if (parentIdx <= 0 || parentIdx > MAX_ENTITY_INDEX)
        return NULL;
    /* End of Fix for 4888088 */

    zRunner = gPhysicalTableHead;
    while (zRunner) {
        if (zRunner->entPhysicalContainedIn == parentIdx) {
            if (child_list == NULL) {
                child_list = (int *)malloc(2 * sizeof(int));
                if (child_list == NULL)
                    return NULL;
                child_list[0] = zRunner->entPhysicalIndex;
                child_list[1] = 0;
                i++;
            } else {
                temp = child_list;
                child_list = (int *)realloc(child_list, (i + 2)*sizeof(int));
                if (child_list == NULL) {
                    free(temp);
                    return NULL;
                }
                child_list[i] = zRunner->entPhysicalIndex;
                child_list[i+1] = 0;
            }
        }
        zRunner = zRunner->pNextEntry;
    }
    return child_list;
}
/* End of Fix for 4915080 */
