892 lines
28 KiB
C
892 lines
28 KiB
C
/*
|
|
* agent_index.c
|
|
*
|
|
* Maintain a registry of index allocations
|
|
* (Primarily required for AgentX support,
|
|
* but it could be more widely useable).
|
|
*/
|
|
|
|
|
|
#include <net-snmp/net-snmp-config.h>
|
|
#include <net-snmp/net-snmp-features.h>
|
|
#include <signal.h>
|
|
#if HAVE_STRING_H
|
|
#include <string.h>
|
|
#endif
|
|
#if HAVE_STDLIB_H
|
|
#include <stdlib.h>
|
|
#endif
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#if TIME_WITH_SYS_TIME
|
|
# include <sys/time.h>
|
|
# include <time.h>
|
|
#else
|
|
# if HAVE_SYS_TIME_H
|
|
# include <sys/time.h>
|
|
# else
|
|
# include <time.h>
|
|
# endif
|
|
#endif
|
|
#if HAVE_NETINET_IN_H
|
|
#include <netinet/in.h>
|
|
#endif
|
|
|
|
#include <net-snmp/net-snmp-includes.h>
|
|
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
|
#include <net-snmp/agent/agent_callbacks.h>
|
|
#include <net-snmp/agent/agent_index.h>
|
|
|
|
#include "snmpd.h"
|
|
#include "agent_global_vars.h"
|
|
#include "mibgroup/struct.h"
|
|
#include <net-snmp/agent/table.h>
|
|
#include <net-snmp/agent/table_iterator.h>
|
|
|
|
#ifdef USING_AGENTX_SUBAGENT_MODULE
|
|
#include "agentx/subagent.h"
|
|
#include "agentx/client.h"
|
|
#endif
|
|
|
|
netsnmp_feature_child_of(agent_index_all, libnetsnmpagent)
|
|
|
|
netsnmp_feature_child_of(remove_index, agent_index_all)
|
|
|
|
/*
|
|
* Initial support for index allocation
|
|
*/
|
|
|
|
struct snmp_index {
|
|
netsnmp_variable_list *varbind; /* or pointer to var_list ? */
|
|
int allocated;
|
|
netsnmp_session *session;
|
|
struct snmp_index *next_oid;
|
|
struct snmp_index *prev_oid;
|
|
struct snmp_index *next_idx;
|
|
} *snmp_index_head = NULL;
|
|
|
|
/*
|
|
* The caller is responsible for free()ing the memory returned by
|
|
* this function.
|
|
*/
|
|
|
|
char *
|
|
register_string_index(oid * name, size_t name_len, char *cp)
|
|
{
|
|
netsnmp_variable_list varbind, *res;
|
|
|
|
memset(&varbind, 0, sizeof(netsnmp_variable_list));
|
|
varbind.type = ASN_OCTET_STR;
|
|
snmp_set_var_objid(&varbind, name, name_len);
|
|
if (cp != ANY_STRING_INDEX) {
|
|
snmp_set_var_value(&varbind, (u_char *) cp, strlen(cp));
|
|
res = register_index(&varbind, ALLOCATE_THIS_INDEX, main_session);
|
|
} else {
|
|
res = register_index(&varbind, ALLOCATE_ANY_INDEX, main_session);
|
|
}
|
|
|
|
if (res == NULL) {
|
|
return NULL;
|
|
} else {
|
|
char *rv = (char *)malloc(res->val_len + 1);
|
|
if (rv) {
|
|
memcpy(rv, res->val.string, res->val_len);
|
|
rv[res->val_len] = 0;
|
|
}
|
|
free(res);
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
int
|
|
register_int_index(oid * name, size_t name_len, int val)
|
|
{
|
|
netsnmp_variable_list varbind, *res;
|
|
|
|
memset(&varbind, 0, sizeof(netsnmp_variable_list));
|
|
varbind.type = ASN_INTEGER;
|
|
snmp_set_var_objid(&varbind, name, name_len);
|
|
varbind.val.string = varbind.buf;
|
|
if (val != ANY_INTEGER_INDEX) {
|
|
varbind.val_len = sizeof(long);
|
|
*varbind.val.integer = val;
|
|
res = register_index(&varbind, ALLOCATE_THIS_INDEX, main_session);
|
|
} else {
|
|
res = register_index(&varbind, ALLOCATE_ANY_INDEX, main_session);
|
|
}
|
|
|
|
if (res == NULL) {
|
|
return -1;
|
|
} else {
|
|
int rv = *(res->val.integer);
|
|
free(res);
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The caller is responsible for free()ing the memory returned by
|
|
* this function.
|
|
*/
|
|
|
|
netsnmp_variable_list *
|
|
register_oid_index(oid * name, size_t name_len,
|
|
oid * value, size_t value_len)
|
|
{
|
|
netsnmp_variable_list varbind;
|
|
|
|
memset(&varbind, 0, sizeof(netsnmp_variable_list));
|
|
varbind.type = ASN_OBJECT_ID;
|
|
snmp_set_var_objid(&varbind, name, name_len);
|
|
if (value != ANY_OID_INDEX) {
|
|
snmp_set_var_value(&varbind, (u_char *) value,
|
|
value_len * sizeof(oid));
|
|
return register_index(&varbind, ALLOCATE_THIS_INDEX, main_session);
|
|
} else {
|
|
return register_index(&varbind, ALLOCATE_ANY_INDEX, main_session);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The caller is responsible for free()ing the memory returned by
|
|
* this function.
|
|
*/
|
|
|
|
netsnmp_variable_list *
|
|
register_index(netsnmp_variable_list * varbind, int flags,
|
|
netsnmp_session * ss)
|
|
{
|
|
netsnmp_variable_list *rv = NULL;
|
|
struct snmp_index *new_index, *idxptr, *idxptr2;
|
|
struct snmp_index *prev_oid_ptr, *prev_idx_ptr;
|
|
int res, res2, i;
|
|
|
|
DEBUGMSGTL(("register_index", "register "));
|
|
DEBUGMSGVAR(("register_index", varbind));
|
|
DEBUGMSG(("register_index", "for session %8p\n", ss));
|
|
|
|
#if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING)
|
|
if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
|
|
NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) {
|
|
return (agentx_register_index(ss, varbind, flags));
|
|
}
|
|
#endif
|
|
/*
|
|
* Look for the requested OID entry
|
|
*/
|
|
prev_oid_ptr = NULL;
|
|
prev_idx_ptr = NULL;
|
|
res = 1;
|
|
res2 = 1;
|
|
for (idxptr = snmp_index_head; idxptr != NULL;
|
|
prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) {
|
|
if ((res = snmp_oid_compare(varbind->name, varbind->name_length,
|
|
idxptr->varbind->name,
|
|
idxptr->varbind->name_length)) <= 0)
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Found the OID - now look at the registered indices
|
|
*/
|
|
if (res == 0 && idxptr) {
|
|
if (varbind->type != idxptr->varbind->type)
|
|
return NULL; /* wrong type */
|
|
|
|
/*
|
|
* If we've been asked for an arbitrary new value,
|
|
* then find the end of the list.
|
|
* If we've been asked for any arbitrary value,
|
|
* then look for an unused entry, and use that.
|
|
* If there aren't any, continue as for new.
|
|
* Otherwise, locate the given value in the (sorted)
|
|
* list of already allocated values
|
|
*/
|
|
if (flags & ALLOCATE_ANY_INDEX) {
|
|
for (idxptr2 = idxptr; idxptr2 != NULL;
|
|
prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
|
|
|
|
if (flags == ALLOCATE_ANY_INDEX && !(idxptr2->allocated)) {
|
|
if ((rv =
|
|
snmp_clone_varbind(idxptr2->varbind)) != NULL) {
|
|
idxptr2->session = ss;
|
|
idxptr2->allocated = 1;
|
|
}
|
|
return rv;
|
|
}
|
|
}
|
|
} else {
|
|
for (idxptr2 = idxptr; idxptr2 != NULL;
|
|
prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
|
|
switch (varbind->type) {
|
|
case ASN_INTEGER:
|
|
res2 =
|
|
(*varbind->val.integer -
|
|
*idxptr2->varbind->val.integer);
|
|
break;
|
|
case ASN_OCTET_STR:
|
|
i = SNMP_MIN(varbind->val_len,
|
|
idxptr2->varbind->val_len);
|
|
res2 =
|
|
memcmp(varbind->val.string,
|
|
idxptr2->varbind->val.string, i);
|
|
break;
|
|
case ASN_OBJECT_ID:
|
|
res2 =
|
|
snmp_oid_compare(varbind->val.objid,
|
|
varbind->val_len / sizeof(oid),
|
|
idxptr2->varbind->val.objid,
|
|
idxptr2->varbind->val_len /
|
|
sizeof(oid));
|
|
break;
|
|
default:
|
|
return NULL; /* wrong type */
|
|
}
|
|
if (res2 <= 0)
|
|
break;
|
|
}
|
|
if (res2 == 0) {
|
|
if (idxptr2->allocated) {
|
|
/*
|
|
* No good: the index is in use.
|
|
*/
|
|
return NULL;
|
|
} else {
|
|
/*
|
|
* Okay, it's unallocated, we can just claim ownership
|
|
* here.
|
|
*/
|
|
if ((rv =
|
|
snmp_clone_varbind(idxptr2->varbind)) != NULL) {
|
|
idxptr2->session = ss;
|
|
idxptr2->allocated = 1;
|
|
}
|
|
return rv;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* OK - we've now located where the new entry needs to
|
|
* be fitted into the index registry tree
|
|
* To recap:
|
|
* 'prev_oid_ptr' points to the head of the OID index
|
|
* list prior to this one. If this is null, then
|
|
* it means that this is the first OID in the list.
|
|
* 'idxptr' points either to the head of this OID list,
|
|
* or the next OID (if this is a new OID request)
|
|
* These can be distinguished by the value of 'res'.
|
|
*
|
|
* 'prev_idx_ptr' points to the index entry that sorts
|
|
* immediately prior to the requested value (if any).
|
|
* If an arbitrary value is required, then this will
|
|
* point to the last allocated index.
|
|
* If this pointer is null, then either this is a new
|
|
* OID request, or the requested value is the first
|
|
* in the list.
|
|
* 'idxptr2' points to the next sorted index (if any)
|
|
* but is not actually needed any more.
|
|
*
|
|
* Clear? Good!
|
|
* I hope you've been paying attention.
|
|
* There'll be a test later :-)
|
|
*/
|
|
|
|
/*
|
|
* We proceed by creating the new entry
|
|
* (by copying the entry provided)
|
|
*/
|
|
new_index = (struct snmp_index *) calloc(1, sizeof(struct snmp_index));
|
|
if (new_index == NULL)
|
|
return NULL;
|
|
|
|
if (NULL == snmp_varlist_add_variable(&new_index->varbind,
|
|
varbind->name,
|
|
varbind->name_length,
|
|
varbind->type,
|
|
varbind->val.string,
|
|
varbind->val_len)) {
|
|
/*
|
|
* if (snmp_clone_var( varbind, new_index->varbind ) != 0 )
|
|
*/
|
|
free(new_index);
|
|
return NULL;
|
|
}
|
|
new_index->session = ss;
|
|
new_index->allocated = 1;
|
|
|
|
if (varbind->type == ASN_OCTET_STR && flags == ALLOCATE_THIS_INDEX)
|
|
new_index->varbind->val.string[new_index->varbind->val_len] = 0;
|
|
|
|
/*
|
|
* If we've been given a value, then we can use that, but
|
|
* otherwise, we need to create a new value for this entry.
|
|
* Note that ANY_INDEX and NEW_INDEX are both covered by this
|
|
* test (since NEW_INDEX & ANY_INDEX = ANY_INDEX, remember?)
|
|
*/
|
|
if (flags & ALLOCATE_ANY_INDEX) {
|
|
if (prev_idx_ptr) {
|
|
if (snmp_clone_var(prev_idx_ptr->varbind, new_index->varbind)
|
|
!= 0) {
|
|
free(new_index);
|
|
return NULL;
|
|
}
|
|
} else
|
|
new_index->varbind->val.string = new_index->varbind->buf;
|
|
|
|
switch (varbind->type) {
|
|
case ASN_INTEGER:
|
|
if (prev_idx_ptr) {
|
|
(*new_index->varbind->val.integer)++;
|
|
} else
|
|
*(new_index->varbind->val.integer) = 1;
|
|
new_index->varbind->val_len = sizeof(long);
|
|
break;
|
|
case ASN_OCTET_STR:
|
|
if (prev_idx_ptr) {
|
|
i = new_index->varbind->val_len - 1;
|
|
while (new_index->varbind->buf[i] == 'z') {
|
|
new_index->varbind->buf[i] = 'a';
|
|
i--;
|
|
if (i < 0) {
|
|
i = new_index->varbind->val_len;
|
|
new_index->varbind->buf[i] = 'a';
|
|
new_index->varbind->buf[i + 1] = 0;
|
|
}
|
|
}
|
|
new_index->varbind->buf[i]++;
|
|
} else
|
|
strcpy((char *) new_index->varbind->buf, "aaaa");
|
|
new_index->varbind->val_len =
|
|
strlen((char *) new_index->varbind->buf);
|
|
break;
|
|
case ASN_OBJECT_ID:
|
|
if (prev_idx_ptr) {
|
|
i = prev_idx_ptr->varbind->val_len / sizeof(oid) - 1;
|
|
while (new_index->varbind->val.objid[i] == 255) {
|
|
new_index->varbind->val.objid[i] = 1;
|
|
i--;
|
|
if (i == 0 && new_index->varbind->val.objid[0] == 2) {
|
|
new_index->varbind->val.objid[0] = 1;
|
|
i = new_index->varbind->val_len / sizeof(oid);
|
|
new_index->varbind->val.objid[i] = 0;
|
|
new_index->varbind->val_len += sizeof(oid);
|
|
}
|
|
}
|
|
new_index->varbind->val.objid[i]++;
|
|
} else {
|
|
/*
|
|
* If the requested OID name is small enough,
|
|
* * append another OID (1) and use this as the
|
|
* * default starting value for new indexes.
|
|
*/
|
|
if ((varbind->name_length + 1) * sizeof(oid) <= 40) {
|
|
for (i = 0; i < (int) varbind->name_length; i++)
|
|
new_index->varbind->val.objid[i] =
|
|
varbind->name[i];
|
|
new_index->varbind->val.objid[varbind->name_length] =
|
|
1;
|
|
new_index->varbind->val_len =
|
|
(varbind->name_length + 1) * sizeof(oid);
|
|
} else {
|
|
/*
|
|
* Otherwise use '.1.1.1.1...'
|
|
*/
|
|
i = 40 / sizeof(oid);
|
|
if (i > 4)
|
|
i = 4;
|
|
new_index->varbind->val_len = i * (sizeof(oid));
|
|
for (i--; i >= 0; i--)
|
|
new_index->varbind->val.objid[i] = 1;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
snmp_free_var(new_index->varbind);
|
|
free(new_index);
|
|
return NULL; /* Index type not supported */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Try to duplicate the new varbind for return.
|
|
*/
|
|
|
|
if ((rv = snmp_clone_varbind(new_index->varbind)) == NULL) {
|
|
snmp_free_var(new_index->varbind);
|
|
free(new_index);
|
|
return NULL;
|
|
}
|
|
|
|
/*
|
|
* Right - we've set up the new entry.
|
|
* All that remains is to link it into the tree.
|
|
* There are a number of possible cases here,
|
|
* so watch carefully.
|
|
*/
|
|
if (prev_idx_ptr) {
|
|
new_index->next_idx = prev_idx_ptr->next_idx;
|
|
new_index->next_oid = prev_idx_ptr->next_oid;
|
|
prev_idx_ptr->next_idx = new_index;
|
|
} else {
|
|
if (res == 0 && idxptr) {
|
|
new_index->next_idx = idxptr;
|
|
new_index->next_oid = idxptr->next_oid;
|
|
} else {
|
|
new_index->next_idx = NULL;
|
|
new_index->next_oid = idxptr;
|
|
}
|
|
|
|
if (prev_oid_ptr) {
|
|
while (prev_oid_ptr) {
|
|
prev_oid_ptr->next_oid = new_index;
|
|
prev_oid_ptr = prev_oid_ptr->next_idx;
|
|
}
|
|
} else
|
|
snmp_index_head = new_index;
|
|
}
|
|
return rv;
|
|
}
|
|
|
|
/*
|
|
* Release an allocated index,
|
|
* to allow it to be used elsewhere
|
|
*/
|
|
netsnmp_feature_child_of(release_index,netsnmp_unused)
|
|
#ifndef NETSNMP_FEATURE_REMOVE_RELEASE_INDEX
|
|
int
|
|
release_index(netsnmp_variable_list * varbind)
|
|
{
|
|
return (unregister_index(varbind, TRUE, NULL));
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_RELEASE_INDEX */
|
|
|
|
#ifndef NETSNMP_FEATURE_REMOVE_REMOVE_INDEX
|
|
/*
|
|
* Completely remove an allocated index,
|
|
* due to errors in the registration process.
|
|
*/
|
|
int
|
|
remove_index(netsnmp_variable_list * varbind, netsnmp_session * ss)
|
|
{
|
|
return (unregister_index(varbind, FALSE, ss));
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_REMOVE_INDEX */
|
|
|
|
void
|
|
unregister_index_by_session(netsnmp_session * ss)
|
|
{
|
|
struct snmp_index *idxptr, *idxptr2;
|
|
for (idxptr = snmp_index_head; idxptr != NULL;
|
|
idxptr = idxptr->next_oid)
|
|
for (idxptr2 = idxptr; idxptr2 != NULL;
|
|
idxptr2 = idxptr2->next_idx)
|
|
if (idxptr2->session == ss) {
|
|
idxptr2->allocated = 0;
|
|
idxptr2->session = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
int
|
|
unregister_index(netsnmp_variable_list * varbind, int remember,
|
|
netsnmp_session * ss)
|
|
{
|
|
struct snmp_index *idxptr, *idxptr2;
|
|
struct snmp_index *prev_oid_ptr, *prev_idx_ptr;
|
|
int res, res2, i;
|
|
|
|
#if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING)
|
|
if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID,
|
|
NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) {
|
|
return (agentx_unregister_index(ss, varbind));
|
|
}
|
|
#endif
|
|
/*
|
|
* Look for the requested OID entry
|
|
*/
|
|
prev_oid_ptr = NULL;
|
|
prev_idx_ptr = NULL;
|
|
res = 1;
|
|
res2 = 1;
|
|
for (idxptr = snmp_index_head; idxptr != NULL;
|
|
prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) {
|
|
if ((res = snmp_oid_compare(varbind->name, varbind->name_length,
|
|
idxptr->varbind->name,
|
|
idxptr->varbind->name_length)) <= 0)
|
|
break;
|
|
}
|
|
|
|
if (res != 0)
|
|
return INDEX_ERR_NOT_ALLOCATED;
|
|
if (varbind->type != idxptr->varbind->type)
|
|
return INDEX_ERR_WRONG_TYPE;
|
|
|
|
for (idxptr2 = idxptr; idxptr2 != NULL;
|
|
prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) {
|
|
switch (varbind->type) {
|
|
case ASN_INTEGER:
|
|
res2 =
|
|
(*varbind->val.integer -
|
|
*idxptr2->varbind->val.integer);
|
|
break;
|
|
case ASN_OCTET_STR:
|
|
i = SNMP_MIN(varbind->val_len,
|
|
idxptr2->varbind->val_len);
|
|
res2 =
|
|
memcmp(varbind->val.string,
|
|
idxptr2->varbind->val.string, i);
|
|
break;
|
|
case ASN_OBJECT_ID:
|
|
res2 =
|
|
snmp_oid_compare(varbind->val.objid,
|
|
varbind->val_len / sizeof(oid),
|
|
idxptr2->varbind->val.objid,
|
|
idxptr2->varbind->val_len /
|
|
sizeof(oid));
|
|
break;
|
|
default:
|
|
return INDEX_ERR_WRONG_TYPE; /* wrong type */
|
|
}
|
|
if (res2 <= 0)
|
|
break;
|
|
}
|
|
if (res2 != 0 || (res2 == 0 && !idxptr2->allocated)) {
|
|
return INDEX_ERR_NOT_ALLOCATED;
|
|
}
|
|
if (ss != idxptr2->session)
|
|
return INDEX_ERR_WRONG_SESSION;
|
|
|
|
/*
|
|
* If this is a "normal" index unregistration,
|
|
* mark the index entry as unused, but leave
|
|
* it in situ. This allows differentiation
|
|
* between ANY_INDEX and NEW_INDEX
|
|
*/
|
|
if (remember) {
|
|
idxptr2->allocated = 0; /* Unused index */
|
|
idxptr2->session = NULL;
|
|
return SNMP_ERR_NOERROR;
|
|
}
|
|
/*
|
|
* If this is a failed attempt to register a
|
|
* number of indexes, the successful ones
|
|
* must be removed completely.
|
|
*/
|
|
if (prev_idx_ptr) {
|
|
prev_idx_ptr->next_idx = idxptr2->next_idx;
|
|
} else if (prev_oid_ptr) {
|
|
if (idxptr2->next_idx) /* Use p_idx_ptr as a temp variable */
|
|
prev_idx_ptr = idxptr2->next_idx;
|
|
else
|
|
prev_idx_ptr = idxptr2->next_oid;
|
|
while (prev_oid_ptr) {
|
|
prev_oid_ptr->next_oid = prev_idx_ptr;
|
|
prev_oid_ptr = prev_oid_ptr->next_idx;
|
|
}
|
|
} else {
|
|
if (idxptr2->next_idx)
|
|
snmp_index_head = idxptr2->next_idx;
|
|
else
|
|
snmp_index_head = idxptr2->next_oid;
|
|
}
|
|
snmp_free_var(idxptr2->varbind);
|
|
free(idxptr2);
|
|
return SNMP_ERR_NOERROR;
|
|
}
|
|
|
|
netsnmp_feature_child_of(unregister_indexes,netsnmp_unused)
|
|
#ifndef NETSNMP_FEATURE_REMOVE_UNREGISTER_INDEXES
|
|
int
|
|
unregister_string_index(oid * name, size_t name_len, char *cp)
|
|
{
|
|
netsnmp_variable_list varbind;
|
|
|
|
memset(&varbind, 0, sizeof(netsnmp_variable_list));
|
|
varbind.type = ASN_OCTET_STR;
|
|
snmp_set_var_objid(&varbind, name, name_len);
|
|
snmp_set_var_value(&varbind, (u_char *) cp, strlen(cp));
|
|
return (unregister_index(&varbind, FALSE, main_session));
|
|
}
|
|
|
|
int
|
|
unregister_int_index(oid * name, size_t name_len, int val)
|
|
{
|
|
netsnmp_variable_list varbind;
|
|
|
|
memset(&varbind, 0, sizeof(netsnmp_variable_list));
|
|
varbind.type = ASN_INTEGER;
|
|
snmp_set_var_objid(&varbind, name, name_len);
|
|
varbind.val.string = varbind.buf;
|
|
varbind.val_len = sizeof(long);
|
|
*varbind.val.integer = val;
|
|
return (unregister_index(&varbind, FALSE, main_session));
|
|
}
|
|
|
|
int
|
|
unregister_oid_index(oid * name, size_t name_len,
|
|
oid * value, size_t value_len)
|
|
{
|
|
netsnmp_variable_list varbind;
|
|
|
|
memset(&varbind, 0, sizeof(netsnmp_variable_list));
|
|
varbind.type = ASN_OBJECT_ID;
|
|
snmp_set_var_objid(&varbind, name, name_len);
|
|
snmp_set_var_value(&varbind, (u_char *) value,
|
|
value_len * sizeof(oid));
|
|
return (unregister_index(&varbind, FALSE, main_session));
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_UNREGISTER_INDEXES */
|
|
|
|
void
|
|
dump_idx_registry(void)
|
|
{
|
|
struct snmp_index *idxptr, *idxptr2;
|
|
u_char *sbuf = NULL, *ebuf = NULL;
|
|
size_t sbuf_len = 0, sout_len = 0, ebuf_len = 0, eout_len = 0;
|
|
|
|
if (snmp_index_head != NULL) {
|
|
printf("\nIndex Allocations:\n");
|
|
}
|
|
|
|
for (idxptr = snmp_index_head; idxptr != NULL;
|
|
idxptr = idxptr->next_oid) {
|
|
sout_len = 0;
|
|
if (sprint_realloc_objid(&sbuf, &sbuf_len, &sout_len, 1,
|
|
idxptr->varbind->name,
|
|
idxptr->varbind->name_length)) {
|
|
printf("%s indexes:\n", sbuf);
|
|
} else {
|
|
printf("%s [TRUNCATED] indexes:\n", sbuf);
|
|
}
|
|
|
|
for (idxptr2 = idxptr; idxptr2 != NULL;
|
|
idxptr2 = idxptr2->next_idx) {
|
|
switch (idxptr2->varbind->type) {
|
|
case ASN_INTEGER:
|
|
printf(" %ld for session %8p, allocated %d\n",
|
|
*idxptr2->varbind->val.integer, idxptr2->session,
|
|
idxptr2->allocated);
|
|
break;
|
|
case ASN_OCTET_STR:
|
|
printf(" \"%s\" for session %8p, allocated %d\n",
|
|
idxptr2->varbind->val.string, idxptr2->session,
|
|
idxptr2->allocated);
|
|
break;
|
|
case ASN_OBJECT_ID:
|
|
eout_len = 0;
|
|
if (sprint_realloc_objid(&ebuf, &ebuf_len, &eout_len, 1,
|
|
idxptr2->varbind->val.objid,
|
|
idxptr2->varbind->val_len /
|
|
sizeof(oid))) {
|
|
printf(" %s for session %8p, allocated %d\n", ebuf,
|
|
idxptr2->session, idxptr2->allocated);
|
|
} else {
|
|
printf
|
|
(" %s [TRUNCATED] for sess %8p, allocated %d\n",
|
|
ebuf, idxptr2->session, idxptr2->allocated);
|
|
}
|
|
break;
|
|
default:
|
|
printf("unsupported type (%d/0x%02x)\n",
|
|
idxptr2->varbind->type, idxptr2->varbind->type);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (sbuf != NULL) {
|
|
free(sbuf);
|
|
}
|
|
if (ebuf != NULL) {
|
|
free(ebuf);
|
|
}
|
|
}
|
|
|
|
netsnmp_feature_child_of(count_indexes, netsnmp_unused)
|
|
#ifndef NETSNMP_FEATURE_REMOVE_UNUSED
|
|
unsigned long
|
|
count_indexes(oid * name, size_t namelen, int include_unallocated)
|
|
{
|
|
struct snmp_index *i = NULL, *j = NULL;
|
|
unsigned long n = 0;
|
|
|
|
for (i = snmp_index_head; i != NULL; i = i->next_oid) {
|
|
if (netsnmp_oid_equals(name, namelen,
|
|
i->varbind->name,
|
|
i->varbind->name_length) == 0) {
|
|
for (j = i; j != NULL; j = j->next_idx) {
|
|
if (j->allocated || include_unallocated) {
|
|
n++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return n;
|
|
}
|
|
#endif /* NETSNMP_FEATURE_REMOVE_UNUSED */
|
|
|
|
#ifdef TESTING
|
|
netsnmp_variable_list varbind;
|
|
netsnmp_session main_sess, *main_session = &main_sess;
|
|
|
|
void
|
|
test_string_register(int n, char *cp)
|
|
{
|
|
varbind->name[4] = n;
|
|
if (register_string_index(varbind->name, varbind.name_length, cp) ==
|
|
NULL)
|
|
printf("allocating %s failed\n", cp);
|
|
}
|
|
|
|
void
|
|
test_int_register(int n, int val)
|
|
{
|
|
varbind->name[4] = n;
|
|
if (register_int_index(varbind->name, varbind.name_length, val) == -1)
|
|
printf("allocating %d/%d failed\n", n, val);
|
|
}
|
|
|
|
void
|
|
test_oid_register(int n, int subid)
|
|
{
|
|
netsnmp_variable_list *res;
|
|
|
|
varbind->name[4] = n;
|
|
if (subid != -1) {
|
|
varbind->val.objid[5] = subid;
|
|
res = register_oid_index(varbind->name, varbind.name_length,
|
|
varbind->val.objid,
|
|
varbind->val_len / sizeof(oid));
|
|
} else
|
|
res =
|
|
register_oid_index(varbind->name, varbind.name_length, NULL,
|
|
0);
|
|
|
|
if (res == NULL)
|
|
printf("allocating %d/%d failed\n", n, subid);
|
|
}
|
|
|
|
void
|
|
main(int argc, char argv[])
|
|
{
|
|
oid name[] = { 1, 2, 3, 4, 0 };
|
|
int i;
|
|
|
|
memset(&varbind, 0, sizeof(netsnmp_variable_list));
|
|
snmp_set_var_objid(&varbind, name, 5);
|
|
varbind->type = ASN_OCTET_STR;
|
|
/*
|
|
* Test index structure linking:
|
|
* a) sorted by OID
|
|
*/
|
|
test_string_register(20, "empty OID");
|
|
test_string_register(10, "first OID");
|
|
test_string_register(40, "last OID");
|
|
test_string_register(30, "middle OID");
|
|
|
|
/*
|
|
* b) sorted by index value
|
|
*/
|
|
test_string_register(25, "eee: empty IDX");
|
|
test_string_register(25, "aaa: first IDX");
|
|
test_string_register(25, "zzz: last IDX");
|
|
test_string_register(25, "mmm: middle IDX");
|
|
printf("This next one should fail....\n");
|
|
test_string_register(25, "eee: empty IDX"); /* duplicate */
|
|
printf("done\n");
|
|
|
|
/*
|
|
* c) test initial index linking
|
|
*/
|
|
test_string_register(5, "eee: empty initial IDX");
|
|
test_string_register(5, "aaa: replace initial IDX");
|
|
|
|
/*
|
|
* Did it all work?
|
|
*/
|
|
dump_idx_registry();
|
|
unregister_index_by_session(main_session);
|
|
/*
|
|
* Now test index allocation
|
|
* a) integer values
|
|
*/
|
|
test_int_register(110, -1); /* empty */
|
|
test_int_register(110, -1); /* append */
|
|
test_int_register(110, 10); /* append exact */
|
|
printf("This next one should fail....\n");
|
|
test_int_register(110, 10); /* exact duplicate */
|
|
printf("done\n");
|
|
test_int_register(110, -1); /* append */
|
|
test_int_register(110, 5); /* insert exact */
|
|
|
|
/*
|
|
* b) string values
|
|
*/
|
|
test_string_register(120, NULL); /* empty */
|
|
test_string_register(120, NULL); /* append */
|
|
test_string_register(120, "aaaz");
|
|
test_string_register(120, NULL); /* minor rollover */
|
|
test_string_register(120, "zzzz");
|
|
test_string_register(120, NULL); /* major rollover */
|
|
|
|
/*
|
|
* c) OID values
|
|
*/
|
|
|
|
test_oid_register(130, -1); /* empty */
|
|
test_oid_register(130, -1); /* append */
|
|
|
|
varbind->val_len = varbind.name_length * sizeof(oid);
|
|
memcpy(varbind->buf, varbind.name, varbind.val_len);
|
|
varbind->val.objid = (oid *) varbind.buf;
|
|
varbind->val_len += sizeof(oid);
|
|
|
|
test_oid_register(130, 255); /* append exact */
|
|
test_oid_register(130, -1); /* minor rollover */
|
|
test_oid_register(130, 100); /* insert exact */
|
|
printf("This next one should fail....\n");
|
|
test_oid_register(130, 100); /* exact duplicate */
|
|
printf("done\n");
|
|
|
|
varbind->val.objid = (oid *) varbind.buf;
|
|
for (i = 0; i < 6; i++)
|
|
varbind->val.objid[i] = 255;
|
|
varbind->val.objid[0] = 1;
|
|
test_oid_register(130, 255); /* set up rollover */
|
|
test_oid_register(130, -1); /* medium rollover */
|
|
|
|
for (i = 0; i < 6; i++)
|
|
varbind->val.objid[i] = 255;
|
|
varbind->val.objid[0] = 2;
|
|
test_oid_register(130, 255); /* set up rollover */
|
|
test_oid_register(130, -1); /* major rollover */
|
|
|
|
/*
|
|
* Did it all work?
|
|
*/
|
|
dump_idx_registry();
|
|
|
|
/*
|
|
* Test the various "invalid" requests
|
|
* (unsupported types, mis-matched types, etc)
|
|
*/
|
|
printf("The rest of these should fail....\n");
|
|
test_oid_register(110, -1);
|
|
test_oid_register(110, 100);
|
|
test_oid_register(120, -1);
|
|
test_oid_register(120, 100);
|
|
test_string_register(110, NULL);
|
|
test_string_register(110, "aaaa");
|
|
test_string_register(130, NULL);
|
|
test_string_register(130, "aaaa");
|
|
test_int_register(120, -1);
|
|
test_int_register(120, 1);
|
|
test_int_register(130, -1);
|
|
test_int_register(130, 1);
|
|
printf("done - this dump should be the same as before\n");
|
|
dump_idx_registry();
|
|
}
|
|
#endif
|