
/*****************************************************************************
* Copyright (c) 1990-98 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
*
*****************************************************************************/

#include <ntddk.h>
#include <wchar.h>

// Streams Headers
#include "types.h"
#include "wan_proto.h"
#include "wan_control.h"

#include "dsapi.h"
#include "dsioctl.h"
#include "dsmp.h"
#include "dgsna.h"
#include "ioctls.h"
#include "pnp.h"
#include "power.h"

#include "digilib.h"
#include "dxbreg.h"

/*
 **		Linked list of the devices
 */

#define DOSDEVICE_PATH      L"\\DosDevices\\"


DEVICE_OBJECT	* DgSnaDevices = NULL;
KSPIN_LOCK		gSnaDevicesSpinLock = 0;
DRIVER_OBJECT   * gpDriverObject = NULL;

extern NTSTATUS	DgSnaProcessCommands(PDEVICE_OBJECT ,PIRP );
extern NTSTATUS	DgSnaOpen(PDEVICE_OBJECT, PIRP);
extern NTSTATUS	DgSnaClose(PDEVICE_OBJECT,PIRP);
extern VOID 	DgSnaReadRequestDpc(PKDPC pDpc,PVOID context, PVOID sa1, PVOID sa2);



VOID
DgSnaUnload( PDRIVER_OBJECT  pDriverObject)
{
	LIST_ENTRY	  * p;
	PPORT_EXT		pPortExt;
	PDEVICE_OBJECT	pSnaDevice;
	KIRQL			Irql;

	DigiDump(DIGIINIT,("DgSnaUnload: Entry\n"));
#if !NT5_BUILD
	while(DgSnaDevices)
	{
		pSnaDevice		= DgSnaDevices;
		pPortExt		= pSnaDevice->DeviceExtension;
		DgSnaDevices	= pPortExt->nextPort;

		DigiDump(DIGIOPENCLOSE,("DgSnaUnload: Delete Port=%x, Device=%x\n",pPortExt,pSnaDevice));

		{
			UNICODE_STRING SymbolicName = { 0 };

		  	if ( NT_SUCCESS( DigiStrSymbolicName( &SymbolicName, pPortExt->snadeviceName.Buffer ) ) )
			{
				IoDeleteSymbolicLink( &SymbolicName );
				DigiStrFreeUnicodeString( &SymbolicName );
			}
	    }
		IoDeleteDevice(pSnaDevice);
	}
#endif
	DigiDump(DIGIINIT,("DgSnaUnload: Exit\n"));
}

VOID
DgSnaRemoveSnaDevice(IN PDEVICE_OBJECT	pSdo
	)

// Note - Future Enhancement*
//
//  This routine could be simplified if the list of devices pointed to the
//  extensions and not the device object.

