/*
 * Note: this file originally auto-generated by mib2c using
 *       version : 1.48 $ of : mfd-top.m2c,v $ 
 *
 * $Id$
 */
/** \page MFD helper for ifTable
 *
 * \section intro Introduction
 * Introductory text.
 *
 */
/*
 * standard Net-SNMP includes 
 */
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-features.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>

#ifndef NETSNMP_NO_WRITE_SUPPORT
netsnmp_feature_require(interface_access_entry_set_admin_status);
#endif /* NETSNMP_NO_WRITE_SUPPORT */

/*
 * include our parent header 
 */
#include "ifTable.h"
#include "ifTable_defs.h"

#include <net-snmp/agent/mib_modules.h>

#include "ifTable_interface.h"

#ifdef USING_IP_MIB_IPV4INTERFACETABLE_IPV4INTERFACETABLE_MODULE
#   include "ip-mib/ipv4InterfaceTable/ipv4InterfaceTable.h"
#endif
#ifdef USING_IP_MIB_IPV6INTERFACETABLE_IPV6INTERFACETABLE_MODULE
#   include "ip-mib/ipv6InterfaceTable/ipv6InterfaceTable.h"
#endif
#ifdef USING_IF_MIB_IFXTABLE_IFXTABLE_MODULE
#   include "if-mib/ifXTable/ifXTable.h"
#endif

const oid       ifTable_oid[] = { IFTABLE_OID };
const int       ifTable_oid_size = OID_LENGTH(ifTable_oid);

ifTable_registration ifTable_user_context;
static ifTable_registration *ifTable_user_context_p;

void            initialize_table_ifTable(void);
void            shutdown_table_ifTable(void);

static int
_if_number_handler(netsnmp_mib_handler *handler,
                   netsnmp_handler_registration *reginfo,
                   netsnmp_agent_request_info *reqinfo,
                   netsnmp_request_info *requests);


/**
 * Initializes the ifTable module. Called before the snmpd configuration has
 * been read.
 */
static int
_init_ifTable(int majorID, int minorID, void *serverargs, void *clientarg)
{
    static int      ifTable_did_init = 0;

    DEBUGMSGTL(("verbose:ifTable:init_ifTable", "called\n"));

    netsnmp_access_interface_init();

    /*
     * TODO:300:o: Perform ifTable one-time module initialization.
     */
    if (++ifTable_did_init != 1) {
        DEBUGMSGTL(("ifTable:init_ifTable", "ignoring duplicate call\n"));
        return 0;
    }

    /*
     * here we initialize all the tables we're planning on supporting
     */
    if (should_init("ifTable")) {

#ifdef USING_IP_MIB_IPV4INTERFACETABLE_IPV4INTERFACETABLE_MODULE
        if (should_init("ipv4InterfaceTable"))
            initialize_table_ipv4InterfaceTable();
#endif

#ifdef USING_IP_MIB_IPV6INTERFACETABLE_IPV6INTERFACETABLE_MODULE
        if (should_init("ipv6InterfaceTable"))
            initialize_table_ipv6InterfaceTable();
#endif

        initialize_table_ifTable();

#ifdef USING_IF_MIB_IFXTABLE_IFXTABLE_MODULE
        if (should_init("ifXTable"))
            initialize_table_ifXTable();
#endif
    }

    return 0;
}                               /* init_ifTable */

void
init_ifTable(void)
{
    snmp_register_callback(SNMP_CALLBACK_LIBRARY,
                           SNMP_CALLBACK_PRE_READ_CONFIG,
                           _init_ifTable, NULL);
}

/**
 * Shut-down the ifTable module (agent is exiting)
 */
void
shutdown_ifTable(void)
{
    if (should_init("ifTable"))
        shutdown_table_ifTable();

}

/**
 * Initialize the table ifTable 
 *    (Define its contents and how it's structured)
 */
void
initialize_table_ifTable(void)
{
    u_long          flags;

    DEBUGMSGTL(("verbose:ifTable:initialize_table_ifTable", "called\n"));

    /*
     * TODO:301:o: Perform ifTable one-time table initialization.
     */

    /*
     * TODO:302:o: |->Initialize ifTable user context
     * if you'd like to pass in a pointer to some data for this
     * table, allocate or set it up here.
     */
    /*
     * a netsnmp_data_list is a simple way to store void pointers. A simple
     * string token is used to add, find or remove pointers.
     */
    ifTable_user_context_p = netsnmp_create_data_list("ifTable", NULL, NULL);

    /*
     * No support for any flags yet, but in the future you would
     * set any flags here.
     */
    flags = 0;

    /*
     * call interface initialization code
     */
    _ifTable_initialize_interface(ifTable_user_context_p, flags);

    /*
     * register scalar for ifNumber
     */
    {
        const oid       reg_oid[] = { IFTABLE_NUMBER };
        netsnmp_handler_registration *myreg;

        myreg =
            netsnmp_create_handler_registration("if number",
                                                _if_number_handler,
                                                reg_oid,
                                                OID_LENGTH(reg_oid),
                                                HANDLER_CAN_RONLY);
        netsnmp_register_scalar(myreg);
    }

}                               /* initialize_table_ifTable */

/**
 * Shutdown the table ifTable
 */
void
shutdown_table_ifTable(void)
{
    /*
     * call interface shutdown code
     */
    _ifTable_shutdown_interface(ifTable_user_context_p);
    netsnmp_free_all_list_data(ifTable_user_context_p);
    ifTable_user_context_p = NULL;
}

/**
 * pre-request callback
 * @param  user_context
 *
 *
 * @retval MFD_SUCCESS              : success.
 * @retval MFD_ERROR                : other error
 */
int
ifTable_pre_request(ifTable_registration * user_context)
{
    DEBUGMSGTL(("verbose:ifTable:ifTable_pre_request", "called\n"));

    /*
     * TODO:510:o: Perform ifTable pre-request actions.
     */

    return MFD_SUCCESS;
}                               /* ifTable_pre_request */

/**
 * post-request callback
 *
 * Note:
 *   New rows have been inserted into the container, and
 *   deleted rows have been removed from the container and
 *   released.
 *
 * @param user_context
 * @param rc : MFD_SUCCESS if all requests succeeded
 *
 * @retval MFD_SUCCESS : success.
 * @retval MFD_ERROR   : other error (ignored)
 */
int
ifTable_post_request(ifTable_registration * user_context, int rc)
{
    DEBUGMSGTL(("verbose:ifTable:ifTable_post_request", "called\n"));

    /*
     * TODO:511:o: Perform ifTable post-request actions.
     */

    /*
     * check to set if any rows were changed.
     */
    if (ifTable_dirty_get()) {
        /*
         * check if request was successful. If so, this would be
         * a good place to save data to its persistent store.
         */
        if (MFD_SUCCESS == rc) {
            /*
             * notify library to save changed rows
             */
            snmp_store_needed(netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
                                             NETSNMP_DS_LIB_APPTYPE));
        }

        ifTable_dirty_set(0);   /* clear table dirty flag */
    }

    return MFD_SUCCESS;
}                               /* ifTable_post_request */


/**********************************************************************
 **********************************************************************
 ***
 *** Table ifTable
 ***
 **********************************************************************
 **********************************************************************/
/*
 * IF-MIB::ifTable is subid 2 of interfaces.
 * Its status is Current.
 * OID: .1.3.6.1.2.1.2.2, length: 8
 */

/*
 * ---------------------------------------------------------------------
 * * TODO:200:r: Implement ifTable data context functions.
 */

/**
 * @internal
 * set row context indexes
 *
 * @param reqreq_ctx the row context that needs updated indexes
 * @param ifIndex_val
 *
 * @retval MFD_SUCCESS     : success.
 * @retval MFD_ERROR       : other error.
 *
 * @remark
 *  This function sets the mib indexs, then updates the oid indexs
 *  from the mib index.
 */
