/*
* This file was created to separate data storage from MIB implementation.
*
* Portions of this file are copyrighted by:
* Copyright (c) 2016 VMware, Inc. All rights reserved.
* Use is subject to license terms specified in the COPYING file
* distributed with the Net-SNMP package.
*/
/*
* This should always be included first before anything else
*/
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-features.h>
#include <sys/types.h>
#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 "agent_global_vars.h"
#include "header_complex.h"
#include "snmpNotifyTable_data.h"
#include "notification/snmpNotifyFilterProfileTable_data.h"
#include "target/snmpTargetParamsEntry_data.h"
#include "target/snmpTargetAddrEntry_data.h"
#include "target/target.h"
#include "agentx/subagent.h"
#include "snmp-notification-mib/snmpNotifyFilterTable/snmpNotifyFilterTable_data_storage.h"
#include <net-snmp/agent/agent_callbacks.h>
#include <net-snmp/agent/agent_trap.h>
#include <net-snmp/agent/mib_module_config.h>
#include "net-snmp/agent/sysORTable.h"
#ifdef USING_NOTIFICATION_LOG_MIB_NOTIFICATION_LOG_MODULE
# include "notification-log-mib/notification_log.h"
#endif
SNMPCallback store_snmpNotifyTable;
static int
_unregister_notification_cb(int major, int minor,
void *serverarg, void *clientarg);
/*
* global storage of our data, saved in and configured by header_complex()
*/
static struct header_complex_index *snmpNotifyTableStorage = NULL;
static int _active = 0;
static int
_checkFilter(const char* paramName, netsnmp_pdu *pdu)
{
/*
* find appropriate filterProfileEntry
*/
netsnmp_variable_list *var, *trap_var = NULL;
char *profileName;
size_t profileNameLen;
struct vacm_viewEntry *vp, *head;
int vb_oid_excluded = 0, free_trapvar = 0;
netsnmp_assert(NULL != paramName);
netsnmp_assert(NULL != pdu);
DEBUGMSGTL(("send_notifications", "checking filters for '%s'...\n",
paramName));
/*
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.
*/
/** xxx paramName from session doesn't have length. will be
* trouble with paramNames with embedded NULL */
profileName = get_FilterProfileName(paramName, strlen(paramName),
&profileNameLen);
if (NULL == profileName) /* try default */
profileName = get_FilterProfileName("default", 7, &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 = snmpNotifyFilter_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.
*/
if (NULL != pdu->variables) {
trap_var = find_varbind_in_list( pdu->variables,
snmptrap_oid, snmptrap_oid_len);
}
#if !defined(NETSNMP_DISABLE_SNMPV1)
else {
/** snmpv1 pdus have no varbinds. build trapoid */
oid enterprise[MAX_OID_LEN];
size_t enterprise_len;
enterprise_len = OID_LENGTH(enterprise);
if ((netsnmp_build_trap_oid(pdu, enterprise, &enterprise_len)
!= SNMPERR_SUCCESS) ||
!snmp_varlist_add_variable(&trap_var, snmptrap_oid,
snmptrap_oid_len,
ASN_OBJECT_ID, (u_char*)enterprise,
enterprise_len*sizeof(oid))) {
snmp_log(LOG_WARNING,
"checkFilter: failed to build snmpTrapOID varbind\n");
} else
free_trapvar = 1;
}
#endif /* NETSNMP_DISABLE_SNMPV1 */
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);
if (free_trapvar)
snmp_free_varbind(trap_var);
return 1;
}
}
if (free_trapvar) {
snmp_free_varbind(trap_var);
trap_var = NULL;
}
/*
* 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;
DEBUGMSGTL(("send_notifications", "starting: pdu=%p, vars=%p\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) {
#ifndef NETSNMP_DISABLE_SNMPV1
if (sptr->version == SNMP_VERSION_1 &&
minor != SNMPD_CALLBACK_SEND_TRAP1) {
continue;
} else
#endif
if (sptr->version == SNMP_VERSION_3
#ifndef NETSNMP_DISABLE_SNMPV2C
|| sptr->version == SNMP_VERSION_2c
#endif
) {
if(minor != SNMPD_CALLBACK_SEND_TRAP2)
continue;
if (nptr->snmpNotifyType == SNMPNOTIFYTYPE_INFORM) {
template_pdu->command = SNMP_MSG_INFORM;
} else {
template_pdu->command = SNMP_MSG_TRAP2;
}
}
if (sess->paramName) {
int filter = _checkFilter(sess->paramName, template_pdu);
if (filter)
continue;
}
send_trap_to_sess(sptr, template_pdu);
++count;
} /* 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 = NULL;
struct targetParamTable_struct *pptr = NULL;
struct snmpNotifyTable_data *nptr = NULL;
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;
const char *name, *tag, *notifyProfile;
int nameLen, tagLen, notifyProfileLen;
if (!args || !(args->ss)) {
return (0);
}
args->rc = SNMPERR_GENERR;
confirm = args->confirm;
ss = args->ss;
name = args->nameData;
nameLen = args->nameLen;
tag = args->tagData;
tagLen = args->tagLen;
notifyProfile = args->profileData;
notifyProfileLen = args->profileLen;
/*
* XXX: START move target creation to target code
*/
if (NULL == name) {
int len;
for (i = 0; i < MAX_ENTRIES; i++) {
sprintf(buf, "internal%d", i);
len = strlen(buf);
if ((get_addrForName2(buf,len) == NULL) &&
(get_paramEntry2(buf,len) == 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);
}
name = buf;
nameLen = len;
if (NULL == tag) {
tag = buf;
tagLen = len;
}
} else {
if (NULL == tag) {
tag = name;
tagLen = nameLen;
}
}
/*
* address
*/
t = snmp_sess_transport(snmp_sess_pointer(ss));
if (!t) {
snmp_log(LOG_ERR,
"Cannot add new trap destination, transport is closed.");
snmp_sess_close(ss);
return 0;
}
ptr = snmpTargetAddrTable_create();
if (!ptr)
goto bail;
ptr->nameData = netsnmp_memdup_nt(name, nameLen, &ptr->nameLen);
memcpy(ptr->tDomain, t->domain, t->domain_length * sizeof(oid));
ptr->tDomainLen = t->domain_length;
if (t->f_get_taddr)
t->f_get_taddr(t, &ptr->tAddress, &ptr->tAddressLen);
else
netsnmp_assert(0);
ptr->timeout = ss->timeout / 1000;
ptr->retryCount = ss->retries;
SNMP_FREE(ptr->tagListData);
ptr->tagListData = netsnmp_memdup_nt(tag, tagLen, &ptr->tagListLen);
/** link to target param table */
ptr->paramsData = netsnmp_memdup_nt(name, nameLen, &ptr->paramsLen);
if (!ptr->paramsData || !ptr->tagListData || !ptr->nameData)
goto bail;
ptr->storageType = ST_READONLY;
ptr->rowStatus = RS_ACTIVE;
ptr->sess = ss;
DEBUGMSGTL(("trapsess", "adding %s to trap table\n", ptr->nameData));
snmpTargetAddrTable_add(ptr);
/*
* param
*/
pptr = snmpTargetParamTable_create();
if (NULL == pptr)
goto bail;
/** link from target addr table */
pptr->paramNameData = netsnmp_memdup_nt(ptr->paramsData, ptr->paramsLen,
&pptr->paramNameLen);
if (!pptr->paramNameData)
goto bail;
pptr->mpModel = ss->version;
if (ss->version == SNMP_VERSION_3) {
pptr->secModel = ss->securityModel;
pptr->secLevel = ss->securityLevel;
pptr->secNameData = netsnmp_memdup_nt(ss->securityName,
ss->securityNameLen,
&pptr->secNameLen);
if (pptr->secNameData == NULL)
goto bail;
}
#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->secNameData = NULL;
if (ss->community && (ss->community_len > 0)) {
pptr->secNameData = netsnmp_memdup_nt(ss->community,
ss->community_len,
&pptr->secNameLen);
if (pptr->secNameData == NULL)
goto bail;
}
}
#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);
if (nptr == NULL)
goto bail;
++_active;
nptr->snmpNotifyName = netsnmp_memdup_nt(name, nameLen,
&nptr->snmpNotifyNameLen);
/** selects target addr */
nptr->snmpNotifyTag = netsnmp_memdup_nt(tag, tagLen,
&nptr->snmpNotifyTagLen);
if (!nptr->snmpNotifyName || !nptr->snmpNotifyTag)
goto bail;
nptr->snmpNotifyType = confirm ?
SNMPNOTIFYTYPE_INFORM : SNMPNOTIFYTYPE_TRAP;
nptr->snmpNotifyStorageType = ST_READONLY;
nptr->snmpNotifyRowStatus = RS_ACTIVE;
if (snmpNotifyTable_add(nptr) == SNMPERR_GENERR) {
snmpNotifyTable_dispose(nptr);
nptr = NULL;
goto bail;
}
/*
* filter profile
*/
if (NULL != notifyProfile) {
struct snmpNotifyFilterProfileTable_data *profile;
profile = snmpNotifyFilterProfileTable_create(ptr->paramsData,
ptr->paramsLen,
notifyProfile,
notifyProfileLen);
if (NULL == profile) {
snmp_log(LOG_ERR, "couldn't create notify filter profile\n");
goto bail;
} else {
profile->snmpNotifyFilterProfileRowStatus = RS_ACTIVE;
profile->snmpNotifyFilterProfileStorType = ST_READONLY;
if (snmpNotifyFilterProfileTable_add(profile) != SNMPERR_SUCCESS) {
snmp_log(LOG_ERR, "couldn't add notify filter profile\n");
snmpNotifyFilterProfileTable_free(profile);
}
}
}
args->rc = SNMPERR_SUCCESS;
return 0;
bail:
snmp_log(LOG_ERR, "Cannot add new trap destination");
if (NULL != nptr)
snmpNotifyTable_remove(nptr);
if (NULL != pptr)
snmpTargetParamTable_remove(pptr);
if (NULL != ptr)
snmpTargetAddrTable_remove(ptr);
snmp_sess_close(ss);
return 0;
}
void
snmpNotifyTable_dispose(struct snmpNotifyTable_data *thedata)
{
if (NULL == thedata)
return;
SNMP_FREE(thedata->snmpNotifyName);
SNMP_FREE(thedata->snmpNotifyTag);
free(thedata);
--_active;
}
/*
* 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_all_notifications(int major, int minor,
void *serverarg, void *clientarg)
{
struct header_complex_index *hptr, *nhptr;
for (hptr = snmpNotifyTableStorage; hptr; hptr = nhptr) {
struct snmpNotifyTable_data *nptr = hptr->data;
nhptr = hptr->next;
if (nptr->snmpNotifyStorageType == ST_READONLY) {
header_complex_extract_entry(&snmpNotifyTableStorage, hptr);
snmpNotifyTable_dispose(nptr);
}
}
snmpNotifyTableStorage = NULL;
return (0);
}
/*
* init_snmpNotifyTable_data():
* Initialization routine. This is called when the agent starts up.
*/
void
init_snmpNotifyTable_data(void)
{
static int done = 0;
if (++done != 1) {
DEBUGMSGTL(("snmpNotifyTable_data", "multiple init calls"));
return;
}
DEBUGMSGTL(("snmpNotifyTable_data", "initializing... "));
/*
* we need to be called back later to store our data
*/
snmp_register_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
store_snmpNotifyTable, NULL);
#ifndef DISABLE_SNMPV1
snmp_register_callback(SNMP_CALLBACK_APPLICATION,
SNMPD_CALLBACK_SEND_TRAP1, send_notifications,
NULL);
#endif
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_UNREGISTER_NOTIFICATIONS,
_unregister_notification_cb, NULL);
snmp_register_callback(SNMP_CALLBACK_APPLICATION,
SNMPD_CALLBACK_PRE_UPDATE_CONFIG,
notifyTable_unregister_all_notifications, NULL);
DEBUGMSGTL(("snmpNotifyTable_data", "done.\n"));
}
void
shutdown_snmpNotifyTable_data(void)
{
DEBUGMSGTL(("snmpNotifyTable_data", "shutting down ... "));
snmp_unregister_callback(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_STORE_DATA,
store_snmpNotifyTable, NULL, FALSE);
notifyTable_unregister_all_notifications(SNMP_CALLBACK_APPLICATION,
SNMPD_CALLBACK_PRE_UPDATE_CONFIG,
NULL, NULL);
snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
SNMPD_CALLBACK_PRE_UPDATE_CONFIG,
notifyTable_unregister_all_notifications, NULL,
FALSE);
snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
SNMPD_CALLBACK_REGISTER_NOTIFICATIONS,
notifyTable_register_notifications, NULL, FALSE);
snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
SNMPD_CALLBACK_UNREGISTER_NOTIFICATIONS,
_unregister_notification_cb, NULL, FALSE);
snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
SNMPD_CALLBACK_SEND_TRAP2, send_notifications,
NULL, FALSE);
#ifndef DISABLE_SNMPV1
snmp_unregister_callback(SNMP_CALLBACK_APPLICATION,
SNMPD_CALLBACK_SEND_TRAP1, send_notifications,
NULL, FALSE);
#endif
DEBUGMSGTL(("trap:notify:shutdown", "active count %d\n", _active));
if (_active != 0) {
DEBUGMSGTL(("trap:notify:shutdown",
"unexpected count %d after cleanup!\n",_active));
snmp_log(LOG_WARNING,
"notify count %d, not 0, after shutdown.\n", _active);
}
DEBUGMSGTL(("snmpNotifyTable_data", "done.\n"));
}
/*
* snmpNotifyTable_add(): adds a structure node to our data set
*/
int
snmpNotifyTable_add(struct snmpNotifyTable_data *thedata)
{
netsnmp_variable_list *vars = NULL;
int retVal;
if (NULL == thedata)
return SNMPERR_GENERR;
DEBUGMSGTL(("snmpNotifyTable_data", "adding data... "));
/*
* add the index variables to the varbind list, which is
* used by header_complex to index the data. the allocated
* variable will be freed by header_complex_maybe_add_data().
*/
snmp_varlist_add_variable(&vars, NULL, 0, ASN_PRIV_IMPLIED_OCTET_STR, (u_char *) thedata->snmpNotifyName, thedata->snmpNotifyNameLen); /* snmpNotifyName */
if (header_complex_maybe_add_data(&snmpNotifyTableStorage, vars, thedata, 1)
!= NULL){
DEBUGMSGTL(("snmpNotifyTable", "registered an entry\n"));
retVal = SNMPERR_SUCCESS;
}else{
retVal = SNMPERR_GENERR;
}
DEBUGMSGTL(("snmpNotifyTable", "done.\n"));
return retVal;
}
struct snmpNotifyTable_data *
snmpNotifyTable_extract(struct snmpNotifyTable_data *thedata)
{
struct header_complex_index *hptr;
hptr = header_complex_find_entry(snmpNotifyTableStorage, thedata);
if (NULL == hptr)
return NULL;
return header_complex_extract_entry((struct header_complex_index**)
&snmpNotifyTableStorage, hptr);
}
int
snmpNotifyTable_remove(struct snmpNotifyTable_data *thedata)
{
struct snmpNotifyTable_data *nptr = snmpNotifyTable_extract(thedata);
if (nptr) {
snmpNotifyTable_dispose(nptr);
return 1;
}
return 0;
}
struct snmpNotifyTable_data *
get_notifyTable2(const char *name, size_t nameLen)
{
struct header_complex_index *hptr;
for (hptr = snmpNotifyTableStorage; hptr; hptr = hptr->next) {
struct snmpNotifyTable_data *nptr = hptr->data;
if (nptr->snmpNotifyNameLen == nameLen && nptr->snmpNotifyName &&
memcmp(nptr->snmpNotifyName, name, nameLen) == 0)
return nptr;
}
return NULL;
}
struct snmpNotifyTable_data *
find_row_notifyTable(struct variable *vp, oid * name, size_t * len, int exact,
size_t * var_len, WriteMethod ** write_method)
{
struct snmpNotifyTable_data *result =
header_complex((struct header_complex_index *)
snmpNotifyTableStorage, vp, name, len, exact,
var_len, write_method);
return result;
}
void
snmpNotifyTable_unregister_notification(const char *name, unsigned char nameLen)
{
struct targetAddrTable_struct *ta = get_addrForName2(name,nameLen);
struct targetParamTable_struct *tp = get_paramEntry2(name,nameLen);
struct snmpNotifyTable_data *nt = get_notifyTable2(name,nameLen);
struct snmpNotifyFilterProfileTable_data *fp =
snmpNotifyFilterProfileTable_find(name, nameLen);
DEBUGMSGTL(("trapsess", "removing %s from trap tables\n", name));
if (NULL != nt)
snmpNotifyTable_remove(nt);
else
DEBUGMSGTL(("snmpNotifyTable:unregister",
"No NotifyTable entry for %s\n", name));
if (NULL != tp)
snmpTargetParamTable_remove(tp);
else
DEBUGMSGTL(("snmpNotifyTable:unregister",
"No TargetParamTable entry for %s\n", name));
if (NULL != ta)
snmpTargetAddrTable_remove(ta);
else
DEBUGMSGTL(("snmpNotifyTable:unregister",
"No TargetAddrTable entry for %s\n", name));
if (NULL != fp)
snmpNotifyFilterProfileTable_remove(fp);
else
DEBUGMSGTL(("snmpNotifyTable:unregister",
"No FilterProfileTable entry for %s\n", name));
}
static int
_unregister_notification_cb(int major, int minor,
void *serverarg, void *clientarg)
{
struct agent_add_trap_args *args =
(struct agent_add_trap_args *) serverarg;
if (!args || !(args->nameData))
return 0;
snmpNotifyTable_unregister_notification(args->nameData, args->nameLen);
return 1;
}
/*
* 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;
}