Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4103 lines
108 KiB

/*++
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);
}