/*++
*******************************************************************************
* Copyright (c) 1999-2000 Digi International Inc., All Rights Reserved        *
*                                                                             *
* This software contains proprietary and confidential information of Digi     *
* International Inc.  By accepting transfer of this copy, Recipient agrees    *
* to retain this software in confidence, to prevent disclosure to others,     *
* and to make no use of this software other than that for which it was        *
* delivered.  This is an unpublished copyrighted work of Digi International   *
* Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly   *
* prohibited.                                                                 *
*                                                                             *
* Restricted Rights Legend                                                    *
*                                                                             *
* Use, duplication, or disclosure by the Government is subject to             *
* restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in         *
* Technical Data and Computer Software clause at DFARS 252.227-7031 or        *
* subparagraphs (c)(1) and (2) of the Commercial Computer Software -          *
* Restricted Rights at 48 CFR 52.227-19, as applicable.                       *
*                                                                             *
* Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343          *
*                                                                             *
*******************************************************************************

Module Name:

	freldll.c

Abstract:

	Frame Relay MIB SNMP Extension Agent.

	These files (freldll.c, frelmib.c and frelmib.h) provide an extension agent dll
	which works in conjunction with the SNMP extensible agent for Windows NT.

	This SNMP exeension agent was derived from the sample on the Microsoft SDK.  See
	the Microsoft Windows NT SNMP Programmer's Reference.


Author:

	Carl Caldwell

--*/
// General notes:
//
// The Microsoft extendible agent for Windows NT is implemented by dynamically
// linking to Extension Agent DLLs that implement portions of the MIB.  These
// Extension Agents are configured in the Windows NT Registration Database.
// When the Extendible Agent Service is started, it queries the registry to 
// determine which Extension Agent DLLs have been installed and need to be 
// loaded and initialized.  The Extendible Agent invokes various DLL entry
// points (examples follow in this file) to request MIB queries and obtain
// Extension Agent generated traps.
#include <snmp.h>


// Contains definitions for the table structure describing the MIB.  This
// is used in conjunction with testmib.c where the MIB requests are resolved.
#include "frelmib.h"


// Extension Agent DLLs need access to elapsed time agent has been active.
// This is implemented by initializing the Extension Agent with a time zero
// reference, and allowing the agent to compute elapsed time by subtracting
// the time zero reference from the current system time.  This example
// Extension Agent implements this reference with dwTimeZero.
DWORD dwTimeZero = 0;


// Extension Agent DLLs that generate traps must create a Win32 Event object
// to communicate occurence of traps to the Extendible Agent.  The event
// handle is given to the Extendible Agent when the Extension Agent is 
// initialized, it should be NULL if traps will not be generated.  This
// example Extension Agent simulates the occurance of traps with hSimulateTrap.
HANDLE hSimulateTrap = NULL;

// The data collection thread will be started after MIB initialization. This thread
// will be started by a routine in rs232mib.c that returns the thread handle. If the
// thread terminates the DLL entry point is called at the thread_detach point. This 
// id will be used to determine that the thread died. At this point we will need to 
// notify everyone that the thread is dead so all future requests can fail, and write
// an event out to the event log.
DWORD  lpSxbDataCollectorThreadId;

// Handle used to control the data acquisition thread
HANDLE hSxbCollectionThread;

// The following structure is used to build a port information list from the 
// registry. It contains the informtaion describing each port as required to 
// initialize the MIB structures.
PSXB_PORT_INFO   pSxbPortInfo;

// The following structure is used to access the SXB driver. It contains all
// the information used in collecting information. It is created as a linked
// list so it will be available for expansion and compression. 
PFREL_SXB_INFO   pFrelSxbInfo;

// Termination event handle
HANDLE	terminateEvent;

// The following counter tracks threads that attach to the DLL. When the last 
// one releases, we shut down the driver.
int		attachedThreadCount = 0;

#ifdef SNMP_DLL_DEBUG
char	DebugStr[80];
#define FrDbgPrint OutputDebugString // Print debug info
#else
#define FrDbgPrint(a)  ;					 // Do nothing - use a null statement
#endif

// This is a standard Win32 DLL entry point.  See the Win32 SDK for more
// information on its arguments and their meanings.  This example DLL does 
// not perform any special actions using this mechanism.

