/*
 * Note: this file originally auto-generated by mib2c using
 *        : mib2c.iterate_access.conf$
 */

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-features.h>
#include "route_headers.h"
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "ipCidrRouteTable.h"
#include "ipCidrRouteTable_checkfns.h"
#include "ipCidrRouteTable_access.h"

#include "var_route.h"

netsnmp_feature_require(oid_stash);
netsnmp_feature_require(get_routes);
netsnmp_feature_require(oid_stash_get_data);
netsnmp_feature_require(oid_stash_add_data);

static netsnmp_oid_stash_node *undoStorage;

struct undoInfo {
    void           *ptr;
    size_t          len;
};

void
free_undoInfo(void *vp)
{
    struct undoInfo *ui = (struct undoInfo *) vp;
    if (!ui)
        return;
    SNMP_FREE(ui->ptr);
    SNMP_FREE(ui);
}

/** Initialize the ipCidrRouteTable table by defining its contents and how it's structured */
void
initialize_table_ipCidrRouteTable(void)
{
    static oid      ipCidrRouteTable_oid[] =
        { 1, 3, 6, 1, 2, 1, 4, 24, 4 };
    netsnmp_table_registration_info *table_info;
    netsnmp_handler_registration *my_handler;
    netsnmp_iterator_info *iinfo;

    /** create the table registration information structures */
    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("ipCidrRouteTable",
                                                     ipCidrRouteTable_handler,
                                                     ipCidrRouteTable_oid,
                                                     OID_LENGTH
                                                     (ipCidrRouteTable_oid),
                                                     HANDLER_CAN_RWRITE);

    if (!my_handler || !table_info || !iinfo) {
        snmp_log(LOG_ERR,
                 "malloc failed in initialize_table_ipCidrRouteTable");
        return; /** Serious error. */
    }

    /***************************************************
     * Setting up the table's definition
     */
    netsnmp_table_helper_add_indexes(table_info, ASN_IPADDRESS,
                                                 /** index: ipCidrRouteDest */
                                     ASN_IPADDRESS,
                                                 /** index: ipCidrRouteMask */
                                     ASN_INTEGER,
                                               /** index: ipCidrRouteTos */
                                     ASN_IPADDRESS,
                                                 /** index: ipCidrRouteNextHop */
                                     0);

    /** Define the minimum and maximum accessible columns.  This
        optimizes retrieval. */
    table_info->min_column = 1;
    table_info->max_column = 16;

    /** iterator access routines */
    iinfo->get_first_data_point = ipCidrRouteTable_get_first_data_point;
    iinfo->get_next_data_point = ipCidrRouteTable_get_next_data_point;

    /** you may wish to set these as well */
#ifdef MAYBE_USE_THESE
    iinfo->make_data_context = ipCidrRouteTable_context_convert_function;
    iinfo->free_data_context = ipCidrRouteTable_data_free;

    /** pick *only* one of these if you use them */
    iinfo->free_loop_context = ipCidrRouteTable_loop_free;
    iinfo->free_loop_context_at_end = ipCidrRouteTable_loop_free;
#endif

    /** tie the two structures together */
    iinfo->table_reginfo = table_info;

    /***************************************************
     * registering the table with the master agent
     */
    DEBUGMSGTL(("initialize_table_ipCidrRouteTable",
                "Registering table ipCidrRouteTable as a table iterator\n"));
    netsnmp_register_table_iterator2(my_handler, iinfo);
}

/** Initializes the ipCidrRouteTable module */
void
init_ipCidrRouteTable(void)
{

  /** here we initialize all the tables we're planning on supporting */
    initialize_table_ipCidrRouteTable();
}


/* globals */
static size_t rtsize;
static RTENTRY **rthead;

