

/*++
*******************************************************************************
* Copyright (c) 1990-97 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:

   miniport.c

Abstract:

   This module supplies the interface to the miniport drivers.  Users of
   XWan register miniports they wish to use (configured in the registry).			



Author:

   Jeff Romatoski

Revision History:

	11/08/98  - Initail Version

--*/

#include "xwan.h"


// Global Miniport Device list
BOOLEAN         gXwanMiniportInitialized = FALSE;
LIST_ENTRY      gXwanMiniportDeviceListHead;
KSPIN_LOCK      gXwanMiniportDeviceSpinLock;
LONG	        gXwanMiniportCount		 = 0;

#if NT5_BUILD


// Table of adapter startup routines
static DSMP_DLL_ADAPTER_OPTION SupportedAdapters[] = 
{
	{ DXB_REGVAL_OPTION_ENUM_SYNC570, Sync570DllInitialize, 0 },
};


#define SupportedAdaptersCount		( sizeof SupportedAdapters / sizeof SupportedAdapters[0] )


STATIC PDSMP_DLL_INTERFACE_ROUTINES
XwanInitializeMiniportDll(	IN	PCWSTR	pOption
	)
/*++

Routine Description:

	Find the DLL initialization Routine For this Option.

Arguments:

	pOption			- Option Name (e.g. Sync570)

Return Value:

	PDSMP_DLL_INTERFACE_ROUTINES - A Handle to the Interface Routines.

--*/
{
	PDSMP_DLL_INTERFACE_ROUTINES pDllInterfaceRoutine = NULL;
	int i;	

	for ( i = 0; i < SupportedAdaptersCount; i++ )
	{
		UNICODE_STRING Name;
		UNICODE_STRING OptionName;
		RtlInitUnicodeString( &Name, SupportedAdapters[i].Name );
		RtlInitUnicodeString( &OptionName, pOption);
		if ( RtlEqualUnicodeString( &Name, &OptionName, TRUE ) )
		{
			pDllInterfaceRoutine = SupportedAdapters[i].InitRoutine();

			break;
		}
	}

	// Initialize the SpinLocks and list heads if this is the first call
	if ( InterlockedIncrement(&gXwanMiniportCount) == 1 )
	{
		KeInitializeSpinLock( &gXwanMiniportDeviceSpinLock );
		InitializeListHead( &gXwanMiniportDeviceListHead );
	}

	return pDllInterfaceRoutine;

}


extern NTSTATUS
XwanStartAdapter(	IN	PCWSTR				pOption,
					IN	PDRIVER_OBJECT		pDriverObject,
					IN	PDEVICE_OBJECT		pDeviceObject,
					IN  PUNICODE_STRING		pAdapterName,
					IN	PDIGI_RESOURCE_LIST	pResources,
					IN	ULONG				dwLineCount,
					OUT PPXWAN_ADAPTER		ppXwanAdapter						
	)

/*++

Routine Description:

	Start the Miniport Adapter

Arguments:

	pwDeviceName   - Miniport adapter name (e.g. Dg570mp1)
	pwDeviceSuffix - The major/minor device number.
	ulSnid		   - Unique ID for this adapter

Return Value:

	STATUS_SUCCESS if this miniport is succesfully registered.

--*/
{

	PXWAN_ADAPTER	pXwanAdapter;
	NTSTATUS		Status = STATUS_UNSUCCESSFUL;

	*ppXwanAdapter = NULL;

	// Get the Memory for the Adapter Control Block
	pXwanAdapter = DigiAllocMem( NonPagedPool, sizeof *pXwanAdapter  );
	if ( !pXwanAdapter )
	{
		return STATUS_INSUFFICIENT_RESOURCES;
	}

	// Get the Interface to the Adapter DLL
	pXwanAdapter->hDllInterface = XwanInitializeMiniportDll(pOption);
	ASSERT(pXwanAdapter->hDllInterface);

	if (pXwanAdapter->hDllInterface)
	{

		// Call the Start Adapter Routine
		Status = pXwanAdapter->hDllInterface->StartAdapter(pDriverObject,
														   pDeviceObject,
														   pAdapterName,
												           pResources,
												           dwLineCount,
												           &pXwanAdapter->hAdapter
												           );
		*ppXwanAdapter = pXwanAdapter;

	}


	return Status;

}


