windows-nt/Source/XPSP1/NT/net/snmp/newagent/exe/query.c
2020-09-26 16:20:57 +08:00

1552 lines
37 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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
SnmpUtilVarBindCpy(
&pQLE->SubagentVbl.list[pQLE->SubagentVbl.len++],
&pVLE->ResolvedVb
);
SNMPDBG((
SNMP_LOG_VERBOSE,
"SNMP: SVC: variable %d copied to query 0x%08lx.\n",
pVLE->nErrorIndex,
pQLE
));
// next entry
pLE = pLE->Flink;
}
// create copy of context in case subagent mucks with it
SnmpUtilOctetsCpy(&pQLE->ContextInfo, &pNLE->Community);
} 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);
// release subagent context information
SnmpUtilOctetsFree(&pQLE->ContextInfo);
} __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
SnmpUtilVarBindCpy(&pVLE->ResolvedVb,
&pQLE->SubagentVbl.list[iVb]
);
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)) {
// 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;
}
}
// release working varbind name
SnmpUtilOidFree(&pVLE->ResolvedVb.name);
// transfer name for next iteration
SnmpUtilOidCpy(&pVLE->ResolvedVb.name,
&pQLE->SubagentVbl.list[iVb].name
);
// transfer varbind
SnmpUtilVarBindCpy(
&pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len],
&pQLE->SubagentVbl.list[iVb]
);
// 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;
}
}
// 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 {
// flag varbind as resolved
pVLE->nState = VARBIND_RESOLVED;
// transfer name
SnmpUtilOidCpy(
&pVLE->ResolvedVbl.list[pVLE->ResolvedVbl.len].name,
&pVLE->ResolvedVb.name
);
// 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
SnmpUtilVarBindCpy(&pVLE->ResolvedVb,
&pQLE->SubagentVbl.list[iVb]
);
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;
}