netsnmp_variable_list *
ipCidrRouteTable_set_indexes(RTENTRY *ourroute,
                             netsnmp_variable_list *put_index_data) {
    netsnmp_variable_list *vptr;

    /** ipCidrRouteDest */
    vptr = put_index_data;
    snmp_set_var_value(vptr, (u_char *) &((struct sockaddr_in *) (&ourroute->rt_dst))->sin_addr.s_addr,
                       sizeof(((struct sockaddr_in *) (&ourroute->rt_dst))->sin_addr));

    /** ipCidrRouteMask */
    vptr = vptr->next_variable;
    snmp_set_var_value(vptr, (u_char *) &((struct sockaddr_in *) (&ourroute->rt_genmask))->sin_addr.s_addr,
                       sizeof(((struct sockaddr_in *) (&ourroute->rt_genmask))->sin_addr));

    /** ipCidrRouteTos */
    vptr = vptr->next_variable;
    snmp_set_var_value(vptr, (u_char *) &ourroute->rt_tos,
                       sizeof(ourroute->rt_tos));
    vptr = vptr->next_variable;

    /** ipCidrRouteNextHop */
    snmp_set_var_value(vptr,
                       (u_char *) &((struct sockaddr_in *) (&ourroute->rt_gateway))->sin_addr.s_addr,
                       sizeof(((struct sockaddr_in *) (&ourroute->rt_gateway))->sin_addr));

    return put_index_data;
}

/** returns the first data point within the ipCidrRouteTable 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 *
ipCidrRouteTable_get_first_data_point(void **my_loop_context,
                                      void **my_data_context,
                                      netsnmp_variable_list *
                                      put_index_data,
                                      netsnmp_iterator_info *mydata)
{
    int *position;

    /* we could do this with a file-static variable, but for learning
       purposes we'll use memory allocation to demonstrate simplistic
       freeing of a loop_context */
    position = malloc(sizeof(position));
    if (!position)
        return NULL;

    /* read the routing table into the route array. This function is
       defined in var_route.c, but is sorted incorrectly for this
       table. By using a table_iterator we don't do any sorting
       ourselves and the table_iterator handles it all for us, so we
       don't resort with different criteria. */
    rthead = netsnmp_get_routes(&rtsize);

    if (!rthead) {
        snmp_log(LOG_ERR,"ipCidrRouteTable: failed to get routes\n");
        free(position);
        return NULL;
    }

    /* We use the positinonal count as our loop context */
    *position = 0;
    *my_loop_context = position;

    /* our data context is the individual array element, in this case
       it's the first. */
    *my_data_context = rthead[*position];

    /* now, save the index data into the passed in (linked list) pointer */
    return ipCidrRouteTable_set_indexes(rthead[*position], put_index_data);
}

/** functionally the same as ipCidrRouteTable_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 *
ipCidrRouteTable_get_next_data_point(void **my_loop_context,
                                     void **my_data_context,
                                     netsnmp_variable_list *
                                     put_index_data,
                                     netsnmp_iterator_info *mydata)
{

    int *position = (int *) *my_loop_context;

    /* make sure we were called correctly */
    if (!position)
        return NULL;
    
    /* go to the next route in the list */
    (*position)++;

    /* Are we beyond the end? */
    if (*position >= rtsize) {
        /* End of routes.  stop here by returning NULL */
        SNMP_FREE(position);
        *my_loop_context = NULL;
        *my_data_context = NULL;
        return NULL;
    }

    /* our data context is the individual array element, in this case
       it's the first. */
    *my_data_context = rthead[*position];

    /* now, save the index data into the passed in (linked list) pointer */
    return ipCidrRouteTable_set_indexes(rthead[*position], put_index_data);
}

/** handles requests for the ipCidrRouteTable table, if anything else
   needs to be done */
