/*
 * 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 "entAliasMappingTable.h"
#include "entLogicalTable.h"
#include "entPhysicalTable.h"
#include "entLastChangeTime.h"

entAliasMappingTableEntry_t *gAliasMappingTableHead;
int gAliasMappingTableSize;
static logicalAlias *gCurAliasEntry;



/** Initialize the entAliasMappingTable table by defining its contents and how it's structured */
void
initialize_table_entAliasMappingTable(void)
{
    static oid entAliasMappingTable_oid[] = {1,3,6,1,2,1,47,1,3,2};
    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 4910624 - changing HANDLER_CAN_RWRITE to HANDLER_CAN_RONLY */
    my_handler = netsnmp_create_handler_registration("entAliasMappingTable",
                                                     entAliasMappingTable_handler,
                                                     entAliasMappingTable_oid,
                                                     OID_LENGTH(entAliasMappingTable_oid),
                                                     HANDLER_CAN_RONLY);
    /* End of Fix for 4910624 */
            
    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 */
                                     ASN_INTEGER, /* index: entAliasLogicalIndexOrZero */
                                     0);

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

    /* iterator access routines */
    iinfo->get_first_data_point = entAliasMappingTable_get_first_data_point;
    iinfo->get_next_data_point = entAliasMappingTable_get_next_data_point;

    iinfo->table_reginfo = table_info;

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

/** Initializes the entAliasMappingTable module */
void
init_entAliasMappingTable(void)
{

    /* here we initialize all the tables we're planning on supporting */
    initialize_table_entAliasMappingTable();
    gAliasMappingTableSize = 0;
    gAliasMappingTableHead = NULL;
    gCurAliasEntry = NULL;
}

/** returns the first data point within the entAliasMappingTable 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 *
entAliasMappingTable_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;
    entAliasMappingTableEntry_t *zRunner, *zpValidEntry;
    logicalAlias *zlogicalAliases, *zValidAlias; 
    int bFound=0;

    zRunner = gAliasMappingTableHead;
    zpValidEntry = NULL;
    gCurAliasEntry = NULL;
    while (zRunner) {
        if (zRunner->entPhysicalIndex > 0) {
            zlogicalAliases = zRunner->entlogicalAliases;
            while ((zlogicalAliases != NULL) && 
                   (zlogicalAliases->entAliasMapIdSize >= 0)){
                if (zlogicalAliases->entAliasLogicalIndexorZero >= 0) {
                    bFound = 1;
                    break;
                }
                zlogicalAliases++;
            }
            if (bFound) {
                zpValidEntry = zRunner;
                zValidAlias = zlogicalAliases;
                break;
            }
        }
        zRunner = zRunner->pNextEntry;
    }
    if (zRunner == NULL) return NULL;

    *my_loop_context = (void *) zpValidEntry;
    *my_data_context = (void *) zValidAlias;
    gCurAliasEntry = zValidAlias;

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

    return put_index_data;
}

/** functionally the same as entAliasMappingTable_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 *
entAliasMappingTable_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;
    entAliasMappingTableEntry_t *zRunner, *zpValidEntry;
    logicalAlias *zlogicalAliases, *zValidAlias;
    int bFound=0;

    zRunner = (entAliasMappingTableEntry_t *)*my_loop_context;
    zlogicalAliases = (logicalAlias *) *my_data_context;
    zlogicalAliases = gCurAliasEntry;

    if (zlogicalAliases != NULL)
	zlogicalAliases++;

    while (zRunner) {
        if (zRunner->entPhysicalIndex > 0) {
            while ((zlogicalAliases != NULL) &&
                   (zlogicalAliases->entAliasMapIdSize >= 0)){
                if (zlogicalAliases->entAliasLogicalIndexorZero >= 0) {
                    bFound = 1;
                    break;
                }
                zlogicalAliases++;
            }
            if (bFound) {
                zpValidEntry = zRunner;
                zValidAlias = zlogicalAliases;
                break;
            }
        }
        zRunner = zRunner->pNextEntry;
        if (zRunner)
            zlogicalAliases = zRunner->entlogicalAliases;
    }
    if (zRunner == NULL) return NULL;

    *my_loop_context = (void *) zpValidEntry;
    *my_data_context = (void *) zValidAlias;
    gCurAliasEntry = zValidAlias;

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

    return put_index_data;
}

/** handles requests for the entAliasMappingTable table, if anything else needs to be done */
int
entAliasMappingTable_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;
    logicalAlias *zAliasEntry;
    
    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 entAliasMappingTable table in question */
        zAliasEntry = (logicalAlias *) netsnmp_extract_iterator_context(request);
        if (zAliasEntry == 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_ENTALIASMAPPINGIDENTIFIER:
                snmp_set_var_typed_value(var, ASN_OBJECT_ID, (u_char *) zAliasEntry->entAliasMapId, zAliasEntry->entAliasMapIdSize);
                break;

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

        case MODE_SET_RESERVE1:
            /* set handling... */

        default:
            snmp_log(LOG_ERR, "problem encountered in entAliasMappingTable_handler: unsupported mode\n");
        }
    }
    return SNMP_ERR_NOERROR;
}

