|
|
/*++
Copyright (c) 1992-1997 Microsoft Corporation
Module Name:
query.c
Abstract:
Contains routines for querying subagents.
Environment:
User Mode - Win32
Revision History:
10-Feb-1997 DonRyan Rewrote to implement SNMPv2 support.
--*/ ///////////////////////////////////////////////////////////////////////////////
// //
// Include files //
// //
///////////////////////////////////////////////////////////////////////////////
#include "globals.h"
#include "varbinds.h"
#include "network.h"
#include "query.h"
#include "snmpmgmt.h"
///////////////////////////////////////////////////////////////////////////////
// //
// Private procedures //
// //
///////////////////////////////////////////////////////////////////////////////
BOOL FindQueryBySLE( PQUERY_LIST_ENTRY * ppQLE, PNETWORK_LIST_ENTRY pNLE, PSUBAGENT_LIST_ENTRY pSLE )
/*++
Routine Description:
Allocates query list entry.
Arguments:
ppQLE - pointer to receive query entry pointer.
pNLE - pointer to network list entry.
pSLE - pointer to subagent list entry.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE; PQUERY_LIST_ENTRY pQLE = NULL;
// point to first query
pLE = pNLE->Queries.Flink;
// process each query
while (pLE != &pNLE->Queries) {
// retrieve pointer to query entry from link
pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
// compare subagents
if (pQLE->pSLE == pSLE) {
// transfer
*ppQLE = pQLE;
// success
return TRUE; } // next entry
pLE = pLE->Flink; }
// initialize
*ppQLE = NULL;
// failure
return FALSE; }
BOOL LoadSubagentData( PNETWORK_LIST_ENTRY pNLE, PQUERY_LIST_ENTRY pQLE )
/*++
Routine Description:
Loads data to be passed to the subagent DLL.
Arguments:
pNLE - pointer to network list entry.
pQLE - pointer to current query.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE; PVARBIND_LIST_ENTRY pVLE; SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: query 0x%08lx loading.\n", pQLE ));
// attempt to allocate varbind list
pQLE->SubagentVbl.list = SnmpUtilMemAlloc( pQLE->nSubagentVbs * sizeof(SnmpVarBind) );
// validate varbind list pointer
if (pQLE->SubagentVbl.list != NULL) {
// point to first varbind
pLE = pQLE->SubagentVbs.Flink;
// process each outgoing varbind
while (pLE != &pQLE->SubagentVbs) {
// retrieve pointer to varbind entry from query link
pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, QueryLink);
// transfer varbind
if (SnmpUtilVarBindCpy( &pQLE->SubagentVbl.list[pQLE->SubagentVbl.len], &pVLE->ResolvedVb ) == 0) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not transfer varbind to subagent.\n" ));
return FALSE; }
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d copied to query 0x%08lx.\n", pVLE->nErrorIndex, pQLE )); // increment
pQLE->SubagentVbl.len++;
// next entry
pLE = pLE->Flink; }
} else {
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not allocate varbind list.\n" )); // failure
return FALSE; }
// success
return TRUE; }
BOOL UnloadSubagentData( PQUERY_LIST_ENTRY pQLE )
/*++
Routine Description:
Unloads data passed to the subagent DLL.
Arguments:
pQLE - pointer to current query.
Return Values:
Returns true if successful.
--*/
{ __try { // release subagent varbind list
SnmpUtilVarBindListFree(&pQLE->SubagentVbl);
} __except (EXCEPTION_EXECUTE_HANDLER) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: exception 0x%08lx processing structure from %s.\n", GetExceptionCode(), (pQLE->pSLE != NULL) ? pQLE->pSLE->pPathname : "<unknown>" ));
// failure
return FALSE; }
// success
return TRUE; }
BOOL UpdateResolvedVarBind( PQUERY_LIST_ENTRY pQLE, PVARBIND_LIST_ENTRY pVLE, UINT iVb )
/*++
Routine Description:
Updates resolved varbind with data from subagent DLL.
Arguments:
pQLE - pointer to current query.
pVLE - pointer to varbind.
iVb - index of varbind.
Return Values:
Returns true if successful.
--*/
{ // see if this is non-repeater
if (pVLE->nMaxRepetitions == 1) {
// flag varbind as resolved
pVLE->nState = VARBIND_RESOLVED;
// release memory for current varbind
SnmpUtilVarBindFree(&pVLE->ResolvedVb);
// transfer varbind from subagent
if (SnmpUtilVarBindCpy(&pVLE->ResolvedVb, &pQLE->SubagentVbl.list[iVb] ) == 0) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not transfer varbind from subagent.\n" ));
return FALSE; }
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d name %s.\n", pVLE->nErrorIndex, SnmpUtilOidToA(&pVLE->ResolvedVb.name) ));
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d state '%s'.\n", pVLE->nErrorIndex, VARBINDSTATESTRING(pVLE->nState) ));
// success
return TRUE; } // see if varbind list allocated
if ((pVLE->ResolvedVbl.len == 0) && (pVLE->ResolvedVbl.list == NULL)) {
if (sizeof(SnmpVarBind) > (UINT_MAX/pVLE->nMaxRepetitions)) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: arithmetic overflow: sizeof(SnmpVarBind) 0x%x, pVLE->nMaxRepetitions 0x%x.\n", sizeof(SnmpVarBind), pVLE->nMaxRepetitions ));
return FALSE; // bail...
}
// allocate varbind list to fill in
pVLE->ResolvedVbl.list = SnmpUtilMemAlloc( pVLE->nMaxRepetitions * sizeof(SnmpVarBind) ); // validate pointer before continuing
if (pVLE->ResolvedVbl.list == NULL) {
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not allocate new varbinds.\n" )); // failure
return FALSE; } }
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: pVLE->ResolvedVbl.len %d pVLE->nMaxRepetitions %d.\n", pVLE->ResolvedVbl.len, pVLE->nMaxRepetitions ));
// release working varbind name
SnmpUtilOidFree(&pVLE->ResolvedVb.name);
// transfer name for next iteration
if (SnmpUtilOidCpy(&pVLE->ResolvedVb.name, &pQLE->SubagentVbl.list[iVb].name ) == 0) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not transfer name for next iteration.\n" ));
return FALSE; }
// transfer varbind
if (SnmpUtilVarBindCpy( &pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len], &pQLE->SubagentVbl.list[iVb]) == 0) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not transfer varbind from subagent.\n" ));
return FALSE; }
// increment count
pVLE->ResolvedVbl.len++; // see if this is the last varbind to retrieve
pVLE->nState = (pVLE->nMaxRepetitions > pVLE->ResolvedVbl.len) ? VARBIND_PARTIALLY_RESOLVED : VARBIND_RESOLVED ;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d name %s.\n", pVLE->nErrorIndex, SnmpUtilOidToA(&pVLE->ResolvedVb.name) ));
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d state '%s'.\n", pVLE->nErrorIndex, VARBINDSTATESTRING(pVLE->nState) ));
// success
return TRUE; }
BOOL UpdateVarBind( PNETWORK_LIST_ENTRY pNLE, PQUERY_LIST_ENTRY pQLE, PVARBIND_LIST_ENTRY pVLE, UINT iVb )
/*++
Routine Description:
Updates varbind with data from subagent DLL.
Arguments:
pNLE - pointer to network list entry.
pQLE - pointer to current query.
pVLE - pointer to varbind.
iVb - index of varbind.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE; INT nDiff1; INT nDiff2;
__try { // determine order of returned varbind
nDiff1 = SnmpUtilOidCmp(&pQLE->SubagentVbl.list[iVb].name, &pVLE->ResolvedVb.name );
// see if this is getnext or getbulk
if ((pNLE->Pdu.nType == SNMP_PDU_GETNEXT) || (pNLE->Pdu.nType == SNMP_PDU_GETBULK)) { // determine whether returned varbind in range
nDiff2 = SnmpUtilOidCmp(&pQLE->SubagentVbl.list[iVb].name, &pVLE->pCurrentRLE->LimitOid );
// make sure returned oid in range
if ((nDiff1 > 0) && (nDiff2 < 0)) {
// update resolved variable binding
return UpdateResolvedVarBind(pQLE, pVLE, iVb);
} else if (nDiff2 >= 0) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: %s received getnext request for %s.\n", pQLE->pSLE->pPathname, SnmpUtilOidToA(&pVLE->ResolvedVb.name) ));
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: %s returned out-of-range oid %s.\n", pQLE->pSLE->pPathname, SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name) )); // retrieve pointer to next region
pLE = pVLE->pCurrentRLE->Link.Flink;
// see if we exhausted regions
if (pLE != &g_SupportedRegions) {
PMIB_REGION_LIST_ENTRY pNextRLE;
// retrieve pointer to mib region
pNextRLE = CONTAINING_RECORD(pLE, MIB_REGION_LIST_ENTRY, Link ); // see if next region supported by same subagent
if (pVLE->pCurrentRLE->pSLE == pNextRLE->pSLE) {
BOOL retCode;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: next region also supported by %s.\n", pVLE->pCurrentRLE->pSLE->pPathname ));
// update resolved variable binding
retCode = UpdateResolvedVarBind(pQLE, pVLE, iVb); if (pQLE->SubagentVbl.list[iVb].value.asnType != ASN_NULL) { return retCode; } else { SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: pQLE->SubagentVbl.list[%d].name = %s got ASN_NULL value.\n", iVb, SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name) )); // BUG# 610475
if (retCode) { // UpdateResolvedVarBind succeeds but
// pQLE->SubagentVbl.list[iVb].value has
// ASN_NULL value.
if (pVLE->nMaxRepetitions > 1) { // rollback what has been done in
// UpdateResolvedVarBind when
// (pVLE->nMaxRepetitions > 1).
if (pVLE->ResolvedVbl.len) { SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: rollback what has been done in UpdateResolvedVarBind.\n" ));
// decrement count
pVLE->ResolvedVbl.len--;
// free any resource allocated by UpdateResolvedVarBind
SnmpUtilVarBindFree(&pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len]); } } // pVLE->nState will set to
// VARBIND_PARTIALLY_RESOLVED to make another
// query below.
} else { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: UpdateVarBind: UpdateResolvedVarBind failed. pQLE->SubagentVbl.list[%d].name = %s.\n", iVb, SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name) )); return retCode; } } }
// point to next region
pVLE->pCurrentRLE = pNextRLE; // change state to partially resolved
pVLE->nState = VARBIND_PARTIALLY_RESOLVED;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d state '%s'.\n", pVLE->nErrorIndex, VARBINDSTATESTRING(pVLE->nState) ));
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: variable %d re-assigned to %s.\n", pVLE->nErrorIndex, pVLE->pCurrentRLE->pSLE->pPathname )); } else if ((pVLE->ResolvedVbl.len == 0) && (pVLE->ResolvedVbl.list == NULL)) {
// flag varbind as resolved
pVLE->nState = VARBIND_RESOLVED;
// set default varbind to eomv
pVLE->ResolvedVb.value.asnType = SNMP_EXCEPTION_ENDOFMIBVIEW; // update error status counter for the operation
mgmtCTick(CsnmpOutNoSuchNames);
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d state '%s'.\n", pVLE->nErrorIndex, VARBINDSTATESTRING(pVLE->nState) ));
} else { // transfer name
if (SnmpUtilOidCpy( &pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len].name, &pVLE->ResolvedVb.name) == 0) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not transfer name at line %d.\n", __LINE__ ));
return FALSE; }
// flag varbind as resolved
pVLE->nState = VARBIND_RESOLVED;
// set current varbind to eomv
pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len].value.asnType = SNMP_EXCEPTION_ENDOFMIBVIEW;
// increment count
pVLE->ResolvedVbl.len++;
// update error status counter for the operation
mgmtCTick(CsnmpOutNoSuchNames);
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d state '%s'.\n", pVLE->nErrorIndex, VARBINDSTATESTRING(pVLE->nState) )); }
} else {
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: %s received getnext request for %s.\n", pQLE->pSLE->pPathname, SnmpUtilOidToA(&pVLE->ResolvedVb.name) ));
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: %s returned invalid oid %s.\n", pQLE->pSLE->pPathname, SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name) ));
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: Ban %s subagent, forward the request to a different one.\n", pQLE->pSLE->pPathname ));
// trying to forward this getnext request to the next region but only if not handled
// by the same subagent!
pLE = pVLE->pCurrentRLE->Link.Flink; while( pLE != &g_SupportedRegions) { PMIB_REGION_LIST_ENTRY pNextRLE;
// retrieve pointer to mib region
pNextRLE = CONTAINING_RECORD(pLE, MIB_REGION_LIST_ENTRY, Link );
// if this 'next' region is handled by the same subagent, skip to the next!
if (pVLE->pCurrentRLE->pSLE == pNextRLE->pSLE) { pLE = pNextRLE->Link.Flink; continue; }
// ok, we have one, forward the original GetNext request to it
pVLE->pCurrentRLE = pNextRLE; pVLE->nState = VARBIND_PARTIALLY_RESOLVED;
SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: variable %d re-assigned to %s.\n", pVLE->nErrorIndex, pVLE->pCurrentRLE->pSLE->pPathname )); return TRUE; }
// failure
// here I should emulate a (NO_SUCH_NAME) EndOfMibView, resolve the variable and return TRUE.
pVLE->nState = VARBIND_RESOLVED; pVLE->ResolvedVb.value.asnType = SNMP_EXCEPTION_ENDOFMIBVIEW; pVLE->pCurrentRLE = NULL;
// update error status counter
mgmtCTick(CsnmpOutNoSuchNames);
return TRUE; }
} else if (pNLE->Pdu.nType == SNMP_PDU_GET) {
// must match
if (nDiff1 == 0) {
// flag varbind as resolved
pVLE->nState = VARBIND_RESOLVED;
// release memory for current varbind
SnmpUtilVarBindFree(&pVLE->ResolvedVb);
// transfer varbind from subagent
if (SnmpUtilVarBindCpy(&pVLE->ResolvedVb, &pQLE->SubagentVbl.list[iVb]) == 0) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not transfer varbind from subagent at line %d.\n", __LINE__ ));
return FALSE; }
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d name %s.\n", pVLE->nErrorIndex, SnmpUtilOidToA(&pVLE->ResolvedVb.name) ));
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d state '%s'.\n", pVLE->nErrorIndex, VARBINDSTATESTRING(pVLE->nState) ));
} else {
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: %s received get request for %s.\n", pQLE->pSLE->pPathname, SnmpUtilOidToA(&pVLE->ResolvedVb.name) ));
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: %s returned invalid oid %s.\n", pQLE->pSLE->pPathname, SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name) )); // failure
return FALSE; }
} else if (nDiff1 != 0) { // set request failed -> invalid oid
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: %s received set request for %s.\n", pQLE->pSLE->pPathname, SnmpUtilOidToA(&pVLE->ResolvedVb.name) ));
SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: %s returned invalid oid %s.\n", pQLE->pSLE->pPathname, SnmpUtilOidToA(&pQLE->SubagentVbl.list[iVb].name) )); // failure
return FALSE; } else {
// set request, oids match
// WARNING!! - state might be set prematurely on SET_TEST / SET_CLEANUP
pVLE->nState = VARBIND_RESOLVED; return TRUE; }
} __except (EXCEPTION_EXECUTE_HANDLER) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: exception 0x%08lx processing structure from %s.\n", GetExceptionCode(), pQLE->pSLE->pPathname ));
// failure
return FALSE; }
// success
return TRUE; }
BOOL UpdateVarBinds( PNETWORK_LIST_ENTRY pNLE, PQUERY_LIST_ENTRY pQLE )
/*++
Routine Description:
Updates varbind list entries with data from subagent DLL.
Arguments:
pNLE - pointer to network list entry.
pQLE - pointer to current query.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE; PVARBIND_LIST_ENTRY pVLE; BOOL fOk = TRUE; UINT iVb = 0; // point to first varbind
pLE = pQLE->SubagentVbs.Flink;
// see if error encountered during callback
if (pQLE->nErrorStatus == SNMP_ERRORSTATUS_NOERROR) { // process each outgoing varbind
while (pLE != &pQLE->SubagentVbs) {
// retrieve pointer to varbind entry from query link
pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, QueryLink); // update individual varbind
if (!UpdateVarBind(pNLE, pQLE, pVLE, iVb++)) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: variable %d could not be updated.\n", pQLE->nErrorIndex ));
// update pdu with the proper varbind error index
pNLE->Pdu.Pdu.NormPdu.nErrorStatus = SNMP_ERRORSTATUS_GENERR; pNLE->Pdu.Pdu.NormPdu.nErrorIndex = pVLE->nErrorIndex;
// failure
return FALSE; }
// next entry
pLE = pLE->Flink; } } else {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: searching for errant variable.\n" ));
// update pdu with status returned from subagent
pNLE->Pdu.Pdu.NormPdu.nErrorStatus = pQLE->nErrorStatus;
// process each outgoing varbind
while (pLE != &pQLE->SubagentVbs) {
// retrieve pointer to varbind entry from query link
pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, QueryLink); // see if errant varbind nErrorIndex is starts from 1 !!
if (pQLE->nErrorIndex == ++iVb) { SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: variable %d involved in failure.\n", pVLE->nErrorIndex ));
// update pdu with the proper varbind error index
pNLE->Pdu.Pdu.NormPdu.nErrorIndex = pVLE->nErrorIndex;
// the error code was successfully identified
return TRUE; }
// next entry
pLE = pLE->Flink; } SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: no variable involved in failure.\n" ));
// failure
return FALSE; }
// success
return TRUE; }
BOOL CallSubagent( PQUERY_LIST_ENTRY pQLE, UINT nRequestType, UINT nTransactionId )
/*++
Routine Description: Invokes method from subagent DLL.
Arguments:
pNLE - pointer to network list entry.
nRequestType - type of request to post to subagent.
nTransactionId - identifies snmp pdu sent from manager.
Return Values:
Returns true if successful.
--*/
{ BOOL fOk = FALSE;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: --- query %s begin ---\n", pQLE->pSLE->pPathname ));
__try { // determine which version of query supported
if (pQLE->pSLE->pfnSnmpExtensionQueryEx != NULL) {
// process query using new interface
fOk = (*pQLE->pSLE->pfnSnmpExtensionQueryEx)( nRequestType, nTransactionId, &pQLE->SubagentVbl, &pQLE->ContextInfo, &pQLE->nErrorStatus, &pQLE->nErrorIndex ); // see if query is actually valid for downlevel call
} else if ((pQLE->pSLE->pfnSnmpExtensionQuery != NULL) && ((nRequestType == SNMP_EXTENSION_GET) || (nRequestType == SNMP_EXTENSION_GET_NEXT) || (nRequestType == SNMP_EXTENSION_SET_COMMIT))) { // process query using old interface
fOk = (*pQLE->pSLE->pfnSnmpExtensionQuery)( (BYTE)(UINT)nRequestType, &pQLE->SubagentVbl, &pQLE->nErrorStatus, &pQLE->nErrorIndex );
// see if query can be completed successfully anyway
} else if ((nRequestType == SNMP_EXTENSION_SET_TEST) || (nRequestType == SNMP_EXTENSION_SET_CLEANUP)) {
// fake it
fOk = TRUE; }
} __except (EXCEPTION_EXECUTE_HANDLER) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: exception 0x%08lx calling %s.\n", GetExceptionCode(), pQLE->pSLE->pPathname )); }
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: --- query %s end ---\n", pQLE->pSLE->pPathname ));
// validate
if (!fOk) { // identify failing subagent
pQLE->nErrorStatus = SNMP_ERRORSTATUS_GENERR; pQLE->nErrorIndex = 1;
} else if (pQLE->nErrorStatus != SNMP_ERRORSTATUS_NOERROR) {
// see if error index needs to be adjusted
if ((pQLE->nErrorIndex > pQLE->nSubagentVbs) || (pQLE->nErrorIndex == 0)) {
// set to first varbind
pQLE->nErrorIndex = 1; } } else {
// re-initialize
pQLE->nErrorIndex = 0; }
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: query 0x%08lx %s, errorStatus=%s, errorIndex=%d.\n", pQLE, (pQLE->nErrorStatus == SNMP_ERRORSTATUS_NOERROR) ? "succeeded" : "failed" , SNMPERRORSTRING(pQLE->nErrorStatus), pQLE->nErrorIndex ));
return TRUE; }
BOOL ProcessSet( PNETWORK_LIST_ENTRY pNLE )
/*++
Routine Description:
Processes SNMP_PDU_SET requests.
Arguments:
pNLE - pointer to network list entry.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE = NULL; PQUERY_LIST_ENTRY pQLE; BOOL fOk = TRUE;
// load subagent queries
if (!LoadQueries(pNLE)) {
// unload immediately
UnloadQueries(pNLE);
// failure
return FALSE; } // point to first query
pLE = pNLE->Queries.Flink;
// process each subagent query
while (fOk && (pLE != &pNLE->Queries)) {
// retrieve pointer to query entry from link
pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
// load outgoing varbinds
fOk = LoadSubagentData(pNLE, pQLE);
// validate
if (fOk) {
// dispatch
CallSubagent( pQLE, SNMP_EXTENSION_SET_TEST, pNLE->nTransactionId );
// process results returned
fOk = UpdateVarBinds(pNLE, pQLE); }
// next entry (or reverse direction)
pLE = fOk ? pLE->Flink : pLE->Blink; } // validate
if (fOk) {
// if this line is missing => GenErr on UpdatePdu()
pLE = pNLE->Queries.Flink;
// process each subagent query
while (fOk && (pLE != &pNLE->Queries)) {
// retrieve pointer to query entry from link
pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
// dispatch
CallSubagent( pQLE, SNMP_EXTENSION_SET_COMMIT, pNLE->nTransactionId );
// process results returned
fOk = UpdateVarBinds(pNLE, pQLE);
// next entry (or reverse direction)
pLE = fOk ? pLE->Flink : pLE->Blink; }
// validate
if (!fOk) {
// process each subagent query
while (pLE != &pNLE->Queries) {
// retrieve pointer to query entry from link
pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
// dispatch
CallSubagent( pQLE, SNMP_EXTENSION_SET_UNDO, pNLE->nTransactionId );
// process results returned
UpdateVarBinds(pNLE, pQLE);
// previous entry
pLE = pLE->Blink; } }
// point to last query
pLE = pNLE->Queries.Blink; } // process each subagent query
while (pLE != &pNLE->Queries) {
// retrieve pointer to query entry from link
pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
// dispatch
CallSubagent( pQLE, SNMP_EXTENSION_SET_CLEANUP, pNLE->nTransactionId );
// process results returned
UpdateVarBinds(pNLE, pQLE);
// previous entry
pLE = pLE->Blink; }
// cleanup queries
UnloadQueries(pNLE);
return TRUE; }
BOOL ProcessGet( PNETWORK_LIST_ENTRY pNLE )
/*++
Routine Description:
Queries subagents to resolve varbinds.
Arguments:
pNLE - pointer to network list entry.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE; PQUERY_LIST_ENTRY pQLE = NULL; BOOL fOk = TRUE;
// load subagent queries
if (!LoadQueries(pNLE)) {
// unload immediately
UnloadQueries(pNLE);
// failure
return FALSE; } // point to first query
pLE = pNLE->Queries.Flink;
// process each subagent query
while (fOk && (pLE != &pNLE->Queries)) {
// retrieve pointer to query entry from link
pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
// load outgoing varbinds
fOk = LoadSubagentData(pNLE, pQLE);
// validate
if (fOk) {
// dispatch
CallSubagent( pQLE, SNMP_EXTENSION_GET, pNLE->nTransactionId );
// process results returned
fOk = UpdateVarBinds(pNLE, pQLE); }
// next entry
pLE = pLE->Flink; } // cleanup queries
UnloadQueries(pNLE);
return fOk; }
BOOL ProcessGetBulk( PNETWORK_LIST_ENTRY pNLE )
/*++
Routine Description:
Queries subagents to resolve varbinds.
Arguments:
pNLE - pointer to network list entry.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE; PQUERY_LIST_ENTRY pQLE = NULL; BOOL fOk = TRUE;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: getbulk request, non-repeaters %d, max-repetitions %d.\n", pNLE->Pdu.Pdu.BulkPdu.nNonRepeaters, pNLE->Pdu.Pdu.BulkPdu.nMaxRepetitions ));
// loop
while (fOk) {
// load subagent queries
fOk = LoadQueries(pNLE);
// validate
if (fOk && !IsListEmpty(&pNLE->Queries)) {
// point to first query
pLE = pNLE->Queries.Flink;
// process each subagent query
while (fOk && (pLE != &pNLE->Queries)) {
// retrieve pointer to query entry from link
pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
// load outgoing varbinds
fOk = LoadSubagentData(pNLE, pQLE);
// validate
if (fOk) {
// dispatch
CallSubagent( pQLE, SNMP_EXTENSION_GET_NEXT, pNLE->nTransactionId );
// process results returned
fOk = UpdateVarBinds(pNLE, pQLE); }
// next entry
pLE = pLE->Flink; }
} else if (IsListEmpty(&pNLE->Queries)) {
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: no more queries to process.\n" ));
break; // finished...
}
// cleanup queries
UnloadQueries(pNLE); }
return fOk; }
///////////////////////////////////////////////////////////////////////////////
// //
// Public procedures //
// //
///////////////////////////////////////////////////////////////////////////////
BOOL AllocQLE( PQUERY_LIST_ENTRY * ppQLE )
/*++
Routine Description:
Allocates query list entry.
Arguments:
ppQLE - pointer to receive list entry pointer.
Return Values:
Returns true if successful.
--*/
{ BOOL fOk = FALSE; PQUERY_LIST_ENTRY pQLE = NULL;
// attempt to allocate structure
pQLE = AgentMemAlloc(sizeof(QUERY_LIST_ENTRY));
// validate
if (pQLE != NULL) {
// initialize outgoing varbind list
InitializeListHead(&pQLE->SubagentVbs);
// success
fOk = TRUE; } else { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not allocate query.\n" )); }
// transfer
*ppQLE = pQLE;
return fOk; }
BOOL FreeQLE( PQUERY_LIST_ENTRY pQLE )
/*++
Routine Description:
Creates queries from varbind list entries.
Arguments:
pNLE - pointer to network list entry with SNMP message.
Return Values:
Returns true if successful.
--*/
{ // validate pointer
if (pQLE != NULL) {
// release subagent info
UnloadSubagentData(pQLE);
// release structure
AgentMemFree(pQLE); }
return TRUE; }
BOOL LoadQueries( PNETWORK_LIST_ENTRY pNLE )
/*++
Routine Description:
Creates queries from varbind list entries.
Arguments:
pNLE - pointer to network list entry.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE; PVARBIND_LIST_ENTRY pVLE; PQUERY_LIST_ENTRY pQLE = NULL;
// point to first varbind
pLE = pNLE->Bindings.Flink;
// process each binding
while (pLE != &pNLE->Bindings) {
// retrieve pointer to varbind entry from link
pVLE = CONTAINING_RECORD(pLE, VARBIND_LIST_ENTRY, Link);
// analyze current state of varbind
if ((pVLE->nState == VARBIND_INITIALIZED) || (pVLE->nState == VARBIND_PARTIALLY_RESOLVED)) {
// attempt to locate existing query
if (FindQueryBySLE(&pQLE, pNLE, pVLE->pCurrentRLE->pSLE)) {
// attach varbind entry to query via query link
InsertTailList(&pQLE->SubagentVbs, &pVLE->QueryLink);
// change varbind state
pVLE->nState = VARBIND_RESOLVING;
// increment total
pQLE->nSubagentVbs++;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d added to existing query 0x%08lx.\n", pVLE->nErrorIndex, pQLE ));
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d state '%s'.\n", pVLE->nErrorIndex, VARBINDSTATESTRING(pVLE->nState) ));
// attempt to allocate entry
} else if (AllocQLE(&pQLE)) { // obtain subagent pointer
pQLE->pSLE = pVLE->pCurrentRLE->pSLE;
// insert into query list
InsertTailList(&pNLE->Queries, &pQLE->Link);
// attach varbind entry to query via query link
InsertTailList(&pQLE->SubagentVbs, &pVLE->QueryLink);
// change varbind state
pVLE->nState = VARBIND_RESOLVING;
// increment total
pQLE->nSubagentVbs++;
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d added to new query 0x%08lx.\n", pVLE->nErrorIndex, pQLE ));
SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: variable %d state '%s'.\n", pVLE->nErrorIndex, VARBINDSTATESTRING(pVLE->nState) ));
} else { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not contruct query.\n" ));
// failure
return FALSE; } }
// next entry
pLE = pLE->Flink; } // success
return TRUE; }
BOOL UnloadQueries( PNETWORK_LIST_ENTRY pNLE )
/*++
Routine Description:
Destroys queries from varbind list entries.
Arguments:
pNLE - pointer to network list entry with SNMP message.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE; PQUERY_LIST_ENTRY pQLE; // process each query entry
while (!IsListEmpty(&pNLE->Queries)) {
// point to first query
pLE = RemoveHeadList(&pNLE->Queries);
// retrieve pointer to query from link
pQLE = CONTAINING_RECORD(pLE, QUERY_LIST_ENTRY, Link);
// release
FreeQLE(pQLE); }
return TRUE; }
BOOL ProcessQueries( PNETWORK_LIST_ENTRY pNLE )
/*++
Routine Description:
Queries subagents to resolve varbinds.
Arguments:
pNLE - pointer to network list entry.
Return Values:
Returns true if successful.
--*/
{ // determine pdu
switch (pNLE->Pdu.nType) {
case SNMP_PDU_GETNEXT: case SNMP_PDU_GETBULK: // multiple non-exact reads
return ProcessGetBulk(pNLE);
case SNMP_PDU_GET: // single exact read
return ProcessGet(pNLE);
case SNMP_PDU_SET:
// single exact write
return ProcessSet(pNLE); }
// failure
return FALSE; }
|