{
	PPORT_EXT		pCurrentPortExt = NULL;
	PPORT_EXT		pPreviousPortExt = NULL;
	PDEVICE_OBJECT	pSnaDevice;
	PDEVICE_OBJECT	pCurrentSnaDevice;
	PDEVICE_OBJECT	pPreviousSnaDevice;
	PDEVICE_OBJECT	pNextSnaDevice;
	KIRQL			Irql;
	NTSTATUS		Status;
	UNICODE_STRING  SymbolicName = { 0 };

	DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: Entry, Device = %x\n",pSdo));

    if (pSdo == NULL)
    {
	    DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: Pointer to SNA device object is NULL!\n"));
        return;
    }

	KeAcquireSpinLock(&gSnaDevicesSpinLock,&Irql);

	pPreviousSnaDevice	= DgSnaDevices;
	pCurrentSnaDevice	= DgSnaDevices;

    if (DgSnaDevices == NULL)
    {
	    DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: No SNA device to delete.\n"));
	    KeReleaseSpinLock(&gSnaDevicesSpinLock,Irql);
        goto Exit;
    }

	// The Device will only be in the list if a Link Service is configured for it.
	while ((pCurrentSnaDevice != 0) && (pCurrentSnaDevice != pSdo))
	{
		DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: Loop Current = %x, pPreviousSnaDevice = %x\n",pCurrentSnaDevice,pPreviousSnaDevice));
		pCurrentPortExt = pCurrentSnaDevice->DeviceExtension;
        if (pCurrentPortExt == NULL)
        {
			DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: No SNA device found.\n"));
            KeReleaseSpinLock(&gSnaDevicesSpinLock,Irql);
            goto Exit;
        }
		pPreviousSnaDevice = pCurrentSnaDevice;
		pCurrentSnaDevice  = pCurrentPortExt->nextPort;
    }

    if (pCurrentPortExt == NULL)
    {
		DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: No SNA device found.\n"));
        KeReleaseSpinLock(&gSnaDevicesSpinLock,Irql);
        goto Exit;
    }

	if (pCurrentSnaDevice == pSdo)
	{

		// Remove the Device from the list
		pNextSnaDevice = pCurrentPortExt->nextPort;

		if (pCurrentSnaDevice == DgSnaDevices)
		{
			DgSnaDevices = pNextSnaDevice;
			DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: DgSnaDevices = %x\n",DgSnaDevices));
		}
		else
		{
			pPreviousPortExt = pPreviousSnaDevice->DeviceExtension;
			pPreviousPortExt->nextPort = pNextSnaDevice;
		}

	    KeReleaseSpinLock(&gSnaDevicesSpinLock,Irql);

        DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: Delete = %x\n",pCurrentSnaDevice));

        // Clean up the Device
        Status = DigiStrSymbolicName( &SymbolicName, pCurrentPortExt->snadeviceName.Buffer );
        if ( NT_SUCCESS( Status ) )
        {
            IoDeleteSymbolicLink( &SymbolicName );
            DigiStrFreeUnicodeString( &SymbolicName );
        }
	}

Exit:
    IoDeleteDevice(pSdo);
    DigiDump(DIGIINIT,("DIGISNA!DgSnaRemoveSnaDevice: Exit\n"));
}


NTSTATUS
DgUniStringInit(UNICODE_STRING * pUniString, ULONG size)
{

	NTSTATUS	status = STATUS_SUCCESS;

	pUniString->Length = 0;
	pUniString->MaximumLength = (USHORT) (size * sizeof(WCHAR)) +
										sizeof(WCHAR);		// for termination


	pUniString->Buffer = ExAllocatePool(NonPagedPool,
										pUniString->MaximumLength);

	if (pUniString->Buffer == NULL)
		{
      status = STATUS_INSUFFICIENT_RESOURCES;
		}
	else
		{

		// Zero the Buffer; this will always insure that the buffer can
		// be used as a null terminated string.
		RtlZeroMemory(pUniString->Buffer, pUniString->MaximumLength);

		}

	return status;

}