int
ipCidrRouteTable_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;

    void           *data_context;

    /** column and row index encoded portion */
    const oid * const suffix =
        requests->requestvb->name + reginfo->rootoid_len + 1;
    const size_t suffix_len = requests->requestvb->name_length -
        (reginfo->rootoid_len + 1);

    for (request = requests; request; request = request->next) {
        var = request->requestvb;
        if (request->processed != 0)
            continue;

        data_context = netsnmp_extract_iterator_context(request);
        if (data_context == 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) {
        case MODE_GET:
            switch (table_info->colnum) {
            case COLUMN_IPCIDRROUTEDEST:
                {
                    u_long         *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteDest(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_IPADDRESS,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTEMASK:
                {
                    u_long         *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteMask(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_IPADDRESS,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTETOS:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval = get_ipCidrRouteTos(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTENEXTHOP:
                {
                    u_long         *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteNextHop(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_IPADDRESS,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTEIFINDEX:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteIfIndex(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTETYPE:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteType(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTEPROTO:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteProto(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTEAGE:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval = get_ipCidrRouteAge(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTEINFO:
                {
                    oid            *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteInfo(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_OBJECT_ID,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTENEXTHOPAS:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteNextHopAS(data_context,
                                                 &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTEMETRIC1:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteMetric1(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTEMETRIC2:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteMetric2(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTEMETRIC3:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteMetric3(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTEMETRIC4:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteMetric4(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTEMETRIC5:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteMetric5(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

            case COLUMN_IPCIDRROUTESTATUS:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    retval =
                        get_ipCidrRouteStatus(data_context, &retval_len);
                    snmp_set_var_typed_value(var, ASN_INTEGER,
                                             (const u_char *) retval,
                                             retval_len);
                }
                break;

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

        case MODE_SET_RESERVE1:
                /** mib2cXXX: clear out old undo info if we have any.  Remove if
                   table_iterator becomes un-serialized */
            netsnmp_oid_stash_free(&undoStorage, free_undoInfo);

            switch (table_info->colnum) {
            case COLUMN_IPCIDRROUTEIFINDEX:
                {
                    int             ret =
                        check_ipCidrRouteIfIndex(request->requestvb->type,
                                                 (long *) request->
                                                 requestvb->val.string,
                                                 request->requestvb->
                                                 val_len);
                    if (ret != 0) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTETYPE:
                {
                    int             ret =
                        check_ipCidrRouteType(request->requestvb->type,
                                              (long *) request->requestvb->
                                              val.string,
                                              request->requestvb->val_len);
                    if (ret != 0) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEINFO:
                {
                    int             ret =
                        check_ipCidrRouteInfo(request->requestvb->type,
                                              (oid *) request->requestvb->
                                              val.string,
                                              request->requestvb->val_len);
                    if (ret != 0) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTENEXTHOPAS:
                {
                    int             ret =
                        check_ipCidrRouteNextHopAS(request->requestvb->
                                                   type,
                                                   (long *) request->
                                                   requestvb->val.string,
                                                   request->requestvb->
                                                   val_len);
                    if (ret != 0) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC1:
                {
                    int             ret =
                        check_ipCidrRouteMetric1(request->requestvb->type,
                                                 (long *) request->
                                                 requestvb->val.string,
                                                 request->requestvb->
                                                 val_len);
                    if (ret != 0) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC2:
                {
                    int             ret =
                        check_ipCidrRouteMetric2(request->requestvb->type,
                                                 (long *) request->
                                                 requestvb->val.string,
                                                 request->requestvb->
                                                 val_len);
                    if (ret != 0) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC3:
                {
                    int             ret =
                        check_ipCidrRouteMetric3(request->requestvb->type,
                                                 (long *) request->
                                                 requestvb->val.string,
                                                 request->requestvb->
                                                 val_len);
                    if (ret != 0) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC4:
                {
                    int             ret =
                        check_ipCidrRouteMetric4(request->requestvb->type,
                                                 (long *) request->
                                                 requestvb->val.string,
                                                 request->requestvb->
                                                 val_len);
                    if (ret != 0) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC5:
                {
                    int             ret =
                        check_ipCidrRouteMetric5(request->requestvb->type,
                                                 (long *) request->
                                                 requestvb->val.string,
                                                 request->requestvb->
                                                 val_len);
                    if (ret != 0) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTESTATUS:
                {
                    int             ret =
                        check_ipCidrRouteStatus(request->requestvb->type,
                                                (long *) request->
                                                requestvb->val.string,
                                                request->requestvb->
                                                val_len);
                    if (ret != 0) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            default:
                netsnmp_set_request_error(reqinfo, requests,
                                          SNMP_ERR_NOTWRITABLE);
                break;
            }
            break;

        case MODE_SET_RESERVE2:
                /** save a variable copy */
            switch (table_info->colnum) {
            case COLUMN_IPCIDRROUTEIFINDEX:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    struct undoInfo *ui;
                    retval =
                        get_ipCidrRouteIfIndex(data_context, &retval_len);
                    if (retval) {
                        ui = SNMP_MALLOC_STRUCT(undoInfo);
                        ui->len = retval_len;
                        ui->ptr = netsnmp_memdup(retval, ui->len);
                        netsnmp_oid_stash_add_data(&undoStorage,
                                                   suffix, suffix_len, ui);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTETYPE:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    struct undoInfo *ui;
                    retval =
                        get_ipCidrRouteType(data_context, &retval_len);
                    if (retval) {
                        ui = SNMP_MALLOC_STRUCT(undoInfo);
                        ui->len = retval_len;
                        ui->ptr = netsnmp_memdup(retval, ui->len);
                        netsnmp_oid_stash_add_data(&undoStorage,
                                                   suffix, suffix_len, ui);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEINFO:
                {
                    oid            *retval;
                    size_t          retval_len = 0;
                    struct undoInfo *ui;
                    retval =
                        get_ipCidrRouteInfo(data_context, &retval_len);
                    if (retval) {
                        ui = SNMP_MALLOC_STRUCT(undoInfo);
                        ui->len = retval_len;
                        ui->ptr = netsnmp_memdup(retval, ui->len);
                        netsnmp_oid_stash_add_data(&undoStorage,
                                                   suffix, suffix_len, ui);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTENEXTHOPAS:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    struct undoInfo *ui;
                    retval =
                        get_ipCidrRouteNextHopAS(data_context,
                                                 &retval_len);
                    if (retval) {
                        ui = SNMP_MALLOC_STRUCT(undoInfo);
                        ui->len = retval_len;
                        ui->ptr = netsnmp_memdup(retval, ui->len);
                        netsnmp_oid_stash_add_data(&undoStorage,
                                                   suffix, suffix_len, ui);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC1:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    struct undoInfo *ui;
                    retval =
                        get_ipCidrRouteMetric1(data_context, &retval_len);
                    if (retval) {
                        ui = SNMP_MALLOC_STRUCT(undoInfo);
                        ui->len = retval_len;
                        ui->ptr = netsnmp_memdup(retval, ui->len);
                        netsnmp_oid_stash_add_data(&undoStorage,
                                                   suffix, suffix_len, ui);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC2:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    struct undoInfo *ui;
                    retval =
                        get_ipCidrRouteMetric2(data_context, &retval_len);
                    if (retval) {
                        ui = SNMP_MALLOC_STRUCT(undoInfo);
                        ui->len = retval_len;
                        ui->ptr = netsnmp_memdup(retval, ui->len);
                        netsnmp_oid_stash_add_data(&undoStorage,
                                                   suffix, suffix_len, ui);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC3:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    struct undoInfo *ui;
                    retval =
                        get_ipCidrRouteMetric3(data_context, &retval_len);
                    if (retval) {
                        ui = SNMP_MALLOC_STRUCT(undoInfo);
                        ui->len = retval_len;
                        ui->ptr = netsnmp_memdup(retval, ui->len);
                        netsnmp_oid_stash_add_data(&undoStorage,
                                                   suffix, suffix_len, ui);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC4:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    struct undoInfo *ui;
                    retval =
                        get_ipCidrRouteMetric4(data_context, &retval_len);
                    if (retval) {
                        ui = SNMP_MALLOC_STRUCT(undoInfo);
                        ui->len = retval_len;
                        ui->ptr = netsnmp_memdup(retval, ui->len);
                        netsnmp_oid_stash_add_data(&undoStorage,
                                                   suffix, suffix_len, ui);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC5:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    struct undoInfo *ui;
                    retval =
                        get_ipCidrRouteMetric5(data_context, &retval_len);
                    if (retval) {
                        ui = SNMP_MALLOC_STRUCT(undoInfo);
                        ui->len = retval_len;
                        ui->ptr = netsnmp_memdup(retval, ui->len);
                        netsnmp_oid_stash_add_data(&undoStorage,
                                                   suffix, suffix_len, ui);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTESTATUS:
                {
                    long           *retval;
                    size_t          retval_len = 0;
                    struct undoInfo *ui;
                    retval =
                        get_ipCidrRouteStatus(data_context, &retval_len);
                    if (retval) {
                        ui = SNMP_MALLOC_STRUCT(undoInfo);
                        ui->len = retval_len;
                        ui->ptr = netsnmp_memdup(retval, ui->len);
                        netsnmp_oid_stash_add_data(&undoStorage,
                                                   suffix, suffix_len, ui);
                    }
                }
                break;
            }
            break;

        case MODE_SET_FREE:
                /** Forget undo data, if exists */
            netsnmp_oid_stash_free(&undoStorage, free_undoInfo);
            break;

        case MODE_SET_ACTION:
                /** save a variable copy */
            switch (table_info->colnum) {
            case COLUMN_IPCIDRROUTEIFINDEX:
                {
                    int             ret =
                        set_ipCidrRouteIfIndex(data_context,
                                               (long *) request->
                                               requestvb->val.string,
                                               request->requestvb->
                                               val_len);
                    if (ret) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTETYPE:
                {
                    int             ret = set_ipCidrRouteType(data_context,
                                                              (long *)
                                                              request->
                                                              requestvb->
                                                              val.string,
                                                              request->
                                                              requestvb->
                                                              val_len);
                    if (ret) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEINFO:
                {
                    int             ret = set_ipCidrRouteInfo(data_context,
                                                              (oid *)
                                                              request->
                                                              requestvb->
                                                              val.string,
                                                              request->
                                                              requestvb->
                                                              val_len);
                    if (ret) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTENEXTHOPAS:
                {
                    int             ret =
                        set_ipCidrRouteNextHopAS(data_context,
                                                 (long *) request->
                                                 requestvb->val.string,
                                                 request->requestvb->
                                                 val_len);
                    if (ret) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC1:
                {
                    int             ret =
                        set_ipCidrRouteMetric1(data_context,
                                               (long *) request->
                                               requestvb->val.string,
                                               request->requestvb->
                                               val_len);
                    if (ret) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC2:
                {
                    int             ret =
                        set_ipCidrRouteMetric2(data_context,
                                               (long *) request->
                                               requestvb->val.string,
                                               request->requestvb->
                                               val_len);
                    if (ret) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC3:
                {
                    int             ret =
                        set_ipCidrRouteMetric3(data_context,
                                               (long *) request->
                                               requestvb->val.string,
                                               request->requestvb->
                                               val_len);
                    if (ret) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC4:
                {
                    int             ret =
                        set_ipCidrRouteMetric4(data_context,
                                               (long *) request->
                                               requestvb->val.string,
                                               request->requestvb->
                                               val_len);
                    if (ret) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC5:
                {
                    int             ret =
                        set_ipCidrRouteMetric5(data_context,
                                               (long *) request->
                                               requestvb->val.string,
                                               request->requestvb->
                                               val_len);
                    if (ret) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTESTATUS:
                {
                    int             ret =
                        set_ipCidrRouteStatus(data_context,
                                              (long *) request->requestvb->
                                              val.string,
                                              request->requestvb->val_len);
                    if (ret) {
                        netsnmp_set_request_error(reqinfo, requests, ret);
                    }
                }
                break;
            }
            break;

        case MODE_SET_COMMIT:
                /** answers were all good.  Forget undo data */
            netsnmp_oid_stash_free(&undoStorage, free_undoInfo);
                /** mib2cXXX: call commit hook */
            break;

        case MODE_SET_UNDO:
                /** save a variable copy */
            switch (table_info->colnum) {
            case COLUMN_IPCIDRROUTEIFINDEX:
                {
                    int             retval;
                    struct undoInfo *ui;
                    ui = netsnmp_oid_stash_get_data(undoStorage,
                                                    suffix, suffix_len);
                    retval =
                        set_ipCidrRouteIfIndex(data_context, ui->ptr,
                                               ui->len);
                    if (retval) {
                        netsnmp_set_request_error(reqinfo, requests,
                                                  SNMP_ERR_UNDOFAILED);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTETYPE:
                {
                    int             retval;
                    struct undoInfo *ui;
                    ui = netsnmp_oid_stash_get_data(undoStorage,
                                                    suffix, suffix_len);
                    retval =
                        set_ipCidrRouteType(data_context, ui->ptr,
                                            ui->len);
                    if (retval) {
                        netsnmp_set_request_error(reqinfo, requests,
                                                  SNMP_ERR_UNDOFAILED);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEINFO:
                {
                    int             retval;
                    struct undoInfo *ui;
                    ui = netsnmp_oid_stash_get_data(undoStorage,
                                                    suffix, suffix_len);
                    retval =
                        set_ipCidrRouteInfo(data_context, ui->ptr,
                                            ui->len);
                    if (retval) {
                        netsnmp_set_request_error(reqinfo, requests,
                                                  SNMP_ERR_UNDOFAILED);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTENEXTHOPAS:
                {
                    int             retval;
                    struct undoInfo *ui;
                    ui = netsnmp_oid_stash_get_data(undoStorage,
                                                    suffix, suffix_len);
                    retval =
                        set_ipCidrRouteNextHopAS(data_context, ui->ptr,
                                                 ui->len);
                    if (retval) {
                        netsnmp_set_request_error(reqinfo, requests,
                                                  SNMP_ERR_UNDOFAILED);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC1:
                {
                    int             retval;
                    struct undoInfo *ui;
                    ui = netsnmp_oid_stash_get_data(undoStorage,
                                                    suffix, suffix_len);
                    retval =
                        set_ipCidrRouteMetric1(data_context, ui->ptr,
                                               ui->len);
                    if (retval) {
                        netsnmp_set_request_error(reqinfo, requests,
                                                  SNMP_ERR_UNDOFAILED);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC2:
                {
                    int             retval;
                    struct undoInfo *ui;
                    ui = netsnmp_oid_stash_get_data(undoStorage,
                                                    suffix, suffix_len);
                    retval =
                        set_ipCidrRouteMetric2(data_context, ui->ptr,
                                               ui->len);
                    if (retval) {
                        netsnmp_set_request_error(reqinfo, requests,
                                                  SNMP_ERR_UNDOFAILED);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC3:
                {
                    int             retval;
                    struct undoInfo *ui;
                    ui = netsnmp_oid_stash_get_data(undoStorage,
                                                    suffix, suffix_len);
                    retval =
                        set_ipCidrRouteMetric3(data_context, ui->ptr,
                                               ui->len);
                    if (retval) {
                        netsnmp_set_request_error(reqinfo, requests,
                                                  SNMP_ERR_UNDOFAILED);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC4:
                {
                    int             retval;
                    struct undoInfo *ui;
                    ui = netsnmp_oid_stash_get_data(undoStorage,
                                                    suffix, suffix_len);
                    retval =
                        set_ipCidrRouteMetric4(data_context, ui->ptr,
                                               ui->len);
                    if (retval) {
                        netsnmp_set_request_error(reqinfo, requests,
                                                  SNMP_ERR_UNDOFAILED);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTEMETRIC5:
                {
                    int             retval;
                    struct undoInfo *ui;
                    ui = netsnmp_oid_stash_get_data(undoStorage,
                                                    suffix, suffix_len);
                    retval =
                        set_ipCidrRouteMetric5(data_context, ui->ptr,
                                               ui->len);
                    if (retval) {
                        netsnmp_set_request_error(reqinfo, requests,
                                                  SNMP_ERR_UNDOFAILED);
                    }
                }
                break;
            case COLUMN_IPCIDRROUTESTATUS:
                {
                    int             retval;
                    struct undoInfo *ui;
                    ui = netsnmp_oid_stash_get_data(undoStorage,
                                                    suffix, suffix_len);
                    retval =
                        set_ipCidrRouteStatus(data_context, ui->ptr,
                                              ui->len);
                    if (retval) {
                        netsnmp_set_request_error(reqinfo, requests,
                                                  SNMP_ERR_UNDOFAILED);
                    }
                }
                break;
            }
                /** mib2cXXX: remove cache!  hard to do when serialized, however */
            break;

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