BOOL WINAPI DllMain(
    HANDLE hDll,
    DWORD  dwReason,
    LPVOID lpReserved)
    {

		switch(dwReason)
		{
			case DLL_PROCESS_ATTACH:
				FrDbgPrint("FR: DLL_PROCESS_ATTACH Entry Point\n");
				break;

			case DLL_PROCESS_DETACH:
				FrDbgPrint("FR: DLL_PROCESS_DETACH Entry Point\n");
				frel_Terminate_MIB_Data_Collection(pFrelSxbInfo, pSxbPortInfo);
				break;
        
			case DLL_THREAD_ATTACH:
				FrDbgPrint("FR: DLL_THREAD_ATTACH Entry Point \n");
				break;
        
			case DLL_THREAD_DETACH:
				FrDbgPrint("FR: DLL_THREAD_DETACH Entry Point\n");
				break;
        
			default:
				FrDbgPrint("FR: UNKNOWN Dll Entry Point\n");
				break;
		} // end switch()

    return TRUE;
} // end DllEntryPoint()


// Extension Agent DLLs provide the following entry point to coordinate the
// initializations of the Extension Agent and the Extendible Agent.  The
// Extendible Agent provides the Extension Agent with a time zero reference;
// and the Extension Agent provides the Extendible Agent with an Event handle 
// for communicating occurence of traps, and an object identifier representing
// the root of the MIB subtree that the Extension Agent supports.

BOOL WINAPI SnmpExtensionInit(
    IN  DWORD               dwTimeZeroReference,
    OUT HANDLE              *hPollForTrapEvent,
    OUT AsnObjectIdentifier *supportedView)
{

	BOOL Status = FALSE;
	UINT SnmpStatus;

    // Create an event that waits on termination notification
	terminateEvent = CreateEvent( NULL, TRUE, FALSE, NULL );

    // Record the time reference provided by the Extendible Agent.
    dwTimeZero = dwTimeZeroReference;

    // Create an Event that will be used to communicate the occurence of traps
    // to the Extendible Agent.  The Extension Agent will assert this Event
    // when a trap has occured.  This is explained further later in this file.
    *hPollForTrapEvent = CreateEvent(NULL, FALSE, FALSE, NULL);

    // Indicate the MIB view supported by this Extension Agent, an object
    // identifier representing the sub root of the MIB that is supported.
    *supportedView = MIB_OidPrefix; // NOTE!  structure copy

    // Record the trap Event.  This example Extension Agent simulates traps by 
    // generating a trap after every given number of processed requests.
    hSimulateTrap = *hPollForTrapEvent;

	//Initialize the SXB Port Information structures  
    if ((pSxbPortInfo = SNMP_malloc(sizeof(struct SXB_PORT_INFO))) == NULL)
		goto Exit;

	if ( frel_Init_Sxb_Port_Info(pSxbPortInfo) != 0 )
	{
		FrDbgPrint("FR: Snmp initsxbportinfo failed!\n");
		goto Exit;
	}

	//Initialize the SXB driver data collection structures  
    if ((pFrelSxbInfo = SNMP_malloc(sizeof(struct FREL_SXB_INFO))) == NULL)
		goto Exit;

	if ( frel_Init_MIB_Data_Structures(pFrelSxbInfo, pSxbPortInfo) != 0 )
	{
		FrDbgPrint("FR: Snmp initmibdatastructures failed!\n");
		goto Exit;
	}

    // Initialize the tables in the MIB from the registry values created when the
    // WAN Links product was installed
	SnmpStatus = InitMibTableEntries(pFrelSxbInfo, pSxbPortInfo);
	if (SnmpStatus != SNMP_ERRORSTATUS_NOERROR)
	{
		FrDbgPrint("FR: Snmp initmibtableentries failed!\n");
		goto Exit;
	}

	//Start the SXB data collector thread
	hSxbCollectionThread =  CreateThread(
										NULL, 0,
										(LPTHREAD_START_ROUTINE)frel_Update_MIB_Data,
										pFrelSxbInfo, 0,
										&lpSxbDataCollectorThreadId );

	if (hSxbCollectionThread == NULL)
		goto Exit;

	FrDbgPrint("FR: SnmpExtensionInit returning Success!\n");
	Status = TRUE;

Exit:
	return Status;
} // end SnmpExtensionInit()