/* Add an entry into the Alias Mapping Table
   returns 0 for success
   1 for entry already exist
   -1 for failure
   -2 for stale index
*/

int
addAliasMappingTableEntry(int xentPhysicalIndex, int xentLogicalIndex, 
                          oid *xAliasMapId, int xAliasMapIdSize)
{
    entAliasMappingTableEntry_t *zAliasTableEntry, *zRunner, *zlastEntry;
    entPhysicalEntry_t *physentry;
    entLogicalEntry_t *zLogicalEntry;
    logicalAlias *zLogicalAliases;

    /* Fix for 4927412: Rejects NULL xAliasMapId */
    if (xAliasMapId == NULL)
        return -1;
    /* End of Fix for 4927412 */

    /* Fix for 4888088: logical index cannot be smaller than zero, */
    /*                  and physical index cannot be smaller than */
    /*                  or equal to zero.  -2 for stale entries  */
    if (xentPhysicalIndex <= 0 || xentPhysicalIndex > MAX_ENTITY_INDEX || xentLogicalIndex < 0 || xentLogicalIndex > MAX_ENTITY_INDEX)
        return -1;
    physentry = getPhysicalTableStaleEntry(xentPhysicalIndex);
    if (physentry != NULL)
        return -2;

    zLogicalEntry = getLogicalTableStaleEntry(xentLogicalIndex);
    if (zLogicalEntry != NULL)
        return -2;
    /* End of Fix for 4888088 */

    physentry = getPhysicalTableEntry(xentPhysicalIndex);

    if (physentry != NULL) {
	if (physentry->entPhysicalClass != 10) return (-1);
    } else return (-1);

    if (xentLogicalIndex != 0) {
	zLogicalEntry = getLogicalTableEntry(xentLogicalIndex);
	if (zLogicalEntry == NULL) return (-1);
    }
    if (xAliasMapId == NULL) return (-1);

    zlastEntry = NULL;
    zRunner = gAliasMappingTableHead;
    while (zRunner != NULL) {
        if (zRunner->entPhysicalIndex == xentPhysicalIndex) {
            break;
        }
        zlastEntry = zRunner;
        zRunner = zRunner->pNextEntry;
    }
    if (zRunner != NULL ) {/* Found a entry with physical index */
        logicalAlias *p;
        p = zRunner->entlogicalAliases;
        if (p == NULL) {
            zLogicalAliases = (logicalAlias *) malloc(2 * sizeof (logicalAlias));
            if (!zLogicalAliases) return -1;
            zLogicalAliases[0].entAliasLogicalIndexorZero = xentLogicalIndex;
            zLogicalAliases[0].entAliasMapId = malloc(xAliasMapIdSize);
            if (!zLogicalAliases[0].entAliasMapId) return -1;
            memcpy(zLogicalAliases[0].entAliasMapId, xAliasMapId, 
                   xAliasMapIdSize);
            zLogicalAliases[0].entAliasMapIdSize = xAliasMapIdSize;
            zLogicalAliases[1].entAliasLogicalIndexorZero = 0;
            zLogicalAliases[1].entAliasMapId = NULL;
            zLogicalAliases[1].entAliasMapIdSize = -1;
            zRunner->entlogicalAliases = zLogicalAliases;
        } else {/* Add phy index to last entry in the array */
            int i=0;
            while (p != NULL && p->entAliasMapIdSize >= 0) {
                if (p->entAliasLogicalIndexorZero == xentLogicalIndex) return (1);
                if (p->entAliasMapIdSize < 0 ) {
                    p->entAliasLogicalIndexorZero = xentLogicalIndex;
                    p->entAliasMapId = malloc(xAliasMapIdSize);
                    if (!p->entAliasMapId) return -1;
                    memcpy(p->entAliasMapId, xAliasMapId, xAliasMapIdSize);
                    p->entAliasMapIdSize = xAliasMapIdSize;
                }
                p++;
                i++;
            }
            zRunner->entlogicalAliases =
                (logicalAlias *)realloc(zRunner->entlogicalAliases, (i + 2)*sizeof(logicalAlias));
            zRunner->entlogicalAliases[i].entAliasLogicalIndexorZero = 
                xentLogicalIndex;
            zRunner->entlogicalAliases[i].entAliasMapId = 
                malloc(xAliasMapIdSize);
            if (!zRunner->entlogicalAliases[i].entAliasMapId) return -1;
            memcpy(zRunner->entlogicalAliases[i].entAliasMapId, xAliasMapId,
                   xAliasMapIdSize);
            zRunner->entlogicalAliases[i].entAliasMapIdSize = xAliasMapIdSize;
            zRunner->entlogicalAliases[i+1].entAliasLogicalIndexorZero = 0;
            zRunner->entlogicalAliases[i+1].entAliasMapId = NULL;
            zRunner->entlogicalAliases[i+1].entAliasMapIdSize = -1;
        }
	configChanged();
        return (0);
    }

    /* New entry*/
    zAliasTableEntry = (entAliasMappingTableEntry_t *)malloc(sizeof(entAliasMappingTableEntry_t));
    if (!zAliasTableEntry) return -1;
    zAliasTableEntry->entPhysicalIndex = xentPhysicalIndex;
    zLogicalAliases = (logicalAlias *) malloc(2 * sizeof (logicalAlias));
    if (!zLogicalAliases) return -1;
    zLogicalAliases[0].entAliasLogicalIndexorZero = xentLogicalIndex;
    zLogicalAliases[0].entAliasMapId = malloc(xAliasMapIdSize);
    if (!zLogicalAliases[0].entAliasMapId) return -1;
    memcpy(zLogicalAliases[0].entAliasMapId, xAliasMapId,
           xAliasMapIdSize);
    zLogicalAliases[0].entAliasMapIdSize = xAliasMapIdSize;
    zLogicalAliases[1].entAliasLogicalIndexorZero = 0;
    zLogicalAliases[1].entAliasMapId = NULL;
    zLogicalAliases[1].entAliasMapIdSize = -1;
    zAliasTableEntry->entlogicalAliases = zLogicalAliases;
    zAliasTableEntry->pNextEntry = NULL;
    if (gAliasMappingTableHead){
        zlastEntry->pNextEntry = zAliasTableEntry;
    } else {
        gAliasMappingTableHead = zAliasTableEntry;
    }
    gAliasMappingTableSize++;
    configChanged();
    return (0);
}