extern NTSTATUS
XwanRegisterMiniport( IN PXWAN_ADAPTER	pXwanAdapter,
					  IN ULONG			ulLineNumber,
					  IN ULONG			ulSnid
	)

/*++

Routine Description:

	This routine is called by DIGISOH for every miniport defined to
	use DIGISOH.  The XWAN streams device should not access this
	miniport list until it is fully initialized.  DIGISOH needs to
	build this list before allowing the streams to be opened.

Arguments:

	pwDeviceName   - Miniport adapter name (e.g. Dg570mp1)
	pwDeviceSuffix - The major/minor device number.
	ulSnid		   - Unique ID for this adapter

Return Value:

	STATUS_SUCCESS if this miniport is succesfully registered.

--*/
{

	UNICODE_STRING			ucMiniportDeviceName;
	PXWAN_MINIPORT_INSTANCE	pXwanMiniportInstance;
	PLIST_ENTRY				pListEntry;
	NTSTATUS				Status;
	KIRQL					Irql;
	
	KeAcquireSpinLock( &gXwanMiniportDeviceSpinLock, &Irql );

	// Make sure the DeviceName and the Snid are unique.
	for ( pListEntry  = gXwanMiniportDeviceListHead.Flink;
		  pListEntry != &gXwanMiniportDeviceListHead;
		  pListEntry  = pListEntry->Flink )
	{
		pXwanMiniportInstance = CONTAINING_RECORD( pListEntry,
												   XWAN_MINIPORT_INSTANCE,
												   ListEntry );

		// duplicate SNID?
		if ( ulSnid == pXwanMiniportInstance->ulSnid )	
		{
			return STATUS_OBJECTID_EXISTS;
		}
	}

	KeReleaseSpinLock( &gXwanMiniportDeviceSpinLock, Irql );

	// Get a new Miniport Device control block.
	pXwanMiniportInstance = DigiAllocMem( NonPagedPool, sizeof( XWAN_MINIPORT_INSTANCE ) );
	if ( !pXwanMiniportInstance )
	{
		return ( STATUS_INSUFFICIENT_RESOURCES );
	}
	RtlZeroMemory ( pXwanMiniportInstance, sizeof( XWAN_MINIPORT_INSTANCE ) );

	// Initialize the MiniPort Device
	pXwanMiniportInstance->pXwanAdapter = pXwanAdapter;
	pXwanMiniportInstance->ulSnid		= ulSnid;	
	pXwanMiniportInstance->ulLineNumber	= ulLineNumber;	

	// Add the Device to the list.
	ExInterlockedInsertTailList( &gXwanMiniportDeviceListHead,
								 &pXwanMiniportInstance->ListEntry,
								 &gXwanMiniportDeviceSpinLock);

	return ( STATUS_SUCCESS );
}



extern void
XwanDeregisterMiniports(IN PXWAN_ADAPTER	pXwanAdapter
	)

/*++

Routine Description:

	Release all the resources associated with the Miniport

Arguments:

Return Value:

--*/
{

	PXWAN_MINIPORT_INSTANCE	pXwanMiniportInstance;
	PLIST_ENTRY				pListEntry,pNextListEntry;
	KIRQL					Irql;

	KeAcquireSpinLock( &gXwanMiniportDeviceSpinLock, &Irql );

	// Make sure the DeviceName and the Snid are unique.
	for ( pListEntry	  = gXwanMiniportDeviceListHead.Flink, pNextListEntry = gXwanMiniportDeviceListHead.Flink;
		  pNextListEntry != &gXwanMiniportDeviceListHead;
		  pListEntry      = pNextListEntry)
	{
		pXwanMiniportInstance = CONTAINING_RECORD( pListEntry,
												   XWAN_MINIPORT_INSTANCE,
												   ListEntry );

		pNextListEntry = pListEntry->Flink;

		// Is this Miniport instance associated with our adapter?
		if ( pXwanAdapter == pXwanMiniportInstance->pXwanAdapter )	
		{

			// Remove the Device From the List
			RemoveEntryList(&pXwanMiniportInstance->ListEntry);

			// Free the Miniport Device memory
			DigiFreeMem( pXwanMiniportInstance );
		}
	}

	KeReleaseSpinLock( &gXwanMiniportDeviceSpinLock, Irql );

	return;
}