NTSTATUS
DgSnaGetKey(IN UNICODE_STRING *pPath, OUT UNICODE_STRING *pKeyName, ULONG dgSnaKeyIndex)
{

	HANDLE      dgHandle;					// Handle to a dgsna  key.
	NTSTATUS    status;						// Kernel status return value.
	ULONG       dgKeyInfoLength;			// Size of enumerated key.

	UNICODE_STRING			dgKeyString;    // Unicode string for enumerated key.
	KEY_BASIC_INFORMATION	*dgKeyInfo;     // Registry Key information.
	OBJECT_ATTRIBUTES		dgAttributes;   // Driver's attribute value.

	DigiDump(DIGIINIT,("DgSnaGetKey: Entry path %wZ, dgSnaKeyIndex = %d\n",pPath,dgSnaKeyIndex));

    // Get Driver's attributes to prepare to open the registry key.
    InitializeObjectAttributes(&dgAttributes,
							   pPath,
							   OBJ_CASE_INSENSITIVE,
							   NULL,
							   NULL);

    // Open the Driver's key.
    status = ZwOpenKey(&dgHandle, KEY_READ, &dgAttributes);
    if (! NT_SUCCESS(status))
    {
		DigiDump(DIGIINIT,("DgSnaGetKey: Could not open key\n"));
        return (status);
    }

    // Get memory to store key info.
    dgKeyInfo = (PKEY_BASIC_INFORMATION)
                ExAllocatePool(NonPagedPool, DGSNA_MAX_PATH_LENGTH);

    if (dgKeyInfo == NULL)
    {
        ZwClose(dgHandle);
		DigiDump(DIGIINIT,("DgSnaGetKey: Insufficient Reources\n"));
		return (STATUS_INSUFFICIENT_RESOURCES);
    }

	DigiDump(DIGIINIT,("DgSnaGetKey: dgSnaKeyIndex = %d\n",dgSnaKeyIndex));

    // Get the Driver's index'th item.  The key is "discovered" in this
    // manner because the keys could be named non-incrementally.
    status = ZwEnumerateKey(dgHandle, dgSnaKeyIndex, KeyBasicInformation,
                            dgKeyInfo,DGSNA_MAX_PATH_LENGTH ,
                            &dgKeyInfoLength);

    if ((! NT_SUCCESS(status)) ||
        (dgKeyInfoLength > DGSNA_MAX_PATH_LENGTH))
    {

        ZwClose(dgHandle);
        ExFreePool(dgKeyInfo);
		DigiDump(DIGIINIT,("DgSnaGetKey: ZwEnumerateKey failed, %x\n",status));
        return (status);
    }

    // Use dgKeyInfo buffer.
    dgKeyString.Length			= (USHORT) dgKeyInfo->NameLength;
    dgKeyString.MaximumLength	= (USHORT) dgKeyInfo->NameLength;
    dgKeyString.Buffer			= (PWSTR) dgKeyInfo->Name;

    // Deliminate the Key
    (void) RtlAppendUnicodeToString(pPath, L"\\");

    // Point Key at the Driver's subkey of DgSnaAdapters.
    pKeyName->Length		= dgKeyString.Length;
    pKeyName->MaximumLength = dgKeyString.MaximumLength;
    pKeyName->Buffer		= pPath->Buffer + (pPath->Length / sizeof(WCHAR));

    // Append the key onto the Driver's Registry path to be used to
    // traverse the  subkey .
    (void) RtlAppendUnicodeStringToString(pPath, &dgKeyString);

    // Cleanup before exiting.
    ZwClose(dgHandle);
    ExFreePool(dgKeyInfo);

	DigiDump(DIGIINIT,("DgSnaGetKey: Entry path %wZ\n",pPath));

	return (STATUS_SUCCESS);

}


