|
|
/*++
Copyright (c) 1992-1997 Microsoft Corporation
Module Name:
trapthrd.c
Abstract:
Contains routines for trap processing thread.
Environment:
User Mode - Win32
Revision History:
10-Feb-1997 DonRyan Rewrote to implement SNMPv2 support.
--*/ ///////////////////////////////////////////////////////////////////////////////
// //
// Include files //
// //
///////////////////////////////////////////////////////////////////////////////
#include "globals.h"
#include "trapthrd.h"
#include "subagnts.h"
#include "snmppdus.h"
#include "trapmgrs.h"
#include "snmpmgrs.h"
#include "network.h"
#include "snmpmgmt.h"
///////////////////////////////////////////////////////////////////////////////
// //
// Global variables //
// //
///////////////////////////////////////////////////////////////////////////////
static SnmpVarBindList g_NullVbl = { NULL, 0 };
///////////////////////////////////////////////////////////////////////////////
// //
// Private procedures //
// //
///////////////////////////////////////////////////////////////////////////////
BOOL LoadWaitObjects( DWORD * pnWaitObjects, PHANDLE * ppWaitObjects, PSUBAGENT_LIST_ENTRY ** pppNLEs )
/*++
Routine Description:
Loads arrays with necessary wait object information.
Arguments:
pnWaitObjects - pointer to receive count of wait objects.
ppWaitObjects - pointer to receive wait object handles.
pppNLEs - pointer to receive array of associated subagents pointers.
Return Values:
Returns true if successful.
--*/
{ PLIST_ENTRY pLE; PSUBAGENT_LIST_ENTRY pNLE; PSUBAGENT_LIST_ENTRY * ppNLEs = NULL; PHANDLE pWaitObjects = NULL; DWORD nWaitObjects = 2; BOOL fOk = FALSE;
EnterCriticalSection(&g_RegCriticalSectionB); // point to first subagent
pLE = g_Subagents.Flink;
// process each subagent
while (pLE != &g_Subagents) {
// retreive pointer to subagent list entry from link
pNLE = CONTAINING_RECORD(pLE, SUBAGENT_LIST_ENTRY, Link);
// check for subagent trap event
if (pNLE->hSubagentTrapEvent != NULL) { // increment
nWaitObjects++; }
// next entry
pLE = pLE->Flink; } // attempt to allocate array of subagent pointers
ppNLEs = AgentMemAlloc(nWaitObjects * sizeof(PSUBAGENT_LIST_ENTRY)); // validate pointers
if (ppNLEs != NULL) {
// attempt to allocate array of event handles
pWaitObjects = AgentMemAlloc(nWaitObjects * sizeof(HANDLE));
// validate pointer
if (pWaitObjects != NULL) {
// success
fOk = TRUE;
} else { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not allocate handle array.\n" ));
// release array
AgentMemFree(ppNLEs); // re-init
ppNLEs = NULL; }
} else { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: could not allocate subagent pointers.\n" )); } if (fOk) { // initialize
DWORD dwIndex = 0;
// point to first subagent
pLE = g_Subagents.Flink;
// process each subagent and check for overflow
while ((pLE != &g_Subagents) && (dwIndex < nWaitObjects - 1)) {
// retreive pointer to subagent list entry from link
pNLE = CONTAINING_RECORD(pLE, SUBAGENT_LIST_ENTRY, Link);
// check for subagent trap event
if (pNLE->hSubagentTrapEvent != NULL) { // copy subagent trap event handle
pWaitObjects[dwIndex] = pNLE->hSubagentTrapEvent;
// copy subagent pointer
ppNLEs[dwIndex] = pNLE;
// next
dwIndex++; }
// next entry
pLE = pLE->Flink; }
// copy registry update event into second last entry
pWaitObjects[dwIndex++] = g_hRegistryEvent;
// copy termination event into last entry
pWaitObjects[dwIndex++] = g_hTerminationEvent;
// validate number of items
if (dwIndex != nWaitObjects) { SNMPDBG(( SNMP_LOG_WARNING, "SNMP: SVC: updating number of events from %d to %d.\n", nWaitObjects, dwIndex ));
// use latest number
nWaitObjects = dwIndex; } }
// transfer wait object information
*pnWaitObjects = fOk ? nWaitObjects : 0; *ppWaitObjects = pWaitObjects; *pppNLEs = ppNLEs;
LeaveCriticalSection(&g_RegCriticalSectionB);
return fOk; }
BOOL UnloadWaitObjects( PHANDLE pWaitObjects, PSUBAGENT_LIST_ENTRY * ppNLEs )
/*++
Routine Description:
Loads arrays with necessary wait object information.
Arguments:
pWaitObjects - pointer to wait object handles.
ppNLEs - pointer to array of associated subagents pointers.
Return Values:
Returns true if successful.
--*/
{ // release array
AgentMemFree(pWaitObjects);
// release array
AgentMemFree(ppNLEs); return TRUE; }
BOOL GenerateExtensionTrap( AsnObjectIdentifier * pEnterpriseOid, AsnInteger32 nGenericTrap, AsnInteger32 nSpecificTrap, AsnTimeticks nTimeStamp, SnmpVarBindList * pVbl )
/*
Routine Description:
Generates trap for subagent.
Arguments:
pEnterpriseOid - pointer to EnterpriseOid OID.
nGenericTrap - generic trap identifier.
nSpecificTrap - EnterpriseOid specific trap identifier.
nTimeStamp - timestamp to include in trap.
pVbl - pointer to optional variables.
Return Values:
Returns true if successful.
*/
{ SNMP_PDU Pdu; BOOL fOk = FALSE;
// note this is in older format
Pdu.nType = SNMP_PDU_V1TRAP;
// validate pointer
if (pVbl != NULL) {
// copy varbinds
Pdu.Vbl = *pVbl;
} else {
// initialize
Pdu.Vbl.len = 0; Pdu.Vbl.list = NULL; }
// validate enterprise oid
if ((pEnterpriseOid != NULL) && (pEnterpriseOid->ids != NULL) && (pEnterpriseOid->idLength != 0)) {
// transfer specified enterprise oid
Pdu.Pdu.TrapPdu.EnterpriseOid = *pEnterpriseOid;
} else {
// transfer microsoft enterprise oid
// Note: transfer the AsnObjectIdentifier structure as a whole, but no new memory is allocated
// for the 'ids' buffer. Hence, Pdu....EnterpriseOid should not be 'SnmpUtilFreeOid'!!
Pdu.Pdu.TrapPdu.EnterpriseOid = snmpMgmtBase.AsnObjectIDs[OsnmpSysObjectID].asnValue.object; }
// make sure that the system uptime is consistent by overriding
Pdu.Pdu.TrapPdu.nTimeticks = nTimeStamp ? SnmpSvcGetUptime() : 0;
// transfer the remaining parameters
Pdu.Pdu.TrapPdu.nGenericTrap = nGenericTrap; Pdu.Pdu.TrapPdu.nSpecificTrap = nSpecificTrap;
// initialize agent address structure
Pdu.Pdu.TrapPdu.AgentAddr.dynamic = FALSE; Pdu.Pdu.TrapPdu.AgentAddr.stream = NULL; Pdu.Pdu.TrapPdu.AgentAddr.length = 0;
// send trap to managers
return GenerateTrap(&Pdu); }
///////////////////////////////////////////////////////////////////////////////
// //
// Public procedures //
// //
///////////////////////////////////////////////////////////////////////////////
BOOL ProcessSubagentEvents( )
/*++
Routine Description:
Processes subagent trap events.
Arguments:
None.
Return Values:
Returns true if successful.
--*/
{ BOOL fOk = FALSE; PSUBAGENT_LIST_ENTRY * ppNLEs = NULL; PHANDLE pWaitObjects = NULL; DWORD nWaitObjects = 0; DWORD dwIndex;
// attempt to load waitable objects into array
if (LoadWaitObjects(&nWaitObjects, &pWaitObjects, &ppNLEs)) {
// loop
for (;;) {
// subagent event or termination
dwIndex = WaitForMultipleObjects( nWaitObjects, pWaitObjects, FALSE, INFINITE );
// check for process termination event first
// note: g_hTerminationEvent is a manual reset event
if (WAIT_OBJECT_0 == WaitForSingleObject(g_hTerminationEvent, 0)) { SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: shutting down trap thread.\n" )); break; // bail...
// check for registry update event next
} else if (dwIndex == (WAIT_OBJECT_0 + nWaitObjects - 2)) { SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: recalling LoadWaitObjects.\n" )); if (!LoadWaitObjects(&nWaitObjects, &pWaitObjects, &ppNLEs)) break;
// check for subagent trap notification event
} else if (dwIndex < (WAIT_OBJECT_0 + nWaitObjects - 1)) {
AsnObjectIdentifier EnterpriseOid; AsnInteger nGenericTrap; AsnInteger nSpecificTrap; AsnInteger nTimeStamp; SnmpVarBindList Vbl;
PFNSNMPEXTENSIONTRAP pfnSnmpExtensionTrap;
// retrieve pointer to subagent trap entry point
pfnSnmpExtensionTrap = ppNLEs[dwIndex]->pfnSnmpExtensionTrap; // validate function pointer
if (pfnSnmpExtensionTrap != NULL) {
__try {
// loop until false is returned
while ((*pfnSnmpExtensionTrap)( &EnterpriseOid, &nGenericTrap, &nSpecificTrap, &nTimeStamp, &Vbl)) { // send extension trap
GenerateExtensionTrap( &EnterpriseOid, nGenericTrap, nSpecificTrap, nTimeStamp, &Vbl );
SnmpUtilVarBindListFree(&Vbl); // check for process termination event while we are in this while loop
if (WAIT_OBJECT_0 == WaitForSingleObject(g_hTerminationEvent, 0)) { SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: shutting down trap thread in \"while((*pfnSnmpExtensionTrap)\" loop.\n" )); break; // bail...
} } } __except (EXCEPTION_EXECUTE_HANDLER) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: exception 0x%08lx polling %s.\n", GetExceptionCode(), ppNLEs[dwIndex]->pPathname )); } } } } // release memory for wait objects
UnloadWaitObjects(pWaitObjects, ppNLEs); }
return fOk; }
BOOL GenerateTrap( PSNMP_PDU pPdu )
/*
Routine Description:
Generates trap for agent.
Arguments:
pPdu - pointer to initialized TRAP or TRAPv1 PDU.
Return Values:
Returns true if successful.
*/
{ BOOL fOk = TRUE; PLIST_ENTRY pLE1; PLIST_ENTRY pLE2; PLIST_ENTRY pLE3; PNETWORK_LIST_ENTRY pNLE; PMANAGER_LIST_ENTRY pMLE; PTRAP_DESTINATION_LIST_ENTRY pTLE; AsnOctetString CommunityOctets; DWORD dwStatus; DWORD dwIPAddr;
EnterCriticalSection(&g_RegCriticalSectionC); // obtain first trap destination
pLE1 = g_TrapDestinations.Flink;
// process each trap destination
while (pLE1 != &g_TrapDestinations) {
// retrieve pointer to outgoing transport structure
pTLE = CONTAINING_RECORD(pLE1, TRAP_DESTINATION_LIST_ENTRY, Link);
// copy community string into octet structure
CommunityOctets.length = strlen(pTLE->pCommunity); CommunityOctets.stream = pTLE->pCommunity; CommunityOctets.dynamic = FALSE;
// obtain first manager
pLE2 = pTLE->Managers.Flink;
// process each receiving manager
while (pLE2 != &pTLE->Managers) {
// retrieve pointer to next manager
pMLE = CONTAINING_RECORD(pLE2, MANAGER_LIST_ENTRY, Link); // refresh addr
UpdateMLE(pMLE);
// don't send traps to addresses that are DEAD or NULL
if (pMLE->dwAge == MGRADDR_DEAD || !IsValidSockAddr(&pMLE->SockAddr)) { pLE2 = pLE2->Flink; continue; } // obtain first outgoing transport
pLE3 = g_OutgoingTransports.Flink;
// process each outgoing transport
while (pLE3 != &g_OutgoingTransports) {
// retrieve pointer to outgoing transport structure
pNLE = CONTAINING_RECORD(pLE3, NETWORK_LIST_ENTRY, Link);
// initialize buffer length
pNLE->Buffer.len = NLEBUFLEN;
// can only send on same protocol
if (pNLE->SockAddr.sa_family != pMLE->SockAddr.sa_family) { pLE3 = pLE3->Flink; continue; }
// modify agent address
if (pNLE->SockAddr.sa_family == AF_INET) {
struct sockaddr_in * pSockAddrIn; DWORD szSockToBind;
// see if the trap destination address is valid and if the
// card to use for sending the trap could be determined
if (WSAIoctl(pNLE->Socket, SIO_ROUTING_INTERFACE_QUERY, &pMLE->SockAddr, sizeof(pMLE->SockAddr), &pNLE->SockAddr, sizeof(pNLE->SockAddr), &szSockToBind, NULL, NULL) == SOCKET_ERROR) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: cannot determine interface to use for trap destination %s [err=%d].\n", inet_ntoa(((struct sockaddr_in *)&pMLE->SockAddr)->sin_addr), WSAGetLastError() )); // if we can't determine on what interface the trap will be sent from, just bail.
pLE3 = pLE3->Flink; continue; } // obtain pointer to protocol specific structure
pSockAddrIn = (struct sockaddr_in * )&pNLE->SockAddr;
// copy agent address into temp buffer
dwIPAddr = pSockAddrIn->sin_addr.s_addr;
// initialize agent address structure
pPdu->Pdu.TrapPdu.AgentAddr.dynamic = FALSE; pPdu->Pdu.TrapPdu.AgentAddr.stream = (LPBYTE)&dwIPAddr; pPdu->Pdu.TrapPdu.AgentAddr.length = sizeof(dwIPAddr);
} else {
// re-initialize agent address structure
pPdu->Pdu.TrapPdu.AgentAddr.dynamic = FALSE; pPdu->Pdu.TrapPdu.AgentAddr.stream = NULL; pPdu->Pdu.TrapPdu.AgentAddr.length = 0; }
// build message
if (BuildMessage( SNMP_VERSION_1, &CommunityOctets, pPdu, pNLE->Buffer.buf, &pNLE->Buffer.len )) { // synchronous send
dwStatus = WSASendTo( pNLE->Socket, &pNLE->Buffer, 1, &pNLE->dwBytesTransferred, pNLE->dwFlags, &pMLE->SockAddr, pMLE->SockAddrLen, NULL, NULL ); // register outgoing packet into the management structure
mgmtCTick(CsnmpOutPkts); // retister outgoing trap into the management structure
mgmtCTick(CsnmpOutTraps);
// validate return code
if (dwStatus == SOCKET_ERROR) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: error code %d on sending trap to %s.\n", WSAGetLastError(), pTLE->pCommunity )); } }
// next entry
pLE3 = pLE3->Flink; }
// next entry
pLE2 = pLE2->Flink; }
// next entry
pLE1 = pLE1->Flink; } LeaveCriticalSection(&g_RegCriticalSectionC);
return fOk; }
BOOL GenerateColdStartTrap( )
/*
Routine Description:
Generates cold start trap.
Arguments:
None.
Return Values:
Returns true if successful.
*/
{ // generate cold start
return GenerateExtensionTrap( NULL, // pEnterpriseOid
SNMP_GENERICTRAP_COLDSTART, 0, // nSpecificTrapId
0, // nTimeStamp
&g_NullVbl ); }
BOOL GenerateAuthenticationTrap( )
/*
Routine Description:
Generates authentication trap.
Arguments:
None.
Return Values:
Returns true if successful.
*/
{ // generate cold start
return GenerateExtensionTrap( NULL, // pEnterpriseOid
SNMP_GENERICTRAP_AUTHFAILURE, 0, // nSpecificTrapId
SnmpSvcGetUptime(), &g_NullVbl ); }
|