VOID
XwanDisconnectFromMiniport( IN PXWAN_DEVICE_CONTROL		pDevCtl,
						    IN PXWAN_MINIPORT_INSTANCE	pXwanMiniportInstance
	)

/*++

Routine Description:

	Disconnect from the Miniport device (Close).

Arguments:

	pDevCtl					- Device on the Adapter (line)
	pXwanMiniportInstance	- The adpater.

Return Value:

	VOID

--*/
{
	PXWAN_ADAPTER	pXwanAdapter;

	if (pXwanMiniportInstance)
	{
		pXwanAdapter = pXwanMiniportInstance->pXwanAdapter;

		// Close The Device.
		pXwanAdapter->hDllInterface->CloseDevice(pDevCtl->hDevice);

		if (pXwanMiniportInstance) {

			// No longer in use
			pXwanMiniportInstance->bInUse	= FALSE;
			pDevCtl->pXwanMiniportInstance	= NULL;

		}
	}
	
	return;
}



NTSTATUS
XwanLinkMiniport( IN PXWAN_DEVICE_CONTROL		pDevCtl,
				  IN PXWAN_MINIPORT_INSTANCE	pXwanMiniportInstance
	)

/*++

Routine Description:

	Link to a miniport device (Open).

Arguments:

	pDevCtl					- Device on the Adapter (line)
	pXwanMiniportInstance	- The adpater.

Return Value:

	NTSTATUS 

--*/
{

	NTSTATUS		Status;
	PXWAN_ADAPTER	pXwanAdapter = pXwanMiniportInstance->pXwanAdapter;

	// Get a Handle to the Device to be Used for this interface.
	Status = pXwanAdapter->hDllInterface->OpenDevice((DSMP_DLL_ADAPTER_HANDLE) pXwanAdapter->hAdapter,
													 pXwanMiniportInstance->ulLineNumber,
													 &pDevCtl->hDevice
												     );
	return Status;

}


NTSTATUS
XwanMiniportIo( IN ULONG IoCode,
				IN PXWAN_DEVICE_CONTROL pDevCtl,
				IN PVOID pIoBuffer,
				IN ULONG IoBufferLength 
	)
/*++

Routine Description:


Arguments:

	IoCode			- Io Code
  	pDevCtl			- Device on the Adapter (line)
	pIoBuffer		- Pointer to the Io Buffer
	IoBufferLength	- Io Buffer Length

Return Value:

	Status - Miniport Status

Comments:


--*/
{
	PIRP					pIrp;
	KEVENT					IoEvent;
	NTSTATUS				Status = STATUS_INVALID_PARAMETER;
	PXWAN_MINIPORT_INSTANCE	pXwanMiniportInstance = pDevCtl->pXwanMiniportInstance;
	PXWAN_ADAPTER			pXwanAdapter = pXwanMiniportInstance->pXwanAdapter;

	// We must be Linked
	if (pDevCtl->hDevice) {

		// Call the miniport DLL Interface
		switch (IoCode)
		{
			case DSMP_GENERIC_GETFRAME:

				if (IoBufferLength == sizeof(DSMP_GETFRAME))
				{

					PDSMP_GETFRAME pFrame = (PDSMP_GETFRAME) pIoBuffer;
					pFrame->pDataBuffer = pFrame->pUserDataBuffer;

					// Call the Miniport Handler.
					Status = pXwanAdapter->hDllInterface->GetFrame(pDevCtl->hDevice,
																  (PDSMP_GETFRAME) pIoBuffer
																  );
				}
				break;

			case DSMP_GENERIC_PUTFRAME:

				if (IoBufferLength == sizeof(DSMP_PUTFRAME))
				{
					PDSMP_PUTFRAME pFrame = (PDSMP_PUTFRAME) pIoBuffer;
					pFrame->pDataBuffer = pFrame->pUserDataBuffer;

					// Call the Miniport Handler.
					Status = pXwanAdapter->hDllInterface->PutFrame(pDevCtl->hDevice,
																  (PDSMP_PUTFRAME)pIoBuffer
																  );
				}
				break;
			
			case DSMP_GENERIC_GETCONFIG:

				if (IoBufferLength == sizeof(DSMP_CONFIG))
				{
					// Call the Miniport Handler.
					Status = pXwanAdapter->hDllInterface->GetConfig(pDevCtl->hDevice,
																	(PDSMP_CONFIG)pIoBuffer
																	);
				}
				break;
			
			case DSMP_GENERIC_SETCONFIG:

				if (IoBufferLength == sizeof(DSMP_CONFIG))
				{
					// Call the Miniport Handler.
					Status = pXwanAdapter->hDllInterface->SetConfig(pDevCtl->hDevice,
																    (PDSMP_CONFIG)pIoBuffer
																	);
				}
				break;

			case DSMP_GENERIC_GETMODEM:

				if (IoBufferLength == sizeof(DSMP_MODEM))
				{
					// Call the Miniport Handler.
					Status = pXwanAdapter->hDllInterface->GetModem(pDevCtl->hDevice,
						                                           (PDSMP_MODEM)pIoBuffer
																   );
				}
				break;

			case DSMP_GENERIC_SETMODEM:

				if (IoBufferLength == sizeof(DSMP_MODEM))
				{
					// Call the Miniport Handler.
					Status = pXwanAdapter->hDllInterface->SetModem(pDevCtl->hDevice,
						                                           (PDSMP_MODEM)pIoBuffer
																   );
				}
				break;

			case DSMP_GENERIC_GETSTATS:

				if (IoBufferLength == sizeof(DSMP_STATS))
				{
					// Call the Miniport Handler.
					Status = pXwanAdapter->hDllInterface->GetStats(pDevCtl->hDevice,
						                                           (PDSMP_STATS)pIoBuffer
																   );
				}
				break;

			case DSMP_GENERIC_ZEROSTATS:

				// Call the Miniport Handler.
				Status = pXwanAdapter->hDllInterface->ZeroStats(pDevCtl->hDevice);
				break;

			default:
				break;
		}

	}

	return ( Status );
}


