| ## -*- c -*- |
| ###################################################################### |
| ## Do the .h file |
| ###################################################################### |
| @open ${name}.h@ |
| /* |
| * Note: this file originally auto-generated by mib2c using |
| * $Id$ |
| */ |
| #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 |
| * $Id$ |
| */ |
| |
| #include <net-snmp/net-snmp-config.h> |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| #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) |
| { |
| static oid ${i}_oid[] = {$i.commaoid}; |
| 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); |
| |
| 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 retrival. */ |
| @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; |
| |
| oid *suffix; |
| size_t suffix_len; |
| |
| /** column and row index encoded portion */ |
| suffix = requests->requestvb->name + reginfo->rootoid_len + 1; |
| 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; |
| |
| 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, |
| (const u_char *) 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; |
| memdup((u_char **) &ui->ptr, |
| (u_char *) 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 |
| ********************************************************************** |
| |