| #include <net-snmp/net-snmp-config.h> |
| |
| #include <stdlib.h> |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| |
| #include <net-snmp/agent/watcher.h> |
| #include <net-snmp/agent/instance.h> |
| #include <net-snmp/agent/scalar.h> |
| |
| /** @defgroup watcher watcher |
| * Watch a specified variable and process it as an instance or scalar object |
| * @ingroup leaf |
| * @{ |
| */ |
| netsnmp_mib_handler * |
| netsnmp_get_watcher_handler(void) |
| { |
| netsnmp_mib_handler *ret = NULL; |
| |
| ret = netsnmp_create_handler("watcher", |
| netsnmp_watcher_helper_handler); |
| if (ret) { |
| ret->flags |= MIB_HANDLER_AUTO_NEXT; |
| } |
| return ret; |
| } |
| |
| netsnmp_watcher_info * |
| netsnmp_create_watcher_info(void *data, size_t size, u_char type, int flags) |
| { |
| netsnmp_watcher_info *winfo = SNMP_MALLOC_TYPEDEF(netsnmp_watcher_info); |
| |
| winfo->data = data; |
| winfo->data_size = size; |
| winfo->max_size = size; /* Probably wrong for non-fixed size data */ |
| winfo->type = type; |
| if (flags) |
| winfo->flags = flags; |
| else |
| winfo->flags = WATCHER_FIXED_SIZE; |
| |
| return winfo; |
| } |
| |
| int |
| netsnmp_register_watched_instance(netsnmp_handler_registration *reginfo, |
| netsnmp_watcher_info *watchinfo) |
| { |
| netsnmp_mib_handler *whandler; |
| |
| whandler = netsnmp_get_watcher_handler(); |
| whandler->myvoid = (void *)watchinfo; |
| |
| netsnmp_inject_handler(reginfo, whandler); |
| return netsnmp_register_instance(reginfo); |
| } |
| |
| int |
| netsnmp_register_watched_scalar(netsnmp_handler_registration *reginfo, |
| netsnmp_watcher_info *watchinfo) |
| { |
| netsnmp_mib_handler *whandler; |
| |
| whandler = netsnmp_get_watcher_handler(); |
| whandler->myvoid = (void *)watchinfo; |
| |
| netsnmp_inject_handler(reginfo, whandler); |
| return netsnmp_register_scalar(reginfo); |
| } |
| |
| |
| |
| int |
| netsnmp_watcher_helper_handler(netsnmp_mib_handler *handler, |
| netsnmp_handler_registration *reginfo, |
| netsnmp_agent_request_info *reqinfo, |
| netsnmp_request_info *requests) |
| { |
| netsnmp_watcher_info *winfo = (netsnmp_watcher_info *) handler->myvoid; |
| u_char *old_data; |
| |
| DEBUGMSGTL(("helper:watcher", "Got request: %d\n", reqinfo->mode)); |
| DEBUGMSGTL(( "helper:watcher", " oid:")); |
| DEBUGMSGOID(("helper:watcher", requests->requestvb->name, |
| requests->requestvb->name_length)); |
| DEBUGMSG(( "helper:watcher", "\n")); |
| |
| switch (reqinfo->mode) { |
| /* |
| * data requests |
| */ |
| case MODE_GET: |
| snmp_set_var_typed_value(requests->requestvb, |
| winfo->type, |
| winfo->data, |
| winfo->data_size); |
| break; |
| |
| /* |
| * SET requests. Should only get here if registered RWRITE |
| */ |
| case MODE_SET_RESERVE1: |
| if (requests->requestvb->type != winfo->type) { |
| netsnmp_set_request_error(reqinfo, requests, |
| SNMP_ERR_WRONGTYPE); |
| handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; |
| } |
| |
| if (((winfo->flags & WATCHER_MAX_SIZE) && |
| requests->requestvb->val_len > winfo->max_size) || |
| ((winfo->flags & WATCHER_FIXED_SIZE) && |
| requests->requestvb->val_len != winfo->data_size)) { |
| netsnmp_set_request_error(reqinfo, requests, |
| SNMP_ERR_WRONGLENGTH); |
| handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; |
| } |
| break; |
| |
| case MODE_SET_RESERVE2: |
| /* |
| * store old info for undo later |
| */ |
| old_data = netsnmp_memdup(winfo->data, winfo->data_size); |
| if (old_data == NULL) { |
| netsnmp_set_request_error(reqinfo, requests, |
| SNMP_ERR_RESOURCEUNAVAILABLE); |
| handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; |
| return SNMP_ERR_NOERROR; |
| } |
| netsnmp_request_add_list_data(requests, |
| netsnmp_create_data_list |
| ("watcher", old_data, free)); |
| break; |
| |
| case MODE_SET_FREE: |
| /* |
| * nothing to do |
| */ |
| break; |
| |
| case MODE_SET_ACTION: |
| /* |
| * update current |
| */ |
| memcpy(winfo->data, (void *)requests->requestvb->val.string, |
| requests->requestvb->val_len); |
| break; |
| |
| case MODE_SET_UNDO: |
| memcpy(winfo->data, |
| netsnmp_request_get_list_data(requests, "watcher"), |
| winfo->data_size); |
| break; |
| |
| case MODE_SET_COMMIT: |
| winfo->data_size = requests->requestvb->val_len; |
| break; |
| |
| } |
| |
| /* next handler called automatically - 'AUTO_NEXT' */ |
| return SNMP_ERR_NOERROR; |
| } |
| |
| |
| /*************************** |
| * |
| * A specialised form of the above, reporting |
| * the sysUpTime indicated by a given timestamp |
| * |
| ***************************/ |
| |
| netsnmp_mib_handler * |
| netsnmp_get_watched_timestamp_handler(void) |
| { |
| netsnmp_mib_handler *ret = NULL; |
| |
| ret = netsnmp_create_handler("watcher-timestamp", |
| netsnmp_watched_timestamp_handler); |
| if (ret) { |
| ret->flags |= MIB_HANDLER_AUTO_NEXT; |
| } |
| return ret; |
| } |
| |
| int |
| netsnmp_watched_timestamp_register(netsnmp_mib_handler *whandler, |
| netsnmp_handler_registration *reginfo, |
| marker_t timestamp) |
| { |
| whandler->myvoid = (void *)timestamp; |
| netsnmp_inject_handler(reginfo, whandler); |
| return netsnmp_register_scalar(reginfo); /* XXX - or instance? */ |
| } |
| |
| int |
| netsnmp_register_watched_timestamp(netsnmp_handler_registration *reginfo, |
| marker_t timestamp) |
| { |
| netsnmp_mib_handler *whandler; |
| |
| whandler = netsnmp_get_watched_timestamp_handler(); |
| |
| return netsnmp_watched_timestamp_register(whandler, reginfo, timestamp); |
| } |
| |
| |
| int |
| netsnmp_watched_timestamp_handler(netsnmp_mib_handler *handler, |
| netsnmp_handler_registration *reginfo, |
| netsnmp_agent_request_info *reqinfo, |
| netsnmp_request_info *requests) |
| { |
| marker_t timestamp = (marker_t) handler->myvoid; |
| long uptime; |
| |
| DEBUGMSGTL(("helper:watcher:timestamp", |
| "Got request: %d\n", reqinfo->mode)); |
| DEBUGMSGTL(( "helper:watcher:timestamp", " oid:")); |
| DEBUGMSGOID(("helper:watcher:timestamp", requests->requestvb->name, |
| requests->requestvb->name_length)); |
| DEBUGMSG(( "helper:watcher:timestamp", "\n")); |
| |
| switch (reqinfo->mode) { |
| /* |
| * data requests |
| */ |
| case MODE_GET: |
| if (handler->flags & NETSNMP_WATCHER_DIRECT) |
| uptime = * (long*)timestamp; |
| else |
| uptime = netsnmp_marker_uptime( timestamp ); |
| snmp_set_var_typed_value(requests->requestvb, |
| ASN_TIMETICKS, |
| (u_char *) &uptime, |
| sizeof(uptime)); |
| break; |
| |
| /* |
| * Timestamps are inherently Read-Only, |
| * so don't need to support SET requests. |
| */ |
| case MODE_SET_RESERVE1: |
| netsnmp_set_request_error(reqinfo, requests, |
| SNMP_ERR_NOTWRITABLE); |
| handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; |
| return SNMP_ERR_NOTWRITABLE; |
| } |
| |
| /* next handler called automatically - 'AUTO_NEXT' */ |
| return SNMP_ERR_NOERROR; |
| } |
| |
| /*************************** |
| * |
| * Another specialised form of the above, |
| * implementing a 'TestAndIncr' spinlock |
| * |
| ***************************/ |
| |
| netsnmp_mib_handler * |
| netsnmp_get_watched_spinlock_handler(void) |
| { |
| netsnmp_mib_handler *ret = NULL; |
| |
| ret = netsnmp_create_handler("watcher-spinlock", |
| netsnmp_watched_spinlock_handler); |
| if (ret) { |
| ret->flags |= MIB_HANDLER_AUTO_NEXT; |
| } |
| return ret; |
| } |
| |
| int |
| netsnmp_register_watched_spinlock(netsnmp_handler_registration *reginfo, |
| int *spinlock) |
| { |
| netsnmp_mib_handler *whandler; |
| netsnmp_watcher_info *winfo; |
| |
| whandler = netsnmp_get_watched_spinlock_handler(); |
| whandler->myvoid = (void *)spinlock; |
| winfo = netsnmp_create_watcher_info((void *)spinlock, |
| sizeof(int), ASN_INTEGER, WATCHER_FIXED_SIZE); |
| netsnmp_inject_handler(reginfo, whandler); |
| return netsnmp_register_watched_scalar(reginfo, winfo); |
| } |
| |
| |
| int |
| netsnmp_watched_spinlock_handler(netsnmp_mib_handler *handler, |
| netsnmp_handler_registration *reginfo, |
| netsnmp_agent_request_info *reqinfo, |
| netsnmp_request_info *requests) |
| { |
| int *spinlock = (int *) handler->myvoid; |
| netsnmp_request_info *request; |
| |
| DEBUGMSGTL(("helper:watcher:spinlock", |
| "Got request: %d\n", reqinfo->mode)); |
| DEBUGMSGTL(( "helper:watcher:spinlock", " oid:")); |
| DEBUGMSGOID(("helper:watcher:spinlock", requests->requestvb->name, |
| requests->requestvb->name_length)); |
| DEBUGMSG(( "helper:watcher:spinlock", "\n")); |
| |
| switch (reqinfo->mode) { |
| /* |
| * Ensure the assigned value matches the current one |
| */ |
| case MODE_SET_RESERVE1: |
| for (request=requests; request; request=request->next) { |
| if (request->processed) |
| continue; |
| |
| if (*request->requestvb->val.integer != *spinlock) { |
| netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGVALUE); |
| handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; |
| return SNMP_ERR_WRONGVALUE; |
| |
| } |
| } |
| break; |
| |
| /* |
| * Everything else worked, so increment the spinlock |
| */ |
| case MODE_SET_COMMIT: |
| (*spinlock)++; |
| break; |
| } |
| |
| /* next handler called automatically - 'AUTO_NEXT' */ |
| return SNMP_ERR_NOERROR; |
| } |
| |
| /*************************** |
| * |
| * Convenience registration routines - modelled on |
| * the equivalent netsnmp_register_*_instance() calls |
| * |
| ***************************/ |
| |
| int |
| netsnmp_register_ulong_scalar(const char *name, |
| oid * reg_oid, size_t reg_oid_len, |
| u_long * it, |
| Netsnmp_Node_Handler * subhandler) |
| { |
| return netsnmp_register_watched_scalar( |
| netsnmp_create_handler_registration( |
| name, subhandler, |
| reg_oid, reg_oid_len, |
| HANDLER_CAN_RWRITE ), |
| netsnmp_create_watcher_info( |
| (void *)it, sizeof( u_long ), |
| ASN_UNSIGNED, WATCHER_FIXED_SIZE )); |
| } |
| |
| int |
| netsnmp_register_read_only_ulong_scalar(const char *name, |
| oid * reg_oid, size_t reg_oid_len, |
| u_long * it, |
| Netsnmp_Node_Handler * subhandler) |
| { |
| return netsnmp_register_watched_scalar( |
| netsnmp_create_handler_registration( |
| name, subhandler, |
| reg_oid, reg_oid_len, |
| HANDLER_CAN_RONLY ), |
| netsnmp_create_watcher_info( |
| (void *)it, sizeof( u_long ), |
| ASN_UNSIGNED, WATCHER_FIXED_SIZE )); |
| } |
| |
| int |
| netsnmp_register_long_scalar(const char *name, |
| oid * reg_oid, size_t reg_oid_len, |
| long * it, |
| Netsnmp_Node_Handler * subhandler) |
| { |
| return netsnmp_register_watched_scalar( |
| netsnmp_create_handler_registration( |
| name, subhandler, |
| reg_oid, reg_oid_len, |
| HANDLER_CAN_RWRITE ), |
| netsnmp_create_watcher_info( |
| (void *)it, sizeof( long ), |
| ASN_INTEGER, WATCHER_FIXED_SIZE )); |
| } |
| |
| int |
| netsnmp_register_read_only_long_scalar(const char *name, |
| oid * reg_oid, size_t reg_oid_len, |
| long * it, |
| Netsnmp_Node_Handler * subhandler) |
| { |
| return netsnmp_register_watched_scalar( |
| netsnmp_create_handler_registration( |
| name, subhandler, |
| reg_oid, reg_oid_len, |
| HANDLER_CAN_RONLY ), |
| netsnmp_create_watcher_info( |
| (void *)it, sizeof( long ), |
| ASN_INTEGER, WATCHER_FIXED_SIZE )); |
| } |
| |
| |
| int |
| netsnmp_register_int_scalar(const char *name, |
| oid * reg_oid, size_t reg_oid_len, |
| int * it, |
| Netsnmp_Node_Handler * subhandler) |
| { |
| return netsnmp_register_watched_scalar( |
| netsnmp_create_handler_registration( |
| name, subhandler, |
| reg_oid, reg_oid_len, |
| HANDLER_CAN_RWRITE ), |
| netsnmp_create_watcher_info( |
| (void *)it, sizeof( int ), |
| ASN_INTEGER, WATCHER_FIXED_SIZE )); |
| } |
| |
| int |
| netsnmp_register_read_only_int_scalar(const char *name, |
| oid * reg_oid, size_t reg_oid_len, |
| int * it, |
| Netsnmp_Node_Handler * subhandler) |
| { |
| return netsnmp_register_watched_scalar( |
| netsnmp_create_handler_registration( |
| name, subhandler, |
| reg_oid, reg_oid_len, |
| HANDLER_CAN_RONLY ), |
| netsnmp_create_watcher_info( |
| (void *)it, sizeof( int ), |
| ASN_INTEGER, WATCHER_FIXED_SIZE )); |
| } |
| |
| |
| int |
| netsnmp_register_read_only_counter32_scalar(const char *name, |
| oid * reg_oid, size_t reg_oid_len, |
| u_long * it, |
| Netsnmp_Node_Handler * subhandler) |
| { |
| return netsnmp_register_watched_scalar( |
| netsnmp_create_handler_registration( |
| name, subhandler, |
| reg_oid, reg_oid_len, |
| HANDLER_CAN_RONLY ), |
| netsnmp_create_watcher_info( |
| (void *)it, sizeof( u_long ), |
| ASN_COUNTER, WATCHER_FIXED_SIZE )); |
| } |
| /** @} */ |
| |