#include #include #include #include #include #include #include #include "sysORTable.h" #include "system_mib.h" #include netsnmp_feature_require(table_container); /** Typical data structure for a row entry */ typedef struct sysORTable_entry_s { netsnmp_index oid_index; oid sysORIndex; const struct sysORTable* data; } sysORTable_entry; /* * column number definitions for table sysORTable */ #define COLUMN_SYSORINDEX 1 #define COLUMN_SYSORID 2 #define COLUMN_SYSORDESCR 3 #define COLUMN_SYSORUPTIME 4 static netsnmp_container *table = NULL; static u_long sysORLastChange; static oid sysORNextIndex = 1; /** create a new row in the table */ static void register_foreach(const struct sysORTable* data, void* dummy) { sysORTable_entry *entry; sysORLastChange = data->OR_uptime; entry = SNMP_MALLOC_TYPEDEF(sysORTable_entry); if (!entry) { snmp_log(LOG_ERR, "could not allocate storage, sysORTable is inconsistent\n"); } else { const oid firstNext = sysORNextIndex; netsnmp_iterator* it = CONTAINER_ITERATOR(table); do { const sysORTable_entry* value; const oid cur = sysORNextIndex; if (sysORNextIndex == SNMP_MIN(MAX_SUBID, 2147483647UL)) sysORNextIndex = 1; else ++sysORNextIndex; for (value = (sysORTable_entry*)it->curr(it); value && value->sysORIndex < cur; value = (sysORTable_entry*)ITERATOR_NEXT(it)) { } if (value && value->sysORIndex == cur) { if (sysORNextIndex < cur) it->reset(it); } else { entry->sysORIndex = cur; break; } } while (firstNext != sysORNextIndex); ITERATOR_RELEASE(it); if(firstNext == sysORNextIndex) { snmp_log(LOG_ERR, "Failed to locate a free index in sysORTable\n"); free(entry); } else { entry->data = data; entry->oid_index.len = 1; entry->oid_index.oids = &entry->sysORIndex; CONTAINER_INSERT(table, entry); } } } static int register_cb(int major, int minor, void* serv, void* client) { DEBUGMSGTL(("mibII/sysORTable/register_cb", "register_cb(%d, %d, %p, %p)\n", major, minor, serv, client)); register_foreach((struct sysORTable*)serv, NULL); return SNMP_ERR_NOERROR; } /** remove a row from the table */ static int unregister_cb(int major, int minor, void* serv, void* client) { sysORTable_entry *value; netsnmp_iterator* it = CONTAINER_ITERATOR(table); DEBUGMSGTL(("mibII/sysORTable/unregister_cb", "unregister_cb(%d, %d, %p, %p)\n", major, minor, serv, client)); sysORLastChange = ((struct sysORTable*)(serv))->OR_uptime; while ((value = (sysORTable_entry*)ITERATOR_NEXT(it)) && value->data != serv); ITERATOR_RELEASE(it); if(value) { CONTAINER_REMOVE(table, value); free(value); } return SNMP_ERR_NOERROR; } /** handles requests for the sysORTable table */ static int sysORTable_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_request_info *request; DEBUGMSGTL(("mibII/sysORTable/sysORTable_handler", "sysORTable_handler called\n")); if (reqinfo->mode != MODE_GET) { snmp_log(LOG_ERR, "Got unexpected operation for sysORTable\n"); return SNMP_ERR_GENERR; } /* * Read-support (also covers GetNext requests) */ request = requests; while(request && request->processed) request = request->next; while(request) { sysORTable_entry *table_entry; netsnmp_table_request_info *table_info; if (NULL == (table_info = netsnmp_extract_table_info(request))) { snmp_log(LOG_ERR, "could not extract table info for sysORTable\n"); snmp_set_var_typed_value( request->requestvb, SNMP_ERR_GENERR, NULL, 0); } else if(NULL == (table_entry = (sysORTable_entry *) netsnmp_container_table_extract_context(request))) { switch (table_info->colnum) { case COLUMN_SYSORID: case COLUMN_SYSORDESCR: case COLUMN_SYSORUPTIME: netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); break; default: netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT); break; } } else { switch (table_info->colnum) { case COLUMN_SYSORID: snmp_set_var_typed_value( request->requestvb, ASN_OBJECT_ID, (const u_char*)table_entry->data->OR_oid, table_entry->data->OR_oidlen * sizeof(oid)); break; case COLUMN_SYSORDESCR: snmp_set_var_typed_value( request->requestvb, ASN_OCTET_STR, (const u_char*)table_entry->data->OR_descr, strlen(table_entry->data->OR_descr)); break; case COLUMN_SYSORUPTIME: snmp_set_var_typed_integer( request->requestvb, ASN_TIMETICKS, table_entry->data->OR_uptime); break; default: netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT); break; } } do { request = request->next; } while(request && request->processed); } return SNMP_ERR_NOERROR; } static netsnmp_handler_registration *sysORLastChange_reg; static netsnmp_watcher_info sysORLastChange_winfo; static netsnmp_handler_registration *sysORTable_reg; static netsnmp_table_registration_info *sysORTable_table_info; /** Initializes the sysORTable module */ void init_sysORTable(void) { const oid sysORLastChange_oid[] = { 1, 3, 6, 1, 2, 1, 1, 8 }; const oid sysORTable_oid[] = { 1, 3, 6, 1, 2, 1, 1, 9 }; sysORTable_table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); table = netsnmp_container_find("sysORTable:table_container"); if (sysORTable_table_info == NULL || table == NULL) { SNMP_FREE(sysORTable_table_info); CONTAINER_FREE(table); return; } table->container_name = strdup("sysORTable"); netsnmp_table_helper_add_indexes(sysORTable_table_info, ASN_INTEGER, /** index: sysORIndex */ 0); sysORTable_table_info->min_column = COLUMN_SYSORID; sysORTable_table_info->max_column = COLUMN_SYSORUPTIME; sysORLastChange_reg = netsnmp_create_handler_registration( "mibII/sysORLastChange", NULL, sysORLastChange_oid, OID_LENGTH(sysORLastChange_oid), HANDLER_CAN_RONLY); netsnmp_init_watcher_info( &sysORLastChange_winfo, &sysORLastChange, sizeof(u_long), ASN_TIMETICKS, WATCHER_FIXED_SIZE); netsnmp_register_watched_scalar(sysORLastChange_reg, &sysORLastChange_winfo); sysORTable_reg = netsnmp_create_handler_registration( "mibII/sysORTable", sysORTable_handler, sysORTable_oid, OID_LENGTH(sysORTable_oid), HANDLER_CAN_RONLY); netsnmp_container_table_register(sysORTable_reg, sysORTable_table_info, table, TABLE_CONTAINER_KEY_NETSNMP_INDEX); sysORLastChange = netsnmp_get_agent_uptime(); /* * Initialise the contents of the table here */ netsnmp_sysORTable_foreach(®ister_foreach, NULL); /* * Register callbacks */ snmp_register_callback(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_REG_SYSOR, register_cb, NULL); snmp_register_callback(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_UNREG_SYSOR, unregister_cb, NULL); #ifdef USING_MIBII_SYSTEM_MIB_MODULE if (++system_module_count == 3) REGISTER_SYSOR_TABLE(system_module_oid, system_module_oid_len, "The MIB module for SNMPv2 entities"); #endif } void shutdown_sysORTable(void) { #ifdef USING_MIBII_SYSTEM_MIB_MODULE if (system_module_count-- == 3) UNREGISTER_SYSOR_TABLE(system_module_oid, system_module_oid_len); #endif snmp_unregister_callback(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_UNREG_SYSOR, unregister_cb, NULL, 1); snmp_unregister_callback(SNMP_CALLBACK_APPLICATION, SNMPD_CALLBACK_REG_SYSOR, register_cb, NULL, 1); if (table) CONTAINER_CLEAR(table, netsnmp_container_simple_free, NULL); netsnmp_container_table_unregister(sysORTable_reg); sysORTable_reg = NULL; table = NULL; netsnmp_table_registration_info_free(sysORTable_table_info); sysORTable_table_info = NULL; netsnmp_unregister_handler(sysORLastChange_reg); sysORLastChange_reg = NULL; }