int
ifTable_indexes_set(ifTable_rowreq_ctx * rowreq_ctx, long ifIndex_val)
{
    DEBUGMSGTL(("verbose:ifTable:ifTable_indexes_set", "called\n"));

    rowreq_ctx->tbl_idx.ifIndex = ifIndex_val;

    /*
     * convert mib index to oid index
     */
    rowreq_ctx->oid_idx.len = sizeof(rowreq_ctx->oid_tmp) / sizeof(oid);
    if (0 != ifTable_index_to_oid(&rowreq_ctx->oid_idx,
                                  &rowreq_ctx->tbl_idx)) {
        return MFD_ERROR;
    }

    return MFD_SUCCESS;
}                               /* ifTable_indexes_set */


/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifDescr
 * ifDescr is subid 2 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.2
 * Description:
A textual string containing information about the
            interface.  This string should include the name of the
            manufacturer, the product name and the version of the
            interface hardware/software.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 1      hashint   1
 *   settable   0
 *   hint: 255a
 *
 * Ranges:  0 - 255;
 *
 * Its syntax is DisplayString (based on perltype OCTETSTR)
 * The net-snmp type is ASN_OCTET_STR. The C type decl is char (char)
 * This data type requires a length.  (Max 255)
 */
/**
 * Extract the current value of the ifDescr data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifDescr_val_ptr_ptr
 *        Pointer to storage for a char variable
 * @param ifDescr_val_ptr_len_ptr
 *        Pointer to a size_t. On entry, it will contain the size (in bytes)
 *        pointed to by ifDescr.
 *        On exit, this value should contain the data size (in bytes).
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
*
 * @note If you need more than (*ifDescr_val_ptr_len_ptr) bytes of memory,
 *       allocate it using malloc() and update ifDescr_val_ptr_ptr.
 *       <b>DO NOT</b> free the previous pointer.
 *       The MFD helper will release the memory you allocate.
 *
 * @remark If you call this function yourself, you are responsible
 *         for checking if the pointer changed, and freeing any
 *         previously allocated memory. (Not necessary if you pass
 *         in a pointer to static memory, obviously.)
 */
int
ifDescr_get(ifTable_rowreq_ctx * rowreq_ctx, char **ifDescr_val_ptr_ptr,
            size_t * ifDescr_val_ptr_len_ptr)
{
    char           *tmp_descr = NULL;
    u_char          tmp_len = 0;

   /** we should have a non-NULL pointer and enough storage */
    netsnmp_assert((NULL != ifDescr_val_ptr_ptr)
                   && (NULL != *ifDescr_val_ptr_ptr));
    netsnmp_assert(NULL != ifDescr_val_ptr_len_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifDescr_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * if ifDescr is NULL, use the ifName
     */
    if (NULL == rowreq_ctx->data.ifDescr) {
#ifdef USING_IF_MIB_IFXTABLE_IFXTABLE_MODULE
        tmp_descr = rowreq_ctx->data.ifName;
#else
        tmp_descr = NULL;
#endif
    } else
        tmp_descr = rowreq_ctx->data.ifDescr;

    if (NULL != tmp_descr)
        tmp_len = strlen(tmp_descr);
    else
        tmp_len = 0;

    /*
     * TODO:231:o: |-> Extract the current value of the ifDescr data.
     * copy (* ifDescr_val_ptr_ptr ) data and (* ifDescr_val_ptr_len_ptr ) from rowreq_ctx->data
     */
    /*
     * make sure there is enough space for ifDescr data
     */
    if ((NULL == (*ifDescr_val_ptr_ptr)) ||
        ((*ifDescr_val_ptr_len_ptr) < tmp_len)) {
        /*
         * allocate space for ifDescr data
         */
        (*ifDescr_val_ptr_ptr) =
            (char*)malloc(tmp_len * sizeof(rowreq_ctx->data.ifDescr[0]));
        if (NULL == (*ifDescr_val_ptr_ptr)) {
            snmp_log(LOG_ERR, "could not allocate memory\n");
            return MFD_ERROR;
        }
    }
    (*ifDescr_val_ptr_len_ptr) =
        tmp_len * sizeof(rowreq_ctx->data.ifDescr[0]);
    memcpy((*ifDescr_val_ptr_ptr), tmp_descr, (*ifDescr_val_ptr_len_ptr));

    return MFD_SUCCESS;
}                               /* ifDescr_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifType
 * ifType is subid 3 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.3
 * Description:
The type of interface.  Additional values for ifType are
            assigned by the Internet Assigned Numbers Authority (IANA),
            through updating the syntax of the IANAifType textual
            convention.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  1      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 * Enum range: 149/256. Values:  other(1), regular1822(2), hdh1822(3), ddnX25(4), rfc877x25(5), ethernetCsmacd(6), iso88023Csmacd(7), iso88024TokenBus(8), iso88025TokenRing(9), iso88026Man(10), starLan(11), proteon10Mbit(12), proteon80Mbit(13), hyperchannel(14), fddi(15), lapb(16), sdlc(17), ds1(18), e1(19), basicISDN(20), primaryISDN(21), propPointToPointSerial(22), ppp(23), softwareLoopback(24), eon(25), ethernet3Mbit(26), nsip(27), slip(28), ultra(29), ds3(30), sip(31), frameRelay(32), rs232(33), para(34), arcnet(35), arcnetPlus(36), atm(37), miox25(38), sonet(39), x25ple(40), iso88022llc(41), localTalk(42), smdsDxi(43), frameRelayService(44), v35(45), hssi(46), hippi(47), modem(48), aal5(49), sonetPath(50), sonetVT(51), smdsIcip(52), propVirtual(53), propMultiplexor(54), ieee80212(55), fibreChannel(56), hippiInterface(57), frameRelayInterconnect(58), aflane8023(59), aflane8025(60), cctEmul(61), fastEther(62), isdn(63), v11(64), v36(65), g703at64k(66), g703at2mb(67), qllc(68), fastEtherFX(69), channel(70), ieee80211(71), ibm370parChan(72), escon(73), dlsw(74), isdns(75), isdnu(76), lapd(77), ipSwitch(78), rsrb(79), atmLogical(80), ds0(81), ds0Bundle(82), bsc(83), async(84), cnr(85), iso88025Dtr(86), eplrs(87), arap(88), propCnls(89), hostPad(90), termPad(91), frameRelayMPI(92), x213(93), adsl(94), radsl(95), sdsl(96), vdsl(97), iso88025CRFPInt(98), myrinet(99), voiceEM(100), voiceFXO(101), voiceFXS(102), voiceEncap(103), voiceOverIp(104), atmDxi(105), atmFuni(106), atmIma(107), pppMultilinkBundle(108), ipOverCdlc(109), ipOverClaw(110), stackToStack(111), virtualIpAddress(112), mpc(113), ipOverAtm(114), iso88025Fiber(115), tdlc(116), gigabitEthernet(117), hdlc(118), lapf(119), v37(120), x25mlp(121), x25huntGroup(122), trasnpHdlc(123), interleave(124), fast(125), ip(126), docsCableMaclayer(127), docsCableDownstream(128), docsCableUpstream(129), a12MppSwitch(130), tunnel(131), coffee(132), ces(133), atmSubInterface(134), l2vlan(135), l3ipvlan(136), l3ipxvlan(137), digitalPowerline(138), mediaMailOverIp(139), dtm(140), dcn(141), ipForward(142), msdsl(143), ieee1394(144), if_gsn(145), dvbRccMacLayer(146), dvbRccDownstream(147), dvbRccUpstream(148), atmVirtual(149), mplsTunnel(150), srp(151), voiceOverAtm(152), voiceOverFrameRelay(153), idsl(154), compositeLink(155), ss7SigLink(156), propWirelessP2P(157), frForward(158), rfc1483(159), usb(160), ieee8023adLag(161), bgppolicyaccounting(162), frf16MfrBundle(163), h323Gatekeeper(164), h323Proxy(165), mpls(166), mfSigLink(167), hdsl2(168), shdsl(169), ds1FDL(170), pos(171), dvbAsiIn(172), dvbAsiOut(173), plc(174), nfas(175), tr008(176), gr303RDT(177), gr303IDT(178), isup(179), propDocsWirelessMaclayer(180), propDocsWirelessDownstream(181), propDocsWirelessUpstream(182), hiperlan2(183), propBWAp2Mp(184), sonetOverheadChannel(185), digitalWrapperOverheadChannel(186), aal2(187), radioMAC(188), atmRadio(189), imt(190), mvl(191), reachDSL(192), frDlciEndPt(193), atmVciEndPt(194), opticalChannel(195), opticalTransport(196), propAtm(197), voiceOverCable(198), infiniband(199), teLink(200), q2931(201), virtualTg(202), sipTg(203), sipSig(204), docsCableUpstreamChannel(205), econet(206), pon155(207), pon622(208), bridge(209), linegroup(210), voiceEMFGD(211), voiceFGDEANA(212), voiceDID(213), mpegTransport(214), sixToFour(215), gtp(216), pdnEtherLoop1(217), pdnEtherLoop2(218), opticalChannelGroup(219), homepna(220), gfp(221), ciscoISLvlan(222), actelisMetaLOOP(223), fcipLink(224)
 *
 * Its syntax is IANAifType (based on perltype INTEGER)
 * The net-snmp type is ASN_INTEGER. The C type decl is long (u_long)
 */
/**
 * Extract the current value of the ifType data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifType_val_ptr
 *        Pointer to storage for a long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifType_get(ifTable_rowreq_ctx * rowreq_ctx, u_long * ifType_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifType_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifType_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifType data.
     * copy (* ifType_val_ptr ) from rowreq_ctx->data
     */
    (*ifType_val_ptr) = rowreq_ctx->data.ifType;

    return MFD_SUCCESS;
}                               /* ifType_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifMtu
 * ifMtu is subid 4 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.4
 * Description:
The size of the largest packet which can be sent/received
            on the interface, specified in octets.  For interfaces that
            are used for transmitting network datagrams, this is the
            size of the largest network datagram that can be sent on the
            interface.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is INTEGER32 (based on perltype INTEGER32)
 * The net-snmp type is ASN_INTEGER. The C type decl is long (long)
 */