extern NTSTATUS
XwanStopAdapter(	IN PXWAN_ADAPTER	pXwanAdapter						
	)

/*++

Routine Description:

	Stop the Miniport Adapter

Arguments:

	pXwanAdapter   - Adapter Pointer

Return Value:

	STATUS_SUCCESS if this miniport is succesfully registered.

--*/
{

	NTSTATUS		Status = STATUS_SUCCESS;

	// Call the Stop Adapter Routine
	Status = pXwanAdapter->hDllInterface->StopAdapter(pXwanAdapter->hAdapter);

	// Free the memory
	DigiFreeMem(pXwanAdapter);

	return Status;

}

//
// NT4 IOCTL Miniport Interface

#else

extern NTSTATUS
XwanRegisterMiniport( IN PWSTR pwMiniportAdapterName,
					  IN PWSTR pwDeviceSuffix,
					  IN ULONG ulSnid
	)

/*++

Routine Description:

	This routine is called by DIGISOH for every miniport defined to
	use DIGISOH.  The XWAN streams device should not access this
	miniport list until it is fully initialized.  DIGISOH needs to
	build this list before allowing the streams to be opened.

Arguments:

	pwDeviceName   - Miniport adapter name (e.g. Dg570mp1)
	pwDeviceSuffix - The major/minor device number.
	ulSnid		   - Unique ID for this adapter

Return Value:

	STATUS_SUCCESS if this miniport is succesfully registered.

--*/
{

	UNICODE_STRING			ucMiniportDeviceName;
	PXWAN_MINIPORT_INSTANCE	pXwanMiniportInstance;
	PLIST_ENTRY				pListEntry;
	NTSTATUS				Status;

	// Some initialization 
	if ( !gXwanMiniportInitialized )
	{
		InitializeListHead( &gXwanMiniportDeviceListHead );
		gXwanMiniportInitialized = TRUE;
	}

	// Construct a UNICODE string 
	Status = DigiStrAllocUnicodeString ( &ucMiniportDeviceName,
										 L"\\Device\\",
										 pwMiniportAdapterName,
										 pwDeviceSuffix);
	if ( Status != STATUS_SUCCESS)
	{
		return ( STATUS_INSUFFICIENT_RESOURCES );
	}

	// Make sure the DeviceName and the Snid are unique.
	for ( pListEntry  = gXwanMiniportDeviceListHead.Flink;
		  pListEntry != &gXwanMiniportDeviceListHead;
		  pListEntry  = pListEntry->Flink )
	{
		pXwanMiniportInstance = CONTAINING_RECORD( pListEntry,
												   XWAN_MINIPORT_INSTANCE,
												   ListEntry );

		// duplicate SNID?
		if ( ulSnid == pXwanMiniportInstance->ulSnid )	
		{
			return STATUS_OBJECTID_EXISTS;
		}

		// duplicate Miniport Device?
		if (RtlEqualUnicodeString(&ucMiniportDeviceName,
			                      &pXwanMiniportInstance->ucMiniportDeviceName,
								  FALSE))
		{
			return STATUS_OBJECTID_EXISTS;
		}
	}

	// Get a new Miniport Device control block.
	pXwanMiniportInstance = DigiAllocMem( NonPagedPool, sizeof( XWAN_MINIPORT_INSTANCE ) );
	if ( !pXwanMiniportInstance )
	{
		return ( STATUS_INSUFFICIENT_RESOURCES );
	}
	RtlZeroMemory ( pXwanMiniportInstance, sizeof( XWAN_MINIPORT_INSTANCE ) );

	// Initialize the MiniPort Device
	pXwanMiniportInstance->ucMiniportDeviceName = ucMiniportDeviceName;
	pXwanMiniportInstance->ulSnid = ulSnid;	

	// Add the Device to the list.
	InsertTailList( &gXwanMiniportDeviceListHead, &pXwanMiniportInstance->ListEntry );

	return ( STATUS_SUCCESS );
}



