## -*- c -*- ## Portions of this file ar Copyright (C) Apple, Inc. ## Use is subject to license terms specified in the COPYING file ## distributed with the Net-SNMP package. ###################################################################### ## Do the .h file ###################################################################### @open ${name}.h@ /* * Note: this file originally auto-generated by mib2c * using mib2c.container.conf */ #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; @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 mib2c.container.conf */ #include #include #include #include #include #include "${name}.h" @foreach $i table@ #ifdef $i.uc_USE_CACHE static void ${i}_cache_free(netsnmp_cache * cache, void *magic); static int ${i}_cache_load(netsnmp_cache * cache, void *vmagic); #endif @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@ ## 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) { const oid ${i}_oid[] = {$i.commaoid}; const size_t ${i}_oid_len = OID_LENGTH(${i}_oid); netsnmp_handler_registration *reg = NULL; netsnmp_mib_handler *handler = NULL; netsnmp_container *container = NULL; netsnmp_table_registration_info *table_info = NULL; #ifdef $i.uc_USE_CACHE netsnmp_cache *cache = NULL; #endif DEBUGMSGTL(("${name}:init", "initializing table $i\n")); reg = netsnmp_create_handler_registration( "$i", ${i}_handler, ${i}_oid, ${i}_oid_len, @if $i.settable@ HANDLER_CAN_RWRITE @else@ HANDLER_CAN_RONLY @end@ ); if (NULL == reg) { snmp_log(LOG_ERR,"error creating handler registration for $i\n"); goto bail; } @if $i.settable@ /** should a set on a non-existent row create a new one? */ /** reg->modes |= HANDLER_CAN_NOT_CREATE; */ @end@ container = netsnmp_container_find( "$i:table_container" ); if (NULL == container) { snmp_log(LOG_ERR,"error creating container for $i\n"); goto bail; } table_info = SNMP_MALLOC_TYPEDEF( netsnmp_table_registration_info ); if (NULL == table_info) { snmp_log(LOG_ERR,"error allocating table registration for $i\n"); goto bail; } 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; /************************************************* * * inject container_table helper */ handler = netsnmp_container_table_handler_get(table_info, container, TABLE_CONTAINER_KEY_NETSNMP_INDEX); if (NULL == handler) { snmp_log(LOG_ERR,"error allocating table registration for $i\n"); goto bail; } if (SNMPERR_SUCCESS != netsnmp_inject_handler(reg, handler)) { snmp_log(LOG_ERR,"error injecting container_table handler for $i\n"); goto bail; } handler = NULL; /* reg has it, will reuse below */ #ifdef $i.uc_USE_CACHE /************************************************* * * inject cache helper */ cache = netsnmp_cache_create(30, /* timeout in seconds */ ${i}_cache_load, ${i}_cache_free, ${i}_oid, ${i}_oid_len); if (NULL == cache) { snmp_log(LOG_ERR, "error creating cache for $i\n"); goto bail; } cache->flags = NETSNMP_CACHE_DONT_INVALIDATE_ON_SET; cache->magic = container; handler = netsnmp_cache_handler_get(cache); if (NULL == handler) { snmp_log(LOG_ERR, "error creating cache handler for $i\n"); goto bail; } if (SNMPERR_SUCCESS != netsnmp_inject_handler(reg, handler)) { snmp_log(LOG_ERR,"error injecting cache handler for $i\n"); goto bail; } handler = NULL; /* reg has it*/ #endif /* * register the table */ if (SNMPERR_SUCCESS != netsnmp_register_table(reg, table_info)) { snmp_log(LOG_ERR,"error registering table handler for $i\n"); reg = NULL; /* it was freed inside netsnmp_register_table */ goto bail; } /* * Initialise the contents of the table here */ return; /* ok */ /* * Some error occurred during registration. Clean up and bail. */ bail: /* not ok */ if (handler) netsnmp_handler_free(handler); #ifdef $i.uc_USE_CACHE if (cache) netsnmp_cache_free(cache); #endif if (table_info) netsnmp_table_registration_info_free(table_info); if (container) CONTAINER_FREE(container); if (reg) netsnmp_handler_registration_free(reg); } /** Typical data structure for a row entry */ typedef struct ${i}_entry_s { netsnmp_index oid_index; /* 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@ int valid; } ${i}_entry; /** create a new row in the table */ ${i}_entry * ${i}_createEntry(netsnmp_container *container, @foreach $idx index@ @if $idx.needlength@ , $idx.decl* $idx , size_t ${idx}_len @else@ , $idx.decl $idx @end@ @end@ ) { ${i}_entry *entry; entry = SNMP_MALLOC_TYPEDEF(${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->oid_index.len = XXX; entry->oid_index.oids = YYY; CONTAINER_INSERT( container, entry ); return entry; } /** remove a row from the table */ void ${i}_removeEntry(netsnmp_container *container, ${i}_entry *entry) { if (!entry) return; /* Nothing to remove */ CONTAINER_REMOVE( container, entry ); if (entry) SNMP_FREE( entry ); /* XXX - release any other internal resources */ } /** remove a row from the table */ void ${i}_freeEntry(${i}_entry *entry) { if (!entry) return; /* Nothing to remove */ SNMP_FREE( entry ); /* XXX - release any other internal resources */ } /** 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; netsnmp_container *container; ${i}_entry *table_entry; @if $i.settable@ int ret; @end@ DEBUGMSGTL(("${name}:handler", "Processing request (%d)\n", reqinfo->mode)); switch (reqinfo->mode) { /* * Read-support (also covers GetNext requests) */ case MODE_GET: for (request=requests; request; request=request->next) { if (request->processed) continue; table_entry = (${i}_entry *) netsnmp_container_table_extract_context(request); table_info = netsnmp_extract_table_info(request); if ((NULL == table_entry) || (NULL == table_info)) { snmp_log(LOG_ERR, "could not extract table entry or info for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } 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, 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) { if (request->processed) continue; table_entry = (${i}_entry *) netsnmp_container_table_extract_context(request); table_info = netsnmp_extract_table_info(request); if ((NULL == table_entry) || (NULL == table_info)) { snmp_log(LOG_ERR, "could not extract table entry or info for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } 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 possibly '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) { if (request->processed) continue; table_entry = (${i}_entry *) netsnmp_container_table_extract_context(request); table_info = netsnmp_extract_table_info(request); if ((NULL == table_entry) || (NULL == table_info)) { snmp_log(LOG_ERR, "could not extract table entry or info for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } 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: container = netsnmp_container_table_extract(request); if (NULL == container) { snmp_log(LOG_ERR, "could not extract table container for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } table_entry = ${i}_createEntry(container @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_entry) { netsnmp_container_table_insert_row( request, table_entry ); } 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_entry ) { container = netsnmp_container_table_extract(request); if (NULL == container) { snmp_log(LOG_ERR, "could not extract table container for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } table_entry = ${i}_createEntry(container @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_entry) { netsnmp_container_table_insert_row( request, table_entry ); } 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) { if (request->processed) continue; container = netsnmp_container_table_extract(request); if (NULL == container) { snmp_log(LOG_ERR, "could not extract table container for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } table_entry = (${i}_entry *) netsnmp_container_table_extract_context(request); table_info = netsnmp_extract_table_info(request); if ((NULL == table_entry) || (NULL == table_info)) { snmp_log(LOG_ERR, "could not extract table entry or info for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } 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(container, table_entry ); } } @end@ @end@ @else@ @foreach $c column@ @if $c.creatable@ case COLUMN_$c.uc: @end@ @end@ if ( table_entry && !table_entry->valid ) { ${i}_removeEntry(container, table_entry ); } break; @end@ } } @end@ break; case MODE_SET_ACTION: for (request=requests; request; request=request->next) { if (request->processed) continue; table_entry = (${i}_entry *) netsnmp_container_table_extract_context(request); table_info = netsnmp_extract_table_info(request); if ((NULL == table_entry) || (NULL == table_info)) { snmp_log(LOG_ERR, "could not extract table entry or info for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } 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) { if (request->processed) continue; table_entry = (${i}_entry *) netsnmp_container_table_extract_context(request); table_info = netsnmp_extract_table_info(request); if ((NULL == table_entry) || (NULL == table_info)) { snmp_log(LOG_ERR, "could not extract table entry or info for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } 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) { if (request->processed) continue; container = netsnmp_container_table_extract(request); if (NULL == container) { snmp_log(LOG_ERR, "could not extract table container for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } table_entry = (${i}_entry *) netsnmp_container_table_extract_context(request); table_info = netsnmp_extract_table_info(request); if ((NULL == table_entry) || (NULL == table_info)) { snmp_log(LOG_ERR, "could not extract table entry or info for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } 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(container, table_entry ); } } @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(container, 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) { if (request->processed) continue; table_entry = (${i}_entry *) netsnmp_container_table_extract_context(request); table_info = netsnmp_extract_table_info(request); if ((NULL == table_entry) || (NULL == table_info)) { snmp_log(LOG_ERR, "could not extract table entry or info for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } 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: container = netsnmp_container_table_extract(request); if (NULL == container) { snmp_log(LOG_ERR, "could not extract table container for $i\n"); snmp_set_var_typed_value(request->requestvb, SNMP_ERR_GENERR, NULL, 0); continue; } ${i}_removeEntry(container, table_entry ); } @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; } #ifdef $i.uc_USE_CACHE /** * @internal */ static int ${i}_cache_load(netsnmp_cache * cache, void *vmagic) { netsnmp_container *container; DEBUGMSGTL(("internal:${i}:_cache_load", "called\n")); if ((NULL == cache) || (NULL == cache->magic)) { snmp_log(LOG_ERR, "invalid cache for ${i}_cache_load\n"); return -1; } container = (netsnmp_container *)cache->magic; /** should only be called for an invalid or expired cache */ netsnmp_assert((0 == cache->valid) || (1 == cache->expired)); /* * load cache here (or call function to do it) */ /** CONTAINER_INSERT(container, record); */ return 0; } /* _cache_load */ /** * @Internal */ /** remove a row from the table */ static void ${i}_freeEntry_cb(${i}_entry *entry, void *magic) { ${i}_freeEntry(entry); } /** * @internal */ static void ${i}_cache_free(netsnmp_cache * cache, void *magic) { netsnmp_container *container; DEBUGMSGTL(("internal:${i}:_cache_free", "called\n")); if ((NULL == cache) || (NULL == cache->magic)) { snmp_log(LOG_ERR, "invalid cache in ${i}_cache_free\n"); return; } container = (netsnmp_container *) cache->magic; /* * empty (but don't free) cache here */ CONTAINER_CLEAR(container, (netsnmp_container_obj_func*)${i}_freeEntry_cb, NULL); } /* _cache_free */ #endif /* $i.uc_USE_CACHE */ @end@