/**
 * Extract the current value of the ifMtu data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifMtu_val_ptr
 *        Pointer to storage for a long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifMtu_get(ifTable_rowreq_ctx * rowreq_ctx, long *ifMtu_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifMtu_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifMtu_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifMtu data.
     * copy (* ifMtu_val_ptr ) from rowreq_ctx->data
     */
    (*ifMtu_val_ptr) = rowreq_ctx->data.ifMtu;

    return MFD_SUCCESS;
}                               /* ifMtu_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifSpeed
 * ifSpeed is subid 5 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.5
 * Description:
An estimate of the interface's current bandwidth in bits
            per second.  For interfaces which do not vary in bandwidth
            or for those where no accurate estimation can be made, this
            object should contain the nominal bandwidth.  If the
            bandwidth of the interface is greater than the maximum value
            reportable by this object then this object should report its
            maximum value (4,294,967,295) and ifHighSpeed must be used
            to report the interace's speed.  For a sub-layer which has
            no concept of bandwidth, this object should be zero.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is GAUGE (based on perltype GAUGE)
 * The net-snmp type is ASN_GAUGE. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifSpeed data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifSpeed_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifSpeed_get(ifTable_rowreq_ctx * rowreq_ctx, u_long * ifSpeed_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifSpeed_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifSpeed_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifSpeed data.
     * copy (* ifSpeed_val_ptr ) from rowreq_ctx->data
     */
    (*ifSpeed_val_ptr) = rowreq_ctx->data.ifSpeed;

    return MFD_SUCCESS;
}                               /* ifSpeed_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifPhysAddress
 * ifPhysAddress is subid 6 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.6
 * Description:
The interface's address at its protocol sub-layer.  For
            example, for an 802.x interface, this object normally
            contains a MAC address.  The interface's media-specific MIB
            must define the bit and byte ordering and the format of the
            value of this object.  For interfaces which do not have such
            an address (e.g., a serial line), this object should contain
            an octet string of zero length.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   1
 *   settable   0
 *   hint: 1x:
 *
 *
 * Its syntax is PhysAddress (based on perltype OCTETSTR)
 * The net-snmp type is ASN_OCTET_STR. The C type decl is char (char)
 * This data type requires a length.  (Max 255)
 */
/**
 * Extract the current value of the ifPhysAddress data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifPhysAddress_val_ptr_ptr
 *        Pointer to storage for a char variable
 * @param ifPhysAddress_val_ptr_len_ptr
 *        Pointer to a size_t. On entry, it will contain the size (in bytes)
 *        pointed to by ifPhysAddress.
 *        On exit, this value should contain the data size (in bytes).
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
*
 * @note If you need more than (*ifPhysAddress_val_ptr_len_ptr) bytes of memory,
 *       allocate it using malloc() and update ifPhysAddress_val_ptr_ptr.
 *       <b>DO NOT</b> free the previous pointer.
 *       The MFD helper will release the memory you allocate.
 *
 * @remark If you call this function yourself, you are responsible
 *         for checking if the pointer changed, and freeing any
 *         previously allocated memory. (Not necessary if you pass
 *         in a pointer to static memory, obviously.)
 */