/* Returns 0 for successful deletion
   -1 for entry not found
   -2 for stale entry
*/
int
deleteAliasMappingTableEntry(int xentPhysicalIndex, int xentLogicalIndex)
{
    entAliasMappingTableEntry_t *zRunner;
    logicalAlias *zLogicalAliases;
    int zPhyIndx;
    entPhysicalEntry_t *zPhysicalEntry;
    entLogicalEntry_t *zLogicalEntry;

    /* Fix for 4888088: logical index cannot be smaller than zero, */
    /*                  and physical index cannot be smaller than */
    /*                  or equal to zero.  -2 for stale entries */
    if (xentPhysicalIndex <= 0 || xentPhysicalIndex > MAX_ENTITY_INDEX || xentLogicalIndex < 0 || xentLogicalIndex > MAX_ENTITY_INDEX)
        return -1;
    zPhysicalEntry = getPhysicalTableStaleEntry(xentPhysicalIndex);
    if (zPhysicalEntry != NULL)
        return -2;

    zLogicalEntry = getLogicalTableStaleEntry(xentLogicalIndex);
    if (zLogicalEntry != NULL)
        return -2;
    /* End of Fix for 4888088 */

    zRunner = gAliasMappingTableHead;

    while (zRunner != NULL) {
        zPhyIndx = zRunner->entPhysicalIndex;

        if (zPhyIndx > 0) {
            if (zPhyIndx == xentPhysicalIndex) {
                zLogicalAliases = zRunner->entlogicalAliases;
                while (zLogicalAliases != NULL 
                       && zLogicalAliases->entAliasMapIdSize >= 0) {
                    int zLogIndx = zLogicalAliases->entAliasLogicalIndexorZero;
                    if (zLogIndx >=0 ) {
                        if (zLogIndx == xentLogicalIndex) {
                            zLogicalAliases->entAliasLogicalIndexorZero = -1;
                            free(zLogicalAliases->entAliasMapId);
                            zLogicalAliases->entAliasMapId = NULL;
                            zLogicalAliases->entAliasMapIdSize = 0;
                            configChanged();
                            return (0);
                        }
                    } 
                    zLogicalAliases++;
                }
                return (-1);  /* Entry not found */
            }
        } 
        zRunner = zRunner->pNextEntry;
    }
    return (-1);
}

