#include #include #if HAVE_STRING_H #include #else #include #endif #include #include #include #include #include #include #if HAVE_DMALLOC_H #include #endif /** @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; } } 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_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 */ case MODE_SET_RESERVE1: case MODE_SET_RESERVE2: case MODE_SET_ACTION: case MODE_SET_COMMIT: case MODE_SET_UNDO: case MODE_SET_FREE: 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 = root_tmp; ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reginfo->rootoid = root_save; reginfo->rootoid_len--; 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->ubound) return SNMP_ERR_NOERROR; root_tmp[reginfo->rootoid_len++] = subid; 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->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); requests->requestvb->name[reginfo->rootoid_len-1] = ++subid; requests->requestvb->type = ASN_PRIV_RETRY; } reginfo->rootoid = root_save; reginfo->rootoid_len--; return ret; } /* * got here only if illegal mode found */ return SNMP_ERR_GENERR; } /* * @} */