int
ifPhysAddress_get(ifTable_rowreq_ctx * rowreq_ctx,
                  char **ifPhysAddress_val_ptr_ptr,
                  size_t * ifPhysAddress_val_ptr_len_ptr)
{
   /** we should have a non-NULL pointer and enough storage */
    netsnmp_assert((NULL != ifPhysAddress_val_ptr_ptr)
                   && (NULL != *ifPhysAddress_val_ptr_ptr));
    netsnmp_assert(NULL != ifPhysAddress_val_ptr_len_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifPhysAddress_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    if ((rowreq_ctx->data.ifPhysAddress[0] == 0) &&
        (rowreq_ctx->data.ifPhysAddress[1] == 0) &&
        (rowreq_ctx->data.ifPhysAddress[2] == 0) &&
        (rowreq_ctx->data.ifPhysAddress[3] == 0) &&
        (rowreq_ctx->data.ifPhysAddress[4] == 0) &&
        (rowreq_ctx->data.ifPhysAddress[5] == 0)) {
        /*
         * all 0s = empty string
         */
        (*ifPhysAddress_val_ptr_len_ptr) = 0;
        return MFD_SUCCESS;
    }

    /*
     * TODO:231:o: |-> Extract the current value of the ifPhysAddress data.
     * copy (* ifPhysAddress_val_ptr_ptr ) data and (* ifPhysAddress_val_ptr_len_ptr ) from rowreq_ctx->data
     */
    /*
     * make sure there is enough space for ifPhysAddress data
     */
    if ((NULL == (*ifPhysAddress_val_ptr_ptr)) ||
        ((*ifPhysAddress_val_ptr_len_ptr) <
         (rowreq_ctx->data.ifPhysAddress_len *
          sizeof(rowreq_ctx->data.ifPhysAddress[0])))) {
        /*
         * allocate space for ifPhysAddress data
         */
        (*ifPhysAddress_val_ptr_ptr) =
            (char*)malloc(rowreq_ctx->data.ifPhysAddress_len *
                   sizeof(rowreq_ctx->data.ifPhysAddress[0]));
        if (NULL == (*ifPhysAddress_val_ptr_ptr)) {
            snmp_log(LOG_ERR, "could not allocate memory\n");
            return MFD_ERROR;
        }
    }
    (*ifPhysAddress_val_ptr_len_ptr) =
        rowreq_ctx->data.ifPhysAddress_len *
        sizeof(rowreq_ctx->data.ifPhysAddress[0]);
    memcpy((*ifPhysAddress_val_ptr_ptr), rowreq_ctx->data.ifPhysAddress,
           (*ifPhysAddress_val_ptr_len_ptr));

    return MFD_SUCCESS;
}                               /* ifPhysAddress_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifAdminStatus
 * ifAdminStatus is subid 7 of ifEntry.
 * Its status is Current, and its access level is ReadWrite.
 * OID: .1.3.6.1.2.1.2.2.1.7
 * Description:
The desired state of the interface.  The testing(3) state
            indicates that no operational packets can be passed.  When a
            managed system initializes, all interfaces start with
            ifAdminStatus in the down(2) state.  As a result of either
            explicit management action or per configuration information
            retained by the managed system, ifAdminStatus is then
            changed to either the up(1) or testing(3) states (or remains
            in the down(2) state).
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  1      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   1
 *
 * Enum range: 2/8. Values:  up(1), down(2), testing(3)
 *
 * Its syntax is INTEGER (based on perltype INTEGER)
 * The net-snmp type is ASN_INTEGER. The C type decl is long (u_long)
 */
/**
 * Extract the current value of the ifAdminStatus data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifAdminStatus_val_ptr
 *        Pointer to storage for a long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifAdminStatus_get(ifTable_rowreq_ctx * rowreq_ctx,
                  u_long * ifAdminStatus_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifAdminStatus_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifAdminStatus_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifAdminStatus data.
     * copy (* ifAdminStatus_val_ptr ) from rowreq_ctx->data
     */
    (*ifAdminStatus_val_ptr) = rowreq_ctx->data.ifAdminStatus;

    return MFD_SUCCESS;
}                               /* ifAdminStatus_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifOperStatus
 * ifOperStatus is subid 8 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.8
 * Description:
The current operational state of the interface.  The
            testing(3) state indicates that no operational packets can
            be passed.  If ifAdminStatus is down(2) then ifOperStatus
            should be down(2).  If ifAdminStatus is changed to up(1)
            then ifOperStatus should change to up(1) if the interface is
            ready to transmit and receive network traffic; it should
            change to dormant(5) if the interface is waiting for
            external actions (such as a serial line waiting for an
            incoming connection); it should remain in the down(2) state
            if and only if there is a fault that prevents it from going
            to the up(1) state; it should remain in the notPresent(6)
            state if the interface has missing (typically, hardware)
            components.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  1      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 * Enum range: 5/8. Values:  up(1), down(2), testing(3), unknown(4), dormant(5), notPresent(6), lowerLayerDown(7)
 *
 * Its syntax is INTEGER (based on perltype INTEGER)
 * The net-snmp type is ASN_INTEGER. The C type decl is long (u_long)
 */
