/* * DisMan Event MIB: * Core implementation of the object handling behaviour */ #include #include #include #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, sizeof(name)); 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; }