extern void
XwanDeregisterMiniports(
	)

/*++

Routine Description:

	Release all the resources associated with the Miniport list

Arguments:

Return Value:

--*/
{

	PXWAN_MINIPORT_INSTANCE	pXwanMiniportInstance;
	PLIST_ENTRY				pListEntry;

	// Remove the Miniport Devices from the List
	while ( !IsListEmpty(&gXwanMiniportDeviceListHead) )
	{

		// Remove the Device from the list.
		pListEntry = RemoveHeadList( &gXwanMiniportDeviceListHead );

		pXwanMiniportInstance = CONTAINING_RECORD( pListEntry,
												   XWAN_MINIPORT_INSTANCE,
												   ListEntry );

		// Free the UNICODE_STRING memory
		DigiStrFreeUnicodeString( &pXwanMiniportInstance->ucMiniportDeviceName);

		// Free the Miniport Device memory
		DigiFreeMem( pXwanMiniportInstance );

	}

	// No longer initialized 
	gXwanMiniportInitialized = FALSE;

	return;
}


VOID
XwanDisconnectFromMiniport( IN PXWAN_DEVICE_CONTROL		pDevCtl,
						    IN PXWAN_MINIPORT_INSTANCE	pXwanMiniportInstance
	)

/*++

Routine Description:

	Using the SNID streams users can connect to a miniport device.

Arguments:

	ulSnid		   - Unique ID for this adapter

Return Value:

	TRUE	- connected.
	FALSE	- not connected (No Snid, Snid already in use, could not connect
	                         to the driver)

--*/
{

	if (pXwanMiniportInstance) {

		// dereference the miniport File Object

		if ( pDevCtl->pMiniportFileObject )
		{
			ObDereferenceObject( pDevCtl->pMiniportFileObject );
		}

		// No longer in use
		pXwanMiniportInstance->bInUse	= FALSE;
		pDevCtl->pXwanMiniportInstance	= NULL;

	}
	
	return;
}

NTSTATUS
XwanLinkMiniport( IN PXWAN_DEVICE_CONTROL		pDevCtl,
				  IN PXWAN_MINIPORT_INSTANCE	pXwanMiniportInstance
	)

/*++

Routine Description:

	Using the SNID streams users can connect to a miniport device.

Arguments:

	ulSnid		   - Unique ID for this adapter

Return Value:

	TRUE	- connected.
	FALSE	- not connected (No Snid, Snid already in use, could not connect
	                         to the driver)

--*/
{

	NTSTATUS	Status;

	// given name, open the device
	// saving handle for future access
	Status = IoGetDeviceObjectPointer( &pXwanMiniportInstance->ucMiniportDeviceName,
									   FILE_ALL_ACCESS,
								       &pDevCtl->pMiniportFileObject,
									   &pDevCtl->pMiniportDeviceObject );

	if ( Status != STATUS_SUCCESS )
	{
		pDevCtl->pMiniportFileObject = 0;
		pDevCtl->pMiniportDeviceObject = 0;
	}
	else
	{
		ASSERT( pDevCtl->pMiniportFileObject );
		ASSERT( pDevCtl->pMiniportDeviceObject );
	}

	return Status;

}