/**
 * Extract the current value of the ifOperStatus data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifOperStatus_val_ptr
 *        Pointer to storage for a long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifOperStatus_get(ifTable_rowreq_ctx * rowreq_ctx,
                 u_long * ifOperStatus_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifOperStatus_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifOperStatus_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifOperStatus data.
     * copy (* ifOperStatus_val_ptr ) from rowreq_ctx->data
     */
    (*ifOperStatus_val_ptr) = rowreq_ctx->data.ifOperStatus;

    return MFD_SUCCESS;
}                               /* ifOperStatus_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifLastChange
 * ifLastChange is subid 9 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.9
 * Description:
The value of sysUpTime at the time the interface entered
            its current operational state.  If the current state was
            entered prior to the last re-initialization of the local
            network management subsystem, then this object contains a
            zero value.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is TICKS (based on perltype TICKS)
 * The net-snmp type is ASN_TIMETICKS. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifLastChange data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifLastChange_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifLastChange_get(ifTable_rowreq_ctx * rowreq_ctx,
                 u_long * ifLastChange_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifLastChange_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifLastChange_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifLastChange data.
     * copy (* ifLastChange_val_ptr ) from rowreq_ctx->data
     */
    (*ifLastChange_val_ptr) = rowreq_ctx->data.ifLastChange;

    return MFD_SUCCESS;
}                               /* ifLastChange_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifInOctets
 * ifInOctets is subid 10 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.10
 * Description:
The total number of octets received on the interface,
            including framing characters.

            Discontinuities in the value of this counter can occur at
            re-initialization of the management system, and at other
            times as indicated by the value of
            ifCounterDiscontinuityTime.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is COUNTER (based on perltype COUNTER)
 * The net-snmp type is ASN_COUNTER. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifInOctets data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifInOctets_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifInOctets_get(ifTable_rowreq_ctx * rowreq_ctx,
               u_long * ifInOctets_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifInOctets_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifInOctets_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifInOctets data.
     * copy (* ifInOctets_val_ptr ) from rowreq_ctx->data
     */
    (*ifInOctets_val_ptr) = rowreq_ctx->data.ifInOctets;

    return MFD_SUCCESS;
}                               /* ifInOctets_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifInUcastPkts
 * ifInUcastPkts is subid 11 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.11
 * Description:
The number of packets, delivered by this sub-layer to a
            higher (sub-)layer, which were not addressed to a multicast
            or broadcast address at this sub-layer.

            Discontinuities in the value of this counter can occur at
            re-initialization of the management system, and at other
            times as indicated by the value of
            ifCounterDiscontinuityTime.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is COUNTER (based on perltype COUNTER)
 * The net-snmp type is ASN_COUNTER. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifInUcastPkts data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifInUcastPkts_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifInUcastPkts_get(ifTable_rowreq_ctx * rowreq_ctx,
                  u_long * ifInUcastPkts_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifInUcastPkts_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifInUcastPkts_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifInUcastPkts data.
     * copy (* ifInUcastPkts_val_ptr ) from rowreq_ctx->data
     */
    (*ifInUcastPkts_val_ptr) = rowreq_ctx->data.ifInUcastPkts;

    return MFD_SUCCESS;
}                               /* ifInUcastPkts_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifInNUcastPkts
 * ifInNUcastPkts is subid 12 of ifEntry.
 * Its status is Deprecated, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.12
 * Description:
The number of packets, delivered by this sub-layer to a
            higher (sub-)layer, which were addressed to a multicast or
            broadcast address at this sub-layer.

            Discontinuities in the value of this counter can occur at
            re-initialization of the management system, and at other
            times as indicated by the value of
            ifCounterDiscontinuityTime.

            This object is deprecated in favour of ifInMulticastPkts and
            ifInBroadcastPkts.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is COUNTER (based on perltype COUNTER)
 * The net-snmp type is ASN_COUNTER. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifInNUcastPkts data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifInNUcastPkts_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifInNUcastPkts_get(ifTable_rowreq_ctx * rowreq_ctx,
                   u_long * ifInNUcastPkts_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifInNUcastPkts_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifInNUcastPkts_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifInNUcastPkts data.
     * copy (* ifInNUcastPkts_val_ptr ) from rowreq_ctx->data
     */
    (*ifInNUcastPkts_val_ptr) = rowreq_ctx->data.ifInNUcastPkts;

    return MFD_SUCCESS;
}                               /* ifInNUcastPkts_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifInDiscards
 * ifInDiscards is subid 13 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.13
 * Description:
The number of inbound packets which were chosen to be
            discarded even though no errors had been detected to prevent

            their being deliverable to a higher-layer protocol.  One
            possible reason for discarding such a packet could be to
            free up buffer space.

            Discontinuities in the value of this counter can occur at
            re-initialization of the management system, and at other
            times as indicated by the value of
            ifCounterDiscontinuityTime.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is COUNTER (based on perltype COUNTER)
 * The net-snmp type is ASN_COUNTER. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifInDiscards data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifInDiscards_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifInDiscards_get(ifTable_rowreq_ctx * rowreq_ctx,
                 u_long * ifInDiscards_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifInDiscards_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifInDiscards_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifInDiscards data.
     * copy (* ifInDiscards_val_ptr ) from rowreq_ctx->data
     */
    (*ifInDiscards_val_ptr) = rowreq_ctx->data.ifInDiscards;

    return MFD_SUCCESS;
}                               /* ifInDiscards_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifInErrors
 * ifInErrors is subid 14 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.14
 * Description:
For packet-oriented interfaces, the number of inbound
            packets that contained errors preventing them from being
            deliverable to a higher-layer protocol.  For character-
            oriented or fixed-length interfaces, the number of inbound
            transmission units that contained errors preventing them
            from being deliverable to a higher-layer protocol.

            Discontinuities in the value of this counter can occur at
            re-initialization of the management system, and at other
            times as indicated by the value of
            ifCounterDiscontinuityTime.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is COUNTER (based on perltype COUNTER)
 * The net-snmp type is ASN_COUNTER. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifInErrors data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifInErrors_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifInErrors_get(ifTable_rowreq_ctx * rowreq_ctx,
               u_long * ifInErrors_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifInErrors_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifInErrors_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifInErrors data.
     * copy (* ifInErrors_val_ptr ) from rowreq_ctx->data
     */
    (*ifInErrors_val_ptr) = rowreq_ctx->data.ifInErrors;

    return MFD_SUCCESS;
}                               /* ifInErrors_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifInUnknownProtos
 * ifInUnknownProtos is subid 15 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.15
 * Description:
For packet-oriented interfaces, the number of packets
            received via the interface which were discarded because of
            an unknown or unsupported protocol.  For character-oriented
            or fixed-length interfaces that support protocol
            multiplexing the number of transmission units received via
            the interface which were discarded because of an unknown or
            unsupported protocol.  For any interface that does not
            support protocol multiplexing, this counter will always be
            0.

            Discontinuities in the value of this counter can occur at
            re-initialization of the management system, and at other
            times as indicated by the value of
            ifCounterDiscontinuityTime.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is COUNTER (based on perltype COUNTER)
 * The net-snmp type is ASN_COUNTER. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifInUnknownProtos data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifInUnknownProtos_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifInUnknownProtos_get(ifTable_rowreq_ctx * rowreq_ctx,
                      u_long * ifInUnknownProtos_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifInUnknownProtos_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifInUnknownProtos_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifInUnknownProtos data.
     * copy (* ifInUnknownProtos_val_ptr ) from rowreq_ctx->data
     */
    (*ifInUnknownProtos_val_ptr) = rowreq_ctx->data.ifInUnknownProtos;

    return MFD_SUCCESS;
}                               /* ifInUnknownProtos_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifOutOctets
 * ifOutOctets is subid 16 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.16
 * Description:
The total number of octets transmitted out of the
            interface, including framing characters.

            Discontinuities in the value of this counter can occur at
            re-initialization of the management system, and at other
            times as indicated by the value of
            ifCounterDiscontinuityTime.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is COUNTER (based on perltype COUNTER)
 * The net-snmp type is ASN_COUNTER. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifOutOctets data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifOutOctets_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifOutOctets_get(ifTable_rowreq_ctx * rowreq_ctx,
                u_long * ifOutOctets_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifOutOctets_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifOutOctets_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifOutOctets data.
     * copy (* ifOutOctets_val_ptr ) from rowreq_ctx->data
     */
    (*ifOutOctets_val_ptr) = rowreq_ctx->data.ifOutOctets;

    return MFD_SUCCESS;
}                               /* ifOutOctets_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifOutUcastPkts
 * ifOutUcastPkts is subid 17 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.17
 * Description:
The total number of packets that higher-level protocols
            requested be transmitted, and which were not addressed to a
            multicast or broadcast address at this sub-layer, including
            those that were discarded or not sent.

            Discontinuities in the value of this counter can occur at
            re-initialization of the management system, and at other
            times as indicated by the value of
            ifCounterDiscontinuityTime.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is COUNTER (based on perltype COUNTER)
 * The net-snmp type is ASN_COUNTER. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifOutUcastPkts data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifOutUcastPkts_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifOutUcastPkts_get(ifTable_rowreq_ctx * rowreq_ctx,
                   u_long * ifOutUcastPkts_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifOutUcastPkts_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifOutUcastPkts_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifOutUcastPkts data.
     * copy (* ifOutUcastPkts_val_ptr ) from rowreq_ctx->data
     */
    (*ifOutUcastPkts_val_ptr) = rowreq_ctx->data.ifOutUcastPkts;

    return MFD_SUCCESS;
}                               /* ifOutUcastPkts_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifOutNUcastPkts
 * ifOutNUcastPkts is subid 18 of ifEntry.
 * Its status is Deprecated, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.18
 * Description:
The total number of packets that higher-level protocols
            requested be transmitted, and which were addressed to a
            multicast or broadcast address at this sub-layer, including
            those that were discarded or not sent.

            Discontinuities in the value of this counter can occur at
            re-initialization of the management system, and at other
            times as indicated by the value of
            ifCounterDiscontinuityTime.

            This object is deprecated in favour of ifOutMulticastPkts
            and ifOutBroadcastPkts.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is COUNTER (based on perltype COUNTER)
 * The net-snmp type is ASN_COUNTER. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifOutNUcastPkts data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifOutNUcastPkts_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifOutNUcastPkts_get(ifTable_rowreq_ctx * rowreq_ctx,
                    u_long * ifOutNUcastPkts_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifOutNUcastPkts_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifOutNUcastPkts_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifOutNUcastPkts data.
     * copy (* ifOutNUcastPkts_val_ptr ) from rowreq_ctx->data
     */
    (*ifOutNUcastPkts_val_ptr) = rowreq_ctx->data.ifOutNUcastPkts;

    return MFD_SUCCESS;
}                               /* ifOutNUcastPkts_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifOutDiscards
 * ifOutDiscards is subid 19 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.19
 * Description:
The number of outbound packets which were chosen to be
            discarded even though no errors had been detected to prevent
            their being transmitted.  One possible reason for discarding
            such a packet could be to free up buffer space.

            Discontinuities in the value of this counter can occur at
            re-initialization of the management system, and at other
            times as indicated by the value of
            ifCounterDiscontinuityTime.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is COUNTER (based on perltype COUNTER)
 * The net-snmp type is ASN_COUNTER. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifOutDiscards data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifOutDiscards_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifOutDiscards_get(ifTable_rowreq_ctx * rowreq_ctx,
                  u_long * ifOutDiscards_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifOutDiscards_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifOutDiscards_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifOutDiscards data.
     * copy (* ifOutDiscards_val_ptr ) from rowreq_ctx->data
     */
    (*ifOutDiscards_val_ptr) = rowreq_ctx->data.ifOutDiscards;

    return MFD_SUCCESS;
}                               /* ifOutDiscards_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifOutErrors
 * ifOutErrors is subid 20 of ifEntry.
 * Its status is Current, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.20
 * Description:
For packet-oriented interfaces, the number of outbound
            packets that could not be transmitted because of errors.
            For character-oriented or fixed-length interfaces, the
            number of outbound transmission units that could not be
            transmitted because of errors.

            Discontinuities in the value of this counter can occur at
            re-initialization of the management system, and at other
            times as indicated by the value of
            ifCounterDiscontinuityTime.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is COUNTER (based on perltype COUNTER)
 * The net-snmp type is ASN_COUNTER. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifOutErrors data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifOutErrors_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifOutErrors_get(ifTable_rowreq_ctx * rowreq_ctx,
                u_long * ifOutErrors_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifOutErrors_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifOutErrors_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifOutErrors data.
     * copy (* ifOutErrors_val_ptr ) from rowreq_ctx->data
     */
    (*ifOutErrors_val_ptr) = rowreq_ctx->data.ifOutErrors;

    return MFD_SUCCESS;
}                               /* ifOutErrors_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifOutQLen
 * ifOutQLen is subid 21 of ifEntry.
 * Its status is Deprecated, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.21
 * Description:
The length of the output packet queue (in packets).
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is GAUGE (based on perltype GAUGE)
 * The net-snmp type is ASN_GAUGE. The C type decl is u_long (u_long)
 */