// Extension Agent DLLs provide the following entry point to communicate traps
// to the Extendible Agent.  The Extendible Agent will query this entry point
// when the trap Event (supplied at initialization time) is asserted, which
// indicates that zero or more traps may have occured.  The Extendible Agent 
// will repetedly call this entry point until FALSE is returned, indicating 
// that all outstanding traps have been processed.
BOOL WINAPI SnmpExtensionTrap(
    OUT AsnObjectIdentifier *enterprise,
    OUT AsnInteger          *genericTrap,
    OUT AsnInteger          *specificTrap,
    OUT AsnTimeticks        *timeStamp,
    OUT RFC1157VarBindList  *variableBindings)
{
    // The body of this routine is an extremely simple example/simulation of
    // the trap functionality.  A real implementation will be more complex.


    // The following define data inserted into the trap below.  The Lan Manager
    // bytesAvailAlert from the Lan Manager Alerts-2 MIB is generated with an
    // empty variable bindings list.

    static UINT OidList[]  = { 1, 3, 6, 1, 4, 1, 77, 2 };
    static UINT OidListLen = 8;


    // The following variable is used for the simulation, it allows a single
    // trap to be generated and then causes FALSE to be returned indicating
    // no more traps.
    static whichTime = 0;


    // The following if/else support the simulation.
    if (whichTime == 0)
    {
        whichTime = 1;    // Supports the simulation.

        // Communicate the trap data to the Extendible Agent.
        enterprise->idLength = OidListLen;
        enterprise->ids = OidList;

        *genericTrap      = SNMP_GENERICTRAP_ENTERSPECIFIC;
        *specificTrap     = 1;                    // the bytesAvailAlert trap
        *timeStamp        = GetCurrentTime() - dwTimeZero;
        variableBindings->list = NULL;
        variableBindings->len  = 0;
        // Indicate that valid trap data exists in the parameters.
        return TRUE;
    }
    else
    {
        whichTime = 0;    // Supports the simulation.

        // Indicate that no more traps are available and parameters do not
        // refer to any valid data.
        return FALSE;
    }
} // end SnmpExtensionTrap()


// Extension Agent DLLs provide the following entry point to resolve queries
// for MIB variables in their supported MIB view (supplied at initialization
// time).  The requestType is Get/GetNext/Set.
BOOL WINAPI SnmpExtensionQuery(
    IN BYTE                   requestType,
    IN OUT RFC1157VarBindList *variableBindings,
    OUT AsnInteger            *errorStatus,
    OUT AsnInteger            *errorIndex)
{
    static unsigned long requestCount = 0;  // Supports the trap simulation.
    UINT    I;


    // Iterate through the variable bindings list to resolve individual
    // variable bindings.

    for ( I=0;I < variableBindings->len;I++ )
    {
        *errorStatus = ResolveVarBind( &variableBindings->list[I], requestType );

        // Test and handle case where Get Next past end of MIB view supported
        // by this Extension Agent occurs.  Special processing is required to 
        // communicate this situation to the Extendible Agent so it can take 
        // appropriate action, possibly querying other Extension Agents.
        if ( *errorStatus == SNMP_ERRORSTATUS_NOSUCHNAME &&
             requestType == MIB_ACTION_GETNEXT )
        {
           *errorStatus = SNMP_ERRORSTATUS_NOERROR;


           // Modify variable binding of such variables so the OID points
           // just outside the MIB view supported by this Extension Agent.
           // The Extendible Agent tests for this, and takes appropriate
           // action.
           SNMP_oidfree( &variableBindings->list[I].name );
           SNMP_oidcpy( &variableBindings->list[I].name, &MIB_OidPrefix );
           variableBindings->list[I].name.ids[MIB_PREFIX_LEN-1] ++;
        }

        // If an error was indicated, communicate error status and error
        // index to the Extendible Agent.  The Extendible Agent will ensure
        // that the origional variable bindings are returned in the response
        // packet.
        if ( *errorStatus != SNMP_ERRORSTATUS_NOERROR )
        {
    	   *errorIndex = I+1;
	       goto Exit;
	    }
    }

Exit:
    // Indicate that Extension Agent processing was sucessfull.
    return SNMPAPI_NOERROR;

} // end SnmpExtensionQuery()
