blob: cf950c1e0a827d45341e12494c0ddbe46b138edf [file] [log] [blame]
/*
* DisMan Event MIB:
* Core implementation of the object handling behaviour
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "disman/event/mteObjects.h"
netsnmp_tdata *objects_table_data;
/*
* Initialize the container for the object table
* regardless of which initialisation routine is called first.
*/
void
init_objects_table_data(void)
{
if (!objects_table_data)
objects_table_data = netsnmp_tdata_create_table("mteObjectsTable", 0);
}
SNMPCallback _init_default_mteObject_lists;
/** Initializes the mteObjects module */
void
init_mteObjects(void)
{
init_objects_table_data();
/*
* Insert fixed object lists for the default trigger
* notifications, once the MIB files have been read in.
*/
snmp_register_callback(SNMP_CALLBACK_LIBRARY,
SNMP_CALLBACK_POST_READ_CONFIG,
_init_default_mteObject_lists, NULL);
}
void
_init_default_mteObject( const char *oname, const char *object, int index, int wcard)
{
struct mteObject *entry;
entry = mteObjects_addOID( "_snmpd", oname, index, object, 0 );
if (entry) {
entry->flags |= MTE_OBJECT_FLAG_ACTIVE|
MTE_OBJECT_FLAG_FIXED |
MTE_OBJECT_FLAG_VALID;
if (wcard)
entry->flags |= MTE_OBJECT_FLAG_WILD;
}
}
int
_init_default_mteObject_lists( int majorID, int minorID,
void *serverargs, void *clientarg)
{
static int _defaults_init = 0;
if (_defaults_init)
return 0;
/* mteHotTrigger */
_init_default_mteObject( "_triggerFire", ".1.3.6.1.2.1.88.2.1.1", 1, 0);
/* mteHotTargetName */
_init_default_mteObject( "_triggerFire", ".1.3.6.1.2.1.88.2.1.2", 2, 0);
/* mteHotContextName */
_init_default_mteObject( "_triggerFire", ".1.3.6.1.2.1.88.2.1.3", 3, 0);
/* mteHotOID */
_init_default_mteObject( "_triggerFire", ".1.3.6.1.2.1.88.2.1.4", 4, 0);
/* mteHotValue */
_init_default_mteObject( "_triggerFire", ".1.3.6.1.2.1.88.2.1.5", 5, 0);
/* mteHotTrigger */
_init_default_mteObject( "_triggerFail", ".1.3.6.1.2.1.88.2.1.1", 1, 0);
/* mteHotTargetName */
_init_default_mteObject( "_triggerFail", ".1.3.6.1.2.1.88.2.1.2", 2, 0);
/* mteHotContextName */
_init_default_mteObject( "_triggerFail", ".1.3.6.1.2.1.88.2.1.3", 3, 0);
/* mteHotOID */
_init_default_mteObject( "_triggerFail", ".1.3.6.1.2.1.88.2.1.4", 4, 0);
/* mteFailedReason */
_init_default_mteObject( "_triggerFail", ".1.3.6.1.2.1.88.2.1.6", 5, 0);
/* ifIndex */
_init_default_mteObject( "_linkUpDown", ".1.3.6.1.2.1.2.2.1.1", 1, 1);
/* ifAdminStatus */
_init_default_mteObject( "_linkUpDown", ".1.3.6.1.2.1.2.2.1.7", 2, 1);
/* ifOperStatus */
_init_default_mteObject( "_linkUpDown", ".1.3.6.1.2.1.2.2.1.8", 3, 1);
_defaults_init = 1;
return 0;
}
/* ===================================================
*
* APIs for maintaining the contents of the mteObjectsTable container.
*
* =================================================== */
/*
* Create a new row in the object table
*/
netsnmp_tdata_row *
mteObjects_createEntry(const char *owner, const char *oname, int index, int flags)
{
struct mteObject *entry;
netsnmp_tdata_row *row, *row2;
size_t owner_len = (owner) ? strlen(owner) : 0;
size_t oname_len = (oname) ? strlen(oname) : 0;
/*
* Create the mteObjects entry, and the
* (table-independent) row wrapper structure...
*/
entry = SNMP_MALLOC_TYPEDEF(struct mteObject);
if (!entry)
return NULL;
row = netsnmp_tdata_create_row();
if (!row) {
SNMP_FREE(entry);
return NULL;
}
row->data = entry;
/*
* ... initialize this row with the indexes supplied
* and the default values for the row...
*/
if (owner)
memcpy(entry->mteOwner, owner, owner_len);
netsnmp_tdata_row_add_index(row, ASN_OCTET_STR,
entry->mteOwner, owner_len);
if (oname)
memcpy(entry->mteOName, oname, oname_len);
netsnmp_tdata_row_add_index(row, ASN_OCTET_STR,
entry->mteOName, oname_len);
entry->mteOIndex = index;
netsnmp_tdata_row_add_index(row, ASN_INTEGER,
&entry->mteOIndex, sizeof(long));
entry->mteObjectID_len = 2; /* .0.0 */
if (flags & MTE_OBJECT_FLAG_FIXED)
entry->flags |= MTE_OBJECT_FLAG_FIXED;
/*
* Check whether there's already a row with the same indexes
* (XXX - relies on private internal data ???)
*/
row2 = netsnmp_tdata_row_get_byoid(objects_table_data,
row->oid_index.oids,
row->oid_index.len);
if (row2) {
if (flags & MTE_OBJECT_FLAG_NEXT) {
/*
* If appropriate, keep incrementing the final
* index value until we find a free slot...
*/
while (row2) {
row->oid_index.oids[row->oid_index.len]++;
row2 = netsnmp_tdata_row_get_byoid(objects_table_data,
row->oid_index.oids,
row->oid_index.len);
}
} else {
/*
* ... otherwise, this is an error.
* Tidy up, and return failure.
*/
netsnmp_tdata_delete_row(row);
SNMP_FREE(entry);
return NULL;
}
}
/*
* ... finally, insert the row into the (common) table container
*/
netsnmp_tdata_add_row(objects_table_data, row);
return row;
}
/*
* Add a row to the object table
*/
struct mteObject *
mteObjects_addOID(const char *owner, const char *oname, int index,
const char *oid_name_buf, int wild )
{
netsnmp_tdata_row *row;
struct mteObject *entry;
oid name_buf[ MAX_OID_LEN ];
size_t name_buf_len;
name_buf_len = MAX_OID_LEN;
if (!snmp_parse_oid(oid_name_buf, name_buf, &name_buf_len)) {
snmp_log(LOG_ERR, "payload OID: %s\n", oid_name_buf);
config_perror("unknown payload OID");
return NULL;
}
row = mteObjects_createEntry(owner, oname, index,
MTE_OBJECT_FLAG_FIXED|MTE_OBJECT_FLAG_NEXT);
entry = (struct mteObject *)row->data;
entry->mteObjectID_len = name_buf_len;
memcpy(entry->mteObjectID, name_buf, name_buf_len*sizeof(oid));
if (wild)
entry->flags |= MTE_OBJECT_FLAG_WILD;
entry->flags |= MTE_OBJECT_FLAG_VALID|
MTE_OBJECT_FLAG_ACTIVE;
return entry;
}
/*
* Remove a row from the event table
*/
void
mteObjects_removeEntry(netsnmp_tdata_row *row)
{
struct mteObject *entry;
if (!row)
return; /* Nothing to remove */
entry = (struct mteObject *)
netsnmp_tdata_remove_and_delete_row(objects_table_data, row);
SNMP_FREE(entry);
}
/*
* Remove all matching rows from the event table
*/
void
mteObjects_removeEntries( const char *owner, char *oname )
{
netsnmp_tdata_row *row;
netsnmp_variable_list owner_var, oname_var;
memset(&owner_var, 0, sizeof(owner_var));
memset(&oname_var, 0, sizeof(oname_var));
snmp_set_var_typed_value( &owner_var, ASN_OCTET_STR,
owner, strlen(owner));
snmp_set_var_typed_value( &oname_var, ASN_OCTET_STR,
oname, strlen(oname));
owner_var.next_variable = &oname_var;
row = netsnmp_tdata_row_next_byidx( objects_table_data, &owner_var );
while (row && !netsnmp_tdata_compare_subtree_idx( row, &owner_var )) {
mteObjects_removeEntry(row);
row = netsnmp_tdata_row_next_byidx( objects_table_data, &owner_var );
}
return;
}
/* ===================================================
*
* API for retrieving a list of matching objects
*
* =================================================== */
int
mteObjects_vblist( netsnmp_variable_list *vblist,
char *owner, char *oname,
oid *suffix, size_t sfx_len )
{
netsnmp_tdata_row *row;
struct mteObject *entry;
netsnmp_variable_list owner_var, oname_var;
netsnmp_variable_list *var = vblist;
oid name[MAX_OID_LEN];
size_t name_len;
if (!oname || !*oname) {
DEBUGMSGTL(("disman:event:objects", "No objects to add (%s)\n",
owner));
return 1; /* Empty object name means nothing to add */
}
DEBUGMSGTL(("disman:event:objects", "Objects add (%s, %s)\n",
owner, oname ));
/*
* Retrieve any matching entries from the mteObjectTable
* and add them to the specified varbind list.
*/
memset(&owner_var, 0, sizeof(owner_var));
memset(&oname_var, 0, sizeof(oname_var));
snmp_set_var_typed_value( &owner_var, ASN_OCTET_STR,
owner, strlen(owner));
snmp_set_var_typed_value( &oname_var, ASN_OCTET_STR,
oname, strlen(oname));
owner_var.next_variable = &oname_var;
row = netsnmp_tdata_row_next_byidx( objects_table_data, &owner_var );
while (row && !netsnmp_tdata_compare_subtree_idx( row, &owner_var )) {
entry = (struct mteObject *)netsnmp_tdata_row_entry(row);
memset(name, 0, MAX_OID_LEN);
memcpy(name, entry->mteObjectID,
entry->mteObjectID_len*sizeof(oid));
name_len = entry->mteObjectID_len;
/*
* If the trigger value is wildcarded (sfx_len > 0),
* *and* this object entry is wildcarded,
* then add the supplied instance suffix.
* Otherwise use the Object OID as it stands.
*/
if (sfx_len &&
entry->flags & MTE_OBJECT_FLAG_WILD) {
memcpy(&name[name_len], suffix, sfx_len*sizeof(oid));
name_len += sfx_len;
}
snmp_varlist_add_variable( &var, name, name_len, ASN_NULL, NULL, 0);
row = netsnmp_tdata_row_next( objects_table_data, row );
}
return 0;
}
int
mteObjects_internal_vblist( netsnmp_variable_list *vblist,
char *oname,
struct mteTrigger *trigger,
netsnmp_session *sess)
{
netsnmp_variable_list *var = NULL, *vp;
oid mteHotTrigger[] = {1, 3, 6, 1, 2, 1, 88, 2, 1, 1, 0};
oid mteHotTarget[] = {1, 3, 6, 1, 2, 1, 88, 2, 1, 2, 0};
oid mteHotContext[] = {1, 3, 6, 1, 2, 1, 88, 2, 1, 3, 0};
oid mteHotOID[] = {1, 3, 6, 1, 2, 1, 88, 2, 1, 4, 0};
oid mteHotValue[] = {1, 3, 6, 1, 2, 1, 88, 2, 1, 5, 0};
oid ifIndexOid[] = {1, 3, 6, 1, 2, 1, 2, 2, 1, 1, 0};
oid ifAdminStatus[] = {1, 3, 6, 1, 2, 1, 2, 2, 1, 7, 0};
oid ifOperStatus[] = {1, 3, 6, 1, 2, 1, 2, 2, 1, 8, 0};
oid if_index;
/*
* Construct the varbinds for this (internal) event...
*/
if (!strcmp(oname, "_triggerFire")) {
snmp_varlist_add_variable( &var,
mteHotTrigger, OID_LENGTH(mteHotTrigger),
ASN_OCTET_STR, trigger->mteTName,
strlen(trigger->mteTName));
snmp_varlist_add_variable( &var,
mteHotTarget, OID_LENGTH(mteHotTarget),
ASN_OCTET_STR, trigger->mteTriggerTarget,
strlen(trigger->mteTriggerTarget));
snmp_varlist_add_variable( &var,
mteHotContext, OID_LENGTH(mteHotContext),
ASN_OCTET_STR, trigger->mteTriggerContext,
strlen(trigger->mteTriggerContext));
snmp_varlist_add_variable( &var,
mteHotOID, OID_LENGTH(mteHotOID),
ASN_OBJECT_ID, (char *)trigger->mteTriggerFired->name,
trigger->mteTriggerFired->name_length*sizeof(oid));
snmp_varlist_add_variable( &var,
mteHotValue, OID_LENGTH(mteHotValue),
trigger->mteTriggerFired->type,
trigger->mteTriggerFired->val.string,
trigger->mteTriggerFired->val_len);
} else if ((!strcmp(oname, "_linkUpDown" ))) {
/*
* The ifOperStatus varbind that triggered this entry
* is held in the trigger->mteTriggerFired field
*
* We can retrieve the ifIndex and ifOperStatus values
* from this varbind. But first we need to tweak the
* static ifXXX OID arrays to include the correct index.
* (or this could be passed in from the calling routine?)
*
* Unfortunately we don't have the current AdminStatus value,
* so we'll need to make another query to retrieve that.
*/
if_index = trigger->mteTriggerFired->name[10];
ifIndexOid[ 10 ] = if_index;
ifAdminStatus[ 10 ] = if_index;
ifOperStatus[ 10 ] = if_index;
snmp_varlist_add_variable( &var,
ifIndexOid, OID_LENGTH(ifIndexOid),
ASN_INTEGER, &if_index, sizeof(if_index));
/* Set up a dummy varbind for ifAdminStatus... */
snmp_varlist_add_variable( &var,
ifAdminStatus, OID_LENGTH(ifAdminStatus),
ASN_INTEGER,
trigger->mteTriggerFired->val.integer,
trigger->mteTriggerFired->val_len);
/* ... then retrieve the actual value */
netsnmp_query_get( var->next_variable, sess );
snmp_varlist_add_variable( &var,
ifOperStatus, OID_LENGTH(ifOperStatus),
ASN_INTEGER,
trigger->mteTriggerFired->val.integer,
trigger->mteTriggerFired->val_len);
} else {
DEBUGMSGTL(("disman:event:objects",
"Unknown internal objects tag (%s)\n", oname));
return 1;
}
/*
* ... and insert them into the main varbind list
* (at the point specified)
*/
for (vp = var; vp && vp->next_variable; vp=vp->next_variable)
;
vp->next_variable = vblist->next_variable;
vblist->next_variable = var;
return 0;
}