/**
 * Extract the current value of the ifOutQLen data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifOutQLen_val_ptr
 *        Pointer to storage for a u_long variable
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
 */
int
ifOutQLen_get(ifTable_rowreq_ctx * rowreq_ctx, u_long * ifOutQLen_val_ptr)
{
   /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != ifOutQLen_val_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifOutQLen_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifOutQLen data.
     * copy (* ifOutQLen_val_ptr ) from rowreq_ctx->data
     */
    (*ifOutQLen_val_ptr) = rowreq_ctx->data.ifOutQLen;

    return MFD_SUCCESS;
}                               /* ifOutQLen_get */

/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifSpecific
 * ifSpecific is subid 22 of ifEntry.
 * Its status is Deprecated, and its access level is ReadOnly.
 * OID: .1.3.6.1.2.1.2.2.1.22
 * Description:
A reference to MIB definitions specific to the particular
            media being used to realize the interface.  It is

            recommended that this value point to an instance of a MIB
            object in the media-specific MIB, i.e., that this object
            have the semantics associated with the InstancePointer
            textual convention defined in RFC 2579.  In fact, it is
            recommended that the media-specific MIB specify what value
            ifSpecific should/can take for values of ifType.  If no MIB
            definitions specific to the particular media are available,
            the value should be set to the OBJECT IDENTIFIER { 0 0 }.
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  0      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   0
 *
 *
 * Its syntax is OBJECTID (based on perltype OBJECTID)
 * The net-snmp type is ASN_OBJECT_ID. The C type decl is oid (oid)
 * This data type requires a length.  (Max 255)
 */
/**
 * Extract the current value of the ifSpecific data.
 *
 * Set a value using the data context for the row.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifSpecific_val_ptr_ptr
 *        Pointer to storage for a oid variable
 * @param ifSpecific_val_ptr_len_ptr
 *        Pointer to a size_t. On entry, it will contain the size (in bytes)
 *        pointed to by ifSpecific.
 *        On exit, this value should contain the data size (in bytes).
 *
 * @retval MFD_SUCCESS         : success
 * @retval MFD_SKIP            : skip this node (no value for now)
 * @retval MFD_ERROR           : Any other error
*
 * @note If you need more than (*ifSpecific_val_ptr_len_ptr) bytes of memory,
 *       allocate it using malloc() and update ifSpecific_val_ptr_ptr.
 *       <b>DO NOT</b> free the previous pointer.
 *       The MFD helper will release the memory you allocate.
 *
 * @remark If you call this function yourself, you are responsible
 *         for checking if the pointer changed, and freeing any
 *         previously allocated memory. (Not necessary if you pass
 *         in a pointer to static memory, obviously.)
 */