DgSnaGetAdapterKeyValues(PUNICODE_STRING pPath,
								  PORT_EXT * pDeviceExtension)
{

RTL_QUERY_REGISTRY_TABLE	dgSnaInfo[4];
RTL_QUERY_REGISTRY_TABLE	portInfo[6];
UNICODE_STRING				linePathDigiSNA;
UNICODE_STRING				linePath;
UNICODE_STRING				deviceName;
UNICODE_STRING				linkServicePath;
ANSI_STRING					ansiString;
NTSTATUS					status = STATUS_SUCCESS;
ULONG						snid;
ULONG						zero = 0;

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues :Entry path %wZ\n",	pPath));

	status = DgUniStringInit(&linkServicePath,DGSNA_MAX_PATH_LENGTH);

	if (! NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Init linkServicePath Failed Status = %x\n",status));
		goto Exit;
	}

	status = DgUniStringInit(&deviceName,DGSNA_MAX_PATH_LENGTH);

	if (! NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Init deviceName Failed Status = %x\n",status));
		ExFreePool(linkServicePath.Buffer);
		goto Exit;
	}

	status = DgUniStringInit(&linePathDigiSNA,DGSNA_MAX_PATH_LENGTH);

	if (! NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Init linePathDigiSNA Failed Status = %x\n",status));
		ExFreePool(linkServicePath.Buffer);
		ExFreePool(deviceName.Buffer);
		goto Exit;
	}

   	RtlZeroMemory(dgSnaInfo, sizeof(dgSnaInfo));

	dgSnaInfo[0].Flags			= RTL_QUERY_REGISTRY_DIRECT |
								  RTL_QUERY_REGISTRY_REQUIRED;
	dgSnaInfo[0].Name			= L"DigiDxbPath";
	dgSnaInfo[0].EntryContext	= &linePathDigiSNA ;

	dgSnaInfo[1].Flags			= RTL_QUERY_REGISTRY_DIRECT |
								  RTL_QUERY_REGISTRY_REQUIRED;
	dgSnaInfo[1].Name			= L"Device";
	dgSnaInfo[1].EntryContext	= &pDeviceExtension->symbolicName ;


	dgSnaInfo[2].Flags			= RTL_QUERY_REGISTRY_DIRECT |
								  RTL_QUERY_REGISTRY_REQUIRED;
	dgSnaInfo[2].Name			= L"LinkServicePath";
	dgSnaInfo[2].EntryContext	= &linkServicePath ;

	status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE, pPath->Buffer,
                                        dgSnaInfo, NULL, NULL);


	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : pPath Query Registry Failed Status = %x\n",status));
		goto cleanUpAndExit;
	}

	// Add the OS Specific DSAPI Adapter Path onto the Line Path
	status = DigiStrAllocUnicodeString( &linePath, DXB_REDIRECTPATH_ROOT, linePathDigiSNA.Buffer, NULL );

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : linePath  = %wZ\n",&linePath));

	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Init linePath Failed Status = %x\n",status));
		goto cleanUpAndExit;
	}

	RtlZeroMemory(portInfo, sizeof(portInfo));


	portInfo[0].Flags			= RTL_QUERY_REGISTRY_DIRECT |
								  RTL_QUERY_REGISTRY_REQUIRED;
	portInfo[0].Name			= L"Device";
	portInfo[0].EntryContext	= &pDeviceExtension->adapterName ;

	status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
									linePath.Buffer,
                                    portInfo,
									NULL,
									NULL);

	if (!NT_SUCCESS(status)) {

		RtlZeroMemory(portInfo, sizeof(portInfo));

		portInfo[0].Flags			= RTL_QUERY_REGISTRY_DIRECT |
									  RTL_QUERY_REGISTRY_REQUIRED;
		portInfo[0].Name			= L"Adapter";
		portInfo[0].EntryContext	= &pDeviceExtension->adapterName ;

		status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
									linePath.Buffer,
                                    portInfo,
									NULL,
									NULL);
		if (!NT_SUCCESS(status))
		{
			DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : No Device or Adapter Status = %x\n",status));
			goto cleanUpAndExit;
		}

	}

	RtlZeroMemory(portInfo, sizeof(portInfo));

    portInfo[0].Flags			= RTL_QUERY_REGISTRY_DIRECT |
					              RTL_QUERY_REGISTRY_REQUIRED;
	portInfo[0].Name			= L"LineName";
	portInfo[0].EntryContext	= &deviceName ;

	portInfo[1].Flags			= RTL_QUERY_REGISTRY_DIRECT |
								  RTL_QUERY_REGISTRY_REQUIRED;
	portInfo[1].Name			= L"Snid";
	portInfo[1].EntryContext	= &snid ;

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : DxbPath %ws\n",linePath.Buffer));

	status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
									linePath.Buffer,
                                    portInfo,
									NULL,
									NULL);

	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : RtlQueryRegistryValues failed status %x\n",status));
		DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : len adptrname %x linename %x snid %x\n",portInfo[0].DefaultLength,portInfo[1].DefaultLength,  portInfo[2].DefaultLength));

		goto cleanUpAndExit;
	}

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Adaptername %wZ lineName %wZ  snid %x status - %x\n",&pDeviceExtension->adapterName, &deviceName,snid, status));

	ansiString.Buffer			= pDeviceExtension->deviceName;
	ansiString.Length			= 0;
	ansiString.MaximumLength	= deviceName.MaximumLength;

	RtlUnicodeStringToAnsiString(&ansiString,&deviceName,
										  FALSE);

	pDeviceExtension->snid =  snid ;

	// get the lineservice parameters
	RtlZeroMemory(portInfo, sizeof(portInfo));

	portInfo[0].Flags			= RTL_QUERY_REGISTRY_DIRECT;
	portInfo[0].Name			= L"InternalClock";
	portInfo[0].EntryContext	= &pDeviceExtension->internalClocking ;
	portInfo[0].DefaultType		= REG_DWORD;
	portInfo[0].DefaultData		= &zero;
	portInfo[0].DefaultLength	= sizeof(pDeviceExtension->internalClocking);

	portInfo[1].Flags			= RTL_QUERY_REGISTRY_DIRECT;
	portInfo[1].Name			= L"LineSpeed";
	portInfo[1].EntryContext	= &pDeviceExtension->lineSpeed ;
	portInfo[1].DefaultType		= REG_DWORD;
	portInfo[1].DefaultData		= &zero;
	portInfo[1].DefaultLength	= sizeof(pDeviceExtension->lineSpeed);

	portInfo[2].Flags			= RTL_QUERY_REGISTRY_DIRECT;
	portInfo[2].Name			= L"LineType";
	portInfo[2].EntryContext	= &pDeviceExtension->lineType ;
	portInfo[2].DefaultType		= REG_DWORD;
	portInfo[2].DefaultData		= &zero;
	portInfo[2].DefaultLength	= sizeof(pDeviceExtension->lineType );

	portInfo[3].Flags			= RTL_QUERY_REGISTRY_DIRECT;
	portInfo[3].Name			= L"Carrier";
	portInfo[3].EntryContext	= &pDeviceExtension->constantRTS ;
	portInfo[3].DefaultType		= REG_DWORD;
	portInfo[3].DefaultData		= &zero;
	portInfo[3].DefaultLength	= sizeof(pDeviceExtension->constantRTS );

	portInfo[4].Flags			= RTL_QUERY_REGISTRY_DIRECT;
	portInfo[4].Name			= L"IBMCSNT";
	portInfo[4].EntryContext	= &pDeviceExtension->ibmComServer ;
	portInfo[4].DefaultType		= REG_DWORD;
	portInfo[4].DefaultData		= &zero;
	portInfo[4].DefaultLength	= sizeof(pDeviceExtension->ibmComServer );


	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : LinkServicePath %wZ\n",&linkServicePath));

	status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
									linkServicePath.Buffer,
									portInfo,
									NULL,
									NULL);

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : AdapterKeyValues\n\tSnid %x %c\n\tDeviceName %wZ \
						\n\tLineName %s\n\tAdapterName %wZ  \n\t linespeed %d %x \n\t \
						lineType %x %d\n\t InternalClock %d %x\n",
						pDeviceExtension->snid,
						(UCHAR) pDeviceExtension->snid,
						&pDeviceExtension->symbolicName,
						pDeviceExtension->deviceName,
						&pDeviceExtension->adapterName,
						pDeviceExtension->lineSpeed,
						pDeviceExtension->lineSpeed,
						pDeviceExtension->lineType,
						pDeviceExtension->lineType,
						pDeviceExtension->internalClocking,
						pDeviceExtension->internalClocking));


