| #include <net-snmp/net-snmp-config.h> |
| #include <net-snmp/net-snmp-features.h> |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| #include <net-snmp/agent/scalar.h> |
| |
| #ifdef HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| |
| #include <net-snmp/agent/cache_handler.h> |
| #include "agent/nsCache.h" |
| |
| netsnmp_feature_require(cache_get_head) |
| |
| |
| /* |
| * use unadvertised function to get cache head. You really should not |
| * do this, since the internal storage mechanism might change. |
| */ |
| extern netsnmp_cache *netsnmp_cache_get_head(void); |
| |
| |
| #define nsCache 1, 3, 6, 1, 4, 1, 8072, 1, 5 |
| |
| /* |
| * OIDs for the cacheging control scalar objects |
| * |
| * Note that these we're registering the full object rather |
| * than the (sole) valid instance in each case, in order |
| * to handle requests for invalid instances properly. |
| */ |
| |
| /* |
| * ... and for the cache table. |
| */ |
| |
| #define NSCACHE_TIMEOUT 2 |
| #define NSCACHE_STATUS 3 |
| |
| #define NSCACHE_STATUS_ENABLED 1 |
| #define NSCACHE_STATUS_DISABLED 2 |
| #define NSCACHE_STATUS_EMPTY 3 |
| #define NSCACHE_STATUS_ACTIVE 4 |
| #define NSCACHE_STATUS_EXPIRED 5 |
| |
| NETSNMP_IMPORT struct snmp_alarm * |
| sa_find_specific(unsigned int clientreg); |
| |
| |
| void |
| init_nsCache(void) |
| { |
| const oid nsCacheTimeout_oid[] = { nsCache, 1 }; |
| const oid nsCacheEnabled_oid[] = { nsCache, 2 }; |
| const oid nsCacheTable_oid[] = { nsCache, 3 }; |
| |
| netsnmp_table_registration_info *table_info; |
| netsnmp_iterator_info *iinfo; |
| |
| /* |
| * Register the scalar objects... |
| */ |
| DEBUGMSGTL(("nsCacheScalars", "Initializing\n")); |
| netsnmp_register_scalar( |
| netsnmp_create_handler_registration( |
| "nsCacheTimeout", handle_nsCacheTimeout, |
| nsCacheTimeout_oid, OID_LENGTH(nsCacheTimeout_oid), |
| HANDLER_CAN_RWRITE) |
| ); |
| netsnmp_register_scalar( |
| netsnmp_create_handler_registration( |
| "nsCacheEnabled", handle_nsCacheEnabled, |
| nsCacheEnabled_oid, OID_LENGTH(nsCacheEnabled_oid), |
| HANDLER_CAN_RWRITE) |
| ); |
| |
| /* |
| * ... and the table. |
| * We need to define the column structure and indexing.... |
| */ |
| |
| table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); |
| if (!table_info) { |
| return; |
| } |
| netsnmp_table_helper_add_indexes(table_info, ASN_PRIV_IMPLIED_OBJECT_ID, 0); |
| table_info->min_column = NSCACHE_TIMEOUT; |
| table_info->max_column = NSCACHE_STATUS; |
| |
| |
| /* |
| * .... and the iteration information .... |
| */ |
| iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info); |
| if (!iinfo) { |
| return; |
| } |
| iinfo->get_first_data_point = get_first_cache_entry; |
| iinfo->get_next_data_point = get_next_cache_entry; |
| iinfo->table_reginfo = table_info; |
| |
| |
| /* |
| * .... and register the table with the agent. |
| */ |
| netsnmp_register_table_iterator2( |
| netsnmp_create_handler_registration( |
| "tzCacheTable", handle_nsCacheTable, |
| nsCacheTable_oid, OID_LENGTH(nsCacheTable_oid), |
| HANDLER_CAN_RWRITE), |
| iinfo); |
| } |
| |
| |
| /* |
| * nsCache scalar handling |
| */ |
| |
| int |
| handle_nsCacheTimeout(netsnmp_mib_handler *handler, |
| netsnmp_handler_registration *reginfo, |
| netsnmp_agent_request_info *reqinfo, |
| netsnmp_request_info *requests) |
| { |
| long cache_default_timeout = |
| netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, |
| NETSNMP_DS_AGENT_CACHE_TIMEOUT); |
| netsnmp_request_info *request=NULL; |
| |
| switch (reqinfo->mode) { |
| |
| case MODE_GET: |
| for (request = requests; request; request=request->next) { |
| snmp_set_var_typed_value(request->requestvb, ASN_INTEGER, |
| (u_char*)&cache_default_timeout, |
| sizeof(cache_default_timeout)); |
| } |
| break; |
| |
| |
| #ifndef NETSNMP_NO_WRITE_SUPPORT |
| case MODE_SET_RESERVE1: |
| for (request = requests; request; request=request->next) { |
| if ( request->status != 0 ) { |
| return SNMP_ERR_NOERROR; /* Already got an error */ |
| } |
| if ( request->requestvb->type != ASN_INTEGER ) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if ( *request->requestvb->val.integer < 0 ) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE); |
| return SNMP_ERR_WRONGVALUE; |
| } |
| } |
| break; |
| |
| case MODE_SET_COMMIT: |
| netsnmp_ds_set_int(NETSNMP_DS_APPLICATION_ID, |
| NETSNMP_DS_AGENT_CACHE_TIMEOUT, |
| *requests->requestvb->val.integer); |
| break; |
| #endif /* !NETSNMP_NO_WRITE_SUPPORT */ |
| } |
| |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| int |
| handle_nsCacheEnabled(netsnmp_mib_handler *handler, |
| netsnmp_handler_registration *reginfo, |
| netsnmp_agent_request_info *reqinfo, |
| netsnmp_request_info *requests) |
| { |
| long enabled; |
| netsnmp_request_info *request=NULL; |
| |
| switch (reqinfo->mode) { |
| |
| case MODE_GET: |
| enabled = (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, |
| NETSNMP_DS_AGENT_NO_CACHING) |
| ? NSCACHE_STATUS_ENABLED /* Actually True/False */ |
| : NSCACHE_STATUS_DISABLED ); |
| for (request = requests; request; request=request->next) { |
| snmp_set_var_typed_value(request->requestvb, ASN_INTEGER, |
| (u_char*)&enabled, sizeof(enabled)); |
| } |
| break; |
| |
| |
| #ifndef NETSNMP_NO_WRITE_SUPPORT |
| case MODE_SET_RESERVE1: |
| for (request = requests; request; request=request->next) { |
| if ( request->status != 0 ) { |
| return SNMP_ERR_NOERROR; /* Already got an error */ |
| } |
| if ( request->requestvb->type != ASN_INTEGER ) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if ((*request->requestvb->val.integer != NSCACHE_STATUS_ENABLED) && |
| (*request->requestvb->val.integer != NSCACHE_STATUS_DISABLED)) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE); |
| return SNMP_ERR_WRONGVALUE; |
| } |
| } |
| break; |
| |
| case MODE_SET_COMMIT: |
| enabled = *requests->requestvb->val.integer; |
| if (enabled == NSCACHE_STATUS_DISABLED) |
| enabled = 0; |
| netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, |
| NETSNMP_DS_AGENT_NO_CACHING, enabled); |
| break; |
| #endif /* !NETSNMP_NO_WRITE_SUPPORT */ |
| } |
| |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| /* |
| * nsCacheTable handling |
| */ |
| |
| netsnmp_variable_list * |
| get_first_cache_entry(void **loop_context, void **data_context, |
| netsnmp_variable_list *index, |
| netsnmp_iterator_info *data) |
| { |
| netsnmp_cache *cache_head = netsnmp_cache_get_head(); |
| |
| if ( !cache_head ) |
| return NULL; |
| |
| snmp_set_var_value(index, (u_char*)cache_head->rootoid, |
| sizeof(oid) * cache_head->rootoid_len); |
| *loop_context = (void*)cache_head; |
| *data_context = (void*)cache_head; |
| return index; |
| } |
| |
| netsnmp_variable_list * |
| get_next_cache_entry(void **loop_context, void **data_context, |
| netsnmp_variable_list *index, |
| netsnmp_iterator_info *data) |
| { |
| netsnmp_cache *cache = (netsnmp_cache *)*loop_context; |
| cache = cache->next; |
| |
| if ( !cache ) |
| return NULL; |
| |
| snmp_set_var_value(index, (u_char*)cache->rootoid, |
| sizeof(oid) * cache->rootoid_len); |
| *loop_context = (void*)cache; |
| *data_context = (void*)cache; |
| return index; |
| } |
| |
| |
| int |
| handle_nsCacheTable(netsnmp_mib_handler *handler, |
| netsnmp_handler_registration *reginfo, |
| netsnmp_agent_request_info *reqinfo, |
| netsnmp_request_info *requests) |
| { |
| long status; |
| netsnmp_request_info *request = NULL; |
| netsnmp_table_request_info *table_info = NULL; |
| netsnmp_cache *cache_entry = NULL; |
| |
| switch (reqinfo->mode) { |
| |
| case MODE_GET: |
| for (request=requests; request; request=request->next) { |
| if (request->processed != 0) |
| continue; |
| |
| cache_entry = (netsnmp_cache*)netsnmp_extract_iterator_context(request); |
| table_info = netsnmp_extract_table_info(request); |
| |
| switch (table_info->colnum) { |
| case NSCACHE_TIMEOUT: |
| if (!cache_entry) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); |
| continue; |
| } |
| status = cache_entry->timeout; |
| snmp_set_var_typed_value(request->requestvb, ASN_INTEGER, |
| (u_char*)&status, sizeof(status)); |
| break; |
| |
| case NSCACHE_STATUS: |
| if (!cache_entry) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); |
| continue; |
| } |
| status = (cache_entry->enabled ? |
| (cache_entry->timestampM ? |
| (cache_entry->timeout >= 0 && |
| !netsnmp_ready_monotonic(cache_entry->timestampM, |
| 1000*cache_entry->timeout) ? |
| NSCACHE_STATUS_ACTIVE: |
| NSCACHE_STATUS_EXPIRED) : |
| NSCACHE_STATUS_EMPTY) : |
| NSCACHE_STATUS_DISABLED); |
| snmp_set_var_typed_value(request->requestvb, ASN_INTEGER, |
| (u_char*)&status, sizeof(status)); |
| break; |
| |
| default: |
| netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHOBJECT); |
| continue; |
| } |
| } |
| break; |
| |
| |
| #ifndef NETSNMP_NO_WRITE_SUPPORT |
| case MODE_SET_RESERVE1: |
| for (request=requests; request; request=request->next) { |
| if (request->processed != 0) |
| continue; |
| if ( request->status != 0 ) { |
| return SNMP_ERR_NOERROR; /* Already got an error */ |
| } |
| cache_entry = (netsnmp_cache*)netsnmp_extract_iterator_context(request); |
| table_info = netsnmp_extract_table_info(request); |
| |
| switch (table_info->colnum) { |
| case NSCACHE_TIMEOUT: |
| if (!cache_entry) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION); |
| return SNMP_ERR_NOCREATION; |
| } |
| if ( request->requestvb->type != ASN_INTEGER ) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| if (*request->requestvb->val.integer < 0 ) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE); |
| return SNMP_ERR_WRONGVALUE; |
| } |
| break; |
| |
| case NSCACHE_STATUS: |
| if (!cache_entry) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION); |
| return SNMP_ERR_NOCREATION; |
| } |
| if ( request->requestvb->type != ASN_INTEGER ) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGTYPE); |
| return SNMP_ERR_WRONGTYPE; |
| } |
| status = *request->requestvb->val.integer; |
| if (!((status == NSCACHE_STATUS_ENABLED ) || |
| (status == NSCACHE_STATUS_DISABLED ) || |
| (status == NSCACHE_STATUS_EMPTY ))) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_WRONGVALUE); |
| return SNMP_ERR_WRONGVALUE; |
| } |
| break; |
| |
| default: |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_NOCREATION); |
| return SNMP_ERR_NOCREATION; /* XXX - is this right ? */ |
| } |
| } |
| break; |
| |
| |
| case MODE_SET_COMMIT: |
| for (request=requests; request; request=request->next) { |
| if (request->processed != 0) |
| continue; |
| if ( request->status != 0 ) { |
| return SNMP_ERR_NOERROR; /* Already got an error */ |
| } |
| cache_entry = (netsnmp_cache*)netsnmp_extract_iterator_context(request); |
| if (!cache_entry) { |
| netsnmp_set_request_error(reqinfo, request, SNMP_ERR_COMMITFAILED); |
| return SNMP_ERR_COMMITFAILED; /* Shouldn't happen! */ |
| } |
| table_info = netsnmp_extract_table_info(request); |
| |
| switch (table_info->colnum) { |
| case NSCACHE_TIMEOUT: |
| cache_entry->timeout = *request->requestvb->val.integer; |
| /* |
| * check for auto repeat |
| */ |
| if (cache_entry->timer_id) { |
| struct snmp_alarm * sa = |
| sa_find_specific(cache_entry->timer_id); |
| if (NULL != sa) |
| sa->t.tv_sec = cache_entry->timeout; |
| } |
| break; |
| |
| case NSCACHE_STATUS: |
| switch (*request->requestvb->val.integer) { |
| case NSCACHE_STATUS_ENABLED: |
| cache_entry->enabled = 1; |
| break; |
| case NSCACHE_STATUS_DISABLED: |
| cache_entry->enabled = 0; |
| break; |
| case NSCACHE_STATUS_EMPTY: |
| cache_entry->free_cache(cache_entry, cache_entry->magic); |
| free(cache_entry->timestampM); |
| cache_entry->timestampM = NULL; |
| break; |
| } |
| break; |
| } |
| } |
| break; |
| #endif /* !NETSNMP_NO_WRITE_SUPPORT */ |
| } |
| |
| return SNMP_ERR_NOERROR; |
| } |