## -*- c -*- ###################################################################### ## Do the .h file ###################################################################### @open ${name}.h@ /* * Note: this file originally auto-generated by mib2c using * $Id: mib2c.iterate.conf 15999 2007-03-25 22:32:02Z dts12 $ */ #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; @if "$cache" ne "" @ NetsnmpCacheLoad ${i}_load; NetsnmpCacheFree ${i}_free; #define $i.uc_TIMEOUT 60 @end@ @end@ @foreach $i table@ /* column number definitions for table $i */ @foreach $c column@ #define COLUMN_$c.uc $c.subid @end@ @end@ #endif /* $name.uc_H */ ###################################################################### ## Do the .c file ###################################################################### @open ${name}.c@ /* * Note: this file originally auto-generated by mib2c using * $Id: mib2c.iterate.conf 15999 2007-03-25 22:32:02Z dts12 $ */ #include #include #include #include "${name}.h" /** 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@ # Determine the first/last column names @eval $first_column = "-"@ @eval $last_column = "-"@ @foreach $c column@ @if $c.readable@ @if "$first_column" eq "-"@ @eval $first_column = $c@ @end@ @eval $last_column = $c@ @end@ @end@ /** Initialize the $i table by defining its contents and how it's structured */ void initialize_table_$i(void) { static oid ${i}_oid[] = {$i.commaoid}; size_t ${i}_oid_len = OID_LENGTH(${i}_oid); netsnmp_handler_registration *reg; netsnmp_iterator_info *iinfo; netsnmp_table_registration_info *table_info; reg = netsnmp_create_handler_registration( "$i", ${i}_handler, ${i}_oid, ${i}_oid_len, @if $i.settable@ HANDLER_CAN_RWRITE @else@ HANDLER_CAN_RONLY @end@ ); table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); netsnmp_table_helper_add_indexes(table_info, @foreach $idx index@ $idx.type, /* index: $idx */ @end@ 0); table_info->min_column = COLUMN_$first_column.uc; table_info->max_column = COLUMN_$last_column.uc; iinfo = SNMP_MALLOC_TYPEDEF( netsnmp_iterator_info ); iinfo->get_first_data_point = ${i}_get_first_data_point; iinfo->get_next_data_point = ${i}_get_next_data_point; iinfo->table_reginfo = table_info; netsnmp_register_table_iterator( reg, iinfo ); @if "$cache" ne "" @ netsnmp_inject_handler_before( reg, netsnmp_get_cache_handler($i.uc_TIMEOUT, ${i}_load, ${i}_free, ${i}_oid, ${i}_oid_len), TABLE_ITERATOR_NAME); @end@ /* Initialise the contents of the table here */ } /* Typical data structure for a row entry */ struct ${i}_entry { /* Index values */ @foreach $idx index@ @if $idx.needlength@ $idx.decl $idx[NNN]; size_t ${idx}_len; @else@ $idx.decl $idx; @end@ @end@ /* Column values */ @foreach $c column@ @if $c.readable@ @if $c.needlength@ $c.decl $c[NNN]; size_t ${c}_len; @else@ $c.decl $c; @end@ @if $c.settable@ @if !$c.rowstatus@ @if $c.needlength@ $c.decl old_$c[NNN]; size_t old_${c}_len; @else@ $c.decl old_$c; @end@ @end@ @end@ @end@ @end@ /* Illustrate using a simple linked list */ int valid; struct ${i}_entry *next; }; struct ${i}_entry *${i}_head; /* create a new row in the (unsorted) table */ struct ${i}_entry * ${i}_createEntry( @foreach $idx index@ @if $idx.needlength@ $idx.decl* $idx, size_t ${idx}_len, @else@ $idx.decl $idx, @end@ @end@ ) { struct ${i}_entry *entry; entry = SNMP_MALLOC_TYPEDEF(struct ${i}_entry); if (!entry) return NULL; @foreach $idx index@ @if $idx.needlength@ memcpy(entry->$idx, $idx, ${idx}_len); entry->${idx}_len = ${idx}_len; @else@ entry->$idx = $idx; @end@ @end@ entry->next = ${i}_head; ${i}_head = entry; return entry; } /* remove a row from the table */ void ${i}_removeEntry( struct ${i}_entry *entry ) { struct ${i}_entry *ptr, *prev; if (!entry) return; /* Nothing to remove */ for ( ptr = ${i}_head, prev = NULL; ptr != NULL; prev = ptr, ptr = ptr->next ) { if ( ptr == entry ) break; } if ( !ptr ) return; /* Can't find it */ if ( prev == NULL ) ${i}_head = ptr->next; else prev->next = ptr->next; SNMP_FREE( entry ); /* XXX - release any other internal resources */ } @if "$cache" ne "" @ /* Example cache handling - set up linked list from a suitable file */ int ${i}_load( netsnmp_cache *cache, void *vmagic ) { FILE *fp; struct ${i}_entry *this; char buf[STRMAX]; fp = fopen( "/data/for/${i}", "r" ); while ( fgets( buf, STRMAX, fp )) { this = SNMP_MALLOC_TYPEDEF( struct ${i}_entry ); /* Unpick 'buf' and populate 'this' */ this->next = ${i}_head; ${i}_head = this; /* Iterate helper is fine with unordered lists! */ } fclose(fp); } int ${i}_free( netsnmp_cache *cache, void *vmagic ) { struct ${i}_entry *this, *that; for ( this = ${i}_head; this; this=that ) { that = this->next; SNMP_FREE( this ); /* XXX - release any other internal resources */ } ${i}_head = NULL; } @end@ /* Example iterator hook routines - using 'get_next' to do most of the work */ 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) { *my_loop_context = ${i}_head; return ${i}_get_next_data_point(my_loop_context, my_data_context, put_index_data, mydata ); } 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) { struct ${i}_entry *entry = (struct ${i}_entry *)*my_loop_context; netsnmp_variable_list *idx = put_index_data; if ( entry ) { @foreach $idx index@ @if $idx.needlength@ snmp_set_var_value( idx, entry->${idx}, sizeof(entry->${idx}) ); @else@ snmp_set_var_typed_integer( idx, $idx.type, entry->${idx} ); @end@ idx = idx->next_variable; @end@ *my_data_context = (void *)entry; *my_loop_context = (void *)entry->next; return put_index_data; } else { return NULL; } } /** handles requests for the $i table */ 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; struct ${i}_entry *table_entry; switch (reqinfo->mode) { /* * Read-support (also covers GetNext requests) */ case MODE_GET: for (request=requests; request; request=request->next) { table_entry = (struct ${i}_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info( request); switch (table_info->colnum) { @foreach $c column@ @if $c.readable@ case COLUMN_$c.uc: if ( !table_entry ) { netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); continue; } @if $c.needlength@ snmp_set_var_typed_value( request->requestvb, $c.type, (u_char*)table_entry->$c, table_entry->${c}_len); @else@ snmp_set_var_typed_integer( request->requestvb, $c.type, table_entry->$c); @end@ break; @end@ @end@ default: netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT); break; } } break; @if $i.settable@ /* * Write-support */ case MODE_SET_RESERVE1: for (request=requests; request; request=request->next) { table_entry = (struct ${i}_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info( request); switch (table_info->colnum) { @foreach $c column@ @if $c.settable@ case COLUMN_$c.uc: @if $c.rowstatus@ ret = netsnmp_check_vb_rowstatus(request->requestvb, (table_entry ? RS_ACTIVE : RS_NONEXISTENT )); @else@ @if $c.needlength@ /* or possiblc 'netsnmp_check_vb_type_and_size' */ ret = netsnmp_check_vb_type_and_max_size( request->requestvb, $c.type, sizeof(table_entry->$c)); @else@ /* or possibly 'netsnmp_check_vb_int_range' */ ret = netsnmp_check_vb_int( request->requestvb ); @end@ @end@ if ( ret != SNMP_ERR_NOERROR ) { netsnmp_set_request_error( reqinfo, request, ret ); return SNMP_ERR_NOERROR; } break; @end@ @end@ default: netsnmp_set_request_error( reqinfo, request, SNMP_ERR_NOTWRITABLE ); return SNMP_ERR_NOERROR; } } break; case MODE_SET_RESERVE2: @if $i.creatable@ for (request=requests; request; request=request->next) { table_entry = (struct ${i}_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info( request); switch (table_info->colnum) { @if $i.rowstatus@ @foreach $c column@ @if $c.rowstatus@ case COLUMN_$c.uc: switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: case RS_CREATEANDWAIT: table_row = ${i}_createEntry( @foreach $idx index@ @if $idx.needlength@ , table_info->indexes->val.string , table_info->indexes->val_len @else@ , *table_info->indexes->val.integer @end@ @end@ ); if (table_row) { netsnmp_insert_iterator_context( request, table_row ); } else { netsnmp_set_request_error( reqinfo, request, SNMP_ERR_RESOURCEUNAVAILABLE ); return SNMP_ERR_NOERROR; } } @end@ @end@ @else@ @foreach $c column@ @if $c.creatable@ case COLUMN_$c.uc: @end@ @end@ if ( !table_row ) { table_row = ${i}_createEntry( @foreach $idx index@ @if $idx.needlength@ , table_info->indexes->val.string , table_info->indexes->val_len @else@ , *table_info->indexes->val.integer @end@ @end@ ); if (table_row) { netsnmp_insert_iterator_context( request, table_row ); } else { netsnmp_set_request_error( reqinfo, request, SNMP_ERR_RESOURCEUNAVAILABLE ); return SNMP_ERR_NOERROR; } } break; @end@ } } @end@ break; case MODE_SET_FREE: @if $i.creatable@ for (request=requests; request; request=request->next) { table_entry = (struct ${i}_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info( request); switch (table_info->colnum) { @if $i.rowstatus@ @foreach $c column@ @if $c.rowstatus@ case COLUMN_$c.uc: switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: case RS_CREATEANDWAIT: if (table_entry && !table_entry->valid) { ${i}_removeEntry(table_data, table_row ); } } @end@ @end@ @else@ @foreach $c column@ @if $c.creatable@ case COLUMN_$c.uc: @end@ @end@ if ( table_entry && !table_entry->valid ) { ${i}_removeEntry(table_data, table_row ); } break; @end@ } } @end@ break; case MODE_SET_ACTION: for (request=requests; request; request=request->next) { table_entry = (struct ${i}_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info( request); switch (table_info->colnum) { @foreach $c column@ @if $c.settable@ @if !$c.rowstatus@ case COLUMN_$c.uc: @if $c.needlength@ memcpy( table_entry->old_$c, table_entry->$c, sizeof(table_entry->$c)); table_entry->old_${c}_len = table_entry->${c}_len; memset( table_entry->$c, 0, sizeof(table_entry->$c)); memcpy( table_entry->$c, request->requestvb->val.string, request->requestvb->val_len); table_entry->${c}_len = request->requestvb->val_len; @else@ table_entry->old_$c = table_entry->$c; table_entry->$c = *request->requestvb->val.integer; @end@ break; @end@ @end@ @end@ } } @if $i.rowstatus@ /* Check the internal consistency of an active row */ for (request=requests; request; request=request->next) { table_entry = (struct ${i}_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info( request); switch (table_info->colnum) { @foreach $c column@ @if $c.rowstatus@ case COLUMN_$c.uc: switch (*request->requestvb->val.integer) { case RS_ACTIVE: case RS_CREATEANDGO: if (/* XXX */) { netsnmp_set_request_error( reqinfo, request, SNMP_ERR_INCONSISTENTVALUE ); return SNMP_ERR_NOERROR; } } @end@ @end@ } } @end@ break; case MODE_SET_UNDO: for (request=requests; request; request=request->next) { table_entry = (struct ${i}_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info( request); switch (table_info->colnum) { @foreach $c column@ @if $c.settable@ case COLUMN_$c.uc: @if $i.rowstatus@ @if $c.rowstatus@ switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: case RS_CREATEANDWAIT: if (table_entry && !table_entry->valid) { ${i}_removeEntry(table_data, table_row ); } } @else@ @if $c.needlength@ memcpy( table_entry->$c, table_entry->old_$c, sizeof(table_entry->$c)); memset( table_entry->old_$c, 0, sizeof(table_entry->$c)); table_entry->${c}_len = table_entry->old_${c}_len; @else@ table_entry->$c = table_entry->old_$c; table_entry->old_$c = 0; @end@ @end@ @else@ @if $c.creatable@ if ( table_entry && !table_entry->valid ) { ${i}_removeEntry(table_data, table_row ); } else { @if $c.needlength@ memcpy( table_entry->$c, table_entry->old_$c, sizeof(table_entry->$c)); memset( table_entry->old_$c, 0, sizeof(table_entry->$c)); table_entry->${c}_len = table_entry->old_${c}_len; @else@ table_entry->$c = table_entry->old_$c; table_entry->old_$c = 0; @end@ } @else@ @if $c.needlength@ memcpy( table_entry->$c, table_entry->old_$c, sizeof(table_entry->$c)); memset( table_entry->old_$c, 0, sizeof(table_entry->$c)); table_entry->${c}_len = table_entry->old_${c}_len; @else@ table_entry->$c = table_entry->old_$c; table_entry->old_$c = 0; @end@ @end@ @end@ break; @end@ @end@ } } break; case MODE_SET_COMMIT: @if $i.creatable@ for (request=requests; request; request=request->next) { table_entry = (struct ${i}_entry *) netsnmp_extract_iterator_context(request); table_info = netsnmp_extract_table_info( request); switch (table_info->colnum) { @if $i.rowstatus@ @foreach $c column@ @if $c.rowstatus@ case COLUMN_$c.uc: switch (*request->requestvb->val.integer) { case RS_CREATEANDGO: table_entry->valid = 1; /* Fall-through */ case RS_ACTIVE: table_entry->$c = RS_ACTIVE; break; case RS_CREATEANDWAIT: table_entry->valid = 1; /* Fall-through */ case RS_NOTINSERVICE: table_entry->$c = RS_NOTINSERVICE; break; case RS_DESTROY: ${i}_removeEntry(table_data, table_row ); } @end@ @end@ @else@ @foreach $c column@ @if $c.creatable@ case COLUMN_$c.uc: @end@ @end@ if ( table_entry && !table_entry->valid ) { table_entry->valid = 1; } @end@ } } @end@ break; @end@ } return SNMP_ERR_NOERROR; } @end@