cleanUpAndExit:


	DigiStrFreeUnicodeString( &linePath );
	ExFreePool(linkServicePath.Buffer);
	ExFreePool(linePathDigiSNA.Buffer);
	ExFreePool(deviceName.Buffer);

Exit:

	DigiDump(DIGIINIT,("DgSnaGetAdapterKeyValues : Exit Status = %x\n",status));

	return status;

}


NTSTATUS
DgSnaInitializeDevice(	IN	UNICODE_STRING	* pdeviceName,
						IN	DRIVER_OBJECT	* pDriverObject,
						IN  PDEVICE_OBJECT	* ppDeviceObject

)

{

	UNICODE_STRING				symbolicName	= {0};
	UNICODE_STRING				deviceName		= {0};
	UNICODE_STRING				uniTemp			= {0};
	NTSTATUS					status;
	DEVICE_OBJECT				* pSnaAdapter;
	PORT_EXT					* pDgSnaAdapterExt;
	ULONG						i;
	KIRQL						Irql;

	DigiDump(DIGIINIT,("DgSnaInitializeDevice : Entry  pdeviceName = %wZ, pDriverObject = %x\n",
													pdeviceName,pDriverObject));

	RtlInitUnicodeString( &deviceName, NULL );
	status = DigiStrDeviceName( &deviceName, pdeviceName->Buffer );

	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaInitializeDevice : Init deviceName Failed Status = %x\n",status));
		goto Exit;
	}

	DigiDump(DIGIINIT,("DgSnaInitializeDevice : FindAdapters Creating %wZ\n",&deviceName));

	status = IoCreateDevice(pDriverObject,
			                sizeof (PORT_EXT),
							&deviceName,
							FILE_DEVICE_DS,
							0,
							FALSE,
							&pSnaAdapter);

	DigiDump(DIGIINIT,("DgSnaInitializeDevice : FindAdapters Created %wZ status %x\n",&deviceName,status));

	if (NT_SUCCESS(status))
	{
		pDgSnaAdapterExt = pSnaAdapter->DeviceExtension;
		pDgSnaAdapterExt->pDeviceObject = pSnaAdapter;

		InitializeListHead(&pDgSnaAdapterExt->readBuffers);
		InitializeListHead(&pDgSnaAdapterExt->pendedReadBuffers);
		InitializeListHead(&pDgSnaAdapterExt->completedReadBuffers);
		InitializeListHead(&pDgSnaAdapterExt->writeBuffers);
		InitializeListHead(&pDgSnaAdapterExt->pendedWriteBuffers);

		// Initialize the Close Event
		KeInitializeEvent( &pDgSnaAdapterExt->evClose, NotificationEvent, FALSE );

		for(i=0;i<DGSNA_MAX_READ_ENTRIES;++i)
		{
			InsertHeadList(&pDgSnaAdapterExt->readBuffers,
						   &(pDgSnaAdapterExt->readListEntryArray[i].listEntry));

			DigiDump(DIGIINIT,("DgSnaInitializeDevice :read entry %d %x\n",i,&pDgSnaAdapterExt->readListEntryArray[i].listEntry));

			pDgSnaAdapterExt->readListEntryArray[i].pPortExt = pDgSnaAdapterExt;
			pDgSnaAdapterExt->readListEntryArray[i].bufferSize = DGSNA_MAX_PACKET_SIZE;

		}

		for(i=0;i<DGSNA_MAX_WRITE_ENTRIES;++i)
		{
			InsertHeadList(&pDgSnaAdapterExt->writeBuffers,
						   &(pDgSnaAdapterExt->writeListEntryArray[i].listEntry));

			DigiDump(DIGIINIT,("DgSnaInitializeDevice :write entry %d %x\n",i,&pDgSnaAdapterExt->writeListEntryArray[i].listEntry));

			pDgSnaAdapterExt->writeListEntryArray[i].pPortExt = pDgSnaAdapterExt;
			pDgSnaAdapterExt->writeListEntryArray[i].bufferSize = DGSNA_MAX_PACKET_SIZE;

		}


		KeInitializeDpc(&pDgSnaAdapterExt->dpcReadRequest,
						DgSnaReadRequestDpc,
						pDgSnaAdapterExt);

		KeInitializeTimer(&pDgSnaAdapterExt->readRequestTimer);

		pDgSnaAdapterExt->readRequestTimeout = RtlConvertLongToLargeInteger(DGSNA_READ_REQ_TIMEOUT * -1);

		KeInitializeSpinLock(&pDgSnaAdapterExt->ownership);

		pDgSnaAdapterExt->symbolicName.Length			= 0;
		pDgSnaAdapterExt->symbolicName.Buffer			= pDgSnaAdapterExt->symbolicNameBuffer;
		pDgSnaAdapterExt->symbolicName.MaximumLength	= sizeof(pDgSnaAdapterExt->symbolicNameBuffer);


		pDgSnaAdapterExt->adapterName.Buffer			= pDgSnaAdapterExt->adapterNameBuffer;
		pDgSnaAdapterExt->adapterName.Length			= 0;
		pDgSnaAdapterExt->adapterName.MaximumLength		= sizeof(pDgSnaAdapterExt->adapterNameBuffer);

		pDgSnaAdapterExt->snadeviceName.Buffer			= pDgSnaAdapterExt->snadeviceNameBuffer;
		pDgSnaAdapterExt->snadeviceName.Length			= 0;
		pDgSnaAdapterExt->snadeviceName.MaximumLength	= sizeof(pDgSnaAdapterExt->snadeviceNameBuffer);

		status = DigiStrSymbolicName( &symbolicName, pdeviceName->Buffer );

		if ( NT_SUCCESS( status ) )
		{
			RtlCopyUnicodeString( &pDgSnaAdapterExt->symbolicName, &symbolicName );
			RtlCopyUnicodeString( &pDgSnaAdapterExt->snadeviceName, pdeviceName );

			DigiDump(DIGIINIT,("DgSnaFindAdapters : FindAdapters Creating  %wZ\n",&symbolicName));

			status = IoCreateSymbolicLink(&symbolicName, &deviceName);

			if ( NT_SUCCESS( status ) )
			{

				DigiDump(DIGIINIT,("DgSnaInitializeDevice : FindAdapters Created  %wZ status %x\n",&symbolicName,status));

				// Add the Device to the Global List
				KeAcquireSpinLock(&gSnaDevicesSpinLock,&Irql);
				pDgSnaAdapterExt->nextPort = DgSnaDevices;
				DgSnaDevices = pSnaAdapter;
	 			KeReleaseSpinLock(&gSnaDevicesSpinLock,Irql);

				if (ppDeviceObject)
				{
					*ppDeviceObject = pSnaAdapter;
				}
			}
		}

	} //if

	if (symbolicName.Buffer)
		DigiStrFreeUnicodeString( &symbolicName );

	if (deviceName.Buffer)
		DigiStrFreeUnicodeString( &deviceName );