NTSTATUS
XwanMiniportIo( IN ULONG IoCode,
				IN PXWAN_DEVICE_CONTROL pDevCtl,
				IN PVOID pIoBuffer,
				IN ULONG IoBufferLength 
	)
/*++

Routine Description:


Arguments:


Return Value:

	???

Comments:


--*/
{
	PIRP            pIrp;
	KEVENT          IoEvent;
	IO_STATUS_BLOCK IoStatus;
	NTSTATUS        Status = STATUS_UNSUCCESSFUL;

	// send an IOCTL (via Irp) to the miniport
	// build irp, call driver, free irp

	// We must be Linked
	if (pDevCtl->pMiniportDeviceObject) {

		KeInitializeEvent( &IoEvent, NotificationEvent, FALSE );
		RtlZeroMemory( &IoStatus, sizeof( IoStatus ) );

		ASSERT( KeGetCurrentIrql() == PASSIVE_LEVEL );

		// Note: Because all miniport ioctls complete synchronously we don't 
		// supply a completion routine. The I/O manager automatically frees the
		// Irp when the lower driver completes. Don't free it again!

		pIrp = IoBuildDeviceIoControlRequest( ( ULONG ) IoCode,
											  pDevCtl->pMiniportDeviceObject,
											  pIoBuffer,
											  IoBufferLength,
											  pIoBuffer,
											  IoBufferLength,
											  FALSE,
											  &IoEvent,
											  &IoStatus );

		// this should always succeed, but we want to know if it doesn't

		if ( !pIrp )
		{
			ASSERT( pIrp );

			return ( STATUS_INSUFFICIENT_RESOURCES );
		}

		Status = IoCallDriver( pDevCtl->pMiniportDeviceObject, pIrp );

		// this should never pend
		if ( Status == STATUS_PENDING )
		{
			ASSERT( FALSE );

		}

	}

	return ( Status );
}


#endif   // NT5_BUILD


BOOLEAN
XwanConnectToMiniport( IN PXWAN_DEVICE_CONTROL pDevCtl,
					   IN ULONG ulSnid
	)

/*++

Routine Description:

	Using the SNID streams users can connect to a miniport device.

Arguments:

	ulSnid		   - Unique ID for this adapter

Return Value:

	TRUE	- connected.
	FALSE	- not connected (No Snid, Snid already in use, could not connect
	                         to the driver)

--*/
{

	PXWAN_MINIPORT_INSTANCE	pXwanMiniportInstance;
	PLIST_ENTRY				pListEntry;
	BOOLEAN					bSnidFound = FALSE;
	NTSTATUS				Status;

	// Find a Miniport Device that matches the SNID.
	for ( pListEntry  = gXwanMiniportDeviceListHead.Flink;
		  pListEntry != &gXwanMiniportDeviceListHead;
		  pListEntry  = pListEntry->Flink )
	{
		pXwanMiniportInstance = CONTAINING_RECORD( pListEntry,
												   XWAN_MINIPORT_INSTANCE,
												   ListEntry );

		// Is this the one?
		if ( ulSnid == pXwanMiniportInstance->ulSnid )	
		{
			// SNID already taken
			if (pXwanMiniportInstance->bInUse) 
			{
				return FALSE;
			}
			else
			{
				bSnidFound = TRUE;
				break;
			}
		}

	}

	ASSERT( bSnidFound );

	// If the SNID was found then let's connect to the driver.
	if ( bSnidFound )
	{

		// Link to the MiniPort
		Status = XwanLinkMiniport(pDevCtl,pXwanMiniportInstance);
		if (Status != STATUS_SUCCESS)
		{
			return FALSE;
		}
		else
		{
			// This one is now in use
			pXwanMiniportInstance->bInUse	= TRUE;
			pDevCtl->pXwanMiniportInstance	= pXwanMiniportInstance;
		}
	}
	
	return bSnidFound;
}
