blob: 9cbb4d320c8e8aa15efec5ba7b6b5829395e0da6 [file] [log] [blame]
#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 ));
}
/** @} */