int
ifSpecific_get(ifTable_rowreq_ctx * rowreq_ctx,
               oid ** ifSpecific_val_ptr_ptr,
               size_t * ifSpecific_val_ptr_len_ptr)
{
   /** we should have a non-NULL pointer and enough storage */
    netsnmp_assert((NULL != ifSpecific_val_ptr_ptr)
                   && (NULL != *ifSpecific_val_ptr_ptr));
    netsnmp_assert(NULL != ifSpecific_val_ptr_len_ptr);


    DEBUGMSGTL(("verbose:ifTable:ifSpecific_get", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:231:o: |-> Extract the current value of the ifSpecific data.
     * copy (* ifSpecific_val_ptr_ptr ) data and (* ifSpecific_val_ptr_len_ptr ) from rowreq_ctx->data
     */
#ifdef IFTABLE_HAS_IFSPECIFIC
    /*
     * make sure there is enough space for ifSpecific data
     */
    if ((NULL == (*ifSpecific_val_ptr_ptr)) ||
        ((*ifSpecific_val_ptr_len_ptr) <
         (rowreq_ctx->data.ifSpecific_len *
          sizeof(rowreq_ctx->data.ifSpecific[0])))) {
        /*
         * allocate space for ifSpecific data
         */
        (*ifSpecific_val_ptr_ptr) =
            malloc(rowreq_ctx->data.ifSpecific_len *
                   sizeof(rowreq_ctx->data.ifSpecific[0]));
        if (NULL == (*ifSpecific_val_ptr_ptr)) {
            snmp_log(LOG_ERR, "could not allocate memory\n");
            return MFD_ERROR;
        }
    }
    (*ifSpecific_val_ptr_len_ptr) =
        rowreq_ctx->data.ifSpecific_len *
        sizeof(rowreq_ctx->data.ifSpecific[0]);
    memcpy((*ifSpecific_val_ptr_ptr), rowreq_ctx->data.ifSpecific,
           (*ifSpecific_val_ptr_len_ptr));
#else
    /*
     * hard coded
     */
    netsnmp_assert((*ifSpecific_val_ptr_len_ptr) > (size_t)nullOidLen);
    (*ifSpecific_val_ptr_len_ptr) = (size_t)nullOidLen;
    memcpy(*ifSpecific_val_ptr_ptr, &nullOid, (size_t)nullOidLen);
#endif

    return MFD_SUCCESS;
}                               /* ifSpecific_get */



/** @} */

#ifndef NETSNMP_NO_WRITE_SUPPORT

/**********************************************************************
 **********************************************************************
 ***
 *** Table ifTable
 ***
 **********************************************************************
 **********************************************************************/
/*
 * IF-MIB::ifTable is subid 2 of interfaces.
 * Its status is Current.
 * OID: .1.3.6.1.2.1.2.2, length: 8
 */
    /*
     * NOTE: if you update this chart, please update the versions in
     *       local/mib2c-conf.d/parent-set.m2i
     *       agent/mibgroup/helpers/baby_steps.c
     * while you're at it.
     */
    /*
     ***********************************************************************
     * Baby Steps Flow Chart (2004.06.05)                                  *
     *                                                                     *
     * +--------------+    +================+    U = unconditional path    *
     * |optional state|    ||required state||    S = path for success      *
     * +--------------+    +================+    E = path for error        *
     ***********************************************************************
     *
     *                        +--------------+
     *                        |     pre      |
     *                        |   request    |
     *                        +--------------+
     *                               | U
     *                        +==============+
     *       +----------------||  object    ||
     *       |              E ||  lookup    ||
     *       |                +==============+
     *       |                       | S
     *       |                +==============+
     *       |              E ||   check    ||
     *       |<---------------||   values   ||
     *       |                +==============+
     *       |                       | S
     *       |                +==============+
     *       |       +<-------||   undo     ||
     *       |       |      E ||   setup    ||
     *       |       |        +==============+
     *       |       |               | S
     *       |       |        +==============+
     *       |       |        ||    set     ||-------------------------->+
     *       |       |        ||   value    || E                         |
     *       |       |        +==============+                           |
     *       |       |               | S                                 |
     *       |       |        +--------------+                           |
     *       |       |        |    check     |-------------------------->|
     *       |       |        |  consistency | E                         |
     *       |       |        +--------------+                           |
     *       |       |               | S                                 |
     *       |       |        +==============+         +==============+  |
     *       |       |        ||   commit   ||-------->||     undo   ||  |
     *       |       |        ||            || E       ||    commit  ||  |
     *       |       |        +==============+         +==============+  |
     *       |       |               | S                     U |<--------+
     *       |       |        +--------------+         +==============+
     *       |       |        | irreversible |         ||    undo    ||
     *       |       |        |    commit    |         ||     set    ||
     *       |       |        +--------------+         +==============+
     *       |       |               | U                     U |
     *       |       +-------------->|<------------------------+
     *       |                +==============+
     *       |                ||   undo     ||
     *       |                ||  cleanup   ||
     *       |                +==============+
     *       +---------------------->| U
     *                        +--------------+
     *                        |    post      |
     *                        |   request    |
     *                        +--------------+
     *
     */

/**
 * Setup up context with information needed to undo a set request.
 *
     * Undo storage is in (* ifSpecific_val_ptr_ptr )*
 * This function will be called before the individual node undo setup
 * functions are called. If you need to do any undo setup that is not
 * related to a specific column, you can do it here.
 *
 * Note that the undo context has been allocated with ifTable_allocate_data().
 * Note that an individual node's undo_setup function will only be called
 * if that node is being set to a new value.
 *
 * If there is any setup specific to a particular column (e.g. allocating
 * memory for a string), you should do that setup in the node's undo_setup
 * function, so it won't be done unless it is necessary.
 *
 * @param rowreq_ctx
 *        Pointer to the table context (ifTable_rowreq_ctx)
 *
 * @retval MFD_SUCCESS : success
 * Undo storage is in (* ifSpecific_val_ptr_ptr )*
 * @retval MFD_ERROR   : error. set will fail.
 */
int
ifTable_undo_setup(ifTable_rowreq_ctx * rowreq_ctx)
{
    int             rc = MFD_SUCCESS;

    DEBUGMSGTL(("verbose:ifTable:ifTable_undo_setup", "called\n"));

    /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:451:M: |-> Setup ifTable undo.
     * set up ifTable undo information, in preparation for a set.
     * Undo storage is in (* ifSpecific_val_ptr_ptr )*
     */

    return rc;
}                               /* ifTable_undo_setup */

/**
 * Undo a set request.
 *
 * This function will be called before the individual node undo
 * functions are called. If you need to do any undo that is not
 * related to a specific column, you can do it here.
 *
 * Note that an individual node's undo function will only be called
 * if that node is being set to a new value.
 *
 * If there is anything  specific to a particular column (e.g. releasing
 * memory for a string), you should do that setup in the node's undo
 * function, so it won't be done unless it is necessary.
 *
 * @param rowreq_ctx
 *        Pointer to the table context (ifTable_rowreq_ctx)
 *
 * @retval MFD_SUCCESS : success
 * @retval MFD_ERROR   : error. set will fail.
 */
int
ifTable_undo(ifTable_rowreq_ctx * rowreq_ctx)
{
    int             rc = MFD_SUCCESS;

    DEBUGMSGTL(("verbose:ifTable:ifTable_undo", "called\n"));

    /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:451:M: |-> ifTable undo.
     * ifTable undo information, in response to a failed set.
     * Undo storage is in (* ifSpecific_val_ptr_ptr )*
     */

    return rc;
}                               /* ifTable_undo_setup */

/**
 * Cleanup up context undo information.
 *
 * This function will be called after set/commit processing. If you
 * allocated any resources in undo_setup, this is the place to release
 * those resources.
 *
 * This function is called regardless of the success or failure of the set
 * request. If you need to perform different steps for cleanup depending
 * on success or failure, you can add a flag to the rowreq_ctx.
 *
 * @param rowreq_ctx
 *        Pointer to the table context (ifTable_rowreq_ctx)
 *
 * @retval MFD_SUCCESS : success
 * @retval MFD_ERROR   : error
 */
int
ifTable_undo_cleanup(ifTable_rowreq_ctx * rowreq_ctx)
{
    int             rc = MFD_SUCCESS;

    DEBUGMSGTL(("verbose:ifTable:ifTable_undo_cleanup", "called\n"));

    /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:452:M: |-> Cleanup ifTable undo.
     * Undo storage is in (* ifSpecific_val_ptr_ptr )*
     */

    return rc;
}                               /* ifTable_undo_cleanup */

/**
 * commit new values.
 *
 * At this point, you should have done everything you can to ensure that
 * this commit will not fail.
 *
 * Should you need different behavior depending on which columns were
 * set, rowreq_ctx->column_set_flags will indicate which writeable columns were
 * set. The definitions for the COLUMN_*_FLAG bits can be found in
 * ifTable.h.
 * A new row will have the MFD_ROW_CREATED bit set in rowreq_flags.
 *
 * @param rowreq_ctx Pointer to the users context.
 *
 * @retval MFD_SUCCESS : success
 * @retval MFD_ERROR   : error
 */
int
ifTable_commit(ifTable_rowreq_ctx * rowreq_ctx)
{
    int             rc = MFD_SUCCESS;
    int             save_flags;

    DEBUGMSGTL(("verbose:ifTable:ifTable_commit", "called\n"));

    /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * save flags, then clear until we actually do something
     */
    save_flags = rowreq_ctx->column_set_flags;
    rowreq_ctx->column_set_flags = 0;

    /*
     * commit ifTable data
     * 1) check the column's flag in save_flags to see if it was set.
     * 2) clear the flag when you handle that column
     * 3) set the column's flag in column_set_flags if it needs undo
     *    processing in case of a failure.
     */
    if (save_flags & COLUMN_IFADMINSTATUS_FLAG) {
        save_flags &= ~COLUMN_IFADMINSTATUS_FLAG;       /* clear ifAdminStatus */
        /*
         * TODO:482:o: |-> commit column ifAdminStatus.
         */
        rc = netsnmp_access_interface_entry_set_admin_status(rowreq_ctx->
                                                             data.ifentry,
                                                             rowreq_ctx->
                                                             data.
                                                             ifAdminStatus);
        if (0 != rc) {
            snmp_log(LOG_ERR,
                     "ifTable column ifAdminStatus commit failed\n");
        } else {
            /*
             * set flag, in case we need to undo ifAdminStatus
             */
            rowreq_ctx->column_set_flags |= COLUMN_IFADMINSTATUS_FLAG;
        }
    }

    /*
     * if we successfully commited this row, set the dirty flag.
     */
    if (MFD_SUCCESS == rc) {
        rowreq_ctx->rowreq_flags |= MFD_ROW_DIRTY;
    }

    if (save_flags) {
        snmp_log(LOG_ERR, "unhandled columns (0x%x) in commit\n",
                 save_flags);
        return MFD_ERROR;
    }

    return rc;
}                               /* ifTable_commit */

/**
 * undo commit new values.
 *
 * Should you need different behavior depending on which columns were
 * set, rowreq_ctx->column_set_flags will indicate which writeable columns were
 * set. The definitions for the COLUMN_*_FLAG bits can be found in
 * ifTable.h.
 * A new row will have the MFD_ROW_CREATED bit set in rowreq_flags.
 *
 * @param rowreq_ctx
 *        Pointer to the users context.
 *
 * @retval MFD_SUCCESS : success
 * @retval MFD_ERROR   : error
 */
int
ifTable_undo_commit(ifTable_rowreq_ctx * rowreq_ctx)
{
    int             rc = MFD_SUCCESS;

    DEBUGMSGTL(("verbose:ifTable:ifTable_undo_commit", "called\n"));

    /** we should have a non-NULL pointer */
    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:485:M: |-> Undo ifTable commit.
     * check the column's flag in rowreq_ctx->column_set_flags to see
     * if it was set during commit, then undo it.
     *
     * eg: if (rowreq_ctx->column_set_flags & COLUMN__FLAG) {}
     */
    /*
     * no undo cleanup, undo entry simply freed
     */


    /*
     * if we successfully un-commited this row, clear the dirty flag.
     */
    if (MFD_SUCCESS == rc) {
        rowreq_ctx->rowreq_flags &= ~MFD_ROW_DIRTY;
    }

    return rc;
}                               /* ifTable_undo_commit */

/*
 * TODO:440:M: Implement ifTable node value checks.
 * TODO:450:M: Implement ifTable undo functions.
 * TODO:460:M: Implement ifTable set functions.
 * TODO:480:M: Implement ifTable commit functions.
 */
/*---------------------------------------------------------------------
 * IF-MIB::ifEntry.ifAdminStatus
 * ifAdminStatus is subid 7 of ifEntry.
 * Its status is Current, and its access level is ReadWrite.
 * OID: .1.3.6.1.2.1.2.2.1.7
 * Description:
The desired state of the interface.  The testing(3) state
            indicates that no operational packets can be passed.  When a
            managed system initializes, all interfaces start with
            ifAdminStatus in the down(2) state.  As a result of either
            explicit management action or per configuration information
            retained by the managed system, ifAdminStatus is then
            changed to either the up(1) or testing(3) states (or remains
            in the down(2) state).
 *
 * Attributes:
 *   accessible 1     isscalar 0     enums  1      hasdefval 0
 *   readable   1     iscolumn 1     ranges 0      hashint   0
 *   settable   1
 *
 * Enum range: 2/8. Values:  up(1), down(2), testing(3)
 *
 * Its syntax is INTEGER (based on perltype INTEGER)
 * The net-snmp type is ASN_INTEGER. The C type decl is long (u_long)
 */
/**
 * Check that the proposed new value is potentially valid.
 *
 * @param rowreq_ctx
 *        Pointer to the row request context.
 * @param ifAdminStatus_val
 *        A long containing the new value.
 *
 * @retval MFD_SUCCESS        : incoming value is legal
 * @retval MFD_NOT_VALID_NOW  : incoming value is not valid now
 * @retval MFD_NOT_VALID_EVER : incoming value is never valid
 *
 * This is the place to check for requirements that are not
 * expressed in the mib syntax (for example, a requirement that
 * is detailed in the description for an object).
 *
 * You should check that the requested change between the undo value and the
 * new value is legal (ie, the transistion from one value to another
 * is legal).
 *      
 *@note
 * This check is only to determine if the new value
 * is \b potentially valid. This is the first check of many, and
 * is one of the simplest ones.
 * 
 *@note
 * this is not the place to do any checks for values
 * which depend on some other value in the mib. Those
 * types of checks should be done in the
 * ifTable_check_dependencies() function.
 *
 * The following checks have already been done for you:
 *    The syntax is ASN_INTEGER
 *    The value is one of  up(1), down(2), testing(3)
 *
 * If there a no other checks you need to do, simply return MFD_SUCCESS.
 *
 */
int
ifAdminStatus_check_value(ifTable_rowreq_ctx * rowreq_ctx,
                          u_long ifAdminStatus_val)
{
    DEBUGMSGTL(("verbose:ifTable:ifAdminStatus_check_value", "called\n"));

    /** should never get a NULL pointer */
    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:441:o: |-> Check for valid ifAdminStatus value.
     */
    /*
     * we don't support test
     */
    if (ifAdminStatus_val == IFADMINSTATUS_TESTING)
        return MFD_ERROR;

    return MFD_SUCCESS;         /* ifAdminStatus value not illegal */
}                               /* ifAdminStatus_check_value */

/**
 * Save old value information
 *
 * @param rowreq_ctx
 *        Pointer to the table context (ifTable_rowreq_ctx)
 *
 * @retval MFD_SUCCESS : success
 * @retval MFD_ERROR   : error. set will fail.
 *
 * This function will be called after the table level undo setup function
 * ifTable_undo_setup has been called.
 *
 *@note
 * this function will only be called if a new value is set for this column.
 *
 * If there is any setup specific to a particular column (e.g. allocating
 * memory for a string), you should do that setup in this function, so it
 * won't be done unless it is necessary.
 */
int
ifAdminStatus_undo_setup(ifTable_rowreq_ctx * rowreq_ctx)
{
    DEBUGMSGTL(("verbose:ifTable:ifAdminStatus_undo_setup", "called\n"));

    /** should never get a NULL pointer */
    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:455:o: |-> Setup ifAdminStatus undo.
     */
    /*
     * copy ifAdminStatus data
     * set rowreq_ctx->undo->ifAdminStatus from rowreq_ctx->data.ifAdminStatus
     */
    rowreq_ctx->undo->ifAdminStatus = rowreq_ctx->data.ifAdminStatus;

    return MFD_SUCCESS;
}                               /* ifAdminStatus_undo_setup */

/**
 * Set the new value.
 *
 * @param rowreq_ctx
 *        Pointer to the users context. You should know how to
 *        manipulate the value from this object.
 * @param ifAdminStatus_val
 *        A long containing the new value.
 */
int
ifAdminStatus_set(ifTable_rowreq_ctx * rowreq_ctx,
                  u_long ifAdminStatus_val)
{

    DEBUGMSGTL(("verbose:ifTable:ifAdminStatus_set", "called\n"));

    /** should never get a NULL pointer */
    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:461:M: |-> Set ifAdminStatus value.
     * set ifAdminStatus value in rowreq_ctx->data
     */
    rowreq_ctx->data.ifAdminStatus = ifAdminStatus_val;

    return MFD_SUCCESS;
}                               /* ifAdminStatus_set */

/**
 * undo the previous set.
 *
 * @param rowreq_ctx
 *        Pointer to the users context.
 */
int
ifAdminStatus_undo(ifTable_rowreq_ctx * rowreq_ctx)
{

    DEBUGMSGTL(("verbose:ifTable:ifAdminStatus_undo", "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:456:o: |-> Clean up ifAdminStatus undo.
     */
    /*
     * copy ifAdminStatus data
     * set rowreq_ctx->data.ifAdminStatus from rowreq_ctx->undo->ifAdminStatus
     */
    rowreq_ctx->data.ifAdminStatus = rowreq_ctx->undo->ifAdminStatus;


    return MFD_SUCCESS;
}                               /* ifAdminStatus_undo */

/**
 * check dependencies
 *
 * This is useful for for tables which have dependencies between columns
 * (or rows, or tables). For example, two columns allocating a percentage
 * of something add up 100%.
 *
 * Should you need different behavior depending on which columns were
 * set, rowreq_ctx->column_set_flags will indicate which writeable columns were
 * set. The definitions for the COLUMN_*_FLAG bits can be found in
 * ifTable.h.
 * A new row will have the MFD_ROW_CREATED bit set in rowreq_flags.
 *
 * @param rowreq_ctx
 *
 * @retval MFD_SUCCESS all the changes to the row are legal
 * @retval MFD_ERROR   one or more changes are not legal
 *
 * (see README-table-ifTable if you don't have dependencies)
 */
int
ifTable_check_dependencies(ifTable_rowreq_ctx * rowreq_ctx)
{
    int             rc = MFD_SUCCESS;

    DEBUGMSGTL(("internal:ifTable:ifTable_check_dependencies",
                "called\n"));

    netsnmp_assert(NULL != rowreq_ctx);

    /*
     * TODO:470:o: Check ifTable row dependencies.
     * check that all new value are legal and consistent with each other
     */
    return rc;
}                               /* ifTable_check_dependencies */


#endif /* !NETSNMP_NO_WRITE_SUPPORT */

static int
_if_number_handler(netsnmp_mib_handler *handler,
                      netsnmp_handler_registration *reginfo,
                      netsnmp_agent_request_info *reqinfo,
                      netsnmp_request_info *requests)
{
    if (MODE_GET == reqinfo->mode) {
        int val = ifTable_container_size();
        snmp_set_var_typed_value(requests->requestvb, ASN_INTEGER,
                                 (u_char *) &val, sizeof(val));
    } else
        netsnmp_assert("bad mode in RO handler");
    
    if (handler->next && handler->next->access_method)
        return netsnmp_call_next_handler(handler, reginfo, reqinfo,
                                         requests);
    
    return SNMP_ERR_NOERROR;
}

/** @} */
/** @{ */
