## -*- c -*- ###################################################################### ## Do the .h file ###################################################################### @open ${name}.h@ /* * Note: this file originally auto-generated by mib2c * using mib2c.iterate_access.conf */ #ifndef $name.uc_H #define $name.uc_H /** other required module components */ config_require(${name}_access) config_require(${name}_checkfns) /* function declarations */ void init_$name(void); @foreach $i table@ void initialize_table_$i(void); Netsnmp_Node_Handler ${i}_handler; @end@ @foreach $i table@ /* column number definitions for table $i */ #include "${name}_columns.h" @run mib2c.column_defines.conf@ /* enum definions */ #include "${name}_enums.h" @run mib2c.column_enums.conf@ @end@ #endif /** $name.uc_H */ ###################################################################### ## Do the .c file ###################################################################### @open ${name}.c@ /* * Note: this file originally auto-generated by mib2c * using mib2c.iterate_access.conf */ #include #include #include #include "${name}.h" #include "${name}_checkfns.h" #include "${name}_access.h" static netsnmp_oid_stash_node *undoStorage = NULL; static netsnmp_oid_stash_node *commitStorage = NULL; struct undoInfo { void *ptr; size_t len; }; struct commitInfo { void *data_context; int have_committed; int new_row; }; void ${name}_free_undoInfo(void *vptr) { struct undoInfo *ui = vptr; if (!ui) return; SNMP_FREE(ui->ptr); SNMP_FREE(ui); } @foreach $i table@ /** Initialize the $i table by defining its contents and how it's structured */ void initialize_table_$i(void) { const oid ${i}_oid[] = {$i.commaoid}; netsnmp_table_registration_info *table_info; netsnmp_handler_registration *my_handler; netsnmp_iterator_info *iinfo; DEBUGMSGTL(("${name}:init", "initializing table $i\n")); /** create the table registration information structures */ table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info); my_handler = netsnmp_create_handler_registration("$i", ${i}_handler, ${i}_oid, OID_LENGTH(${i}_oid), @if $i.settable@ HANDLER_CAN_RWRITE @else@ HANDLER_CAN_RONLY @end@ ); if (!my_handler || !table_info || !iinfo) { snmp_log(LOG_ERR, "malloc failed in initialize_table_$i"); return; /** Serious error. */ } /*************************************************** * Setting up the table's definition */ netsnmp_table_helper_add_indexes(table_info, @foreach $idx index@ $idx.type, /** index: $idx */ @end@ 0); /** Define the minimum and maximum accessible columns. This optimizes retrieval. */ @eval $minv = 0xffffffff@ @eval $maxv = 0@ @foreach $c column@ @if $c.access =~ /(Read|Create)/@ @eval $minv = min($minv, $c.subid)@ @eval $maxv = max($maxv, $c.subid)@ @end@ @end@ table_info->min_column = $minv; table_info->max_column = $maxv; /** iterator access routines */ iinfo->get_first_data_point = ${i}_get_first_data_point; iinfo->get_next_data_point = ${i}_get_next_data_point; /** you may wish to set these as well */ #ifdef MAYBE_USE_THESE iinfo->make_data_context = ${i}_context_convert_function; iinfo->free_data_context = ${i}_data_free; /** pick *only* one of these if you use them */ iinfo->free_loop_context = ${i}_loop_free; iinfo->free_loop_context_at_end = ${i}_loop_free; #endif /** tie the two structures together */ iinfo->table_reginfo = table_info; /*************************************************** * registering the table with the master agent */ DEBUGMSGTL(("initialize_table_$i", "Registering table $i as a table iterator\n")); netsnmp_register_table_iterator(my_handler, iinfo); } @end@ /** Initializes the $name module */ void init_$name(void) { /** here we initialize all the tables we're planning on supporting */ @foreach $i table@ initialize_table_$i(); @end@ } @foreach $i table@ /** handles requests for the $i table, if anything else needs to be done */ int ${i}_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; struct commitInfo *ci = NULL; void *data_context = NULL; /** 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); DEBUGMSGTL(("${name}:handler", "Processing request (%d)\n", reqinfo->mode)); for(request = requests; request; request = request->next) { var = request->requestvb; if (request->processed != 0) continue; switch (reqinfo->mode) { case MODE_GET: data_context = netsnmp_extract_iterator_context(request); if (data_context == NULL) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } break; @if $i.settable@ case MODE_SET_RESERVE1: data_context = netsnmp_extract_iterator_context(request); @if !$i.creatable@ if (data_context == NULL) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION); continue; } @end@ break; default: /* == the other SET modes */ ci = netsnmp_oid_stash_get_data(commitStorage, suffix+1, suffix_len-1); break; @end@ } /** 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) { @foreach $c column@ @if $c.access =~ /(Read|Create)/@ case COLUMN_$c.uc: { $c.decl *retval; size_t retval_len = 0; retval = get_$c(data_context, &retval_len); if (retval) snmp_set_var_typed_value(var, $c.type, retval, retval_len); } break; @end@ @end@ default: /** We shouldn't get here */ snmp_log(LOG_ERR, "problem encountered in ${i}_handler: unknown column\n"); } break; @if $i.settable@ case MODE_SET_RESERVE1: ci = netsnmp_oid_stash_get_data(commitStorage, suffix+1, suffix_len-1); if (!ci) { /** create the commit storage info */ ci = SNMP_MALLOC_STRUCT(commitInfo); if (!data_context) { ci->data_context = ${i}_create_data_context(table_info->indexes, table_info->colnum); ci->new_row = 1; } else { ci->data_context = data_context; } netsnmp_oid_stash_add_data(&commitStorage, suffix+1, suffix_len-1, ci); } break; case MODE_SET_RESERVE2: switch(table_info->colnum) { @foreach $c column@ @if $c.access =~ /(Write|Create)/@ case COLUMN_$c.uc: { $c.decl *retval; size_t retval_len = 0; struct undoInfo *ui = NULL; int ret; /** first, get the old value */ retval = get_$c(ci->data_context, &retval_len); if (retval) { ui = SNMP_MALLOC_STRUCT(undoInfo); ui->len = retval_len; ui->ptr = netsnmp_memdup(retval, ui->len); } /** check the new value, possibly against the older value for a valid state transition */ ret = check_$c(request->requestvb->type, ($c.decl *) request->requestvb->val.string, request->requestvb->val_len, retval, retval_len); if (ret != 0) { netsnmp_set_request_error(reqinfo, request, ret); ${name}_free_undoInfo(ui); } else if (ui) { /** remember information for undo purposes later */ netsnmp_oid_stash_add_data(&undoStorage, suffix, suffix_len, ui); } } break; @end@ @end@ default: netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOTWRITABLE); break; } break; case MODE_SET_ACTION: /** save a variable copy */ switch(table_info->colnum) { @foreach $c column@ @if $c.access =~ /(Write|Create)/@ case COLUMN_$c.uc: { int ret; ret = set_$c(ci->data_context, ($c.decl *) request->requestvb->val.string, request->requestvb->val_len); if (ret) { netsnmp_set_request_error(reqinfo, request, ret); } @if $c.syntax eq "RowStatus"@ if (*request->requestvb->val.integer == RS_DESTROY) { ci->new_row = -1; } @end@ } break; @end@ @end@ } break; case MODE_SET_COMMIT: if (!ci->have_committed) { /** do this once per row only */ ${i}_commit_row(&ci->data_context, ci->new_row); ci->have_committed = 1; } break; case MODE_SET_UNDO: /** save a variable copy */ switch(table_info->colnum) { @foreach $c column@ @if $c.access =~ /(Write|Create)/@ case COLUMN_$c.uc: { int retval; struct undoInfo *ui; ui = netsnmp_oid_stash_get_data(undoStorage, suffix, suffix_len); retval = set_$c(ci->data_context, ui->ptr, ui->len); if (retval) { netsnmp_set_request_error(reqinfo, request, SNMP_ERR_UNDOFAILED); } } break; @end@ @end@ } break; case MODE_SET_FREE: break; @end@ default: snmp_log(LOG_ERR, "problem encountered in ${i}_handler: unsupported mode\n"); } } @if $i.settable@ /** clean up after all requset processing has ended */ switch(reqinfo->mode) { case MODE_SET_UNDO: case MODE_SET_FREE: case MODE_SET_COMMIT: /** clear out the undo cache */ netsnmp_oid_stash_free(&undoStorage, ${name}_free_undoInfo); netsnmp_oid_stash_free(&commitStorage, netsnmp_oid_stash_no_free); } @end@ return SNMP_ERR_NOERROR; } @end@ @run mib2c.check_values.conf@ @run mib2c.access_functions.conf@ @open -@ ********************************************************************** NOTE: The only files you MUST modify should be the following: ${name}_access.c ${name}_access.h ${name}_checkfns_local.h ${name}_checkfns_local.c **********************************************************************