|
|
/*++
Copyright (c) 1992-1996 Microsoft Corporation
Module Name:
snmptfx.c
Abstract:
Provides common varbind resolution functionality for subagents.
Environment:
User Mode - Win32
Revision History:
02-Oct-1996 DonRyan Moved from extensible agent in anticipation of SNMPv2 SPI.
--*/
///////////////////////////////////////////////////////////////////////////////
// //
// Include files //
// //
///////////////////////////////////////////////////////////////////////////////
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h> // using ntrtl's ASSERT
#include <snmp.h>
#include <snmputil.h>
#include <snmpexts.h>
#include <winsock.h>
#define HASH_TABLE_SIZE 101
#define HASH_TABLE_RADIX 18
#define INVALID_INDEX ((DWORD)(-1))
///////////////////////////////////////////////////////////////////////////////
// //
// Private type definitions //
// //
///////////////////////////////////////////////////////////////////////////////
typedef struct _SnmpVarBindXlat {
UINT vlIndex; // index into view list
UINT vblIndex; // index into varbind list
SnmpMibEntry * mibEntry; // pointer to mib information
struct _SnmpExtQuery * extQuery; // pointer to followup query
} SnmpVarBindXlat;
typedef struct _SnmpGenericList {
VOID * data; // context-specific pointer
UINT len; // context-specific length
} SnmpGenericList;
typedef struct _SnmpTableXlat {
AsnObjectIdentifier txOid; // table index oid
SnmpMibTable * txInfo; // table description
UINT txIndex; // index into table list
} SnmpTableXlat;
typedef struct _SnmpExtQuery {
UINT mibAction; // type of query
UINT viewType; // type of view
UINT vblNum; // number of varbinds
SnmpVarBindXlat * vblXlat; // info to reorder varbinds
SnmpTableXlat * tblXlat; // info to parse table oids
SnmpGenericList extData; // context-specific buffer
FARPROC extFunc; // instrumentation callback
} SnmpExtQuery;
#define INVALID_QUERY ((SnmpExtQuery*)(-1))
typedef struct _SnmpExtQueryList {
SnmpExtQuery * query; // list of subagent queries
UINT len; // number of queries in list
UINT action; // original query request
} SnmpExtQueryList;
typedef struct _SnmpHashNode {
SnmpMibEntry * mibEntry; struct _SnmpHashNode * nextEntry;
} SnmpHashNode;
typedef struct _SnmpTfxView {
SnmpMibView * mibView; SnmpHashNode ** hashTable;
} SnmpTfxView;
typedef struct _SnmpTfxInfo {
UINT numViews; SnmpTfxView * tfxViews;
} SnmpTfxInfo;
///////////////////////////////////////////////////////////////////////////////
// //
// Private prototypes //
// //
///////////////////////////////////////////////////////////////////////////////
VOID ValidateQueryList( SnmpTfxInfo * tfxInfo, SnmpExtQueryList * ql, UINT q, RFC1157VarBindList * vbl, UINT * errorStatus, UINT * errorIndex );
///////////////////////////////////////////////////////////////////////////////
// //
// Private procedures //
// //
///////////////////////////////////////////////////////////////////////////////
UINT OidToHashTableIndex( AsnObjectIdentifier * hashOid )
/*++
Routine Description:
Hash function for mib entry access.
Arguments:
hashOid - object identifer to hash into table position.
Return Values:
Returns hash table position.
--*/
{ UINT i; UINT j;
// process each element of the oid
for (i=0, j=0; i < hashOid->idLength; i++) {
// determine table position by summing oid
j = (j * HASH_TABLE_RADIX) + hashOid->ids[i]; }
// adjust to within table
return (j % HASH_TABLE_SIZE); }
VOID FreeHashTable( SnmpHashNode ** hashTable )
/*++
Routine Description:
Destroys hash table used for accessing views.
Arguments:
hashTable - table of hash nodes.
Return Values:
None.
--*/
{ UINT i;
SnmpHashNode * nextNode; SnmpHashNode * hashNode;
if (hashTable == NULL) { return; }
// free hash table and nodes
for (i=0; i < HASH_TABLE_SIZE; i++) {
// point to first item
hashNode = hashTable[i];
// find end of node list
while (hashNode) {
// save pointer to next node
nextNode = hashNode->nextEntry;
// free current node
SnmpUtilMemFree(hashNode);
// retrieve next
hashNode = nextNode; } }
// release table itself
SnmpUtilMemFree(hashTable); }
SnmpHashNode ** AllocHashTable( SnmpMibView * mibView )
/*++
Routine Description:
Initializes view hash table.
Arguments:
mibView - mib view information.
Return Values:
Returns pointer to first entry if successful.
--*/
{ UINT i; UINT j;
UINT numItems; BOOL fInitedOk;
SnmpMibEntry * mibEntry; SnmpHashNode * hashNode; SnmpHashNode ** hashTable = NULL;
// validate parameter
if (mibView == NULL) { return NULL; }
// determine how many items in view
numItems = mibView->viewScalars.len;
// load the first entry in the view
mibEntry = mibView->viewScalars.list;
// allocate hash table using predefined size
hashTable = (SnmpHashNode **)SnmpUtilMemAlloc( HASH_TABLE_SIZE * sizeof(SnmpHashNode *) );
// make sure table is allocated
fInitedOk = (hashTable != NULL);
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: initializing hash table 0x%08lx (%d items).\n", hashTable, numItems ));
// process each item in the subagent's supported view
for (i = 0; (i < numItems) && fInitedOk; i++, mibEntry++) {
// hash into table index
j = OidToHashTableIndex(&mibEntry->mibOid);
// check if table entry taken
if (hashTable[j] == NULL) {
// allocate new node
hashNode = (SnmpHashNode *)SnmpUtilMemAlloc( sizeof(SnmpHashNode) );
// save hash node
hashTable[j] = hashNode;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: adding hash node 0x%08lx to empty slot %d (0x%08lx).\n", hashNode, j, mibEntry ));
} else {
// point to first item
hashNode = hashTable[j];
// find end of node list
while (hashNode->nextEntry) { hashNode = hashNode->nextEntry; }
// allocate new node entry
hashNode->nextEntry = (SnmpHashNode *)SnmpUtilMemAlloc( sizeof(SnmpHashNode) );
// re-init node to edit below
hashNode = hashNode->nextEntry;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: adding hash node 0x%08lx to full slot %d (0x%08lx).\n", hashNode, j, mibEntry )); }
// make sure allocation succeeded
fInitedOk = (hashNode != NULL);
if (fInitedOk) {
// fill in node values
hashNode->mibEntry = mibEntry; } }
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: %s initialized hash table 0x%08lx.\n", fInitedOk ? "successfully" : "unsuccessfully", hashTable ));
if (!fInitedOk) {
// free view hash table
FreeHashTable(hashTable);
// reinitialize
hashTable = NULL; }
return hashTable; }
VOID OidToMibEntry( AsnObjectIdentifier * hashOid, SnmpHashNode ** hashTable, SnmpMibEntry ** mibEntry )
/*++
Routine Description:
Returns mib entry associated with given object identifier.
Arguments:
hashOid - oid to convert to table index. hashTable - table to look up entry. mibEntry - pointer to mib entry information.
Return Values:
None.
--*/
{ UINT i; SnmpHashNode * hashNode; AsnObjectIdentifier newOid;
// create index
i = OidToHashTableIndex(hashOid);
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: searching hash table 0x%08lx slot %d for %s.\n", hashTable, i, SnmpUtilOidToA(hashOid) ));
// retrieve node
hashNode = hashTable[i];
// initialize
*mibEntry = NULL;
// search list
while (hashNode) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: searching hash node 0x%08lx (mibe=0x%08lx) - %s.\n", hashNode, hashNode->mibEntry, SnmpUtilOidToA(&hashNode->mibEntry->mibOid) ));
// retrieve mib identifier
newOid = hashNode->mibEntry->mibOid;
// make sure that the oid matches
if (!SnmpUtilOidCmp(&newOid, hashOid)) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: returning mib entry 0x%08lx.\n", hashNode->mibEntry ));
// return node data
*mibEntry = hashNode->mibEntry; return;
}
// check next node
hashNode = hashNode->nextEntry; } }
int ValidateInstanceIdentifier( AsnObjectIdentifier * indexOid, SnmpMibTable * tableInfo )
/*++
Routine Description:
Validates that oid can be successfully parsed into index entries.
Arguments:
indexOid - object indentifier of potential index. tableInfo - information describing conceptual table.
Return Values:
Returns the comparision between the length of the indexOid and the cumulated lengths of all the indices of the table tableInfo. {-1, 0, 1}
--*/
{ UINT i = 0; UINT j = 0;
int nComp;
BOOL fFixed; BOOL fLimit; BOOL fIndex;
SnmpMibEntry * mibEntry;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: validating index %s via table 0x%08lx.\n", SnmpUtilOidToA(indexOid), tableInfo ));
// see if the table indices are specified
fIndex = (tableInfo->tableIndices != NULL);
// scan mib entries of table indices ensuring match of given oid
for (i = 0; (i < tableInfo->numIndices) && (j < indexOid->idLength); i++) {
// get mib entry from table or directly
mibEntry = fIndex ? tableInfo->tableIndices[i] : &tableInfo->tableEntry[i+1] ;
// determine type
switch (mibEntry->mibType) {
// variable length types
case ASN_OBJECTIDENTIFIER: case ASN_RFC1155_OPAQUE: case ASN_OCTETSTRING:
// check whether this is a fixed length variable or not
fLimit = (mibEntry->mibMinimum || mibEntry->mibMaximum); fFixed = (fLimit && (mibEntry->mibMinimum == mibEntry->mibMaximum));
// validate
if (fFixed) {
// increment fixed length
j += mibEntry->mibMaximum;
} else if (fLimit) {
// check whether the length of the variable is valid
if (((INT)indexOid->ids[j] >= mibEntry->mibMinimum) && ((INT)indexOid->ids[j] <= mibEntry->mibMaximum)) {
// increment given length
j += (indexOid->ids[j] + 1);
} else {
// invalidate
j = INVALID_INDEX; }
} else {
// increment given length
j += (indexOid->ids[j] + 1); }
break;
// implicit fixed size
case ASN_RFC1155_IPADDRESS: // increment
j += 4; break;
case ASN_RFC1155_COUNTER: case ASN_RFC1155_GAUGE: case ASN_RFC1155_TIMETICKS: case ASN_INTEGER: // increment
j++; break;
default: // invalidate
j = INVALID_INDEX; break; } }
if (i<tableInfo->numIndices) nComp = -1; else if (j < indexOid->idLength) nComp = 1; else if (j > indexOid->idLength) nComp = -1; else nComp = 0;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: ValidateInstanceIdentifier; OID %s %s table indices.\n", SnmpUtilOidToA(indexOid), nComp > 0 ? "over-covers" : nComp < 0 ? "shorter than" : "matches" ));
return nComp; }
VOID ValidateAsnAny( AsnAny * asnAny, SnmpMibEntry * mibEntry, UINT mibAction, UINT * errorStatus )
/*++
Routine Description:
Validates asn value with given mib entry.
Arguments:
asnAny - value to set. mibEntry - mib information. mibAction - mib action to be taken. errorStatus - used to indicate success or failure.
Return Values:
None.
--*/
{ BOOL fLimit; BOOL fFixed;
INT asnLen;
BOOL fOk = TRUE;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: validating value for %s request using entry 0x%08lx.\n", (mibAction == MIB_ACTION_SET) ? "write" : "read", mibEntry ));
// validating gets is trivial
if (mibAction != MIB_ACTION_SET) {
// validate instrumentation info
if ((mibEntry->mibGetBufLen == 0) || (mibEntry->mibGetFunc == NULL) || !(mibEntry->mibAccess & MIB_ACCESS_READ)) {
// variable is not available for reading
*errorStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: entry 0x%08lx not read-enabled.\n", mibEntry ));
return; // bail...
}
} else {
// validate instrumentation info
if ((mibEntry->mibSetBufLen == 0) || (mibEntry->mibSetFunc == NULL) || !(mibEntry->mibAccess & MIB_ACCESS_WRITE)) {
// variable is not avaiLable for writing
*errorStatus = SNMP_ERRORSTATUS_NOTWRITABLE;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: entry 0x%08lx not write-enabled.\n", mibEntry ));
return; // bail...
}
if (mibEntry->mibType != asnAny->asnType) { *errorStatus = SNMP_ERRORSTATUS_BADVALUE;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: entry 0x%08lx doesn't match the asnType", mibEntry));
return; // bail...
}
// check whether this is a fixed length variable or not
fLimit = (mibEntry->mibMinimum || mibEntry->mibMaximum); fFixed = (fLimit && (mibEntry->mibMinimum == mibEntry->mibMaximum));
// determine value type
switch (asnAny->asnType) {
// variable length types
case ASN_OBJECTIDENTIFIER:
// retrieve the objects id length
asnLen = asnAny->asnValue.object.idLength;
// fixed?
if (fFixed) {
// make sure the length is correct
fOk = (asnLen == mibEntry->mibMaximum);
} else if (fLimit) {
// make sure the length is correct
fOk = ((asnLen >= mibEntry->mibMinimum) && (asnLen <= mibEntry->mibMaximum)); }
break;
case ASN_RFC1155_OPAQUE: case ASN_OCTETSTRING:
// retrieve the arbitrary length
asnLen = asnAny->asnValue.string.length;
// fixed?
if (fFixed) {
// make sure the length is correct
fOk = (asnLen == mibEntry->mibMaximum);
} else if (fLimit) {
// make sure the length is correct
fOk = ((asnLen >= mibEntry->mibMinimum) && (asnLen <= mibEntry->mibMaximum)); }
break;
case ASN_RFC1155_IPADDRESS:
// make sure the length is correct
fOk = (asnAny->asnValue.address.length == 4); break;
case ASN_INTEGER:
// limited?
if (fLimit) {
// make sure the value in range
fOk = ((asnAny->asnValue.number >= mibEntry->mibMinimum) && (asnAny->asnValue.number <= mibEntry->mibMaximum)); }
break;
default: // error...
fOk = FALSE; break; } }
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: value is %s using entry 0x%08lx.\n", fOk ? "valid" : "invalid", mibEntry ));
// report results
*errorStatus = fOk ? SNMP_ERRORSTATUS_NOERROR : SNMP_ERRORSTATUS_BADVALUE ; }
VOID FindMibEntry( SnmpTfxInfo * tfxInfo, RFC1157VarBind * vb, SnmpMibEntry ** mibEntry, UINT * mibAction, SnmpTableXlat ** tblXlat, UINT vlIndex, UINT * errorStatus )
/*++
Routine Description:
Locates mib entry associated with given varbind.
Arguments:
tfxInfo - context info. vb - variable to locate. mibEntry - mib entry information. mibAction - mib action (may be updated). tblXlat - table translation info. vlIndex - index into view list. errorStatus - used to indicate success or failure.
Return Values:
None.
--*/
{ UINT i; UINT j;
UINT newIndex; UINT numItems; UINT numTables;
BOOL fFoundOk; int indexComp;
AsnObjectIdentifier hashOid; AsnObjectIdentifier indexOid; AsnObjectIdentifier * viewOid;
SnmpMibTable * viewTables; SnmpTfxView * tfxView;
SnmpMibEntry * newEntry = NULL; SnmpTableXlat * newXlat = NULL;
// initialize
*mibEntry = NULL; *tblXlat = NULL;
// retrieve view information
tfxView = &tfxInfo->tfxViews[vlIndex];
// retrieve view object identifier
viewOid = &tfxView->mibView->viewOid;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: FindMibEntry; comp(%s, ", SnmpUtilOidToA(&vb->name) ));
SNMPDBG(( SNMP_LOG_VERBOSE, "%s).\n", SnmpUtilOidToA(viewOid) ));
// if the prefix exactly matchs it is root oid
if (!SnmpUtilOidCmp(&vb->name, viewOid)) { SNMPDBG((SNMP_LOG_VERBOSE, "SNMP: TFX: requested oid is root.\n")); *errorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; return; }
// if the prefix does not match it is not in hash table
if (SnmpUtilOidNCmp(&vb->name, viewOid, viewOid->idLength)) { SNMPDBG((SNMP_LOG_TRACE, "SNMP: TFX: requested oid not in view.\n")); *errorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; return; }
// construct new oid sans root prefix
hashOid.ids = &vb->name.ids[viewOid->idLength]; hashOid.idLength = vb->name.idLength - viewOid->idLength;
// retrieve mib entry and index via hash table
OidToMibEntry(&hashOid, tfxView->hashTable, &newEntry);
// check if mib entry found
fFoundOk = (newEntry != NULL);
// try mib tables
if (!fFoundOk) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: searching mib tables for %s.\n", SnmpUtilOidToA(&hashOid) ));
// retrieve mib table information
numTables = tfxView->mibView->viewTables.len; viewTables = tfxView->mibView->viewTables.list;
// scan mib tables for a match to the given oid
for (i=0; (i < numTables) && !fFoundOk; i++, viewTables++) {
// retrieve entry for table entry
numItems = viewTables->numColumns; newEntry = viewTables->tableEntry;
if (!SnmpUtilOidNCmp( &hashOid, &newEntry->mibOid, newEntry->mibOid.idLength)) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: searching table 0x%08lx (%s).\n", newEntry, SnmpUtilOidToA(&newEntry->mibOid) ));
// next
++newEntry;
// scan mib table entries for a match
for (j=0; j < numItems; j++, newEntry++) {
// compare with oid of table entry
if (!SnmpUtilOidNCmp( &hashOid, &newEntry->mibOid, newEntry->mibOid.idLength)) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: validating mib entry 0x%08lx (%s).\n", newEntry, SnmpUtilOidToA(&newEntry->mibOid) ));
// construct new oid sans table entry prefix
indexOid.ids = &hashOid.ids[newEntry->mibOid.idLength]; indexOid.idLength = hashOid.idLength - newEntry->mibOid.idLength;
// verify rest of oid is valid index
indexComp = ValidateInstanceIdentifier( &indexOid, viewTables ); fFoundOk = (indexComp < 0 && *mibAction == MIB_ACTION_GETNEXT) || (indexComp == 0);
// is index?
if (fFoundOk) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: saving index oid %s.\n", SnmpUtilOidToA(&indexOid) ));
// alloc a table traslation entry only if the object is accessible
if (newEntry->mibAccess != MIB_ACCESS_NONE) { // allocate table translation structure
newXlat = (SnmpTableXlat *)SnmpUtilMemAlloc( sizeof(SnmpTableXlat) ); // Prefix bug # 445169
if (newXlat != NULL) { // copy index object identifier
if (! SnmpUtilOidCpy(&newXlat->txOid, &indexOid)) { // report memory allocation problem
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: SnmpUtilOidCpy at line %d failed.\n", __LINE__));
// free previous allocated memory
SnmpUtilMemFree(newXlat); *errorStatus = SNMP_ERRORSTATUS_GENERR; return; // bail...
}
// save table information
newXlat->txInfo = viewTables; newXlat->txIndex = i; } else { // report memory allocation problem
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: unable to allocate memory.\n" )); *errorStatus = SNMP_ERRORSTATUS_GENERR; return; // bail...
} }
break; // finished...
} } } } }
} else {
UINT newOff;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: searching mib tables for %s.\n", SnmpUtilOidToA(&hashOid) ));
// retrieve mib table information
numTables = tfxView->mibView->viewTables.len; viewTables = tfxView->mibView->viewTables.list;
// scan mib tables for an entry in table
for (i=0; i < numTables; i++, viewTables++) {
// columns are positioned after entry
if (newEntry > viewTables->tableEntry) {
// calculate the difference between pointers
newOff = (UINT)((ULONG_PTR)newEntry - (ULONG_PTR)viewTables->tableEntry);
// calculate table offset
newOff /= sizeof(SnmpMibEntry);
// determine if entry within region
if (newOff <= viewTables->numColumns && newEntry->mibAccess != MIB_ACCESS_NONE) {
// allocate table translation structure
newXlat = (SnmpTableXlat *)SnmpUtilMemAlloc( sizeof(SnmpTableXlat) ); // Prefix bug # 445169
if (newXlat != NULL) { // save table information
newXlat->txInfo = viewTables; newXlat->txIndex = i;
// initialize index oid
newXlat->txOid.ids = NULL; newXlat->txOid.idLength = 0;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: mib entry is in table 0x%08lx (%s).\n", viewTables->tableEntry, SnmpUtilOidToA(&viewTables->tableEntry->mibOid) ));
break; // finished...
} else { // report memory allocation problem
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: unable to allocate memory.\n" )); *errorStatus = SNMP_ERRORSTATUS_GENERR; return; // bail...
} } } } }
// found entry?
if (fFoundOk) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: FindMibEntry; found %s\n", SnmpUtilOidToA(&newEntry->mibOid) )); // pass back results
*mibEntry = newEntry; *tblXlat = newXlat;
} else {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: unable to exactly match varbind.\n" ));
// unable to locate varbind in mib table
*errorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; } }
VOID FindNextMibEntry( SnmpTfxInfo * tfxInfo, RFC1157VarBind * vb, SnmpMibEntry ** mibEntry, UINT * mibAction, SnmpTableXlat ** tblXlat, UINT vlIndex, UINT * errorStatus )
/*++
Routine Description:
Locates next mib entry associated with given varbind.
Arguments:
tfxInfo - context info. vb - variable to locate. mibEntry - mib entry information. mibAction - mib action (may be updated). tblXlat - table translation info. vlIndex - index into view list. errorStatus - used to indicate success or failure.
Return Values:
None.
--*/
{ UINT mibStatus;
SnmpMibEntry * newEntry = NULL; SnmpTableXlat * newXlat = NULL;
SnmpTfxView * tfxView;
// table?
if (*tblXlat) { SNMPDBG((SNMP_LOG_VERBOSE, "SNMP: TFX: querying table.\n")); return; // simply query table...
}
// retrieve view information
tfxView = &tfxInfo->tfxViews[vlIndex];
// retrieve entry
newEntry = *mibEntry;
// initialize
*mibEntry = NULL; *tblXlat = NULL;
// continuing?
if (newEntry) { // next
++newEntry; SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: searching mib at next entry 0x%08lx (%s).\n", newEntry, SnmpUtilOidToA(&newEntry->mibOid) )); } else { // retrieve first mib entry in supported view
newEntry = tfxView->mibView->viewScalars.list; SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: searching mib at first entry 0x%08lx.\n", newEntry )); }
// initialize status to start search
mibStatus = SNMP_ERRORSTATUS_NOSUCHNAME;
// scan
for (;; newEntry++) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: FindNextMibEntry; scanning view %s ", SnmpUtilOidToA(&tfxView->mibView->viewOid) ));
SNMPDBG(( SNMP_LOG_VERBOSE, " scalar %s.\n", SnmpUtilOidToA(&newEntry->mibOid) ));
// if last entry then we stop looking
if (newEntry->mibType == ASN_PRIVATE_EOM) {
SNMPDBG((SNMP_LOG_TRACE, "SNMP: TFX: encountered end of mib.\n"));
*errorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; return; // bail...
}
// skip over place holder mib entries
if (newEntry->mibType != ASN_PRIVATE_NODE) {
// validate asn value against info in mib entry
ValidateAsnAny(&vb->value, newEntry, *mibAction, &mibStatus);
// bail if we found a valid entry...
if (mibStatus == SNMP_ERRORSTATUS_NOERROR) { break; } } }
// retrieved an entry but is it in a table?
if (mibStatus == SNMP_ERRORSTATUS_NOERROR) {
UINT i; UINT newOff; UINT numTables;
SnmpMibTable * viewTables;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: mib entry 0x%08lx found (%s).\n", newEntry, SnmpUtilOidToA(&newEntry->mibOid) ));
// retrieve table information from view
numTables = tfxView->mibView->viewTables.len; viewTables = tfxView->mibView->viewTables.list;
// scan mib tables for an entry in table
for (i=0; i < numTables; i++, viewTables++) {
// columns are positioned after entry
if (newEntry > viewTables->tableEntry) {
// calculate the difference between pointers
newOff = (UINT)((ULONG_PTR)newEntry - (ULONG_PTR)viewTables->tableEntry);
// calculate table offset
newOff /= sizeof(SnmpMibEntry);
// determine if entry within region
if (newOff <= viewTables->numColumns) {
// allocate table translation structure
newXlat = (SnmpTableXlat *)SnmpUtilMemAlloc( sizeof(SnmpTableXlat) ); // Prefix bug # 445169
if (newXlat != NULL) { // save table information
newXlat->txInfo = viewTables; newXlat->txIndex = i;
// initialize index oid
newXlat->txOid.ids = NULL; newXlat->txOid.idLength = 0;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: mib entry is in table 0x%08lx (%s).\n", viewTables->tableEntry, SnmpUtilOidToA(&viewTables->tableEntry->mibOid) ));
break; // finished...
} else { // report memory allocation problem
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: unable to allocate memory.\n" )); *errorStatus = SNMP_ERRORSTATUS_GENERR; return; // bail...
} } } }
// pass back results
*mibEntry = newEntry; *tblXlat = newXlat;
// update mib action of scalar getnext
if (!newXlat && (*mibAction == MIB_ACTION_GETNEXT)) {
*mibAction = MIB_ACTION_GET;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: altered mib action to MIB_ACTION_GET.\n" )); } }
// pass back status
*errorStatus = mibStatus; }
VOID FindAnyMibEntry( SnmpTfxInfo * tfxInfo, RFC1157VarBind * vb, SnmpMibEntry ** mibEntry, UINT * mibAction, SnmpTableXlat ** tblXlat, UINT vlIndex, UINT * errorStatus )
/*++
Routine Description:
Locates any mib entry associated with given varbind.
Arguments:
tfxInfo - context info. vb - variable to locate. mibEntry - mib entry information. mibAction - mib action (may be updated). tblXlat - table translation info. vlIndex - index into view list. errorStatus - used to indicate success or failure.
Return Values:
None.
--*/
{ BOOL fExact; BOOL fBefore;
SnmpTfxView * tfxView;
// retrieve view information
tfxView = &tfxInfo->tfxViews[vlIndex];
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: FindAnyMibEntry; comp(%s, ", SnmpUtilOidToA(&vb->name) )); SNMPDBG(( SNMP_LOG_VERBOSE, "%s[, %d]).\n", SnmpUtilOidToA(&tfxView->mibView->viewOid), tfxView->mibView->viewOid.idLength ));
// look for oid before view
fBefore = (0 > SnmpUtilOidNCmp( &vb->name, &tfxView->mibView->viewOid, tfxView->mibView->viewOid.idLength ));
// look for exact match
fExact = !fBefore && !SnmpUtilOidCmp( &vb->name, &tfxView->mibView->viewOid );
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: fBefore=%d fExact=%d\n", fBefore, fExact )); // check for random oid...
if (!fBefore && !fExact) {
AsnObjectIdentifier relOid; AsnObjectIdentifier * viewOid; SnmpMibEntry * newEntry = NULL;
// point to the first item in the list
newEntry = tfxView->mibView->viewScalars.list;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: linear search from first entry 0x%08lx.\n", newEntry ));
// retrieve the view object identifier
viewOid = &tfxView->mibView->viewOid;
// construct new oid sans root prefix
relOid.ids = &vb->name.ids[viewOid->idLength]; relOid.idLength = vb->name.idLength - viewOid->idLength;
// scan mib entries
while ((newEntry->mibType != ASN_PRIVATE_EOM) && (SnmpUtilOidCmp(&relOid, &newEntry->mibOid) > 0)) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: skipping %s.\n", SnmpUtilOidToA(&newEntry->mibOid) ));
// next
newEntry++; }
// if last entry then we stop looking
if (newEntry->mibType == ASN_PRIVATE_EOM) {
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: encountered end of mib.\n" ));
*errorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; return; // bail...
}
// backup to find next
*mibEntry = --newEntry; *tblXlat = NULL;
// find next
FindNextMibEntry( tfxInfo, vb, mibEntry, mibAction, tblXlat, vlIndex, errorStatus );
} else {
// initialize
*mibEntry = NULL; *tblXlat = NULL;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: searching for first entry.\n" ));
// find next
FindNextMibEntry( tfxInfo, vb, mibEntry, mibAction, tblXlat, vlIndex, errorStatus ); SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: FindAnyMibEntry; error %d on %s(.", *errorStatus, SnmpUtilOidToA(&tfxInfo->tfxViews[vlIndex].mibView->viewOid) )); SNMPDBG(( SNMP_LOG_VERBOSE, "%s).\n", SnmpUtilOidToA(&(*mibEntry)->mibOid) )); } }
VOID VarBindToMibEntry( SnmpTfxInfo * tfxInfo, RFC1157VarBind * vb, SnmpMibEntry ** mibEntry, UINT * mibAction, SnmpTableXlat ** tblXlat, UINT vlIndex, UINT * errorStatus )
/*++
Routine Description:
Locates mib entry associated with given varbind.
Arguments:
tfxInfo - context information. vb - variable to locate. mibEntry - mib entry information. mibAction - mib action (may be updated). tblXlat - table translation info. vlIndex - index into view list. errorStatus - used to indicate success or failure.
Return Values:
None.
--*/
{ BOOL fAnyOk; BOOL fFoundOk; BOOL fErrorOk;
// determine whether we need exact match
fAnyOk = (*mibAction == MIB_ACTION_GETNEXT);
// find match
FindMibEntry( tfxInfo, vb, mibEntry, mibAction, tblXlat, vlIndex, errorStatus ); SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: VarBindToMibEntry; errorStatus=%d.\n", *errorStatus ));
// get next?
if (fAnyOk) {
// search again
if (*errorStatus == SNMP_ERRORSTATUS_NOERROR) {
// find next entry
FindNextMibEntry( tfxInfo, vb, mibEntry, mibAction, tblXlat, vlIndex, errorStatus );
} else if (*errorStatus == SNMP_ERRORSTATUS_NOSUCHNAME) {
// find any entry
FindAnyMibEntry( tfxInfo, vb, mibEntry, mibAction, tblXlat, vlIndex, errorStatus ); }
} else if (*errorStatus == SNMP_ERRORSTATUS_NOERROR) {
// validate asn value against mib entry information
ValidateAsnAny(&vb->value, *mibEntry, *mibAction, errorStatus);
// make sure valid before passing back entry
if (*errorStatus != SNMP_ERRORSTATUS_NOERROR) {
// table entry?
if (*tblXlat) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: freeing index info (%s).\n", SnmpUtilOidToA(&(*tblXlat)->txOid) ));
// free index oid
SnmpUtilOidFree(&(*tblXlat)->txOid);
// free table info
SnmpUtilMemFree(*tblXlat);
}
// nullify results
*mibEntry = NULL; *tblXlat = NULL; } } }
BOOL CheckUpdateIndex( AsnObjectIdentifier *indexOid, UINT nStartFrom, UINT nExpecting ) /*++
Routine Description:
Checks if an index OID contains all the components expected. If not, the index is updated to point before the very first OID requested.
Arguments: indexOid - pointer to the index to be checked. nStartFrom - the point from where the index is checked. nExpecting - the index should have at least expectTo components from startFrom.
Return value: TRUE if index was valid or has been updated successfully. FALSE otherwise (index was shorter then expected and all filled with 0s).
--*/ { int i;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: CheckUpdateIndex; checking %s.\n", SnmpUtilOidToA(indexOid) ));
if (indexOid->idLength >= nStartFrom + nExpecting) { SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: CheckUpdateIndex; valid, unchanged.\n" ));
return TRUE; }
for (i = indexOid->idLength-1; i >= (int)nStartFrom; i--) { if (indexOid->ids[i] > 0) { indexOid->ids[i]--; indexOid->idLength = i+1;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: CheckUpdateIndex; valid, changed to %s.\n", SnmpUtilOidToA(indexOid) ));
return TRUE; } }
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: CheckUpdateIndex; invalid, to be removed.\n" ));
return FALSE; }
VOID ParseInstanceIdentifier( SnmpTableXlat * tblXlat, AsnAny * objArray, UINT mibAction, UINT * errorStatus )
/*++
Routine Description:
Converts table index oid into object array.
Arguments:
tblXlat - table translation information. objArray - instrumentation object array. mibAction - action requested of subagent.
Return Values:
None.
--*/
{ UINT i; UINT j; UINT k; UINT l; UINT m;
BOOL fFixed; BOOL fLimit; BOOL fIndex; BOOL fEmpty; BOOL fExceed;
UINT numItems;
SnmpMibEntry * mibEntry; AsnObjectIdentifier * indexOid;
LPDWORD lpIpAddress;
*errorStatus = SNMP_ERRORSTATUS_NOERROR; // init return status
// retrieve index oid
indexOid = &tblXlat->txOid;
// is this valid oid
fEmpty = (indexOid->idLength == 0);
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: converting index %s to obj array via table 0x%08lx.\n", fEmpty ? "<tbd>" : SnmpUtilOidToA(indexOid), tblXlat->txInfo ));
// retrieve root entry and entry count
numItems = tblXlat->txInfo->numIndices;
// see if the table indices are specified
fIndex = (tblXlat->txInfo->tableIndices != NULL); fExceed = FALSE; // scan mib entries of table indices
for (i=0, j=0; (i < numItems) && (j < indexOid->idLength); i++) {
// get mib entry from table or directly
mibEntry = fIndex ? tblXlat->txInfo->tableIndices[i] : &tblXlat->txInfo->tableEntry[i+1] ;
// retrieve array index
k = (mibAction == MIB_ACTION_SET) ? (UINT)(CHAR)mibEntry->mibSetBufOff : (UINT)(CHAR)mibEntry->mibGetBufOff ;
// determine type
switch (mibEntry->mibType) {
// variable length types
case ASN_OBJECTIDENTIFIER:
// check whether this is a fixed length variable or not
fLimit = (mibEntry->mibMinimum || mibEntry->mibMaximum); fFixed = (fLimit && (mibEntry->mibMinimum == mibEntry->mibMaximum));
// validate
if (fFixed) {
// fixed length; indexOid should have at least l components more
l = mibEntry->mibMaximum;
if (!CheckUpdateIndex(indexOid, j, l)) { // out from switch and for
j+=l; break; }
} else { // variable length
l = indexOid->ids[j];
if (!CheckUpdateIndex(indexOid, j, l+1)) { // out from switch and for
j+=l+1; break; }
// BUG# 457746
// the length of OID might have been changed by
// CheckUpdateIndex
l = indexOid->ids[j]; // update the length if necessary
j++; }
// copy the type of asn variable
objArray[k].asnType = mibEntry->mibType;
// allocate object using length above
objArray[k].asnValue.object.idLength = l; objArray[k].asnValue.object.ids = SnmpUtilMemAlloc( objArray[k].asnValue.object.idLength * sizeof(UINT) );
if (objArray[k].asnValue.object.ids == NULL) { // report memory allocation problem
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: unable to allocate memory.\n" )); objArray[k].asnValue.object.idLength = 0; *errorStatus = SNMP_ERRORSTATUS_GENERR; return; // bail...
} // transfer data
for (m=0; m < l; m++, j++) {
// transfer oid element to buffer
if (!fExceed && j < indexOid->idLength) { objArray[k].asnValue.object.ids[m] = indexOid->ids[j]; } else { if (!fExceed) fExceed = TRUE; // this certainly is the last index from the request
}
if (fExceed) { objArray[k].asnValue.object.ids[m] = (UINT)(-1); } }
break;
case ASN_RFC1155_OPAQUE: case ASN_OCTETSTRING:
// check whether this is a fixed length variable or not
fLimit = (mibEntry->mibMinimum || mibEntry->mibMaximum); fFixed = (fLimit && (mibEntry->mibMinimum == mibEntry->mibMaximum));
// validate
if (fFixed) {
// fixed length
l = mibEntry->mibMaximum;
if (!CheckUpdateIndex(indexOid, j, l)) { // out from switch and for
j+=l; break; }
} else {
// variable length
l = indexOid->ids[j];
if (!CheckUpdateIndex(indexOid, j, l+1)) { j+=l+1; break; }
// BUG# 457746
// the length of octet string might have been changed by
// CheckUpdateIndex
l = indexOid->ids[j]; // update the length if necessary
j++; }
// copy the type of asn variable
objArray[k].asnType = mibEntry->mibType;
// allocate object
objArray[k].asnValue.string.length = l; objArray[k].asnValue.string.dynamic = TRUE; objArray[k].asnValue.string.stream = SnmpUtilMemAlloc( objArray[k].asnValue.string.length * sizeof(CHAR) );
if (objArray[k].asnValue.string.stream == NULL) { // report memory allocation problem
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: unable to allocate memory.\n" )); objArray[k].asnValue.string.length = 0; objArray[k].asnValue.string.dynamic = FALSE; *errorStatus = SNMP_ERRORSTATUS_GENERR; return; // bail...
} // transfer data
for (m=0; m < l; m++, j++) {
// convert oid element to character
if (j < indexOid->idLength) { if (!fExceed && indexOid->ids[j] <= (UCHAR)(-1)) objArray[k].asnValue.string.stream[m] = (BYTE)(indexOid->ids[j]); else fExceed=TRUE; } else { if (!fExceed) fExceed = TRUE; // this certainly is the last index from the request
}
if (fExceed) { objArray[k].asnValue.string.stream[m] = (UCHAR)(-1); } }
break;
// implicit fixed size
case ASN_RFC1155_IPADDRESS:
if (!CheckUpdateIndex(indexOid, j, 4)) { // out from switch and for
j+=4; break; }
// copy the type of asn variable
objArray[k].asnType = mibEntry->mibType;
// allocate object
objArray[k].asnValue.string.length = 4; objArray[k].asnValue.string.dynamic = TRUE; objArray[k].asnValue.string.stream = SnmpUtilMemAlloc( objArray[k].asnValue.string.length * sizeof(CHAR) );
if (objArray[k].asnValue.string.stream == NULL) { // report memory allocation problem
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: unable to allocate memory.\n" )); objArray[k].asnValue.string.length = 0; objArray[k].asnValue.string.dynamic = FALSE; *errorStatus = SNMP_ERRORSTATUS_GENERR; return; // bail...
}
// cast to dword in order to manipulate ip address
lpIpAddress = (LPDWORD)objArray[k].asnValue.string.stream;
// transfer data into buffer
for (m=0; m<4; m++, j++) { *lpIpAddress <<= 8;
if (!fExceed && j < indexOid->idLength) { if (indexOid->ids[j] <= (UCHAR)(-1)) *lpIpAddress += indexOid->ids[j]; else fExceed = TRUE; } else { if (!fExceed) fExceed = TRUE; // this certainly is the last index from the request
} if (fExceed) { *lpIpAddress += (UCHAR)(-1); } }
// ensure network byte order
*lpIpAddress = htonl(*lpIpAddress);
break;
case ASN_RFC1155_COUNTER: case ASN_RFC1155_GAUGE: case ASN_RFC1155_TIMETICKS: case ASN_INTEGER:
// copy the type of asn variable
objArray[k].asnType = mibEntry->mibType;
// transfer value as integer
objArray[k].asnValue.number = fExceed ? (UINT)(-1) : indexOid->ids[j]; j++; break;
default: // invalidate
j = INVALID_INDEX; break; } } }
BOOL IsTableIndex( SnmpMibEntry * mibEntry, SnmpTableXlat * tblXlat ) { UINT newOff; BOOL fFoundOk = FALSE; BOOL fIndex;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: comparing mibEntry 0x%08lx to table 0x%08lx.\n", mibEntry, tblXlat->txInfo ));
// see if the table indices are specified
fIndex = (tblXlat->txInfo->tableIndices != NULL);
#if DBG
newOff = 0; #endif
if (fIndex) {
// rummage through index list looking for match
for (newOff = 0; (newOff < tblXlat->txInfo->numIndices) && !fFoundOk; newOff++ ) {
// compare mib entry with the next specified index
fFoundOk = (mibEntry == tblXlat->txInfo->tableIndices[newOff]); }
} else {
// make sure pointer greater than table entry
if (mibEntry > tblXlat->txInfo->tableEntry) {
// calculate the difference between pointers
newOff = (UINT)((ULONG_PTR)mibEntry - (ULONG_PTR)tblXlat->txInfo->tableEntry);
// calculate table offset
newOff /= sizeof(SnmpMibEntry);
// determine whether entry within region
fFoundOk = (newOff <= tblXlat->txInfo->numIndices); } }
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: mibEntry %s a component of the table's index (off=%d, len=%d).\n", fFoundOk ? "is" : "is not", newOff, tblXlat->txInfo->numIndices ));
return fFoundOk; }
VOID MibEntryToQueryList( SnmpMibEntry * mibEntry, UINT mibAction, SnmpExtQueryList * ql, SnmpTableXlat * tblXlat, UINT vlIndex, RFC1157VarBindList * vbl, UINT vb, UINT * errorStatus )
/*++
Routine Description:
Converts mib entry information into subagent query.
Arguments:
mibEntry - mib information. mibAction - action to perform. ql - list of subagent queries. tableXlat - table translation info. vlIndex - index into view list. vbl - original varbind list. vb - original varbind. errorStatus - used to indicate success or failure.
Return Values:
None.
--*/
{ UINT i; UINT j; UINT viewType;
FARPROC extFunc;
AsnAny * objArray; SnmpExtQuery * extQuery;
SnmpExtQuery * tmpExtQuery = NULL; // prefix Bug 445172
SnmpVarBindXlat * tmpVblXlat = NULL; // prefix Bug 445172
BOOL fFoundOk = FALSE;
// determine instrumentation callback
extFunc = (mibAction == MIB_ACTION_SET) ? (FARPROC)mibEntry->mibSetFunc : (FARPROC)mibEntry->mibGetFunc ;
// process existing queries
for (i=0; (i < ql->len) && !fFoundOk; i++) {
// retrieve query ptr
extQuery = &ql->query[i];
// determine if a similar query exists
fFoundOk = ((extQuery->extFunc == extFunc) && (extQuery->mibAction == mibAction));
// compare table indices (if any)
if (fFoundOk && extQuery->tblXlat) {
// make sure
if (tblXlat) {
// compare index oids...
fFoundOk = !SnmpUtilOidCmp( &extQuery->tblXlat->txOid, &tblXlat->txOid );
} else {
// hmmm...
fFoundOk = FALSE; }
} }
// append entry
if (!fFoundOk) {
ql->len++; // add new query to end of list
tmpExtQuery = (SnmpExtQuery *)SnmpUtilMemReAlloc( ql->query, ql->len * sizeof(SnmpExtQuery) ); // Prefix bug 445172
// check memory re-allocation
if (tmpExtQuery == NULL) { if (tblXlat) { // free table oid
SnmpUtilOidFree(&tblXlat->txOid);
// free table info
SnmpUtilMemFree(tblXlat); } ql->len--; // rollback
// report memory allocation problem
*errorStatus = SNMP_ERRORSTATUS_GENERR; return; // bail...
} ql->query = tmpExtQuery;
// retrieve new query pointer
extQuery = &ql->query[ql->len-1];
// save common information
extQuery->mibAction = mibAction; extQuery->viewType = MIB_VIEW_NORMAL; extQuery->extFunc = extFunc;
// initialize list
extQuery->vblNum = 0; extQuery->vblXlat = NULL; extQuery->tblXlat = NULL;
// size the instrumentation buffer
extQuery->extData.len = (mibAction == MIB_ACTION_SET) ? mibEntry->mibSetBufLen : mibEntry->mibGetBufLen ; // allocate the instrumentation buffer
extQuery->extData.data = SnmpUtilMemAlloc( extQuery->extData.len );
// check memory allocation
if (extQuery->extData.data) {
// table?
if (tblXlat) {
// retrieve object array pointer
objArray = (AsnAny *)(extQuery->extData.data);
// Prefix 118006
// initialize asn array
ParseInstanceIdentifier(tblXlat, objArray, mibAction, errorStatus); if (*errorStatus != SNMP_ERRORSTATUS_NOERROR) { // logging...
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: unable to ParseInstanceIdentifier with table info 0x%08lx.\n", tblXlat )); SnmpUtilMemFree(extQuery->extData.data); extQuery->extData.data = NULL; // null pointer to avoid double free or deref.
extQuery->extData.len = 0; // free table oid
SnmpUtilOidFree(&tblXlat->txOid); // free table info
SnmpUtilMemFree(tblXlat);
ql->len--; // rollback
return; // bail
}
// save table info
extQuery->tblXlat = tblXlat; }
} else {
// rollback
extQuery->extData.len = 0; ql->len--;
if (tblXlat) { // free table oid
SnmpUtilOidFree(&tblXlat->txOid);
// free table info
SnmpUtilMemFree(tblXlat); }
// report memory allocation problem
*errorStatus = SNMP_ERRORSTATUS_GENERR; return; // bail...
}
} else if (tblXlat != NULL) {
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: releasing duplicate table info 0x%08lx.\n", tblXlat ));
// free table oid
SnmpUtilOidFree(&tblXlat->txOid);
// free table info
SnmpUtilMemFree(tblXlat); }
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: %s query 0x%08lx.\n", fFoundOk ? "editing" : "adding", extQuery ));
// copy to index
i = extQuery->vblNum;
// allocate entry
extQuery->vblNum++;
tmpVblXlat = (SnmpVarBindXlat *)SnmpUtilMemReAlloc( extQuery->vblXlat, extQuery->vblNum * sizeof(SnmpVarBindXlat) ); if (tmpVblXlat == NULL) { // report memory allocation problem
*errorStatus = SNMP_ERRORSTATUS_GENERR; extQuery->vblNum--; // rollback
return; // bail...
} extQuery->vblXlat = tmpVblXlat;
// copy common xlate information
extQuery->vblXlat[i].vblIndex = vb; extQuery->vblXlat[i].vlIndex = vlIndex; extQuery->vblXlat[i].extQuery = NULL;
// save translation info
extQuery->vblXlat[i].mibEntry = mibEntry;
// determine offset used
i = (mibAction == MIB_ACTION_SET) ? (UINT)(CHAR)mibEntry->mibSetBufOff : (UINT)(CHAR)mibEntry->mibGetBufOff ;
// retrieve object array pointer
objArray = (AsnAny *)(extQuery->extData.data);
// fill in only asn type if get
if (mibAction != MIB_ACTION_SET) {
// ignore table indices
if (extQuery->tblXlat && IsTableIndex(mibEntry,extQuery->tblXlat)) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: requesting index value.\n" ));
} else {
// initialize asn type to match entry
objArray[i].asnType = mibEntry->mibType; }
} else {
// copy user-supplied value into buffer
if (! SnmpUtilAsnAnyCpy(&objArray[i], &vbl->list[vb].value) ) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: MibEntryToQueryList; SnmpUtilAsnAnyCpy failed.\n" ));
// report memory allocation problem
*errorStatus = SNMP_ERRORSTATUS_GENERR; extQuery->vblNum--; // invalidate this SnmpVarBindXlat
return; // bail...
} } }
VOID VarBindToQueryList( SnmpTfxInfo * tfxInfo, RFC1157VarBindList * vbl, SnmpExtQueryList * ql, UINT vb, UINT * errorStatus, UINT * errorIndex, UINT queryView )
/*++
Routine Description:
Adds varbind to query list.
Arguments:
tfxInfo - context info. vbl - list of varbinds. ql - list of subagent queries. vb - index of varbind to add to query. errorStatus - used to indicate success or failure. errorIndex - used to identify an errant varbind. queryView - view of query requested.
Return Values:
None.
--*/
{ INT i; INT nDiff; INT lastViewIndex;
BOOL fAnyOk; BOOL fFoundOk = FALSE;
UINT mibAction;
SnmpMibView * mibView; SnmpMibEntry * mibEntry = NULL; SnmpTableXlat * tblXlat = NULL;
// copy request type
mibAction = ql->action;
// determine whether we need exact match
fAnyOk = (mibAction == MIB_ACTION_GETNEXT);
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: searching subagents to resolve %s (%s).\n", SnmpUtilOidToA(&vbl->list[vb].name), fAnyOk ? "AnyOk" : "AnyNOk" ));
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: VarBindToQueryList; scanning views from %d to %d.\n", queryView, (INT)tfxInfo->numViews ));
// init to NonView
lastViewIndex = -1;
// locate appropriate view (starting at queryView)
for (i = queryView; (i < (INT)tfxInfo->numViews) && !fFoundOk; i++) {
// retrieve the mib view information
mibView = tfxInfo->tfxViews[i].mibView;
// compare root oids
nDiff = SnmpUtilOidNCmp( &vbl->list[vb].name, &mibView->viewOid, mibView->viewOid.idLength );
// analyze results based on request type
fFoundOk = (!nDiff || (fAnyOk && (nDiff < 0)));
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: View %d: comp(%s, ", i, SnmpUtilOidToA(&vbl->list[vb].name) )); SNMPDBG(( SNMP_LOG_VERBOSE, "%s, %d) = %d '%s'\n", SnmpUtilOidToA(&mibView->viewOid), mibView->viewOid.idLength, nDiff, fFoundOk?"Found":"NotFound" ));
// make sure we can obtain mib entry (if available)
if (fFoundOk && (mibView->viewType == MIB_VIEW_NORMAL)) {
// initialize local copy of error status
UINT mibStatus = SNMP_ERRORSTATUS_NOERROR;
// store index
lastViewIndex = i;
// load mib entry
VarBindToMibEntry( tfxInfo, &vbl->list[vb], &mibEntry, &mibAction, &tblXlat, i, &mibStatus );
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: VarBindToMibEntry returned %d.\n", mibStatus ));
// successfully loaded mib entry information
fFoundOk = (mibStatus == SNMP_ERRORSTATUS_NOERROR);
// bail if not searching...
if (!fFoundOk && !fAnyOk) { // pass up error status
*errorStatus = mibStatus; *errorIndex = vb+1; return; // bail...
} } }
// reset error status and index...
*errorStatus = SNMP_ERRORSTATUS_NOERROR; *errorIndex = 0;
// found AND had a valid mibEntry
if (fFoundOk && mibEntry) { // save query
MibEntryToQueryList( mibEntry, mibAction, ql, tblXlat, i-1, vbl, vb, errorStatus );
} else if (fAnyOk){
if (lastViewIndex == -1) lastViewIndex = tfxInfo->numViews - 1;
// not supported in any view...
SnmpUtilOidFree(&vbl->list[vb].name);
// copy varbind
if (SnmpUtilOidCpy( &vbl->list[vb].name, &tfxInfo->tfxViews[lastViewIndex].mibView->viewOid) == 0) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: SnmpUtilOidCpy at line %d failed.\n", __LINE__));
*errorStatus = SNMP_ERRORSTATUS_GENERR; return; // bail...
} // increment last element of view oid
vbl->list[vb].name.ids[(vbl->list[vb].name.idLength-1)]++;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: changing varbind to %s.\n", SnmpUtilOidToA(&vbl->list[vb].name) )); } }
VOID VarBindListToQueryList( SnmpTfxInfo * tfxInfo, RFC1157VarBindList * vbl, SnmpExtQueryList * ql, UINT * errorStatus, UINT * errorIndex )
/*++
Routine Description:
Convert list of varbinds from incoming pdu into a list of individual subagent queries.
Arguments:
tfxInfo - context handle. vbl - list of varbinds in pdu. ql - list of subagent queries. errorStatus - used to indicate success or failure. errorIndex - used to identify an errant varbind.
Return Values:
None.
--*/
{ UINT i; // index into varbind list
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: processing %s request containing %d variable(s).\n", (ql->action == MIB_ACTION_GET) ? "get" : (ql->action == MIB_ACTION_SET) ? "set" : (ql->action == MIB_ACTION_GETNEXT) ? "getnext" : "unknown", vbl->len));
// initialize status return values
*errorStatus = SNMP_ERRORSTATUS_NOERROR; *errorIndex = 0;
// process incoming variable bindings
for (i=0; i < vbl->len; i++) { // find varbind
VarBindToQueryList( tfxInfo, vbl, ql, i, errorStatus, errorIndex, 0 ); if (*errorStatus != SNMP_ERRORSTATUS_NOERROR) { *errorIndex = i+1; // have problem during the processing of (i+1)th varbind
break; } } }
UINT MibStatusToSnmpStatus( UINT mibStatus )
/*++
Routine Description:
Translate mib status into snmp error status.
Arguments:
mibStatus - mib error code.
Return Values:
Returns snmp error status.
--*/
{ UINT errorStatus;
switch (mibStatus) {
case MIB_S_SUCCESS: errorStatus = SNMP_ERRORSTATUS_NOERROR; break;
case MIB_S_INVALID_PARAMETER: errorStatus = SNMP_ERRORSTATUS_BADVALUE; break;
case MIB_S_NOT_SUPPORTED: case MIB_S_NO_MORE_ENTRIES: case MIB_S_ENTRY_NOT_FOUND: errorStatus = SNMP_ERRORSTATUS_NOSUCHNAME; break;
default: errorStatus = SNMP_ERRORSTATUS_GENERR; break; }
return errorStatus; }
VOID AdjustErrorIndex( SnmpExtQuery * q, UINT * errorIndex )
/*++
Routine Description:
Ensure that indices match the original pdu.
Arguments:
q - subagent query. errorIndex - used to identify an errant varbind.
Return Values:
None.
--*/
{ UINT errorIndexOld = *errorIndex;
// make sure within bounds
if (errorIndexOld && (errorIndexOld <= q->vblNum)) {
// determine proper index from xlat info
*errorIndex = q->vblXlat[errorIndexOld-1].vblIndex+1;
} else {
// default to first variable
*errorIndex = q->vblXlat[0].vblIndex+1; } }
BOOL ProcessQuery( SnmpExtQuery * q, UINT * errorStatus, UINT * errorIndex )
/*++
Routine Description:
Query the subagent for requested items.
Arguments:
q - subagent query. errorStatus - used to indicate success or failure. errorIndex - used to identify an errant varbind.
Return Values:
None.
--*/
{ BOOL fOk = TRUE; UINT extStatus = 0;
AsnAny * objArray;
// validate...
if (q == NULL) { return TRUE; }
// retrieve asn object array
objArray = (AsnAny *)(q->extData.data); SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: ProcessQuery - objArray=%lx\n", objArray ));
__try {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: entering subagent code ....\n" )); // query subagent
extStatus = (UINT)(*q->extFunc)( q->mibAction, objArray, errorIndex ); SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: ... subagent code completed.\n" ));
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: subagent returned %s (e=0x%08lx,i=%d).\n", (extStatus == MIB_S_SUCCESS) ? "MIB_S_SUCCESS" : (extStatus == MIB_S_NO_MORE_ENTRIES) ? "MIB_S_NO_MORE_ENTRIES" : (extStatus == MIB_S_ENTRY_NOT_FOUND) ? "MIB_S_ENTRY_NOT_FOUND" : (extStatus == MIB_S_INVALID_PARAMETER) ? "MIB_S_INVALID_PARAMETER" : (extStatus == MIB_S_NOT_SUPPORTED) ? "MIB_S_NOT_SUPPORTED" : "error", extStatus, *errorIndex ));
} __except (EXCEPTION_EXECUTE_HANDLER) {
// report exception code
extStatus = GetExceptionCode();
// disable
fOk = FALSE; }
// save error info
SetLastError(extStatus);
// pass back translated version
*errorStatus = MibStatusToSnmpStatus(extStatus);
return fOk; }
VOID ProcessQueryList( SnmpTfxInfo * tfxInfo, SnmpExtQueryList * ql, RFC1157VarBindList * vbl, UINT * errorStatus, UINT * errorIndex )
/*++
Routine Description:
Process the query list based on request type.
Arguments:
tfxInfo - context information. ql - list of subagent queries. vbl - list of incoming variable bindings. errorStatus - used to indicate success or failure. errorIndex - used to identify an errant varbind.
Return Values:
None.
--*/
{ INT i=0; // index into query list
INT j=0; // index into query list
INT qlLen = ql->len; // save...
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: processing %d subagent queries.\n", qlLen ));
// sets are processed below...
if (ql->action != MIB_ACTION_SET) {
// process list of individual queries
for (i=0; (i < qlLen) && !(*errorStatus); i++ ) {
// send query to subagent
if (ProcessQuery(&ql->query[i], errorStatus, errorIndex)) {
// need to validate getnext results
if (ql->action == MIB_ACTION_GETNEXT) { // exhaust all possibilities...
ValidateQueryList( tfxInfo, ql, i, vbl, errorStatus, errorIndex ); }
// check the subagent status code returned
if (*errorStatus != SNMP_ERRORSTATUS_NOERROR) { // adjust index to match request pdu
AdjustErrorIndex(&ql->query[i], errorIndex); }
} else {
// subagent unable to process query
*errorStatus = SNMP_ERRORSTATUS_GENERR; *errorIndex = 1; // adjust index to match request pdu
AdjustErrorIndex(&ql->query[i], errorIndex); } }
} else {
// process all of the validate queries
for (i=0; (i < qlLen) && !(*errorStatus); i++) {
// alter query type to validate entries
ql->query[i].mibAction = MIB_ACTION_VALIDATE;
// send query to subagent
if (ProcessQuery(&ql->query[i], errorStatus, errorIndex)) {
// check the subagent status code returned
if (*errorStatus != SNMP_ERRORSTATUS_NOERROR) { // adjust index to match request pdu
AdjustErrorIndex(&ql->query[i], errorIndex); }
} else {
// subagent unable to process query
*errorStatus = SNMP_ERRORSTATUS_GENERR; *errorIndex = 1; // adjust index to match request pdu
AdjustErrorIndex(&ql->query[i], errorIndex); } }
// process all of the set queries
for (j=0; (j < qlLen) && !(*errorStatus); j++) {
// alter query type to set entries
ql->query[j].mibAction = MIB_ACTION_SET;
// send query to subagent
if (ProcessQuery(&ql->query[j], errorStatus, errorIndex)) {
// check the subagent status code returned
if (*errorStatus != SNMP_ERRORSTATUS_NOERROR) { // adjust index to match request pdu
AdjustErrorIndex(&ql->query[j], errorIndex); }
} else {
// subagent unable to process query
*errorStatus = SNMP_ERRORSTATUS_GENERR; *errorIndex = 1; // adjust index to match request pdu
AdjustErrorIndex(&ql->query[j], errorIndex); } }
// cleanup...
while (i-- > 0) {
UINT ignoreStatus = 0; // dummy values
UINT ignoreIndex = 0; // dummy values
// alter query type to set entries
ql->query[i].mibAction = MIB_ACTION_CLEANUP;
// send the cleanup request success or not
ProcessQuery(&ql->query[i], &ignoreStatus, &ignoreIndex); } } }
BOOL ConstructInstanceIdentifier( SnmpTableXlat * tblXlat, AsnAny * objArray, AsnObjectIdentifier * newOid, UINT mibAction ) /*++
Routine Description:
Convert asn value into index oid.
Arguments:
tblXlat - table translation info. objArray - asn object array. newOid - relative oid to return. mibAction - action requested of subagent.
Return Values: TRUE if successful
None.
--*/
{ UINT i; UINT j; UINT k; UINT l; UINT m;
BOOL fFixed; BOOL fLimit; BOOL fIndex;
UINT numItems;
SnmpMibEntry * mibEntry;
UINT * tmpIds = NULL; // prefix bug 445170
// initialize
newOid->ids = NULL; newOid->idLength = 0;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: converting obj array to index via table 0x%08lx.\n", tblXlat->txInfo ));
// retrieve root entry and entry count
numItems = tblXlat->txInfo->numIndices;
// see if the table indices are specified
fIndex = (tblXlat->txInfo->tableIndices != NULL);
// scan entries of table indices
for (i=0, j=0; i < numItems; i++) {
// get mib entry from table or directly
mibEntry = fIndex ? tblXlat->txInfo->tableIndices[i] : &tblXlat->txInfo->tableEntry[i+1] ;
// retrieve array index
k = (mibAction == MIB_ACTION_SET) ? (UINT)(CHAR)mibEntry->mibSetBufOff : (UINT)(CHAR)mibEntry->mibGetBufOff ;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: ConstructIndexIdentifier - k=%d\n", k )); // determine type
switch (mibEntry->mibType) {
// variable length types
case ASN_OBJECTIDENTIFIER:
// check whether this is a fixed length variable or not
fLimit = (mibEntry->mibMinimum || mibEntry->mibMaximum); fFixed = (fLimit && (mibEntry->mibMinimum == mibEntry->mibMaximum));
// validate
if (fFixed) {
// fixed length
l = mibEntry->mibMaximum;
// allocate space
newOid->idLength += l;
tmpIds = (UINT *)SnmpUtilMemReAlloc( newOid->ids, newOid->idLength * sizeof(UINT) ); if (tmpIds == NULL) { newOid->idLength = 0; SnmpUtilMemFree(newOid->ids); newOid->ids = NULL; return FALSE; } newOid->ids = tmpIds;
} else {
// determine variable length of object
l = objArray[k].asnValue.object.idLength;
// allocate space
newOid->idLength += (l+1); tmpIds = (UINT *)SnmpUtilMemReAlloc( newOid->ids, newOid->idLength * sizeof(UINT) ); if (tmpIds == NULL) { newOid->idLength = 0; SnmpUtilMemFree(newOid->ids); newOid->ids = NULL; return FALSE; } newOid->ids = tmpIds;
// save length
newOid->ids[j++] = l; }
// transfer data
for (m=0; m < l; m++) {
// transfer oid element from buffer
newOid->ids[j++] = objArray[k].asnValue.object.ids[m]; }
break;
case ASN_RFC1155_OPAQUE: case ASN_OCTETSTRING:
// check whether this is a fixed length variable or not
fLimit = (mibEntry->mibMinimum || mibEntry->mibMaximum); fFixed = (fLimit && (mibEntry->mibMinimum == mibEntry->mibMaximum));
// validate
if (fFixed) {
// fixed length
l = mibEntry->mibMaximum;
// allocate space
newOid->idLength += l; tmpIds = (UINT *)SnmpUtilMemReAlloc( newOid->ids, newOid->idLength * sizeof(UINT) ); if (tmpIds == NULL) { newOid->idLength = 0; SnmpUtilMemFree(newOid->ids); newOid->ids = NULL; return FALSE; } newOid->ids = tmpIds;
} else {
// determine variable length of object
l = objArray[k].asnValue.string.length;
// allocate space
newOid->idLength += (l+1); tmpIds = (UINT *)SnmpUtilMemReAlloc( newOid->ids, newOid->idLength * sizeof(UINT) ); if (tmpIds == NULL) { newOid->idLength = 0; SnmpUtilMemFree(newOid->ids); newOid->ids = NULL; return FALSE; } newOid->ids = tmpIds;
// save length
newOid->ids[j++] = l; }
// transfer data
for (m=0; m < l; m++) {
// convert character
newOid->ids[j++] = (UINT)(UCHAR)objArray[k].asnValue.string.stream[m]; }
break;
// implicit fixed size
case ASN_RFC1155_IPADDRESS:
// allocate space
newOid->idLength += 4; tmpIds = (UINT *)SnmpUtilMemReAlloc( newOid->ids, newOid->idLength * sizeof(UINT) ); if (tmpIds == NULL) { newOid->idLength = 0; SnmpUtilMemFree(newOid->ids); newOid->ids = NULL; return FALSE; } newOid->ids = tmpIds;
// transfer data into buffer
newOid->ids[j++] = (DWORD)(BYTE)objArray[k].asnValue.string.stream[0]; newOid->ids[j++] = (DWORD)(BYTE)objArray[k].asnValue.string.stream[1]; newOid->ids[j++] = (DWORD)(BYTE)objArray[k].asnValue.string.stream[2]; newOid->ids[j++] = (DWORD)(BYTE)objArray[k].asnValue.string.stream[3];
break;
case ASN_RFC1155_COUNTER: case ASN_RFC1155_GAUGE: case ASN_RFC1155_TIMETICKS: case ASN_INTEGER:
// allocate space
newOid->idLength += 1; tmpIds = (UINT *)SnmpUtilMemReAlloc( newOid->ids, newOid->idLength * sizeof(UINT) ); if (tmpIds == NULL) { newOid->idLength = 0; SnmpUtilMemFree(newOid->ids); newOid->ids = NULL; return FALSE; } newOid->ids = tmpIds;
// transfer value as integer
newOid->ids[j++] = objArray[k].asnValue.number; break;
default: // invalidate
j = INVALID_INDEX; break; } } return TRUE; }
VOID DeleteQuery( SnmpExtQuery * q )
/*++
Routine Description:
Deletes individual query.
Arguments:
q - subagent query.
Return Values:
None.
--*/
{ UINT i; // index into xlat array
UINT j; // index into object array
BOOL fSet;
AsnAny * objArray; SnmpMibEntry * mibEntry;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: deleting query 0x%08lx.\n", q ));
// determine whether a set was requested
fSet = (q->mibAction == MIB_ACTION_SET);
// retrieve asn object array
objArray = (AsnAny *)(q->extData.data);
// free requested entries
for (i = 0; i < q->vblNum; i++ ) { // retrieve mib entry
mibEntry = q->vblXlat[i].mibEntry;
ASSERT(mibEntry);
j = fSet ? (UINT)(CHAR)mibEntry->mibSetBufOff : (UINT)(CHAR)mibEntry->mibGetBufOff ; if (objArray) SnmpUtilAsnAnyFree(&objArray[j]);
// free any followup queries
if ((q->vblXlat[i].extQuery != NULL) && (q->vblXlat[i].extQuery != INVALID_QUERY)) { SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: deleting followup query 0x%08lx.\n", q->vblXlat[i].extQuery ));
// free followup query
DeleteQuery(q->vblXlat[i].extQuery);
// free query structure itself
SnmpUtilMemFree(q->vblXlat[i].extQuery); } }
q->vblNum = 0;
// free indices
if (q->tblXlat && objArray) {
BOOL fIndex;
// see if the table indices are specified
fIndex = (q->tblXlat->txInfo->tableIndices != NULL);
// free the individual indices
for (i = 0; i < q->tblXlat->txInfo->numIndices; i++) {
// get mib entry from table or directly from entry
mibEntry = fIndex ? q->tblXlat->txInfo->tableIndices[i] : &q->tblXlat->txInfo->tableEntry[i+1] ;
ASSERT(mibEntry);
// determine the buffer offset used
j = fSet ? (UINT)(CHAR)mibEntry->mibSetBufOff : (UINT)(CHAR)mibEntry->mibGetBufOff ; // free individual index
SnmpUtilAsnAnyFree(&objArray[j]); } } // free buffer
SnmpUtilMemFree(objArray); // avoid double freeing
q->extData.data = NULL;
// free table info
if (q->tblXlat) {
// free object identifier
SnmpUtilOidFree(&q->tblXlat->txOid);
// free the xlat structure
SnmpUtilMemFree(q->tblXlat);
// avoid double freeing
q->tblXlat = NULL; }
// free translation info
SnmpUtilMemFree(q->vblXlat);
// avoid double freeing
q->vblXlat = NULL; }
VOID DeleteQueryList( SnmpExtQueryList * ql )
/*++
Routine Description:
Deletes query list.
Arguments:
ql - list of subagent queries.
Return Values:
None.
--*/
{ UINT q; // index into query list
// process queries
for (q=0; q < ql->len; q++) {
// delete query
DeleteQuery(&ql->query[q]); }
// free query list
SnmpUtilMemFree(ql->query); }
VOID QueryToVarBindList( SnmpTfxInfo * tfxInfo, SnmpExtQuery * q, RFC1157VarBindList * vbl, UINT * errorStatus, UINT * errorIndex ) /*++
Routine Description:
Convert query back into varbind.
Arguments:
tfxInfo - context info q - subagent query. vbl - list of varbinds in outgoing pdu.
Return Values:
None.
--*/
{ UINT i=0; UINT j=0; UINT k=0; UINT l=0;
BOOL fSet;
AsnAny * objArray; SnmpMibEntry * mibEntry;
AsnObjectIdentifier idxOid;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: converting query 0x%08lx to varbinds.\n", q ));
// determine whether a set was requested
fSet = (q->mibAction == MIB_ACTION_SET);
// retrieve asn object array
objArray = (AsnAny *)(q->extData.data);
// copy requested entries
for (j = 0; j < q->vblNum; j++) { // process followup query
if (q->vblXlat[j].extQuery != NULL) {
if (q->vblXlat[j].extQuery != INVALID_QUERY) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: processing followup query 0x%08lx.\n", q->vblXlat[j].extQuery ));
QueryToVarBindList( tfxInfo, q->vblXlat[j].extQuery, vbl, errorStatus, errorIndex );
if (*errorStatus != SNMP_ERRORSTATUS_NOERROR) return; // bail...
else continue; // skip...
} else { i = q->vblXlat[j].vblIndex; SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: returning oid %s without reassembly.\n", SnmpUtilOidToA(&vbl->list[i].name) )); continue; // skip...
} }
// retrieve index
i = q->vblXlat[j].vblIndex;
// retrieve mib entry for requested item
mibEntry = q->vblXlat[j].mibEntry;
k = fSet ? (UINT)(CHAR)mibEntry->mibSetBufOff : (UINT)(CHAR)mibEntry->mibGetBufOff ;
// free original variable
SnmpUtilVarBindFree(&vbl->list[i]);
// copy the asn value first
if (SnmpUtilAsnAnyCpy(&vbl->list[i].value, &objArray[k]) == 0) { // report memory allocation problem
*errorIndex = i+1; // failed in (i+1)th varbind
*errorStatus = SNMP_ERRORSTATUS_GENERR; SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: SnmpUtilAsnAnyCpy at line %d failed on the %d th varbind.\n", __LINE__, i+1 )); return; // bail...
}
// copy root oid of view
if (SnmpUtilOidCpy( &vbl->list[i].name, &tfxInfo->tfxViews[(q->vblXlat[j].vlIndex)].mibView->viewOid) == 0) { // report memory allocation problem
*errorIndex = i+1; // failed in (i+1)th varbind
*errorStatus = SNMP_ERRORSTATUS_GENERR; SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: SnmpUtilOidCpy at line %d failed on the %d th varbind.\n", __LINE__, i+1 )); return; // bail...
}
// copy oid of variable
if (SnmpUtilOidAppend( &vbl->list[i].name, &mibEntry->mibOid) == 0) { // report memory allocation problem
*errorIndex = i+1; // failed in (i+1)th varbind
*errorStatus = SNMP_ERRORSTATUS_GENERR; SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: SnmpUtilOidAppend at line %d failed on the %d th varbind.\n", __LINE__, i+1 )); return; // bail...
}
// copy table index
if (q->tblXlat) {
// convert value to oid
if (ConstructInstanceIdentifier(q->tblXlat, objArray, &idxOid, q->mibAction) == FALSE) { // report memory allocation problem
*errorIndex = i+1; // failed in (i+1)th varbind
*errorStatus = SNMP_ERRORSTATUS_GENERR; SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: ConstructInstanceIdentifier failed with %d th varbind.\n", i+1 )); return; // bail...
}
// append oid to object name
if (SnmpUtilOidAppend(&vbl->list[i].name, &idxOid) == 0) { // free temp oid
SnmpUtilOidFree(&idxOid); // report memory allocation problem
*errorIndex = i+1; // failed in (i+1)th varbind
*errorStatus = SNMP_ERRORSTATUS_GENERR; SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: SnmpUtilOidAppend at line %d failed on the %d th varbind.\n", __LINE__, i+1 )); return; // bail...
}
// free temp oid
SnmpUtilOidFree(&idxOid); }
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: returning oid %s.\n", SnmpUtilOidToA(&vbl->list[i].name) )); } }
VOID QueryListToVarBindList( SnmpTfxInfo * tfxInfo, SnmpExtQueryList * ql, RFC1157VarBindList * vbl, UINT * errorStatus, UINT * errorIndex )
/*++
Routine Description:
Convert query list back into outgoing varbinds.
Arguments:
tfxInfo - context information. ql - list of subagent queries. vbl - list of varbinds in outgoing pdu. errorStatus - used to indicate success or failure. errorIndex - used to identify an errant varbind.
Return Values:
None.
--*/
{ UINT q; // index into queue list
UINT vb; // index into queue varbind list
UINT i; // index into original varbind list
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: request %s, errorStatus=%s, errorIndex=%d.\n", (*errorStatus == SNMP_ERRORSTATUS_NOERROR) ? "succeeded" : "failed", (*errorStatus == SNMP_ERRORSTATUS_NOERROR) ? "NOERROR" : (*errorStatus == SNMP_ERRORSTATUS_NOSUCHNAME) ? "NOSUCHNAME" : (*errorStatus == SNMP_ERRORSTATUS_BADVALUE) ? "BADVALUE" : (*errorStatus == SNMP_ERRORSTATUS_READONLY) ? "READONLY" : (*errorStatus == SNMP_ERRORSTATUS_TOOBIG) ? "TOOBIG" : "GENERR", *errorIndex ));
// only convert back if error not reported
if (*errorStatus == SNMP_ERRORSTATUS_NOERROR) {
// process queries
for (q=0; q < ql->len; q++) {
// translate query data
QueryToVarBindList(tfxInfo, &ql->query[q], vbl, errorStatus, errorIndex); if (*errorStatus != SNMP_ERRORSTATUS_NOERROR) break; } }
// free
DeleteQueryList(ql); }
VOID ValidateQueryList( SnmpTfxInfo * tfxInfo, SnmpExtQueryList * ql, UINT q, RFC1157VarBindList * vbl, UINT * errorStatus, UINT * errorIndex )
/*++
Routine Description:
Validate getnext results and re-query if necessary.
Arguments:
tfxInfo - context information. ql - list of subagent queries. q - subagent query of interest. vbl - list of bindings in incoming pdu. errorStatus - used to indicate success or failure. errorIndex - used to identify an errant varbind.
Return Values:
None.
--*/
{ UINT i; UINT j;
SnmpExtQueryList tmpQl;
UINT vlIndex; UINT vblIndex; UINT mibAction; UINT mibStatus; SnmpMibEntry * mibEntry; SnmpTableXlat * tblXlat; RFC1157VarBindList tmpVbl; BOOL fFoundOk = FALSE;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: verifying results of query 0x%08lx.\n", &ql->query[q] ));
// bail on any error other than no such name
if (*errorStatus != SNMP_ERRORSTATUS_NOSUCHNAME) {
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: *errorStatus != SNMP_ERRORSTATUS_NOSUCHNAME, *errorStatus = %d.\n", *errorStatus ));
return; // bail...
}
// scan query list updating variables
for (i=0; i < ql->query[q].vblNum; i++) {
// initialize
mibEntry = ql->query[q].vblXlat[i].mibEntry; vlIndex = ql->query[q].vblXlat[i].vlIndex; j = ql->query[q].vblXlat[i].vlIndex;
tblXlat = NULL; mibAction = MIB_ACTION_GETNEXT;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: ValidateQueryList; next of %s.\n", SnmpUtilOidToA(&mibEntry->mibOid) ));
// next...
FindNextMibEntry( tfxInfo, NULL, &mibEntry, &mibAction, &tblXlat, vlIndex, errorStatus );
while (*errorStatus == SNMP_ERRORSTATUS_NOERROR) {
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: constructing followup to query 0x%08lx:\n" "SNMP: TFX: \tmibEntry=0x%08lx\n" "SNMP: TFX: \ttblXlat =0x%08lx\n", &ql->query[q], mibEntry, tblXlat ));
// initialize
tmpQl.len = 0; tmpQl.query = NULL; tmpQl.action = MIB_ACTION_GETNEXT;
// create query
MibEntryToQueryList( mibEntry, mibAction, &tmpQl, tblXlat, vlIndex, NULL, ql->query[q].vblXlat[i].vblIndex, errorStatus );
if (*errorStatus != SNMP_ERRORSTATUS_NOERROR) {
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: ValidateQueryList; MibEntryToQueryList returned %d.\n", *errorStatus ));
// delete if necessary
DeleteQueryList(&tmpQl); return; // bail...
}
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: processing followup query 0x%08lx.\n", tmpQl.query ));
// perform query with new oid
ProcessQuery(tmpQl.query, errorStatus, errorIndex);
// calculate results of query
if (*errorStatus == SNMP_ERRORSTATUS_NOERROR) {
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: saving followup 0x%08lx in query 0x%08lx.\n", tmpQl.query, &ql->query[q] ));
// copy query for reassembly purposes
ql->query[q].vblXlat[i].extQuery = tmpQl.query;
break; // process next varbind...
} else if (*errorStatus != SNMP_ERRORSTATUS_NOSUCHNAME) {
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: could not process followup.\n" ));
// delete...
DeleteQueryList(&tmpQl);
return; // bail...
}
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: re-processing followup to query 0x%08lx.\n", &ql->query[q] ));
// delete...
DeleteQueryList(&tmpQl);
// re-initialize and continue...
*errorStatus = SNMP_ERRORSTATUS_NOERROR; tblXlat = NULL; mibAction = MIB_ACTION_GETNEXT;
// next...
FindNextMibEntry( tfxInfo, NULL, &mibEntry, &mibAction, &tblXlat, vlIndex, errorStatus ); }
// NOTE: if we break from the above while loop,
// *errorStatus will be SNMP_ERRORSTATUS_NOERROR
// attempt to query next supported subagent view
if (*errorStatus == SNMP_ERRORSTATUS_NOSUCHNAME) {
// retrieve variable binding list index
vblIndex = ql->query[q].vblXlat[i].vblIndex;
// release old variable binding
SnmpUtilVarBindFree(&vbl->list[vblIndex]);
// copy varbind
if (! SnmpUtilOidCpy(&vbl->list[vblIndex].name, &tfxInfo->tfxViews[j].mibView->viewOid) ) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: ValidateQueryList; SnmpUtilOidCpy failed.\n" ));
*errorStatus = SNMP_ERRORSTATUS_GENERR; return; // bail...
}
// increment last sub-identifier of view oid
vbl->list[vblIndex].name.ids[vbl->list[vblIndex].name.idLength-1]++;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: TFX: query out of view. Pass up %s to service.\n", SnmpUtilOidToA(&vbl->list[vblIndex].name) ));
// this query goes outside the MIB view.
// varbind is set (above) to the first OID outside this view, so let the master agent
// handle the switch between views.
// let QueryToVarBindList() knows that this SnmpVarBindXlat is
// not valid for reassembly purpose.
ql->query[q].vblXlat[i].extQuery = INVALID_QUERY; *errorStatus = SNMP_ERRORSTATUS_NOERROR; continue; // process next varbind...
} else if (*errorStatus != SNMP_ERRORSTATUS_NOERROR) {
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: TFX: ValidateQueryList; FindNextMibEntry returned %d.\n", *errorStatus ));
return; // bail...
} } }
SnmpTfxInfo * AllocTfxInfo( ) { // simply return results from generic memory allocation
return (SnmpTfxInfo *)SnmpUtilMemAlloc(sizeof(SnmpTfxInfo)); }
VOID FreeTfxInfo( SnmpTfxInfo * tfxInfo ) { UINT i; // prefix bug 445171
if (tfxInfo == NULL) { return; } if (tfxInfo->tfxViews == NULL) { SnmpUtilMemFree(tfxInfo); return; }
// walk through list of views
for (i=0; (i < tfxInfo->numViews); i++) {
// release memory for view hash tables
FreeHashTable(tfxInfo->tfxViews[i].hashTable); } SnmpUtilMemFree(tfxInfo->tfxViews); SnmpUtilMemFree(tfxInfo); }
///////////////////////////////////////////////////////////////////////////////
// //
// Public Procedures //
// //
///////////////////////////////////////////////////////////////////////////////
SnmpTfxHandle SNMP_FUNC_TYPE SnmpTfxOpen( DWORD numViews, SnmpMibView * supportedViews ) { UINT i,j; BOOL fOk; SnmpTfxInfo * tfxInfo = NULL;
// validate parameters
if ((numViews == 0) || (supportedViews == NULL)) { return NULL; }
// allocate structure
tfxInfo = AllocTfxInfo();
// validate pointer
if (tfxInfo == NULL) { return NULL; }
// copy number of views
tfxInfo->numViews = numViews;
// allocate individual view structures
tfxInfo->tfxViews = SnmpUtilMemAlloc( tfxInfo->numViews * sizeof(SnmpTfxView) );
// initialize status
fOk = (tfxInfo->tfxViews != NULL);
// initialize each view structure
for (i=0; (i < tfxInfo->numViews) && fOk; i++) {
SnmpHashNode ** tmpHashTable;
// initialize individual view list entry
tmpHashTable = AllocHashTable(&supportedViews[i]);
// initialize status
fOk = (tmpHashTable != NULL);
// validate
if (fOk) {
// save a pointer into the subagent view list
tfxInfo->tfxViews[i].mibView = &supportedViews[i];
// save newly allocated view hash table
tfxInfo->tfxViews[i].hashTable = tmpHashTable; } }
// validate
if (fOk) {
SnmpTfxView tmpTfxView;
// make sure views are sorted
for (i=0; (i < tfxInfo->numViews); i++) {
for(j=i+1; (j < tfxInfo->numViews); j++) {
// in lexographic order?
if (0 < SnmpUtilOidCmp( &(tfxInfo->tfxViews[i].mibView->viewOid), &(tfxInfo->tfxViews[j].mibView->viewOid))) { // no, swap...
tmpTfxView = tfxInfo->tfxViews[i]; tfxInfo->tfxViews[i] = tfxInfo->tfxViews[j]; tfxInfo->tfxViews[i] = tmpTfxView; } } SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: TFX: Adding view [%d] %s.\n", tfxInfo->tfxViews[i].mibView->viewOid.idLength, SnmpUtilOidToA(&(tfxInfo->tfxViews[i].mibView->viewOid)) ));
}
} else {
// free structure
FreeTfxInfo(tfxInfo);
// reinitialize
tfxInfo = NULL; }
return (LPVOID)tfxInfo; }
SNMPAPI SNMP_FUNC_TYPE SnmpTfxQuery( SnmpTfxHandle tfxHandle, BYTE requestType, RFC1157VarBindList * vbl, AsnInteger * errorStatus, AsnInteger * errorIndex ) { SnmpExtQueryList ql; SnmpTfxInfo *tfxInfo = tfxHandle; int i;
// initialize
ql.query = NULL; ql.len = 0; ql.action = requestType;
// disassemble varbinds
VarBindListToQueryList( (SnmpTfxInfo*)tfxHandle, vbl, &ql, errorStatus, errorIndex );
// process queries
ProcessQueryList( (SnmpTfxInfo*)tfxHandle, &ql, vbl, errorStatus, errorIndex );
// reassemble varbinds
QueryListToVarBindList( (SnmpTfxInfo*)tfxHandle, &ql, vbl, errorStatus, errorIndex );
return TRUE; }
VOID SNMP_FUNC_TYPE SnmpTfxClose( SnmpTfxHandle tfxHandle ) { // simply treat as info and release
FreeTfxInfo((SnmpTfxInfo *)tfxHandle); }
|