/*++ 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 #include #include // using ntrtl's ASSERT #include #include #include #include #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 (inumIndices) 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 ? "" : 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); }