Exit:
	return status;

}


NTSTATUS
DgSnaFindAndInitTheLinkService(	IN UNICODE_STRING	* pDeviceName,
								IN PORT_EXT			* pDeviceExtension
)
{

	UNICODE_STRING				LinkServiceRegPath;
	UNICODE_STRING				LinkServiceRegPathTemp;
	UNICODE_STRING				keyName ;
	NTSTATUS					status = STATUS_SUCCESS;

	ULONG						keyIndex = 0;
	ULONG						dgSnaKeyIndex = 0;
	HANDLE						hkAdapter;

	DigiDump(DIGIINIT,("DgSnaFindAndInitTheLinkService : Entry Device = %S\n",pDeviceName->Buffer));


	status = DigiStrAllocUnicodeString( &LinkServiceRegPathTemp,
										L"\\REGISTRY\\Machine\\System\\CurrentControlSet\\SERVICES\\" WANLINKS_NAME_PREFIX_WIDE L"Sna",
										L"\\Parameters\\LinkServices",
										NULL );

	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaFindAndInitTheLinkService : Init LinkServiceRegPathTemp Failed Status = %x\n",status));
		goto Exit;
	}

	status = DgUniStringInit(&LinkServiceRegPath,LinkServiceRegPathTemp.MaximumLength +
									 DGSNA_MAX_PATH_LENGTH);


	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaFindAndInitTheLinkService : Init LinkServiceRegPath Failed Status = %x\n",status));
		goto Exit;
	}

  	RtlAppendUnicodeStringToString(&LinkServiceRegPath,&LinkServiceRegPathTemp);

	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaFindAndInitTheLinkService : Init LinkServiceRegpath Failed Status = %x\n",status));
		goto Exit;
	}

	while (1)
	{

		status = DgSnaGetKey(&LinkServiceRegPath,&keyName,dgSnaKeyIndex);

		// Here the path is complete pathname including
		// the subkey under the services key for  the SNA

		if (status == STATUS_NO_MORE_ENTRIES || !NT_SUCCESS(status))
		{
			break;
		}

		DigiDump(DIGIPNP,("DIGISNA!DgSnaFindAndInitTheLinkService: LinkServiceRegPath = %S, keyname = %S\n",
																	LinkServiceRegPath.Buffer,
																	keyName.Buffer));

		// Get the Device Name
		status = DigiRegOpenKey( &hkAdapter, LinkServiceRegPath.Buffer );

		// Find the Unique Name for the SNA device and that matches the input device.
		if ( NT_SUCCESS( status ) )
		{

			UNICODE_STRING		SnaDevice = {0};

			status = DigiRegQuerySz( hkAdapter, L"Device", &SnaDevice, DigiRegFlagRequired, NULL );

			DigiRegCloseKey(hkAdapter);

	 		if (!NT_SUCCESS(status))
			{
				break;
			}

			if(!RtlCompareUnicodeString(&SnaDevice, pDeviceName, TRUE))
			{
				// Initialize the Link Service
				status = DgSnaGetAdapterKeyValues(&LinkServiceRegPath,pDeviceExtension);
				break;
			}

		}
		else
		{
			DigiDump(DIGIINIT,("DgSnaFindAndInitTheLinkService : Device name not present Status = %x\n",status));
			break;
		}

		// Loop Control
		dgSnaKeyIndex++;
		LinkServiceRegPath.Length = LinkServiceRegPath.Length - (keyName.Length + sizeof(WCHAR));
		keyName.Length = 0;

	}  // while


