/************************************************************** * Copyright (C) 2001 Alex Rozin, Optical Access * * All Rights Reserved * * Permission to use, copy, modify and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * ALEX ROZIN DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL * ALEX ROZIN BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS * SOFTWARE. ******************************************************************/ #include #include #if HAVE_STDLIB_H #include #endif #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if HAVE_UNISTD_H #include #endif #include #include #include #include "event.h" /* * Implementation headers */ #include "agutil_api.h" #include "row_api.h" netsnmp_feature_require(snprint_objid); /* * File scope definitions section */ /* * from MIB compilation */ #define eventEntryFirstIndexBegin 11 #define EVENTINDEX 3 #define EVENTDESCRIPTION 4 #define EVENTTYPE 5 #define EVENTCOMMUNITY 6 #define EVENTLASTTIMESENT 7 #define EVENTOWNER 8 #define EVENTSTATUS 9 #define Leaf_event_index 1 #define Leaf_event_description 2 #define MIN_event_description 0 #define MAX_event_description 127 #define Leaf_event_type 3 #define Leaf_event_community 4 #define MIN_event_community 0 #define MAX_event_community 127 #define Leaf_event_last_time_sent 5 #define Leaf_eventOwner 6 #define Leaf_eventStatus 7 #define LOGEVENTINDEX 3 #define LOGINDEX 4 #define LOGTIME 5 #define LOGDESCRIPTION 6 /* * defaults & limitations */ #define MAX_LOG_ENTRIES_PER_CTRL 200 typedef struct data_struct_t { struct data_struct_t *next; u_long data_index; u_long log_time; char *log_description; } DATA_ENTRY_T; typedef enum { EVENT_NONE = 1, EVENT_LOG, EVENT_TRAP, EVENT_LOG_AND_TRAP } EVENT_TYPE_T; typedef struct { char *event_description; char *event_community; EVENT_TYPE_T event_type; u_long event_last_time_sent; SCROLLER_T scrlr; #if 0 u_long event_last_logged_index; u_long event_number_of_log_entries; DATA_ENTRY_T *log_list; DATA_ENTRY_T *last_log_ptr; #endif } CRTL_ENTRY_T; /* * Main section */ static TABLE_DEFINTION_T EventCtrlTable; static TABLE_DEFINTION_T *table_ptr = &EventCtrlTable; static unsigned char zero_octet_string[1]; /* * Control Table RowApi Callbacks */ static int data_destructor(SCROLLER_T * scrlr, void *free_me) { DATA_ENTRY_T *lptr = free_me; if (lptr->log_description) AGFREE(lptr->log_description); return 0; } int event_Create(RMON_ENTRY_T * eptr) { /* create the body: alloc it and set defaults */ CRTL_ENTRY_T *body; eptr->body = AGMALLOC(sizeof(CRTL_ENTRY_T)); if (!eptr->body) return -3; body = (CRTL_ENTRY_T *) eptr->body; /* * set defaults */ body->event_description = NULL; body->event_community = AGSTRDUP("public"); /* * ag_trace ("Dbg: created event_community=<%s>", body->event_community); */ body->event_type = EVENT_NONE; ROWDATAAPI_init(&body->scrlr, MAX_LOG_ENTRIES_PER_CTRL, MAX_LOG_ENTRIES_PER_CTRL, sizeof(DATA_ENTRY_T), &data_destructor); return 0; } int event_Clone(RMON_ENTRY_T * eptr) { /* copy entry_bod -> clone */ CRTL_ENTRY_T *body = (CRTL_ENTRY_T *) eptr->body; CRTL_ENTRY_T *clone = (CRTL_ENTRY_T *) eptr->tmp; if (body->event_description) clone->event_description = AGSTRDUP(body->event_description); if (body->event_community) clone->event_community = AGSTRDUP(body->event_community); return 0; } int event_Copy(RMON_ENTRY_T * eptr) { CRTL_ENTRY_T *body = (CRTL_ENTRY_T *) eptr->body; CRTL_ENTRY_T *clone = (CRTL_ENTRY_T *) eptr->tmp; if (body->event_type != clone->event_type) { body->event_type = clone->event_type; } if (clone->event_description) { if (body->event_description) AGFREE(body->event_description); body->event_description = AGSTRDUP(clone->event_description); } if (clone->event_community) { if (body->event_community) AGFREE(body->event_community); body->event_community = AGSTRDUP(clone->event_community); } return 0; } int event_Delete(RMON_ENTRY_T * eptr) { CRTL_ENTRY_T *body = (CRTL_ENTRY_T *) eptr; if (body->event_description) AGFREE(body->event_description); if (body->event_community) AGFREE(body->event_community); return 0; } int event_Activate(RMON_ENTRY_T * eptr) { /* init logTable */ CRTL_ENTRY_T *body = (CRTL_ENTRY_T *) eptr->body; ROWDATAAPI_set_size(&body->scrlr, body->scrlr.data_requested, (u_char)(RMON1_ENTRY_VALID == eptr->status) ); return 0; } int event_Deactivate(RMON_ENTRY_T * eptr) { /* free logTable */ CRTL_ENTRY_T *body = (CRTL_ENTRY_T *) eptr->body; /* * free data list */ ROWDATAAPI_descructor(&body->scrlr); return 0; } static int write_eventControl(int action, u_char * var_val, u_char var_val_type, size_t var_val_len, u_char * statP, oid * name, size_t name_len) { long long_temp; char *char_temp; int leaf_id, snmp_status; static int prev_action = COMMIT; RMON_ENTRY_T *hdr; CRTL_ENTRY_T *cloned_body; switch (action) { case RESERVE1: case FREE: case UNDO: case ACTION: case COMMIT: default: return ROWAPI_do_another_action(name, eventEntryFirstIndexBegin, action, &prev_action, table_ptr, sizeof(CRTL_ENTRY_T)); case RESERVE2: /* * get values from PDU, check them and save them in the cloned entry */ long_temp = name[eventEntryFirstIndexBegin]; leaf_id = (int) name[eventEntryFirstIndexBegin - 1]; hdr = ROWAPI_find(table_ptr, long_temp); /* it MUST be OK */ cloned_body = (CRTL_ENTRY_T *) hdr->tmp; switch (leaf_id) { case Leaf_event_index: return SNMP_ERR_NOTWRITABLE; case Leaf_event_description: char_temp = AGMALLOC(1 + MAX_event_description); if (!char_temp) return SNMP_ERR_TOOBIG; snmp_status = AGUTIL_get_string_value(var_val, var_val_type, var_val_len, MAX_event_description, 1, NULL, char_temp); if (SNMP_ERR_NOERROR != snmp_status) { AGFREE(char_temp); return snmp_status; } if (cloned_body->event_description) AGFREE(cloned_body->event_description); cloned_body->event_description = AGSTRDUP(char_temp); /* * ag_trace ("rx: event_description=<%s>", cloned_body->event_description); */ AGFREE(char_temp); break; case Leaf_event_type: snmp_status = AGUTIL_get_int_value(var_val, var_val_type, var_val_len, EVENT_NONE, EVENT_LOG_AND_TRAP, &long_temp); if (SNMP_ERR_NOERROR != snmp_status) { return snmp_status; } cloned_body->event_type = long_temp; break; case Leaf_event_last_time_sent: return SNMP_ERR_NOTWRITABLE; case Leaf_event_community: char_temp = AGMALLOC(1 + MAX_event_community); if (!char_temp) return SNMP_ERR_TOOBIG; snmp_status = AGUTIL_get_string_value(var_val, var_val_type, var_val_len, MAX_event_community, 1, NULL, char_temp); if (SNMP_ERR_NOERROR != snmp_status) { AGFREE(char_temp); return snmp_status; } if (cloned_body->event_community) AGFREE(cloned_body->event_community); cloned_body->event_community = AGSTRDUP(char_temp); AGFREE(char_temp); break; case Leaf_eventOwner: if (hdr->new_owner) AGFREE(hdr->new_owner); hdr->new_owner = AGMALLOC(MAX_OWNERSTRING); if (!hdr->new_owner) return SNMP_ERR_TOOBIG; snmp_status = AGUTIL_get_string_value(var_val, var_val_type, var_val_len, MAX_OWNERSTRING, 1, NULL, hdr->new_owner); if (SNMP_ERR_NOERROR != snmp_status) { return snmp_status; } break; case Leaf_eventStatus: snmp_status = AGUTIL_get_int_value(var_val, var_val_type, var_val_len, RMON1_ENTRY_VALID, RMON1_ENTRY_INVALID, &long_temp); if (SNMP_ERR_NOERROR != snmp_status) { return snmp_status; } hdr->new_status = long_temp; break; default: ag_trace("%s:unknown leaf_id=%d\n", table_ptr->name, (int) leaf_id); return SNMP_ERR_NOSUCHNAME; } /* of switch by 'leaf_id' */ break; } /* of switch by actions */ prev_action = action; return SNMP_ERR_NOERROR; } unsigned char * var_eventTable(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { static long long_ret; static CRTL_ENTRY_T theEntry; RMON_ENTRY_T *hdr; *write_method = write_eventControl; hdr = ROWAPI_header_ControlEntry(vp, name, length, exact, var_len, table_ptr, &theEntry, sizeof(CRTL_ENTRY_T)); if (!hdr) return NULL; *var_len = sizeof(long); /* default */ switch (vp->magic) { case EVENTINDEX: long_ret = hdr->ctrl_index; return (unsigned char *) &long_ret; case EVENTDESCRIPTION: if (theEntry.event_description) { *var_len = strlen(theEntry.event_description); return (unsigned char *) theEntry.event_description; } else { *var_len = 0; return zero_octet_string; } case EVENTTYPE: long_ret = theEntry.event_type; return (unsigned char *) &long_ret; case EVENTCOMMUNITY: if (theEntry.event_community) { *var_len = strlen(theEntry.event_community); return (unsigned char *) theEntry.event_community; } else { *var_len = 0; return zero_octet_string; } case EVENTLASTTIMESENT: long_ret = theEntry.event_last_time_sent; return (unsigned char *) &long_ret; case EVENTOWNER: if (hdr->owner) { *var_len = strlen(hdr->owner); return (unsigned char *) hdr->owner; } else { *var_len = 0; return zero_octet_string; } case EVENTSTATUS: long_ret = hdr->status; return (unsigned char *) &long_ret; default: ag_trace("EventControlTable: unknown vp->magic=%d", (int) vp->magic); ERROR_MSG(""); } return NULL; } static SCROLLER_T * event_extract_scroller(void *v_body) { CRTL_ENTRY_T *body = (CRTL_ENTRY_T *) v_body; return &body->scrlr; } unsigned char * var_logTable(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { static long long_ret; static DATA_ENTRY_T theEntry; RMON_ENTRY_T *hdr; *write_method = NULL; hdr = ROWDATAAPI_header_DataEntry(vp, name, length, exact, var_len, table_ptr, &event_extract_scroller, sizeof(DATA_ENTRY_T), &theEntry); if (!hdr) return NULL; *var_len = sizeof(long); /* default */ switch (vp->magic) { case LOGEVENTINDEX: long_ret = hdr->ctrl_index; return (unsigned char *) &long_ret; case LOGINDEX: long_ret = theEntry.data_index; return (unsigned char *) &long_ret; case LOGTIME: long_ret = theEntry.log_time; return (unsigned char *) &long_ret; case LOGDESCRIPTION: if (theEntry.log_description) { *var_len = strlen(theEntry.log_description); return (unsigned char *) theEntry.log_description; } else { *var_len = 0; return zero_octet_string; } default: ERROR_MSG(""); } return NULL; } /* * External API section */ static char * create_explanaition(CRTL_ENTRY_T * evptr, u_char is_rising, u_long alarm_index, u_long event_index, oid * alarmed_var, size_t alarmed_var_length, u_long value, u_long the_threshold, u_long sample_type, const char *alarm_descr) { #define UNEQ_LENGTH (1 + 11 + 4 + 11 + 1 + 20) char expl[UNEQ_LENGTH]; static char c_oid[SPRINT_MAX_LEN]; size_t sz; char *descr; register char *pch; register char *tmp; snprint_objid(c_oid, sizeof(c_oid)-1, alarmed_var, alarmed_var_length); c_oid[sizeof(c_oid)-1] = '\0'; for (pch = c_oid;;) { tmp = strchr(pch, '.'); if (!tmp) break; if (isdigit((unsigned char)tmp[1]) || '"' == tmp[1]) break; pch = tmp + 1; } snprintf(expl, UNEQ_LENGTH, "=%ld %s= %ld :%ld, %ld", (unsigned long) value, is_rising ? ">" : "<", (unsigned long) the_threshold, (long) alarm_index, (long) event_index); sz = 3 + strlen(expl) + strlen(pch); if (alarm_descr) sz += strlen(alarm_descr); descr = AGMALLOC(sz); if (!descr) { ag_trace("Can't allocate event description"); return NULL; } if (alarm_descr) { strcpy(descr, alarm_descr); strcat(descr, ":"); } else *descr = '\0'; strcat(descr, pch); strcat(descr, expl); return descr; } static void event_send_trap(CRTL_ENTRY_T * evptr, u_char is_rising, u_int alarm_index, u_int value, u_int the_threshold, oid * alarmed_var, size_t alarmed_var_length, u_int sample_type) { static oid objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 }; static oid rmon1_trap_oid[] = { 1, 3, 6, 1, 2, 1, 16, 0, 0 }; static oid alarm_index_oid[] = { 1, 3, 6, 1, 2, 1, 16, 3, 1, 1, 1, 0 }; static oid alarmed_var_oid[] = { 1, 3, 6, 1, 2, 1, 16, 3, 1, 1, 3, 0 }; static oid sample_type_oid[] = { 1, 3, 6, 1, 2, 1, 16, 3, 1, 1, 4, 0 }; static oid value_oid[] = { 1, 3, 6, 1, 2, 1, 16, 3, 1, 1, 5, 0 }; static oid threshold_oid[] = { 1, 3, 6, 1, 2, 1, 16, 3, 1, 1, 7, 0 }; /* rising case */ netsnmp_variable_list *var_list = NULL; /* * set the last 'oid' : risingAlarm or fallingAlarm */ if (is_rising) { rmon1_trap_oid[8] = 1; threshold_oid[10] = 7; } else { rmon1_trap_oid[8] = 2; threshold_oid[10] = 8; } alarm_index_oid[11] = alarm_index; alarmed_var_oid[11] = alarm_index; sample_type_oid[11] = alarm_index; value_oid[11] = alarm_index; threshold_oid[11] = alarm_index; /* * build the var list */ snmp_varlist_add_variable(&var_list, objid_snmptrap, OID_LENGTH(objid_snmptrap), ASN_OBJECT_ID, (u_char *) rmon1_trap_oid, sizeof(rmon1_trap_oid)); snmp_varlist_add_variable(&var_list, alarm_index_oid, OID_LENGTH(alarm_index_oid), ASN_INTEGER, (u_char *) &alarm_index, sizeof(u_int)); snmp_varlist_add_variable(&var_list, alarmed_var_oid, OID_LENGTH(alarmed_var_oid), ASN_OBJECT_ID, (u_char *) alarmed_var, alarmed_var_length * sizeof(oid)); snmp_varlist_add_variable(&var_list, sample_type_oid, OID_LENGTH(sample_type_oid), ASN_INTEGER, (u_char *) &sample_type, sizeof(u_int)); snmp_varlist_add_variable(&var_list, value_oid, OID_LENGTH(value_oid), ASN_INTEGER, (u_char *) &value, sizeof(u_int)); snmp_varlist_add_variable(&var_list, threshold_oid, OID_LENGTH(threshold_oid), ASN_INTEGER, (u_char *) &the_threshold, sizeof(u_int)); send_v2trap(var_list); ag_trace("rmon trap has been sent"); snmp_free_varbind(var_list); } static void event_save_log(CRTL_ENTRY_T * body, char *event_descr) { register DATA_ENTRY_T *lptr; lptr = ROWDATAAPI_locate_new_data(&body->scrlr); if (!lptr) { ag_trace("Err: event_save_log:cannot locate ?"); return; } lptr->log_time = body->event_last_time_sent; if (lptr->log_description) AGFREE(lptr->log_description); lptr->log_description = AGSTRDUP(event_descr); lptr->data_index = ROWDATAAPI_get_total_number(&body->scrlr); /* * ag_trace ("log has been saved, data_index=%d", (int) lptr->data_index); */ } int event_api_send_alarm(u_char is_rising, u_long alarm_index, u_long event_index, oid * alarmed_var, size_t alarmed_var_length, u_long sample_type, u_long value, u_long the_threshold, const char *alarm_descr) { RMON_ENTRY_T *eptr; CRTL_ENTRY_T *evptr; if (!event_index) return SNMP_ERR_NOERROR; #if 0 ag_trace("event_api_send_alarm(%d,%d,%d,'%s')", (int) is_rising, (int) alarm_index, (int) event_index, alarm_descr); #endif eptr = ROWAPI_find(table_ptr, event_index); if (!eptr) { /* * ag_trace ("event cannot find entry %ld", event_index); */ return SNMP_ERR_NOSUCHNAME; } evptr = (CRTL_ENTRY_T *) eptr->body; evptr->event_last_time_sent = AGUTIL_sys_up_time(); if (EVENT_TRAP == evptr->event_type || EVENT_LOG_AND_TRAP == evptr->event_type) { event_send_trap(evptr, is_rising, alarm_index, value, the_threshold, alarmed_var, alarmed_var_length, sample_type); } if (EVENT_LOG == evptr->event_type || EVENT_LOG_AND_TRAP == evptr->event_type) { register char *explain; explain = create_explanaition(evptr, is_rising, alarm_index, event_index, alarmed_var, alarmed_var_length, value, the_threshold, sample_type, alarm_descr); /* * if (explain) ag_trace ("Dbg:'%s'", explain); */ event_save_log(evptr, explain); if (explain) AGFREE(explain); } return SNMP_ERR_NOERROR; } #if 1 /* debug, but may be used for init. TBD: may be token snmpd.conf ? */ int add_event_entry(int ctrl_index, char *event_description, EVENT_TYPE_T event_type, char *event_community) { register RMON_ENTRY_T *eptr; register CRTL_ENTRY_T *body; int ierr; ierr = ROWAPI_new(table_ptr, ctrl_index); if (ierr) { ag_trace("ROWAPI_new failed with %d", ierr); return ierr; } eptr = ROWAPI_find(table_ptr, ctrl_index); if (!eptr) { ag_trace("ROWAPI_find failed"); return -4; } body = (CRTL_ENTRY_T *) eptr->body; /* * set parameters */ if (event_description) { if (body->event_description) AGFREE(body->event_description); body->event_description = AGSTRDUP(event_description); } if (event_community) { if (body->event_community) AGFREE(body->event_community); body->event_community = AGSTRDUP(event_community); } body->event_type = event_type; eptr->new_status = RMON1_ENTRY_VALID; ierr = ROWAPI_commit(table_ptr, ctrl_index); if (ierr) { ag_trace("ROWAPI_commit failed with %d", ierr); } return ierr; } #endif /* * Registration & Initializatio section */ oid eventTable_variables_oid[] = { 1, 3, 6, 1, 2, 1, 16, 9, 1 }; oid logTable_variables_oid[] = { 1, 3, 6, 1, 2, 1, 16, 9, 2 }; struct variable2 eventTable_variables[] = { /* * magic number , variable type, ro/rw , callback fn , L, oidsuffix */ {EVENTINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_eventTable, 2, {1, 1}}, {EVENTDESCRIPTION, ASN_OCTET_STR, NETSNMP_OLDAPI_RWRITE, var_eventTable, 2, {1, 2}}, {EVENTTYPE, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE, var_eventTable, 2, {1, 3}}, {EVENTCOMMUNITY, ASN_OCTET_STR, NETSNMP_OLDAPI_RWRITE, var_eventTable, 2, {1, 4}}, {EVENTLASTTIMESENT, ASN_TIMETICKS, NETSNMP_OLDAPI_RONLY, var_eventTable, 2, {1, 5}}, {EVENTOWNER, ASN_OCTET_STR, NETSNMP_OLDAPI_RWRITE, var_eventTable, 2, {1, 6}}, {EVENTSTATUS, ASN_INTEGER, NETSNMP_OLDAPI_RWRITE, var_eventTable, 2, {1, 7}} }; struct variable2 logTable_variables[] = { /* * magic number , variable type, ro/rw , callback fn , L, oidsuffix */ {LOGEVENTINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_logTable, 2, {1, 1}}, {LOGINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_logTable, 2, {1, 2}}, {LOGTIME, ASN_TIMETICKS, NETSNMP_OLDAPI_RONLY, var_logTable, 2, {1, 3}}, {LOGDESCRIPTION, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_logTable, 2, {1, 4}} }; void init_event(void) { REGISTER_MIB("eventTable", eventTable_variables, variable2, eventTable_variables_oid); REGISTER_MIB("logTable", logTable_variables, variable2, logTable_variables_oid); ROWAPI_init_table(&EventCtrlTable, "Event", 0, &event_Create, &event_Clone, &event_Delete, NULL, /* &event_Validate, */ &event_Activate, &event_Deactivate, &event_Copy); #if 0 add_event_entry(3, "Alarm", EVENT_LOG_AND_TRAP, NULL); /* * add_event_entry (5, ">=", EVENT_LOG_AND_TRAP, NULL); */ #endif }