diff options
Diffstat (limited to 'agent/mibgroup/notification/snmpNotifyTable.c')
-rw-r--r-- | agent/mibgroup/notification/snmpNotifyTable.c | 1141 |
1 files changed, 1141 insertions, 0 deletions
diff --git a/agent/mibgroup/notification/snmpNotifyTable.c b/agent/mibgroup/notification/snmpNotifyTable.c new file mode 100644 index 0000000..66845ba --- /dev/null +++ b/agent/mibgroup/notification/snmpNotifyTable.c @@ -0,0 +1,1141 @@ +/* + * This file was generated by mib2c and is intended for use as + * a mib module for the ucd-snmp snmpd agent. + */ + + +/* + * This should always be included first before anything else + */ +#include <net-snmp/net-snmp-config.h> + +#include <sys/types.h> +#if HAVE_WINSOCK_H +#include <winsock.h> +#endif +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif + +/* + * minimal include directives + */ +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> + +#include "header_complex.h" +#include "snmpNotifyTable.h" +#include "snmpNotifyFilterProfileTable.h" +#include "target/snmpTargetParamsEntry.h" +#include "target/snmpTargetAddrEntry.h" +#include "target/target.h" +#include "snmp-notification-mib/snmpNotifyFilterTable/snmpNotifyFilterTable.h" +#include <net-snmp/agent/agent_callbacks.h> +#include <net-snmp/agent/agent_trap.h> +#include <net-snmp/agent/mib_module_config.h> + +#ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE +# include "notification-log-mib/notification_log.h" +#endif + +SNMPCallback store_snmpNotifyTable; + +/* + * snmpNotifyTable_variables_oid: + * this is the top level oid that we want to register under. This + * is essentially a prefix, with the suffix appearing in the + * variable below. + */ + + +oid snmpNotifyTable_variables_oid[] = + { 1, 3, 6, 1, 6, 3, 13, 1, 1 }; + + +/* + * variable2 snmpNotifyTable_variables: + * this variable defines function callbacks and type return information + * for the snmpNotifyTable mib section + */ + + +struct variable2 snmpNotifyTable_variables[] = { + /* + * magic number , variable type , ro/rw , callback fn , L, oidsuffix + */ +#define SNMPNOTIFYTAG 4 + {SNMPNOTIFYTAG, ASN_OCTET_STR, RWRITE, var_snmpNotifyTable, 2, {1, 2}}, +#define SNMPNOTIFYTYPE 5 + {SNMPNOTIFYTYPE, ASN_INTEGER, RWRITE, var_snmpNotifyTable, 2, {1, 3}}, +#define SNMPNOTIFYSTORAGETYPE 6 + {SNMPNOTIFYSTORAGETYPE, ASN_INTEGER, RWRITE, var_snmpNotifyTable, 2, + {1, 4}}, +#define SNMPNOTIFYROWSTATUS 7 + {SNMPNOTIFYROWSTATUS, ASN_INTEGER, RWRITE, var_snmpNotifyTable, 2, + {1, 5}}, + +}; +/* + * (L = length of the oidsuffix) + */ + + +/* + * global storage of our data, saved in and configured by header_complex() + */ +static struct header_complex_index *snmpNotifyTableStorage = NULL; + +static int +_checkFilter(const char* paramName, netsnmp_pdu *pdu) +{ + /* + * find appropriate filterProfileEntry + */ + netsnmp_variable_list *var, *trap_var; + char *profileName; + size_t profileNameLen; + struct vacm_viewEntry *vp, *head; + int vb_oid_excluded = 0; + extern oid snmptrap_oid[]; + extern size_t snmptrap_oid_len; + + netsnmp_assert(NULL != paramName); + netsnmp_assert(NULL != pdu); + + DEBUGMSGTL(("send_notifications", "checking filters...\n")); + + /* + A notification originator uses the snmpNotifyFilterTable to filter + notifications. A notification filter profile may be associated with + a particular entry in the snmpTargetParamsTable. The associated + filter profile is identified by an entry in the + snmpNotifyFilterProfileTable whose index is equal to the index of the + entry in the snmpTargetParamsTable. If no such entry exists in the + snmpNotifyFilterProfileTable, no filtering is performed for that + management target. + */ + profileName = get_FilterProfileName(paramName, strlen(paramName), + &profileNameLen); + if (NULL == profileName) { + DEBUGMSGTL(("send_notifications", " no matching profile\n")); + return 0; + } + + /* + If such an entry does exist, the value of snmpNotifyFilterProfileName + of the entry is compared with the corresponding portion of the index + of all active entries in the snmpNotifyFilterTable. All such entries + for which this comparison results in an exact match are used for + filtering a notification generated using the associated + snmpTargetParamsEntry. If no such entries exist, no filtering is + performed, and a notification may be sent to the management target. + */ + head = snmpNotifyFilterTable_vacm_view_subtree(profileName); + if (NULL == head) { + DEBUGMSGTL(("send_notifications", " no matching filters\n")); + return 0; + } + + /* + Otherwise, if matching entries do exist, a notification may be sent + if the NOTIFICATION-TYPE OBJECT IDENTIFIER of the notification (this + is the value of the element of the variable bindings whose name is + snmpTrapOID.0, i.e., the second variable binding) is specifically + included, and none of the object instances to be included in the + variable-bindings of the notification are specifically excluded by + the matching entries. + */ + trap_var = find_varbind_in_list( pdu->variables, + snmptrap_oid, + snmptrap_oid_len); + if (NULL != trap_var) { + /* + For a notification name, if none match, + then the notification name is considered excluded, and the + notification should not be sent to this management target. + */ + vp = netsnmp_view_get(head, profileName, trap_var->val.objid, + trap_var->val_len / sizeof(oid), VACM_MODE_FIND); + if ((NULL == vp) || (SNMP_VIEW_INCLUDED != vp->viewType)) { + DEBUGMSGTL(("send_notifications", " filtered (snmpTrapOID.0 ")); + DEBUGMSGOID(("send_notifications",trap_var->val.objid, + trap_var->val_len / sizeof(oid))); + DEBUGMSG(("send_notifications", " not included)\n")); + free(head); + return 1; + } + } + + /* + * check varbinds + */ + for(var = pdu->variables; var; var = var->next_variable) { + /* + For an + object instance, if none match, the object instance is considered + included, and the notification may be sent to this management target. + */ + + if (var == trap_var) { + continue; + } + + vp = netsnmp_view_get(head, profileName, var->name, + var->name_length, VACM_MODE_FIND); + if ((NULL != vp) && (SNMP_VIEW_EXCLUDED == vp->viewType)) { + DEBUGMSGTL(("send_notifications"," filtered (varbind ")); + DEBUGMSGOID(("send_notifications",var->name, var->name_length)); + DEBUGMSG(("send_notifications", " excluded)\n")); + vb_oid_excluded = 1; + break; + } + } + + free(head); + + return vb_oid_excluded; +} + +int +send_notifications(int major, int minor, void *serverarg, void *clientarg) +{ + struct header_complex_index *hptr; + struct snmpNotifyTable_data *nptr; + netsnmp_session *sess, *sptr; + netsnmp_pdu *template_pdu = (netsnmp_pdu *) serverarg; + int count = 0, send = 0; + + DEBUGMSGTL(("send_notifications", "starting: pdu=%x, vars=%x\n", + template_pdu, template_pdu->variables)); + + for (hptr = snmpNotifyTableStorage; hptr; hptr = hptr->next) { + nptr = (struct snmpNotifyTable_data *) hptr->data; + if (nptr->snmpNotifyRowStatus != RS_ACTIVE) + continue; + if (!nptr->snmpNotifyTag) + continue; + + sess = get_target_sessions(nptr->snmpNotifyTag, NULL, NULL); + + /* + * filter appropriately, per section 6 of RFC 3413 + */ + + for (sptr = sess; sptr; sptr = sptr->next) { + send = 0; +#ifndef NETSNMP_DISABLE_SNMPV1 + if (sptr->version == SNMP_VERSION_1 && + minor == SNMPD_CALLBACK_SEND_TRAP1) { + send = 1; + } else +#endif + if ((sptr->version == SNMP_VERSION_3 +#ifndef NETSNMP_DISABLE_SNMPV2C + || sptr->version == SNMP_VERSION_2c +#endif + ) && minor == SNMPD_CALLBACK_SEND_TRAP2) { + if (nptr->snmpNotifyType == SNMPNOTIFYTYPE_INFORM) { + template_pdu->command = SNMP_MSG_INFORM; + } else { + template_pdu->command = SNMP_MSG_TRAP2; + } + send = 1; + } + if (send && sess->paramName) { + int filter = _checkFilter(sess->paramName, template_pdu); + if (filter) + send = 0; + } + if (send) { + send_trap_to_sess(sptr, template_pdu); + ++count; + } /* session to send to */ + } /* for(sptr) */ + } /* for(hptr) */ + + DEBUGMSGTL(("send_notifications", "sent %d notifications\n", count)); + +#ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE + if (count) + log_notification(template_pdu, NULL); +#endif + + return 0; +} + +#define MAX_ENTRIES 1024 + +int +notifyTable_register_notifications(int major, int minor, + void *serverarg, void *clientarg) +{ + struct targetAddrTable_struct *ptr; + struct targetParamTable_struct *pptr; + struct snmpNotifyTable_data *nptr; + int confirm, i; + char buf[SNMP_MAXBUF_SMALL]; + netsnmp_transport *t = NULL; + struct agent_add_trap_args *args = + (struct agent_add_trap_args *) serverarg; + netsnmp_session *ss; + + if (!args || !(args->ss)) { + return (0); + } + confirm = args->confirm; + ss = args->ss; + + /* + * XXX: START move target creation to target code + */ + for (i = 0; i < MAX_ENTRIES; i++) { + sprintf(buf, "internal%d", i); + if (get_addrForName(buf) == NULL && get_paramEntry(buf) == NULL) + break; + } + if (i == MAX_ENTRIES) { + snmp_log(LOG_ERR, + "Can't register new trap destination: max limit reached: %d", + MAX_ENTRIES); + snmp_sess_close(ss); + return (0); + } + + /* + * address + */ + ptr = snmpTargetAddrTable_create(); + ptr->name = strdup(buf); + t = snmp_sess_transport(snmp_sess_pointer(ss)); + memcpy(ptr->tDomain, t->domain, t->domain_length * sizeof(oid)); + ptr->tDomainLen = t->domain_length; + ptr->tAddressLen = t->remote_length; + ptr->tAddress = t->remote; + + ptr->timeout = ss->timeout / 1000; + ptr->retryCount = ss->retries; + SNMP_FREE(ptr->tagList); + ptr->tagList = strdup(ptr->name); + ptr->params = strdup(ptr->name); + ptr->storageType = ST_READONLY; + ptr->rowStatus = RS_ACTIVE; + ptr->sess = ss; + DEBUGMSGTL(("trapsess", "adding to trap table\n")); + snmpTargetAddrTable_add(ptr); + + /* + * param + */ + pptr = snmpTargetParamTable_create(); + pptr->paramName = strdup(buf); + pptr->mpModel = ss->version; + if (ss->version == SNMP_VERSION_3) { + pptr->secModel = ss->securityModel; + pptr->secLevel = ss->securityLevel; + pptr->secName = (char *) malloc(ss->securityNameLen + 1); + memcpy((void *) pptr->secName, (void *) ss->securityName, + ss->securityNameLen); + pptr->secName[ss->securityNameLen] = 0; + } +#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C) + else { + pptr->secModel = +#ifndef NETSNMP_DISABLE_SNMPV1 + ss->version == SNMP_VERSION_1 ? SNMP_SEC_MODEL_SNMPv1 : +#endif + SNMP_SEC_MODEL_SNMPv2c; + pptr->secLevel = SNMP_SEC_LEVEL_NOAUTH; + pptr->secName = NULL; + if (ss->community && (ss->community_len > 0)) { + pptr->secName = (char *) malloc(ss->community_len + 1); + memcpy((void *) pptr->secName, (void *) ss->community, + ss->community_len); + pptr->secName[ss->community_len] = 0; + } + } +#endif + pptr->storageType = ST_READONLY; + pptr->rowStatus = RS_ACTIVE; + snmpTargetParamTable_add(pptr); + /* + * XXX: END move target creation to target code + */ + + /* + * notify table + */ + nptr = SNMP_MALLOC_STRUCT(snmpNotifyTable_data); + nptr->snmpNotifyName = strdup(buf); + nptr->snmpNotifyNameLen = strlen(buf); + nptr->snmpNotifyTag = strdup(buf); + nptr->snmpNotifyTagLen = strlen(buf); + nptr->snmpNotifyType = confirm ? + SNMPNOTIFYTYPE_INFORM : SNMPNOTIFYTYPE_TRAP; + nptr->snmpNotifyStorageType = ST_READONLY; + nptr->snmpNotifyRowStatus = RS_ACTIVE; + + snmpNotifyTable_add(nptr); + return 0; +} + + +/* + * XXX: this really needs to be done for the target mib entries too. + * But we can only trust that we've added stuff here and we don't want + * to destroy other valid entries in the target tables, so... Don't + * do too many kill -HUPs to your agent as re reading the config file + * will be a slow memory leak in the target mib. + */ +int +notifyTable_unregister_notifications(int major, int minor, + void *serverarg, void *clientarg) +{ + struct header_complex_index *hptr, *nhptr; + struct snmpNotifyTable_data *nptr; + + for (hptr = snmpNotifyTableStorage; hptr; hptr = nhptr) { + nptr = (struct snmpNotifyTable_data *) hptr->data; + nhptr = hptr->next; + if (nptr->snmpNotifyStorageType == ST_READONLY) { + header_complex_extract_entry(&snmpNotifyTableStorage, hptr); + SNMP_FREE(nptr->snmpNotifyName); + SNMP_FREE(nptr->snmpNotifyTag); + SNMP_FREE(nptr); + } + } + return (0); +} + +/* + * init_snmpNotifyTable(): + * Initialization routine. This is called when the agent starts up. + * At a minimum, registration of your variables should take place here. + */ +void +init_snmpNotifyTable(void) +{ + DEBUGMSGTL(("snmpNotifyTable", "initializing... ")); + + + /* + * register ourselves with the agent to handle our mib tree + */ + REGISTER_MIB("snmpNotifyTable", snmpNotifyTable_variables, variable2, + snmpNotifyTable_variables_oid); + + + /* + * register our config handler(s) to deal with registrations + */ + snmpd_register_config_handler("snmpNotifyTable", parse_snmpNotifyTable, + NULL, NULL); + + + /* + * we need to be called back later to store our data + */ + snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA, + store_snmpNotifyTable, NULL); + + snmp_register_callback(SNMP_CALLBACK_APPLICATION, + SNMPD_CALLBACK_SEND_TRAP1, send_notifications, + NULL); + snmp_register_callback(SNMP_CALLBACK_APPLICATION, + SNMPD_CALLBACK_SEND_TRAP2, send_notifications, + NULL); + snmp_register_callback(SNMP_CALLBACK_APPLICATION, + SNMPD_CALLBACK_REGISTER_NOTIFICATIONS, + notifyTable_register_notifications, NULL); + snmp_register_callback(SNMP_CALLBACK_APPLICATION, + SNMPD_CALLBACK_PRE_UPDATE_CONFIG, + notifyTable_unregister_notifications, NULL); + + /* + * place any other initialization junk you need here + */ + + + DEBUGMSGTL(("snmpNotifyTable", "done.\n")); +} + + +/* + * snmpNotifyTable_add(): adds a structure node to our data set + */ +int +snmpNotifyTable_add(struct snmpNotifyTable_data *thedata) +{ + netsnmp_variable_list *vars = NULL; + + + DEBUGMSGTL(("snmpNotifyTable", "adding data... ")); + /* + * add the index variables to the varbind list, which is + * used by header_complex to index the data + */ + + + snmp_varlist_add_variable(&vars, NULL, 0, ASN_PRIV_IMPLIED_OCTET_STR, (u_char *) thedata->snmpNotifyName, thedata->snmpNotifyNameLen); /* snmpNotifyName */ + + + + header_complex_add_data(&snmpNotifyTableStorage, vars, thedata); + DEBUGMSGTL(("snmpNotifyTable", "registered an entry\n")); + + + DEBUGMSGTL(("snmpNotifyTable", "done.\n")); + return SNMPERR_SUCCESS; +} + + +/* + * parse_snmpNotifyTable(): + * parses .conf file entries needed to configure the mib. + */ +void +parse_snmpNotifyTable(const char *token, char *line) +{ + size_t tmpint; + struct snmpNotifyTable_data *StorageTmp = + SNMP_MALLOC_STRUCT(snmpNotifyTable_data); + + + DEBUGMSGTL(("snmpNotifyTable", "parsing config... ")); + + + if (StorageTmp == NULL) { + config_perror("malloc failure"); + return; + } + + line = + read_config_read_data(ASN_OCTET_STR, line, + &StorageTmp->snmpNotifyName, + &StorageTmp->snmpNotifyNameLen); + if (StorageTmp->snmpNotifyName == NULL) { + config_perror("invalid specification for snmpNotifyName"); + return; + } + + line = + read_config_read_data(ASN_OCTET_STR, line, + &StorageTmp->snmpNotifyTag, + &StorageTmp->snmpNotifyTagLen); + if (StorageTmp->snmpNotifyTag == NULL) { + config_perror("invalid specification for snmpNotifyTag"); + return; + } + + line = + read_config_read_data(ASN_INTEGER, line, + &StorageTmp->snmpNotifyType, &tmpint); + + line = + read_config_read_data(ASN_INTEGER, line, + &StorageTmp->snmpNotifyStorageType, &tmpint); + + line = + read_config_read_data(ASN_INTEGER, line, + &StorageTmp->snmpNotifyRowStatus, &tmpint); + + + + + snmpNotifyTable_add(StorageTmp); + + + DEBUGMSGTL(("snmpNotifyTable", "done.\n")); +} + + + + +/* + * store_snmpNotifyTable(): + * stores .conf file entries needed to configure the mib. + */ +int +store_snmpNotifyTable(int majorID, int minorID, void *serverarg, + void *clientarg) +{ + char line[SNMP_MAXBUF]; + char *cptr; + size_t tmpint; + struct snmpNotifyTable_data *StorageTmp; + struct header_complex_index *hcindex; + + + DEBUGMSGTL(("snmpNotifyTable", "storing data... ")); + + + for (hcindex = snmpNotifyTableStorage; hcindex != NULL; + hcindex = hcindex->next) { + StorageTmp = (struct snmpNotifyTable_data *) hcindex->data; + + /* + * store permanent and nonvolatile rows. + * XXX should there be a qualification on RowStatus?? + */ + if ((StorageTmp->snmpNotifyStorageType == ST_NONVOLATILE) || + (StorageTmp->snmpNotifyStorageType == ST_PERMANENT) ){ + + memset(line, 0, sizeof(line)); + strcat(line, "snmpNotifyTable "); + cptr = line + strlen(line); + + cptr = + read_config_store_data(ASN_OCTET_STR, cptr, + &StorageTmp->snmpNotifyName, + &StorageTmp->snmpNotifyNameLen); + cptr = + read_config_store_data(ASN_OCTET_STR, cptr, + &StorageTmp->snmpNotifyTag, + &StorageTmp->snmpNotifyTagLen); + cptr = + read_config_store_data(ASN_INTEGER, cptr, + &StorageTmp->snmpNotifyType, + &tmpint); + cptr = + read_config_store_data(ASN_INTEGER, cptr, + &StorageTmp->snmpNotifyStorageType, + &tmpint); + cptr = + read_config_store_data(ASN_INTEGER, cptr, + &StorageTmp->snmpNotifyRowStatus, + &tmpint); + + snmpd_store_config(line); + } + } + DEBUGMSGTL(("snmpNotifyTable", "done.\n")); + return 0; +} + + + + +/* + * var_snmpNotifyTable(): + * Handle this table separately from the scalar value case. + * The workings of this are basically the same as for var_snmpNotifyTable above. + */ +unsigned char * +var_snmpNotifyTable(struct variable *vp, + oid * name, + size_t * length, + int exact, + size_t * var_len, WriteMethod ** write_method) +{ + struct snmpNotifyTable_data *StorageTmp = NULL; + int found = 1; + + DEBUGMSGTL(("snmpNotifyTable", + "var_snmpNotifyTable: Entering... \n")); + /* + * this assumes you have registered all your data properly + */ + if ((StorageTmp = (struct snmpNotifyTable_data *) + header_complex((struct header_complex_index *) + snmpNotifyTableStorage, vp, name, length, exact, + var_len, write_method)) == NULL) { + found = 0; + } + + switch (vp->magic) { + case SNMPNOTIFYTAG: + *write_method = write_snmpNotifyTag; + break; + case SNMPNOTIFYTYPE: + *write_method = write_snmpNotifyType; + break; + case SNMPNOTIFYSTORAGETYPE: + *write_method = write_snmpNotifyStorageType; + break; + case SNMPNOTIFYROWSTATUS: + *write_method = write_snmpNotifyRowStatus; + break; + default: + *write_method = NULL; + } + + if (!found) { + return NULL; + } + + switch (vp->magic) { + case SNMPNOTIFYTAG: + *var_len = StorageTmp->snmpNotifyTagLen; + return (u_char *) StorageTmp->snmpNotifyTag; + + case SNMPNOTIFYTYPE: + *var_len = sizeof(StorageTmp->snmpNotifyType); + return (u_char *) & StorageTmp->snmpNotifyType; + + case SNMPNOTIFYSTORAGETYPE: + *var_len = sizeof(StorageTmp->snmpNotifyStorageType); + return (u_char *) & StorageTmp->snmpNotifyStorageType; + + case SNMPNOTIFYROWSTATUS: + *var_len = sizeof(StorageTmp->snmpNotifyRowStatus); + return (u_char *) & StorageTmp->snmpNotifyRowStatus; + + default: + ERROR_MSG(""); + } + return NULL; +} + +static int +is_delim(const char c) +{ + return (c == 0x020 || c == 0x09 || c == 0x0d || c == 0x0b); +} + +int +snmpTagValid(const char *tag, const size_t tagLen) +{ + size_t i = 0; + + + for (i = 0; i < tagLen; i++) { + if (is_delim(tag[i])) { + /* + * Delimeters aren't allowed. + */ + return 0; + } + } + return 1; +} + +static struct snmpNotifyTable_data *StorageNew; + +int +write_snmpNotifyTag(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) +{ + static char *tmpvar; + struct snmpNotifyTable_data *StorageTmp = NULL; + static size_t tmplen; + size_t newlen = + name_len - (sizeof(snmpNotifyTable_variables_oid) / sizeof(oid) + + 3 - 1); + + + DEBUGMSGTL(("snmpNotifyTable", + "write_snmpNotifyTag entering action=%d... \n", action)); + if (action != RESERVE1 && + (StorageTmp = (struct snmpNotifyTable_data *) + header_complex((struct header_complex_index *) + snmpNotifyTableStorage, NULL, + &name[sizeof(snmpNotifyTable_variables_oid) / + sizeof(oid) + 3 - 1], &newlen, 1, NULL, + NULL)) == NULL) { + if ((StorageTmp = StorageNew) == NULL) + return SNMP_ERR_NOSUCHNAME; /* remove if you support creation here */ + } + + + switch (action) { + case RESERVE1: + if (var_val_type != ASN_OCTET_STR) { + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len < 0 || var_val_len > 255) { + return SNMP_ERR_WRONGLENGTH; + } + if (!snmpTagValid(var_val, var_val_len)) { + return SNMP_ERR_WRONGVALUE; + } + break; + + + case RESERVE2: + /* + * memory reseveration, final preparation... + */ + tmpvar = StorageTmp->snmpNotifyTag; + tmplen = StorageTmp->snmpNotifyTagLen; + StorageTmp->snmpNotifyTag = calloc(1, var_val_len + 1); + if (NULL == StorageTmp->snmpNotifyTag) + return SNMP_ERR_RESOURCEUNAVAILABLE; + break; + + + case FREE: + /* + * Release any resources that have been allocated + */ + break; + + + case ACTION: + memcpy(StorageTmp->snmpNotifyTag, var_val, var_val_len); + StorageTmp->snmpNotifyTagLen = var_val_len; + break; + + + case UNDO: + /* + * Back out any changes made in the ACTION case + */ + SNMP_FREE(StorageTmp->snmpNotifyTag); + StorageTmp->snmpNotifyTag = tmpvar; + StorageTmp->snmpNotifyTagLen = tmplen; + tmpvar = NULL; + break; + + + case COMMIT: + /* + * Things are working well, so it's now safe to make the change + * permanently. Make sure that anything done here can't fail! + */ + SNMP_FREE(tmpvar); + break; + } + + return SNMP_ERR_NOERROR; +} + + + +int +write_snmpNotifyType(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) +{ + static int tmpvar; + struct snmpNotifyTable_data *StorageTmp = NULL; + long value = *((long *) var_val); + size_t newlen = + name_len - (sizeof(snmpNotifyTable_variables_oid) / sizeof(oid) + + 3 - 1); + + + DEBUGMSGTL(("snmpNotifyTable", + "write_snmpNotifyType entering action=%d... \n", action)); + if (action != RESERVE1 && + (StorageTmp = (struct snmpNotifyTable_data *) + header_complex((struct header_complex_index *) + snmpNotifyTableStorage, NULL, + &name[sizeof(snmpNotifyTable_variables_oid) / + sizeof(oid) + 3 - 1], &newlen, 1, NULL, + NULL)) == NULL) { + if ((StorageTmp = StorageNew) == NULL) + return SNMP_ERR_NOSUCHNAME; + } + + switch (action) { + case RESERVE1: + if (var_val_type != ASN_INTEGER) { + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len != sizeof(long)) { + return SNMP_ERR_WRONGLENGTH; + } + if (value < 1 || value > 2) { + return SNMP_ERR_WRONGVALUE; + } + break; + + case ACTION: + tmpvar = StorageTmp->snmpNotifyType; + StorageTmp->snmpNotifyType = value; + break; + + case UNDO: + /* + * Back out any changes made in the ACTION case + */ + StorageTmp->snmpNotifyType = tmpvar; + break; + } + + return SNMP_ERR_NOERROR; +} + + + +int +write_snmpNotifyStorageType(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) +{ + static int tmpvar; + long value = *((long *) var_val); + struct snmpNotifyTable_data *StorageTmp = NULL; + size_t newlen = + name_len - (sizeof(snmpNotifyTable_variables_oid) / sizeof(oid) + + 3 - 1); + + + DEBUGMSGTL(("snmpNotifyTable", + "write_snmpNotifyStorageType entering action=%d... \n", + action)); + if (action != RESERVE1 && + (StorageTmp = (struct snmpNotifyTable_data *) + header_complex((struct header_complex_index *) + snmpNotifyTableStorage, NULL, + &name[sizeof(snmpNotifyTable_variables_oid) / + sizeof(oid) + 3 - 1], &newlen, 1, NULL, + NULL)) == NULL) { + if ((StorageTmp = StorageNew) == NULL) + return SNMP_ERR_NOSUCHNAME; + } + + + switch (action) { + case RESERVE1: + if (var_val_type != ASN_INTEGER) { + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len != sizeof(long)) { + return SNMP_ERR_WRONGLENGTH; + } + if (value != SNMP_STORAGE_OTHER && value != SNMP_STORAGE_VOLATILE + && value != SNMP_STORAGE_NONVOLATILE) { + return SNMP_ERR_WRONGVALUE; + } + break; + + case ACTION: + tmpvar = StorageTmp->snmpNotifyStorageType; + StorageTmp->snmpNotifyStorageType = value; + break; + + case UNDO: + StorageTmp->snmpNotifyStorageType = tmpvar; + break; + } + return SNMP_ERR_NOERROR; +} + + + +int +write_snmpNotifyRowStatus(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) +{ + struct snmpNotifyTable_data *StorageTmp = NULL; + static struct snmpNotifyTable_data *StorageDel; + size_t newlen = + name_len - (sizeof(snmpNotifyTable_variables_oid) / sizeof(oid) + + 3 - 1); + static int old_value; + int set_value = *((long *) var_val); + static netsnmp_variable_list *vars, *vp; + struct header_complex_index *hciptr; + + + DEBUGMSGTL(("snmpNotifyTable", + "write_snmpNotifyRowStatus entering action=%d... \n", + action)); + StorageTmp = (struct snmpNotifyTable_data *) + header_complex((struct header_complex_index *) + snmpNotifyTableStorage, NULL, + &name[sizeof(snmpNotifyTable_variables_oid) / + sizeof(oid) + 3 - 1], &newlen, 1, NULL, NULL); + + switch (action) { + case RESERVE1: + if (var_val_type != ASN_INTEGER || var_val == NULL) { + return SNMP_ERR_WRONGTYPE; + } + if (var_val_len != sizeof(long)) { + return SNMP_ERR_WRONGLENGTH; + } + if (set_value < 1 || set_value > 6 || set_value == RS_NOTREADY) { + return SNMP_ERR_WRONGVALUE; + } + if (StorageTmp == NULL) { + /* + * create the row now? + */ + /* + * ditch illegal values now + */ + if (set_value == RS_ACTIVE || set_value == RS_NOTINSERVICE) { + return SNMP_ERR_INCONSISTENTVALUE; + } + } else { + /* + * row exists. Check for a valid state change + */ + if (set_value == RS_CREATEANDGO + || set_value == RS_CREATEANDWAIT) { + /* + * can't create a row that exists + */ + return SNMP_ERR_INCONSISTENTVALUE; + } + /* + * XXX: interaction with row storage type needed + */ + } + + /* + * memory reseveration, final preparation... + */ + if (StorageTmp == NULL && + (set_value == RS_CREATEANDGO + || set_value == RS_CREATEANDWAIT)) { + /* + * creation + */ + vars = NULL; + + snmp_varlist_add_variable(&vars, NULL, 0, ASN_PRIV_IMPLIED_OCTET_STR, NULL, 0); /* snmpNotifyName */ + + if (header_complex_parse_oid + (& + (name + [sizeof(snmpNotifyTable_variables_oid) / sizeof(oid) + + 2]), newlen, vars) != SNMPERR_SUCCESS) { + /* + * XXX: free, zero vars + */ + snmp_free_var(vars); + return SNMP_ERR_INCONSISTENTNAME; + } + vp = vars; + + + StorageNew = SNMP_MALLOC_STRUCT(snmpNotifyTable_data); + if (StorageNew == NULL) { + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + StorageNew->snmpNotifyName = calloc( 1, vp->val_len + 1 ); + if (StorageNew->snmpNotifyName == NULL) { + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + memcpy(StorageNew->snmpNotifyName, vp->val.string, vp->val_len); + StorageNew->snmpNotifyNameLen = vp->val_len; + vp = vp->next_variable; + + /* + * default values + */ + StorageNew->snmpNotifyStorageType = ST_NONVOLATILE; + StorageNew->snmpNotifyType = SNMPNOTIFYTYPE_TRAP; + StorageNew->snmpNotifyTagLen = 0; + StorageNew->snmpNotifyTag = (char *) calloc(sizeof(char), 1); + if (StorageNew->snmpNotifyTag == NULL) { + return SNMP_ERR_RESOURCEUNAVAILABLE; + } + + StorageNew->snmpNotifyRowStatus = set_value; + snmp_free_var(vars); + } + break; + + case RESERVE2: + break; + + case FREE: + if (StorageNew != NULL) { + SNMP_FREE(StorageNew->snmpNotifyTag); + SNMP_FREE(StorageNew->snmpNotifyName); + free(StorageNew); + StorageNew = NULL; + } + break; + + case ACTION: + if (StorageTmp == NULL && (set_value == RS_CREATEANDGO || + set_value == RS_CREATEANDWAIT)) { + /* + * row creation, so add it + */ + if (StorageNew != NULL) { + snmpNotifyTable_add(StorageNew); + } + } else if (set_value != RS_DESTROY) { + /* + * set the flag? + */ + if (StorageTmp == NULL) + return SNMP_ERR_GENERR; /* should never ever get here */ + + old_value = StorageTmp->snmpNotifyRowStatus; + StorageTmp->snmpNotifyRowStatus = *((long *) var_val); + } else { + /* + * destroy... extract it for now + */ + if (StorageTmp) { + hciptr = header_complex_find_entry(snmpNotifyTableStorage, + StorageTmp); + StorageDel = (struct snmpNotifyTable_data *) + header_complex_extract_entry((struct + header_complex_index **) + &snmpNotifyTableStorage, + hciptr); + } + } + break; + + case UNDO: + /* + * Back out any changes made in the ACTION case + */ + if (StorageTmp == NULL && (set_value == RS_CREATEANDGO || + set_value == RS_CREATEANDWAIT)) { + /* + * row creation, so remove it again + */ + hciptr = header_complex_find_entry(snmpNotifyTableStorage, + StorageNew); + StorageDel = (struct snmpNotifyTable_data *) + header_complex_extract_entry((struct header_complex_index + **) &snmpNotifyTableStorage, + hciptr); + /* + * XXX: free it + */ + } else if (StorageDel != NULL) { + /* + * row deletion, so add it again + */ + snmpNotifyTable_add(StorageDel); + } else if (set_value != RS_DESTROY) { + if (StorageTmp) + StorageTmp->snmpNotifyRowStatus = old_value; + } + break; + + case COMMIT: + if (StorageDel != NULL) { + SNMP_FREE(StorageDel->snmpNotifyTag); + SNMP_FREE(StorageDel->snmpNotifyName); + free(StorageDel); + StorageDel = NULL; + } + if (StorageTmp + && StorageTmp->snmpNotifyRowStatus == RS_CREATEANDGO) { + StorageTmp->snmpNotifyRowStatus = RS_ACTIVE; + StorageNew = NULL; + } else if (StorageTmp && + StorageTmp->snmpNotifyRowStatus == RS_CREATEANDWAIT) { + StorageTmp->snmpNotifyRowStatus = RS_NOTINSERVICE; + StorageNew = NULL; + } + break; + } + return SNMP_ERR_NOERROR; +} |