Exit:

	if ( LinkServiceRegPath.Buffer )
			ExFreePool(LinkServiceRegPath.Buffer);

	if ( LinkServiceRegPathTemp.Buffer )
		DigiStrFreeUnicodeString( &LinkServiceRegPathTemp );

	return status;

}


NTSTATUS
DgSnaFindAdapters(	IN UNICODE_STRING	* registryPath,
					IN DRIVER_OBJECT	* pDriverObject
)
{

	UNICODE_STRING				path;
	UNICODE_STRING				keyName ;
	NTSTATUS					status = STATUS_SUCCESS;

	ULONG						keyIndex = 0;
	ULONG						dgSnaKeyIndex = 0;
	HANDLE						hkAdapter;

	DigiDump(DIGIINIT,("DgSnaFindAdapters : Entry\n"));

	status = DgUniStringInit(&path,registryPath->MaximumLength +
									 DGSNA_MAX_PATH_LENGTH);


	if (!NT_SUCCESS(status))
	{
		DigiDump(DIGIINIT,("DgSnaFindAdapters : Init path Failed Status = %x\n",status));
		goto Exit;
	}


  	RtlAppendUnicodeStringToString(&path,registryPath);
	RtlAppendUnicodeToString(&path,L"\\Parameters\\LinkServices");

	while (1)
	{
		RTL_QUERY_REGISTRY_TABLE	dgSnaInfo[2];

		status = DgSnaGetKey(&path,&keyName,dgSnaKeyIndex);

		// Here the path is complete pathname including
		// the subkey under the services key for  the SNA

		if (status == STATUS_NO_MORE_ENTRIES)
		{
			status = STATUS_SUCCESS;
			break;
		}

		if (!NT_SUCCESS(status))
		{
			break;
		}

		// Get the Device Name
		status = DigiRegOpenKey( &hkAdapter, path.Buffer );

		DigiDump(DIGIPNP,("DIGISNA!DgSnaFindAdapters: path = %S\n",path.Buffer));

		// Find the Unique Name for the SNA device and Open the Device.
		if ( NT_SUCCESS( status ) )
		{

			UNICODE_STRING		SnaDevice = {0};

			status = DigiRegQuerySz( hkAdapter, L"Device", &SnaDevice, DigiRegFlagRequired, NULL );

			DigiRegCloseKey(hkAdapter);

	 		if (!NT_SUCCESS(status))
			{
				break;
			}

			// Initialize the Device
			status = DgSnaInitializeDevice(&SnaDevice,pDriverObject,NULL);
			DigiStrFreeUnicodeString( &SnaDevice );
			if (!NT_SUCCESS(status))
			{
				break;
			}

		}
		else
		{
			DigiDump(DIGIINIT,("DgSnaFindAdapters : Device name not present Status = %x\n",status));
			break;
		}

		// Loop Control
		dgSnaKeyIndex++;
		path.Length = path.Length - (keyName.Length + sizeof(WCHAR));
		keyName.Length = 0;

	}  // while

	ExFreePool(path.Buffer);

Exit:
	return status;

}



