diff options
Diffstat (limited to 'agent/helpers/scalar_group.c')
-rw-r--r-- | agent/helpers/scalar_group.c | 209 |
1 files changed, 209 insertions, 0 deletions
diff --git a/agent/helpers/scalar_group.c b/agent/helpers/scalar_group.c new file mode 100644 index 0000000..6b7f098 --- /dev/null +++ b/agent/helpers/scalar_group.c @@ -0,0 +1,209 @@ +#include <net-snmp/net-snmp-config.h> + +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> + +#include <net-snmp/agent/scalar_group.h> + +#include <stdlib.h> +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif + +#include <net-snmp/agent/instance.h> +#include <net-snmp/agent/serialize.h> + +static netsnmp_scalar_group* +clone_scalar_group(netsnmp_scalar_group* src) +{ + netsnmp_scalar_group *t = SNMP_MALLOC_TYPEDEF(netsnmp_scalar_group); + if(t != NULL) { + t->lbound = src->lbound; + t->ubound = src->ubound; + } + return t; +} + +/** @defgroup scalar_group_group scalar_group + * Process groups of scalars. + * @ingroup leaf + * @{ + */ +netsnmp_mib_handler * +netsnmp_get_scalar_group_handler(oid first, oid last) +{ + netsnmp_mib_handler *ret = NULL; + netsnmp_scalar_group *sgroup = NULL; + + ret = netsnmp_create_handler("scalar_group", + netsnmp_scalar_group_helper_handler); + if (ret) { + sgroup = SNMP_MALLOC_TYPEDEF(netsnmp_scalar_group); + if (NULL == sgroup) { + netsnmp_handler_free(ret); + ret = NULL; + } + else { + sgroup->lbound = first; + sgroup->ubound = last; + ret->myvoid = (void *)sgroup; + ret->data_free = free; + ret->data_clone = (void *(*)(void *))clone_scalar_group; + } + } + return ret; +} + +int +netsnmp_register_scalar_group(netsnmp_handler_registration *reginfo, + oid first, oid last) +{ + netsnmp_inject_handler(reginfo, netsnmp_get_instance_handler()); + netsnmp_inject_handler(reginfo, netsnmp_get_scalar_group_handler(first, last)); + return netsnmp_register_serialize(reginfo); +} + + +int +netsnmp_scalar_group_helper_handler(netsnmp_mib_handler *handler, + netsnmp_handler_registration *reginfo, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + netsnmp_variable_list *var = requests->requestvb; + + netsnmp_scalar_group *sgroup = (netsnmp_scalar_group *)handler->myvoid; + int ret, cmp; + int namelen; + oid subid, root_tmp[MAX_OID_LEN], *root_save; + + DEBUGMSGTL(("helper:scalar_group", "Got request:\n")); + namelen = SNMP_MIN(requests->requestvb->name_length, + reginfo->rootoid_len); + cmp = snmp_oid_compare(requests->requestvb->name, namelen, + reginfo->rootoid, reginfo->rootoid_len); + + DEBUGMSGTL(( "helper:scalar_group", " cmp=%d, oid:", cmp)); + DEBUGMSGOID(("helper:scalar_group", var->name, var->name_length)); + DEBUGMSG(( "helper:scalar_group", "\n")); + + /* + * copy root oid to root_tmp, set instance to 0. (subid set later on) + * save rootoid, since we'll replace it before calling next handler, + * and need to restore it afterwards. + */ + memcpy(root_tmp, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid)); + root_tmp[reginfo->rootoid_len + 1] = 0; + root_save = reginfo->rootoid; + + ret = SNMP_ERR_NOCREATION; + switch (reqinfo->mode) { + /* + * The handling of "exact" requests is basically the same. + * The only difference between GET and SET requests is the + * error/exception to return on failure. + */ + case MODE_GET: + ret = SNMP_NOSUCHOBJECT; + /* Fallthrough */ + +#ifndef NETSNMP_NO_WRITE_SUPPORT + case MODE_SET_RESERVE1: + case MODE_SET_RESERVE2: + case MODE_SET_ACTION: + case MODE_SET_COMMIT: + case MODE_SET_UNDO: + case MODE_SET_FREE: +#endif /* NETSNMP_NO_WRITE_SUPPORT */ + if (cmp != 0 || + requests->requestvb->name_length <= reginfo->rootoid_len) { + /* + * Common prefix doesn't match, or only *just* matches + * the registered root (so can't possibly match a scalar) + */ + netsnmp_set_request_error(reqinfo, requests, ret); + return SNMP_ERR_NOERROR; + } else { + /* + * Otherwise, + * extract the object subidentifier from the request, + * check this is (probably) valid, and then fudge the + * registered 'rootoid' to match, before passing the + * request off to the next handler ('scalar'). + * + * Note that we don't bother checking instance subidentifiers + * here. That's left to the scalar helper. + */ + subid = requests->requestvb->name[reginfo->rootoid_len]; + if (subid < sgroup->lbound || + subid > sgroup->ubound) { + netsnmp_set_request_error(reqinfo, requests, ret); + return SNMP_ERR_NOERROR; + } + root_tmp[reginfo->rootoid_len] = subid; + reginfo->rootoid_len += 2; + reginfo->rootoid = root_tmp; + ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, + requests); + reginfo->rootoid = root_save; + reginfo->rootoid_len -= 2; + return ret; + } + break; + + case MODE_GETNEXT: + /* + * If we're being asked for something before (or exactly matches) + * the registered root OID, then start with the first object. + * If we're being asked for something that exactly matches an object + * OID, then that's what we pass down. + * Otherwise, we pass down the OID of the *next* object.... + */ + if (cmp < 0 || + requests->requestvb->name_length <= reginfo->rootoid_len) { + subid = sgroup->lbound; + } else if (requests->requestvb->name_length == reginfo->rootoid_len+1) + subid = requests->requestvb->name[reginfo->rootoid_len]; + else + subid = requests->requestvb->name[reginfo->rootoid_len]+1; + + /* + * ... always assuming this is (potentially) valid, of course. + */ + if (subid < sgroup->lbound) + subid = sgroup->lbound; + else if (subid > sgroup->ubound) + return SNMP_ERR_NOERROR; + + root_tmp[reginfo->rootoid_len] = subid; + reginfo->rootoid_len += 2; + reginfo->rootoid = root_tmp; + ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, + requests); + /* + * If we didn't get an answer (due to holes in the group) + * set things up to retry again. + */ + if (!requests->delegated && + (requests->requestvb->type == ASN_NULL || + requests->requestvb->type == SNMP_NOSUCHOBJECT || + requests->requestvb->type == SNMP_NOSUCHINSTANCE)) { + snmp_set_var_objid(requests->requestvb, + reginfo->rootoid, reginfo->rootoid_len - 1); + requests->requestvb->name[reginfo->rootoid_len - 2] = ++subid; + requests->requestvb->type = ASN_PRIV_RETRY; + } + reginfo->rootoid = root_save; + reginfo->rootoid_len -= 2; + return ret; + } + /* + * got here only if illegal mode found + */ + return SNMP_ERR_GENERR; +} + +/** @} + */ |