| ## -*- 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 |
| |
| /* function declarations */ |
| void init_$name(void); |
| @foreach $i table@ |
| void initialize_table_$i(void); |
| Netsnmp_Node_Handler ${i}_handler; |
| |
| Netsnmp_First_Data_Point ${i}_get_first_data_point; |
| Netsnmp_Next_Data_Point ${i}_get_next_data_point; |
| @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@ // foreach table |
| |
| #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" |
| |
| @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); |
| |
| /** if your table is read only, it's easiest to change the |
| HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY */ |
| my_handler = netsnmp_create_handler_registration("$i", |
| ${i}_handler, |
| ${i}_oid, |
| OID_LENGTH(${i}_oid), |
| HANDLER_CAN_RWRITE); |
| |
| 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@ // foreach table |
| |
| /** 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@ |
| |
| /** returns the first data point within the $i table data. |
| |
| Set the my_loop_context variable to the first data point structure |
| of your choice (from which you can find the next one). This could |
| be anything from the first node in a linked list, to an integer |
| pointer containing the beginning of an array variable. |
| |
| Set the my_data_context variable to something to be returned to |
| you later (in your main ${i}_handler routine) that will provide |
| you with the data to return in a given row. This could be the |
| same pointer as what my_loop_context is set to, or something |
| different. |
| |
| The put_index_data variable contains a list of snmp variable |
| bindings, one for each index in your table. Set the values of |
| each appropriately according to the data matching the first row |
| and return the put_index_data variable at the end of the function. |
| */ |
| netsnmp_variable_list * |
| ${i}_get_first_data_point(void **my_loop_context, void **my_data_context, |
| netsnmp_variable_list *put_index_data, |
| netsnmp_iterator_info *mydata) |
| { |
| |
| netsnmp_variable_list *vptr; |
| |
| *my_loop_context = /** XXX */; |
| *my_data_context = /** XXX */; |
| |
| vptr = put_index_data; |
| |
| @foreach $idx index@ |
| snmp_set_var_value(vptr, (u_char *) /** XXX: $idx data */, /** XXX: length of $idx data */); |
| vptr = vptr->next_variable; |
| @end@ |
| |
| return put_index_data; |
| } |
| |
| /** functionally the same as ${i}_get_first_data_point, but |
| my_loop_context has already been set to a previous value and should |
| be updated to the next in the list. For example, if it was a |
| linked list, you might want to cast it to your local data type and |
| then return my_loop_context->next. The my_data_context pointer |
| should be set to something you need later (in your main |
| ${i}_handler routine) and the indexes in put_index_data updated |
| again. */ |
| netsnmp_variable_list * |
| ${i}_get_next_data_point(void **my_loop_context, void **my_data_context, |
| netsnmp_variable_list *put_index_data, |
| netsnmp_iterator_info *mydata) |
| { |
| |
| netsnmp_variable_list *vptr; |
| |
| *my_loop_context = /** XXX */; |
| *my_data_context = /** XXX */; |
| |
| vptr = put_index_data; |
| |
| @foreach $idx index@ |
| snmp_set_var_value(vptr, (u_char *) /** XXX: $idx data */, /** XXX: length of $idx data */); |
| vptr = vptr->next_variable; |
| @end@ |
| |
| return put_index_data; |
| } |
| |
| /** 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; |
| |
| for(request = requests; request; request = request->next) { |
| var = request->requestvb; |
| if (request->processed != 0) |
| continue; |
| |
| /** perform anything here that you need to do before each |
| request is processed. */ |
| |
| /** the following extracts the my_data_context pointer set in |
| the loop functions above. You can then use the results to |
| help return data for the columns of the $i table in question */ |
| /** XXX */ = (/** XXX */ *) netsnmp_extract_iterator_context(request); |
| if (/** XXX */ == NULL) { |
| if (reqinfo->mode == MODE_GET) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); |
| continue; |
| } |
| /** XXX: no row existed, if you support creation and this is a |
| set, start dealing with it here, else continue */ |
| } |
| |
| /** extracts the information about the table from the request */ |
| table_info = netsnmp_extract_table_info(request); |
| /** table_info->colnum contains the column number requested */ |
| /** table_info->indexes contains a linked list of snmp variable |
| bindings for the indexes of the table. Values in the list |
| have been set corresponding to the indexes of the |
| request */ |
| if (table_info==NULL) { |
| continue; |
| } |
| |
| switch(reqinfo->mode) { |
| /** the table_iterator helper should change all GETNEXTs |
| into GETs for you automatically, so you don't have to |
| worry about the GETNEXT case. Only GETs and SETs need |
| to be dealt with here */ |
| case MODE_GET: |
| switch(table_info->colnum) { |
| @foreach $c column@ |
| @if $c.access =~ /(Read|Create)/@ |
| case COLUMN_$c.uc: |
| snmp_set_var_typed_value(var, $c.type, (u_char *) /** XXX: column data */, /** XXX: column data length */); |
| break; |
| |
| @end@ |
| @end@ |
| default: |
| /** We shouldn't get here */ |
| snmp_log(LOG_ERR, "problem encountered in ${i}_handler: unknown column\n"); |
| } |
| break; |
| |
| case MODE_SET_RESERVE1: |
| /** set handling... */ |
| |
| default: |
| snmp_log(LOG_ERR, "problem encountered in ${i}_handler: unsupported mode\n"); |
| } |
| } |
| return SNMP_ERR_NOERROR; |
| } |
| @end@ // foreach table |