NTSTATUS
DriverEntry(
    IN DRIVER_OBJECT    *DriverObject,
    IN UNICODE_STRING   *RegistryPath
)

{

	NTSTATUS	status = STATUS_SUCCESS;

	// Set up the debug globals
	DigiDebugInit( RegistryPath,
		(DIGIOPENCLOSE | DIGIPNP | DIGIINIT),
		 DEBUGMODE_ANY
		 );

	DigiDump(DIGIINIT,("DIGISNA DriverEntry : Enter\n"));

	DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL]	= DgSnaProcessCommands;
	DriverObject->MajorFunction[IRP_MJ_CREATE]			= DgSnaOpen;
	DriverObject->MajorFunction[IRP_MJ_CLOSE]			= DgSnaClose;
	DriverObject->DriverUnload							= DgSnaUnload;

#if NT5_BUILD
	DriverObject->MajorFunction[IRP_MJ_PNP]             = DgSnaDevicePnp;
	DriverObject->MajorFunction[IRP_MJ_POWER]           = DgSnaDevicePower;
	DriverObject->DriverExtension->AddDevice            = DgSnaAddDevice;
#else

	status = DgSnaFindAdapters(RegistryPath, DriverObject);

#endif

	gpDriverObject = DriverObject;
	KeInitializeSpinLock(&gSnaDevicesSpinLock);

	DigiDump(DIGIINIT,("DIGISNA DriverEntry : Exit = %x\n",gpDriverObject));

	return (status);


}