static int
FreeAliasMappingTableEntry(entAliasMappingTableEntry_t *xEntry)
{
    logicalAlias *zAliases;
    int nEntries=0;
    if (xEntry == NULL) return (-1);
    zAliases = xEntry->entlogicalAliases;
    while (zAliases != NULL && zAliases->entAliasMapIdSize >= 0) {
        /* Fix for 4906853: we only need to free it (and count) if */
        /* entAliasMapId != NULL.  A better fix is to use a link list */
        /* instead of an array for this structure */
        if (zAliases->entAliasMapId != NULL) {
            free(zAliases->entAliasMapId);
            nEntries++;
        }
        /* End of Fix for 4906853 */
	zAliases++;
    }
    free(xEntry->entlogicalAliases);
    free(xEntry);
    xEntry = NULL;
    return nEntries;
}

/* Deletes all the entries in the table with primary index as
   given physical index
   Return number of entries deleted on success, 
   -1 on failure
   -2 for a existing stale entry
*/

int
deleteAliasMappingPhysicalIndex(int xentPhysicalIndex)
{
    entAliasMappingTableEntry_t *zRunner, *temp, *prevEntry;
    int zPhyIndx, nEntries=0;
    entPhysicalEntry_t *zPhysicalEntry;

    /* Fix for 4888088: We do not need the check for 4883511 anymore, */
    /*                  because entAliasLogicalIndexorZero will never be set */
    /*                  to negative values.  Instead we will check if the */
    /*                  entries are stale (except when xentLogicalIndex = 0) */
    if (xentPhysicalIndex <= 0 || xentPhysicalIndex > MAX_ENTITY_INDEX)
        return -1;
    zPhysicalEntry = getPhysicalTableStaleEntry(xentPhysicalIndex);
    if (zPhysicalEntry != NULL)
        return -2;
    /* End of Fix for 4888088 */

    zRunner = gAliasMappingTableHead;
    prevEntry = NULL;

    while (zRunner != NULL) {
        zPhyIndx = zRunner->entPhysicalIndex;

        if (zPhyIndx > 0) {
            if (zPhyIndx == xentPhysicalIndex) {
                temp = zRunner->pNextEntry;
                zRunner->pNextEntry = NULL;
                if (prevEntry)
                    prevEntry->pNextEntry = temp;
                else
                    gAliasMappingTableHead = temp;
                nEntries = FreeAliasMappingTableEntry(zRunner);
                gAliasMappingTableSize--;
                configChanged();
                return nEntries;
            }
        }
        prevEntry = zRunner;
        zRunner = zRunner->pNextEntry;
    }
    return (-1);
}

/* Deletes all entries of the table for a given logical index.
   Returns the number if entries deleted
   -1 if the entry is not found
   -2 if the logical index is stale 
   The memory allocated is freed when the primary index, physical index
   is deleted.
*/
int
deleteAliasMappingLogicalIndex(int xentLogicalIndex)
{
    entAliasMappingTableEntry_t *zRunner;
    logicalAlias *zLogicalAliases;
    int zPhyIndx, nFound=0;
    entLogicalEntry_t *zLogicalEntry;

    /* Fix for 4888088: Here we are not allowing logical index = 0.  We are */
    /*                  forcing the user to use deleteAliasMappingTableEntry */
    if (xentLogicalIndex <= 0 || xentLogicalIndex > MAX_ENTITY_INDEX)
        return -1;
    zLogicalEntry = getLogicalTableStaleEntry(xentLogicalIndex);
    if (zLogicalEntry != NULL)
        return -2;
    /* End of Fix for 4888088 */

    zRunner = gAliasMappingTableHead;

    while (zRunner != NULL) {
        zPhyIndx = zRunner->entPhysicalIndex;
        if (zPhyIndx > 0) {
            zLogicalAliases = zRunner->entlogicalAliases;
            while (zLogicalAliases != NULL
                   && zLogicalAliases->entAliasMapIdSize >= 0) {
                int zLogIndx = zLogicalAliases->entAliasLogicalIndexorZero;
                if (zLogIndx >= 0 ) {
                    if (zLogIndx == xentLogicalIndex) {
                        zLogicalAliases->entAliasLogicalIndexorZero = -1;
                        free(zLogicalAliases->entAliasMapId);
                        zLogicalAliases->entAliasMapId = NULL;
                        zLogicalAliases->entAliasMapIdSize = 0;
                        nFound++;
                        break;
                    }
                }
                zLogicalAliases++;
            }
        }
        zRunner = zRunner->pNextEntry;
    }
    /* Fix for 4888088 */
    if (nFound) {
        configChanged();
        return (nFound);
    } else {
        return -1;
    }
    /* End of Fix for 4888088 */
}
