Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3024 lines
80 KiB

/*++ BUILD Version: 0000 // Increment this if a change has global effects
Copyright (c) 1994 Microsoft Corporation
Module Name:
ndistapi.c
Abstract:
This module contains the NdisTapi.sys implementation
Author:
Dan Knudson (DanKn) 20-Feb-1994
Notes:
(Future/outstanding issues)
- stuff marked with "PnP" needs to be rev'd for plug 'n play support
Revision History:
--*/
#include "ndis.h"
#include "stdarg.h"
#include "stdio.h"
#include "ntddndis.h"
#include "ndistapi.h"
#include "private.h"
#include "intrface.h"
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
);
VOID
NdisTapiCancel(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
NdisTapiCleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
NdisTapiDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
VOID
NdisTapiUnload(
IN PDRIVER_OBJECT DriverObject
);
#if DBG
VOID
DbgPrt(
IN LONG DbgLevel,
IN PUCHAR DbgMessage,
IN ...
);
#endif
VOID
DoProviderInitComplete(
PPROVIDER_REQUEST ProviderRequest,
NDIS_STATUS Status
);
ULONG
GetLineEvents(
PVOID EventBuffer,
ULONG BufferSize
);
BOOLEAN
SyncInitAllProviders(
void
);
VOID
DoIrpMjCloseWork(
PIRP Irp
);
NDIS_STATUS
SendProviderInitRequest(
PPROVIDER_INFO Provider
);
NDIS_STATUS
SendProviderShutdown(
PPROVIDER_INFO Provider,
PKIRQL oldIrql
);
VOID
NdisTapiIndicateStatus(
IN ULONG_PTR DriverHandle,
IN PVOID StatusBuffer,
IN UINT StatusBufferSize
);
VOID
DoLineOpenCompleteWork(
PNDISTAPI_REQUEST ndisTapiRequest,
PPROVIDER_INFO provider
);
VOID
DoLineOpenWork(
PNDISTAPI_REQUEST ndisTapiRequest,
PPROVIDER_INFO provider
);
NDIS_STATUS
VerifyProvider(
PNDISTAPI_REQUEST ndisTapiRequest,
PPROVIDER_INFO *provider
);
NDIS_STATUS
VerifyLineClose(
PNDISTAPI_REQUEST ndisTapiRequest,
PPROVIDER_INFO provider
);
NTSTATUS
DoIoctlConnectWork(
PIRP Irp,
PVOID ioBuffer,
ULONG inputBufferLength,
ULONG outputBufferLength
);
NTSTATUS
DoIoctlQuerySetWork(
PIRP Irp,
PVOID ioBuffer,
ULONG inputBufferLength,
ULONG outputBufferLength
);
NTSTATUS
DoGetProviderEventsWork(
PIRP Irp,
PVOID ioBuffer,
ULONG inputBufferLength,
ULONG outputBufferLength
);
NTSTATUS
DoLineCreateWork(
PIRP Irp,
PVOID ioBuffer,
ULONG inputBufferLength,
ULONG outputBufferLength
);
//
// Use the alloc_text pragma to specify the driver initialization routines
// (they can be paged out).
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,DriverEntry)
#endif
NPAGED_LOOKASIDE_LIST ProviderEventLookaside;
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path
to driver-specific key in the registry
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
PDEVICE_OBJECT deviceObject = NULL;
NTSTATUS ntStatus;
WCHAR deviceNameBuffer[] = L"\\Device\\NdisTapi";
UNICODE_STRING deviceNameUnicodeString;
UNICODE_STRING registryPath;
DBGOUT ((2, "DriverEntry: enter"));
//
// Create a NON-EXCLUSIVE device, i.e. multiple threads at a time
// can send i/o requests.
//
RtlInitUnicodeString (&deviceNameUnicodeString, deviceNameBuffer);
ntStatus = IoCreateDevice(
DriverObject,
sizeof (KMDD_DEVICE_EXTENSION),
&deviceNameUnicodeString,
FILE_DEVICE_NDISTAPI,
0,
FALSE,
&deviceObject
);
if (NT_SUCCESS(ntStatus))
{
//
// Init the global & sero the extension
//
DeviceExtension =
(PKMDD_DEVICE_EXTENSION) deviceObject->DeviceExtension;
RtlZeroMemory(
DeviceExtension,
sizeof (KMDD_DEVICE_EXTENSION)
);
//
// Create a NULL-terminated registry path & retrieve the registry
// params (EventDataQueueLength)
//
registryPath.Buffer = ExAllocatePoolWithTag(
PagedPool,
RegistryPath->Length + sizeof(UNICODE_NULL),
'IPAT'
);
if (!registryPath.Buffer)
{
DBGOUT((1, "DriverEntry: ExAllocPool for szRegistryPath failed"));
ntStatus = STATUS_UNSUCCESSFUL;
goto DriverEntry_err;
}
else
{
registryPath.Length = RegistryPath->Length;
registryPath.MaximumLength =
registryPath.Length + sizeof(UNICODE_NULL);
RtlZeroMemory(
registryPath.Buffer,
registryPath.MaximumLength
);
RtlMoveMemory(
registryPath.Buffer,
RegistryPath->Buffer,
RegistryPath->Length
);
}
ExFreePool (registryPath.Buffer);
InitializeListHead(&DeviceExtension->ProviderEventList);
ExInitializeNPagedLookasideList(&ProviderEventLookaside,
NULL,
NULL,
0,
sizeof(PROVIDER_EVENT),
'IPAT',
0);
DeviceExtension->DeviceObject = deviceObject;
DeviceExtension->Status = NDISTAPI_STATUS_DISCONNECTED;
DeviceExtension->NdisTapiNumDevices = 0;
DeviceExtension->htCall = 0x80000001;
KeInitializeSpinLock (&DeviceExtension->SpinLock);
InitializeListHead(&DeviceExtension->ProviderRequestList);
//
// Create dispatch points for device control, create, close.
//
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = NdisTapiDispatch;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = NdisTapiCleanup;
DriverObject->DriverUnload = NdisTapiUnload;
}
if (!NT_SUCCESS(ntStatus)) {
DriverEntry_err:
//
// Something went wrong, so clean up
//
DBGOUT((0, "init failed"));
if (deviceObject)
{
while (!(IsListEmpty(&DeviceExtension->ProviderEventList))) {
PPROVIDER_EVENT ProviderEvent;
ProviderEvent = (PPROVIDER_EVENT)
RemoveHeadList(&DeviceExtension->ProviderEventList);
ExFreeToNPagedLookasideList(&ProviderEventLookaside, ProviderEvent);
}
IoDeleteDevice (deviceObject);
}
}
DBGOUT ((2, "DriverEntry: exit"));
return ntStatus;
}
VOID
NdisTapiCancel(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
KIRQL oldIrql;
DBGOUT((2,"NdisTapiCancel: enter"));
//
// Release the cancel spinlock
//
IoReleaseCancelSpinLock (Irp->CancelIrql);
//
// Acquire the SpinLock & check to see if we're canceling a
// pending get-events Irp
//
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
do {
DeviceExtension->IrpsCanceledCount++;
if (Irp == DeviceExtension->EventsRequestIrp) {
DeviceExtension->EventsRequestIrp = NULL;
DeviceExtension->Flags |= EVENTIRP_CANCELED;
break;
}
//
// Try to remove request from our special
// user-mode requests dev queue
//
if (!IsListEmpty(&DeviceExtension->ProviderRequestList)) {
PLIST_ENTRY Entry;
Entry = DeviceExtension->ProviderRequestList.Flink;
while (Entry != &DeviceExtension->ProviderRequestList) {
PPROVIDER_REQUEST pReq;
pReq = (PPROVIDER_REQUEST)Entry;
if (pReq->Irp == Irp) {
RemoveEntryList(&pReq->Linkage);
DeviceExtension->RequestCount--;
DeviceExtension->Flags |= REQUESTIRP_CANCELED;
break;
}
Entry = Entry->Flink;
}
if (Entry == &DeviceExtension->ProviderRequestList) {
DBGOUT((1,"NdisTapiCancel: Irp %p not in device queue?!?", Irp));
DeviceExtension->Flags |= CANCELIRP_NOTFOUND;
}
}
} while (FALSE);
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
//
// Complete the request with STATUS_CANCELLED.
//
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
DBGOUT((2,"NdisTapiCancel: completing irp=%p", Irp));
}
NTSTATUS
NdisTapiCleanup(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine is the dispatch routine for cleanup requests.
All requests queued are completed with STATUS_CANCELLED.
Arguments:
DeviceObject - Pointer to device object.
Irp - Pointer to the request packet.
Return Value:
Status is returned.
--*/
{
KIRQL oldIrql;
PNDISTAPI_REQUEST ndisTapiRequest;
PKDEVICE_QUEUE_ENTRY packet;
DBGOUT((2,"NdisTapiCleanup: enter"));
//
// Sync access to EventsRequestIrp by acquiring SpinLock
//
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
DeviceExtension->Flags |= CLEANUP_INITIATED;
//
// Check to see if there's a get-events request pending that needs
// completing
//
if ((DeviceExtension->EventsRequestIrp != NULL) &&
(DeviceExtension->EventsRequestIrp->Tail.Overlay.OriginalFileObject ==
Irp->Tail.Overlay.OriginalFileObject)) {
PIRP LocalIrp;
//
// Acquire the cancel spinlock, remove the request from the
// cancellable state, and free the cancel spinlock.
//
LocalIrp = DeviceExtension->EventsRequestIrp;
if (IoSetCancelRoutine (LocalIrp, NULL) != NULL) {
DeviceExtension->EventsRequestIrp = NULL;
LocalIrp->IoStatus.Status = STATUS_CANCELLED;
LocalIrp->IoStatus.Information = 0;
DeviceExtension->IrpsCanceledCount++;
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
DBGOUT((2,"NdisTapiCleanup: Completing EventRequestIrp %p", LocalIrp));
IoCompleteRequest (LocalIrp, IO_NO_INCREMENT);
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
}
}
//
// Cancel all outstanding QUERY/SET_INFO requests
//
if (!IsListEmpty(&DeviceExtension->ProviderRequestList)) {
PPROVIDER_REQUEST pReq;
pReq = (PPROVIDER_REQUEST)
DeviceExtension->ProviderRequestList.Flink;
//
// Until we have walked the entire list
//
while ((PVOID)pReq != (PVOID)&DeviceExtension->ProviderRequestList) {
PIRP LocalIrp;
LocalIrp = pReq->Irp;
//
// If the current entry's irp has a fileobject that is
// the same as the cleanup irp's fileobject then remove it
// from the list and cancel it
//
if (LocalIrp->Tail.Overlay.OriginalFileObject ==
Irp->Tail.Overlay.OriginalFileObject) {
//
// Remove the IRP from the cancelable state
//
if (IoSetCancelRoutine (LocalIrp, NULL) == NULL) {
//
// The irp has been canceled. Let
// cancel routine cleanup.
//
pReq =
(PPROVIDER_REQUEST)pReq->Linkage.Flink;
continue;
}
RemoveEntryList(&pReq->Linkage);
DeviceExtension->RequestCount--;
//
// Set the status & info size values appropriately, & complete
// the request
//
ndisTapiRequest = LocalIrp->AssociatedIrp.SystemBuffer;
ndisTapiRequest->ulReturnValue = (ULONG) NDIS_STATUS_FAILURE;
LocalIrp->IoStatus.Status = STATUS_CANCELLED;
LocalIrp->IoStatus.Information = 0;
DeviceExtension->IrpsCanceledCount++;
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
DBGOUT((2,"NdisTapiCleanup: Completing ProviderRequestIrp %p", LocalIrp));
IoCompleteRequest (LocalIrp, IO_NO_INCREMENT);
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
pReq = (PPROVIDER_REQUEST)
DeviceExtension->ProviderRequestList.Flink;
} else {
pReq = (PPROVIDER_REQUEST)
pReq->Linkage.Flink;
}
}
}
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
//
// Complete the cleanup request with STATUS_SUCCESS.
//
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
DBGOUT((2,"NdisTapiCleanup: exit"));
return(STATUS_SUCCESS);
}
NTSTATUS
NdisTapiDispatch(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Process the IRPs sent to this device.
Arguments:
DeviceObject - pointer to a device object
Irp - pointer to an I/O Request Packet
Return Value:
--*/
{
NTSTATUS NtStatus;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
PIO_STACK_LOCATION irpStack;
//
// Get a pointer to the current location in the Irp. This is where
// the function codes and parameters are located.
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
//
// Get the pointer to the input/output buffer and it's length
//
ioBuffer =
Irp->AssociatedIrp.SystemBuffer;
inputBufferLength =
irpStack->Parameters.DeviceIoControl.InputBufferLength;
outputBufferLength =
irpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
DBGOUT ((2, "IRP_MJ_CREATE, Irp=%p", Irp));
InterlockedIncrement(&DeviceExtension->RefCount);
NtStatus = Irp->IoStatus.Status
= STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
break;
case IRP_MJ_CLOSE:
DBGOUT ((2, "IRP_MJ_CLOSE, Irp=%p", Irp));
DoIrpMjCloseWork(Irp);
NtStatus = STATUS_SUCCESS;
break;
case IRP_MJ_DEVICE_CONTROL:
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_NDISTAPI_CONNECT:
DBGOUT ((2, "IOCTL_NDISTAPI_CONNECT, Irp=%p", Irp));
NtStatus =
DoIoctlConnectWork(Irp,
ioBuffer,
inputBufferLength,
outputBufferLength);
break;
case IOCTL_NDISTAPI_QUERY_INFO:
case IOCTL_NDISTAPI_SET_INFO:
DBGOUT ((2, "IOCTL_NDISTAPI_QUERY/SET_INFO, Irp=%p", Irp));
NtStatus =
DoIoctlQuerySetWork(Irp,
ioBuffer,
inputBufferLength,
outputBufferLength);
break;
case IOCTL_NDISTAPI_GET_LINE_EVENTS:
DBGOUT ((2, "IOCTL_NDISTAPI_GET_LINE_EVENTS, Irp=%p", Irp));
NtStatus =
DoGetProviderEventsWork(Irp,
ioBuffer,
inputBufferLength,
outputBufferLength);
break;
case IOCTL_NDISTAPI_CREATE:
DBGOUT ((2, "IOCTL_NDISTAPI_CREATE, Irp=%p", Irp));
NtStatus =
DoLineCreateWork(Irp,
ioBuffer,
inputBufferLength,
outputBufferLength);
break;
default:
DBGOUT ((2, "Unknown IRP_MJ_DEVICE_CONTROL, Irp=%p", Irp));
NtStatus = Irp->IoStatus.Status =
STATUS_INVALID_PARAMETER;
Irp->IoStatus.Information = 0;
break;
}
break;
}
if (NtStatus == STATUS_PENDING) {
return (STATUS_PENDING);
}
ASSERT(NtStatus == Irp->IoStatus.Status);
//
// Unmark the irp pending since we are completing the
// the irp below.
//
irpStack->Control &= ~SL_PENDING_RETURNED;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
DBGOUT((3, "NdisTapiDispatch: completed Irp=%p", Irp));
return NtStatus;
}
VOID
NdisTapiUnload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Free all the allocated resources, etc.
Arguments:
DriverObject - pointer to a driver object
Return Value:
--*/
{
KIRQL oldIrql;
PPROVIDER_INFO provider, nextProvider;
DBGOUT ((2, "NdisTapiUnload: enter"));
//
// Delete the device object & sundry resources
//
while (!(IsListEmpty(&DeviceExtension->ProviderEventList))) {
PPROVIDER_EVENT ProviderEvent;
ProviderEvent = (PPROVIDER_EVENT)
RemoveHeadList(&DeviceExtension->ProviderEventList);
ExFreeToNPagedLookasideList(&ProviderEventLookaside, ProviderEvent);
}
ExDeleteNPagedLookasideList(&ProviderEventLookaside);
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
provider = DeviceExtension->Providers;
while (provider != NULL)
{
nextProvider = provider->Next;
ExFreePool (provider);
provider = nextProvider;
}
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
IoDeleteDevice (DriverObject->DeviceObject);
DBGOUT ((2, "NdisTapiUnload: exit"));
return;
}
VOID
NdisTapiRegisterProvider(
IN NDIS_HANDLE ProviderHandle,
IN PNDISTAPI_CHARACTERISTICS Chars
)
/*++
Routine Description:
This func gets called by Ndis as a result of a Mac driver
registering for Connection Wrapper services.
Arguments:
Return Value:
--*/
{
KIRQL oldIrql;
BOOLEAN sendRequest = FALSE;
NDIS_STATUS ndisStatus;
PPROVIDER_INFO provider, newProvider;
DBGOUT ((2, "NdisTapiRegisterProvider: enter"));
//
// Grab the spin lock & add the new provider, and see whether to
// send the provider an init request
//
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
//
// See if this provider has already registered once.
//
provider = DeviceExtension->Providers;
while (provider != NULL) {
if (provider->Status == PROVIDER_STATUS_OFFLINE &&
RtlCompareMemory(
&provider->Guid,
&Chars->Guid,
sizeof(provider->Guid)) == sizeof(provider->Guid)) {
DBGOUT((
1,
"Found a provider %p for Guid %4.4x-%2.2x-%2.2x-%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x",
provider,
provider->Guid.Data1,
provider->Guid.Data2,
provider->Guid.Data3,
provider->Guid.Data4[0],
provider->Guid.Data4[1],
provider->Guid.Data4[2],
provider->Guid.Data4[3],
provider->Guid.Data4[4],
provider->Guid.Data4[5],
provider->Guid.Data4[6],
provider->Guid.Data4[7]
));
DBGOUT((
1,
"numDevices %d BaseID %d",
provider->NumDevices,
provider->DeviceIDBase
));
provider->Status = PROVIDER_STATUS_PENDING_REINIT;
provider->ProviderHandle = ProviderHandle;
provider->RequestProc = Chars->RequestProc;
provider->MediaType = Chars->MediaType;
break;
}
provider = provider->Next;
}
if (provider == NULL) {
//
// Create a new provider instance
//
newProvider = ExAllocatePoolWithTag(
NonPagedPoolCacheAligned,
sizeof(PROVIDER_INFO),
'IPAT'
);
if (!newProvider) {
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
return;
}
RtlZeroMemory(newProvider, sizeof(PROVIDER_INFO));
newProvider->Status = PROVIDER_STATUS_PENDING_INIT;
newProvider->ProviderHandle = ProviderHandle;
newProvider->RequestProc = Chars->RequestProc;
RtlMoveMemory(
&newProvider->Guid,
&Chars->Guid,
sizeof(newProvider->Guid)
);
newProvider->MediaType = Chars->MediaType;
newProvider->Next = NULL;
DBGOUT((
1,
"New provider for Guid %4.4x-%2.2x-%2.2x-%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x%1.1x",
newProvider->Guid.Data1,
newProvider->Guid.Data2,
newProvider->Guid.Data3,
newProvider->Guid.Data4[0],
newProvider->Guid.Data4[1],
newProvider->Guid.Data4[2],
newProvider->Guid.Data4[3],
newProvider->Guid.Data4[4],
newProvider->Guid.Data4[5],
newProvider->Guid.Data4[6],
newProvider->Guid.Data4[7]
));
//
// Add the new provider, and see whether to send the
// provider an init request
//
if ((provider = DeviceExtension->Providers) == NULL) {
DeviceExtension->Providers = newProvider;
}
else {
while (provider->Next != NULL) {
provider = provider->Next;
}
provider->Next = newProvider;
}
provider = newProvider;
}
//
// The only case where we want to send off an init request to the
// provider directly is when we are currently connected to TAPI,
// and even then only when there are no other inits pending (since
// we must synchronize inits due to calculation of DeviceIDBase)
//
if (DeviceExtension->Status == NDISTAPI_STATUS_CONNECTED) {
//
// TAPI is up.
//
// If TAPI already knows about this provider
// go ahead and init the provider with it's current
// DeviceIDBase.
//
// If TAPI does not know about this provider we
// need to give TAPI an indication of a new device
// coming on line.
//
if (provider->Status == PROVIDER_STATUS_PENDING_REINIT) {
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
ndisStatus =
SendProviderInitRequest (provider);
if (ndisStatus == NDIS_STATUS_PENDING) {
//
// Wait for completion routine to get called
//
KeWaitForSingleObject (&provider->SyncEvent,
Executive,
KernelMode,
FALSE,
(PTIME) NULL);
}
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
//
// Get tapi to reset the state of these lines by
// forcing a line_close...
//
if (provider->DeviceInfo != NULL) {
PDEVICE_INFO DeviceInfo;
ULONG i;
for(i = 0, DeviceInfo = provider->DeviceInfo;
i < provider->NumDevices;
i++, DeviceInfo++) {
NDIS_TAPI_EVENT NdisTapiEvent;
RtlZeroMemory (&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
if (DeviceInfo->htLine != (HTAPI_LINE)NULL)
{
NdisTapiEvent.htLine = DeviceInfo->htLine;
NdisTapiEvent.ulMsg = LINE_CLOSE;
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
NdisTapiIndicateStatus((ULONG_PTR) provider,
&NdisTapiEvent,
sizeof (NDIS_TAPI_EVENT));
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
DeviceInfo->htLine = (HTAPI_LINE)NULL;
DeviceInfo->hdLine = (HDRV_LINE)NULL;
}
}
}
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
} else {
NDIS_TAPI_EVENT NdisTapiEvent;
ASSERT(provider->Status == PROVIDER_STATUS_PENDING_INIT);
provider->Status = PROVIDER_STATUS_PENDING_LINE_CREATE;
//
// If there are no providers in the middle of doing
// line_create's then we will kick off creates for this
// provider.
//
// If we already have a line create pending on a provider
// then we will wait until all of its line creates have
// finished before we start sending them from
// this one.
//
if (!(DeviceExtension->Flags & PENDING_LINECREATE)) {
//
// Do a LINE_CREATE so that we can get the starting
// BaseID for this provider. When TAPI calls us back
// with ProviderCreateLineDevice we will have the
// BaseDeviceID to use for this provider and we will
// then init the provider. Once we find out how many
// devices the provider has we will alert TAPI of the
// additional devices.
//
RtlZeroMemory(&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
provider->TempID = (ULONG_PTR)provider;
DBGOUT((-1,
"LINE_CREATE %d for provider %p",
provider->CreateCount,
provider->TempID
));
NdisTapiEvent.ulMsg = LINE_CREATE;
NdisTapiEvent.ulParam1 = 0;
NdisTapiEvent.ulParam2 = provider->TempID;
NdisTapiEvent.ulParam3 = 0;
DeviceExtension->Flags |= PENDING_LINECREATE;
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
NdisTapiIndicateStatus((ULONG_PTR)provider, &NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
}
else
{
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
}
}
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
}
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
ObReferenceObject(DeviceExtension->DeviceObject);
}
VOID
NdisTapiDeregisterProvider(
IN NDIS_HANDLE ProviderHandle
)
/*++
Routine Description:
This func...
Note that this func does not send the provider a shutdown message,
as an implicit shutdown is assumed when the provider deegisters.
Arguments:
Return Value:
--*/
{
KIRQL oldIrql;
BOOLEAN sendShutdownMsg = FALSE;
PPROVIDER_INFO provider, previousProvider;
DBGOUT ((2, "NdisTapiDeregisterProvider: enter"));
//
// Grab the spin lock protecting the device extension
//
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
//
// Find the provider instance corresponding to ProviderHandle
//
previousProvider = NULL;
provider = DeviceExtension->Providers;
while (provider != NULL &&
provider->ProviderHandle != ProviderHandle) {
previousProvider = provider;
provider = provider->Next;
}
if (provider == NULL) {
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
return;
}
if (provider->Status == PROVIDER_STATUS_ONLINE) {
DeviceExtension->NdisTapiNumDevices -= provider->NumDevices;
}
//
// Send the ProviderShutdown only if the provider
// is not in PROVIDER_STATUS_OFFLINE. Otherwise
// DoIrpMjCloseWork can end up sending
// Providershutdown on a removed adapter.
//
if(provider->Status != PROVIDER_STATUS_OFFLINE)
{
SendProviderShutdown (provider, &oldIrql);
provider->Status = PROVIDER_STATUS_OFFLINE;
}
//
// Do the right thing according to the current NdisTapi state
//
switch (DeviceExtension->Status)
{
case NDISTAPI_STATUS_CONNECTED:
{
UINT i;
//
// Mark provider as offline
//
provider->Status = PROVIDER_STATUS_OFFLINE;
provider->ProviderHandle = NULL;
#if 0
if (provider->DeviceInfo != NULL) {
PDEVICE_INFO DeviceInfo;
for(
i = 0, DeviceInfo = provider->DeviceInfo;
i < provider->NumDevices;
i++, DeviceInfo++
)
{
NDIS_TAPI_EVENT NdisTapiEvent;
RtlZeroMemory (&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
if (DeviceInfo->htLine != (HTAPI_LINE)NULL)
{
NdisTapiEvent.htLine = DeviceInfo->htLine;
NdisTapiEvent.ulMsg = LINE_CLOSE;
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
NdisTapiIndicateStatus((ULONG_PTR) provider,
&NdisTapiEvent,
sizeof (NDIS_TAPI_EVENT));
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
DeviceInfo->htLine = (HTAPI_LINE)NULL;
}
}
}
#endif
// PnP: what if providerInfo->State == PROVIDER_INIT_PENDING
// PnP: what if providerInfo->State == PROVIDER_OFFLINE
break;
}
case NDISTAPI_STATUS_DISCONNECTING:
case NDISTAPI_STATUS_DISCONNECTED:
//
// Fix up pointers, remove provider from list
//
if (previousProvider == NULL) {
DeviceExtension->Providers = provider->Next;
} else {
previousProvider->Next = provider->Next;
}
ExFreePool (provider);
break;
case NDISTAPI_STATUS_CONNECTING:
// PnP: implement
break;
} // switch
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
ObDereferenceObject(DeviceExtension->DeviceObject);
DBGOUT((2, "NdisTapiDeregisterProvider: exit"));
}
VOID
NdisTapiIndicateStatus(
IN ULONG_PTR DriverHandle,
IN PVOID StatusBuffer,
IN UINT StatusBufferSize
)
/*++
Routine Description:
This func gets called by Ndis when a miniport driver calls
NdisIndicateStatus to notify us of an async event
(i.e. new call, call state chg, dev state chg, etc.)
Arguments:
Return Value:
--*/
{
PIRP irp;
KIRQL oldIrql;
ULONG bytesInQueue;
ULONG bytesToMove;
ULONG moveSize;
BOOLEAN satisfiedPendingEventsRequest = FALSE;
PNDIS_TAPI_EVENT ndisTapiEvent;
PNDISTAPI_EVENT_DATA ndisTapiEventData;
DBGOUT((2,"NdisTapiIndicateStatus: enter"));
bytesInQueue = StatusBufferSize;
moveSize = 0;
//
// Sync event buf access by acquiring SpinLock
//
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
//
// The very first thing to do is check if this is a LINE_NEWCALL
// indication. If so, we need to generate a unique tapi call
// handle, which will be both returned to the calling miniport
// (for use in subsequent status indications) and passed up to
// the tapi server.
//
// The algorithim for computing a unique "htCall" is to start
// at the value 0x80000001, and perpetually increment by 2.
// Keeping the low bit set will allow the user-mode TAPI component
// we talk to to distinguish between these incoming call handles
// and outgoing call handles, the latter of which will always
// have the low bit zero'd (since they're really pointers to heap).
// We are again going to use the space between 0x80000001 and 0xFFFFFFFF
// to identify our call handle. This allows for a maximum of 1GB of
// calls to be active at a time. This is done to avoid a conflict
// with ndiswan's connection table index. A bug in the ddk doc's
// had users providing the connectionid instead of ndiswan's context
// in the line get id oid. Ndiswan has to check both of these and
// now that they overlap it can cause problems. NdisWan will use
// 0x00000000 - 0x80000000 for it's context values.
//
// In <= NT 4.0, valid values used to range between 0x80000000
// and 0xffffffff, as we relied on the fact that user-mode
// addresses always had the low bit zero'd. (Not a valid
// assumption anymore!)
//
ndisTapiEvent = StatusBuffer;
if (ndisTapiEvent->ulMsg == LINE_NEWCALL)
{
ndisTapiEvent->ulParam2 = DeviceExtension->htCall;
DeviceExtension->htCall++;
DeviceExtension->htCall++;
if (DeviceExtension->htCall < 0x80000000) {
DeviceExtension->htCall = 0x80000001;
}
}
//
// Check of there is an outstanding request to satisfy
//
if (DeviceExtension->EventsRequestIrp) {
ASSERT(IsListEmpty(&DeviceExtension->ProviderEventList));
//
// Acquire the cancel spinlock, remove the request from the
// cancellable state, and free the cancel spinlock.
//
irp = DeviceExtension->EventsRequestIrp;
if (IoSetCancelRoutine(irp, NULL) != NULL) {
DeviceExtension->EventsRequestIrp = NULL;
//
// Copy as much of the input data possible from the input data
// queue to the SystemBuffer to satisfy the read.
//
ndisTapiEventData = irp->AssociatedIrp.SystemBuffer;
bytesToMove = ndisTapiEventData->ulTotalSize;
moveSize = (bytesInQueue < bytesToMove) ? bytesInQueue : bytesToMove;
RtlMoveMemory (
ndisTapiEventData->Data,
(PCHAR) StatusBuffer,
moveSize
);
//
// Set the flag so that we start the next packet and complete
// this read request (with STATUS_SUCCESS) prior to return.
//
ndisTapiEventData->ulUsedSize = moveSize;
irp->IoStatus.Status = STATUS_SUCCESS;
irp->IoStatus.Information = sizeof(NDISTAPI_EVENT_DATA) + moveSize - 1;
satisfiedPendingEventsRequest = TRUE;
}
} else {
do {
PPROVIDER_EVENT ProviderEvent;
ProviderEvent =
ExAllocateFromNPagedLookasideList(&ProviderEventLookaside);
if (ProviderEvent == NULL) {
break;
}
RtlMoveMemory(&ProviderEvent->Event, StatusBuffer, sizeof(NDIS_TAPI_EVENT));
InsertTailList(&DeviceExtension->ProviderEventList,
&ProviderEvent->Linkage);
DeviceExtension->EventCount++;
} while ( FALSE );
}
//
// Release the spinlock
//
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
//
// If we satisfied an outstanding get events request then complete it
//
if (satisfiedPendingEventsRequest) {
IoCompleteRequest (irp, IO_NO_INCREMENT);
DBGOUT((2, "NdisTapiIndicateStatus: completion req %p", irp));
}
DBGOUT((2,"NdisTapiIndicateStatus: exit"));
return;
}
VOID
NdisTapiCompleteRequest(
IN NDIS_HANDLE NdisHandle,
IN PNDIS_REQUEST NdisRequest,
IN NDIS_STATUS NdisStatus
)
/*++
Routine Description:
This func gets called by Ndis as a result of a Mac driver
calling NdisCompleteRequest of one of our requests.
Arguments:
Return Value:
--*/
{
PIRP Irp;
KIRQL oldIrql;
ULONG requestID;
PNDISTAPI_REQUEST ndisTapiRequest;
PPROVIDER_REQUEST providerRequest;
PPROVIDER_REQUEST tempReq;
PIO_STACK_LOCATION irpStack;
DBGOUT ((2, "NdisTapiCompleteRequest: enter"));
providerRequest =
CONTAINING_RECORD(NdisRequest, PROVIDER_REQUEST, NdisRequest);
do {
if (providerRequest->Flags & INTERNAL_REQUEST) {
//
// This request originated from NdisTapi.sys
//
switch (NdisRequest->DATA.SET_INFORMATION.Oid) {
case OID_TAPI_PROVIDER_INITIALIZE:
DBGOUT((3,
"NdisTapiCompleteRequest: ProviderInit - Provider=%p, reqID=%x, Status=%x",
providerRequest->Provider,
providerRequest->RequestID,
NdisStatus));
switch (DeviceExtension->Status) {
case NDISTAPI_STATUS_CONNECTED:
case NDISTAPI_STATUS_CONNECTING:
DoProviderInitComplete (providerRequest, NdisStatus);
break;
case NDISTAPI_STATUS_DISCONNECTED:
case NDISTAPI_STATUS_DISCONNECTING:
default:
break;
}
break;
case OID_TAPI_PROVIDER_SHUTDOWN:
DBGOUT((3,
"NdisTapiCompleteRequest: ProviderShutdown - Provider=%p, reqID=%x, Status=%x",
providerRequest->Provider,
providerRequest->RequestID,
NdisStatus));
break;
default:
DBGOUT((1, "NdisTapiCompleteRequest: unrecognized Oid"));
break;
}
break;
}
//
// This is a request originating from TAPI
//
//
// Acquire the SpinLock since we're going to be removing a
// TAPI request from the queue, and it might not be the request
// we're looking for. The primary concern is that we could (if
// the request we're really looking for has been removed) remove
// a synchrously-completed request that is about to be removed &
// completed in NdisTapiDispatch, in which case we want to stick
// the request back in the queue before NdisTapiDispatch tries
// to remove it.
//
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
tempReq =
(PPROVIDER_REQUEST)DeviceExtension->ProviderRequestList.Flink;
while ((PVOID)tempReq != (PVOID)&DeviceExtension->ProviderRequestList) {
if (tempReq == providerRequest) {
break;
}
tempReq =
(PPROVIDER_REQUEST)tempReq->Linkage.Flink;
}
if (tempReq != providerRequest) {
#if DBG
DbgPrint("NDISTAPI: NdisTapiCompleteRequest: Request %p not found!\n",
providerRequest);
#endif
DeviceExtension->MissingRequests++;
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
break;
}
Irp = providerRequest->Irp;
ndisTapiRequest = Irp->AssociatedIrp.SystemBuffer;
ASSERT(providerRequest->RequestID ==
*((ULONG *)ndisTapiRequest->Data));
//
// Remove the IRP from the cancelable state
//
if (IoSetCancelRoutine(Irp, NULL) == NULL) {
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
break;
}
RemoveEntryList(&providerRequest->Linkage);
DeviceExtension->RequestCount--;
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
DBGOUT((3,
"NdisTapiCompleteRequest: Irp=%p, Oid=%x, devID=%d, reqID=%x, Status=%x",
Irp,
ndisTapiRequest->Oid,
ndisTapiRequest->ulDeviceID,
*((ULONG *)ndisTapiRequest->Data),
NdisStatus));
//
// Copy the relevant info back to the IRP
//
irpStack = IoGetCurrentIrpStackLocation (Irp);
//
// If this was a succesful QUERY_INFO request copy all the
// data back to the tapi request buf & set
// Irp->IoStatus.Information appropriately. Otherwise, we
// just need to pass back the return value. Also mark irp
// as successfully completed (regardless of actual op result)
//
if ((NdisRequest->RequestType == NdisRequestQueryInformation) &&
(NdisStatus == NDIS_STATUS_SUCCESS)) {
RtlMoveMemory(ndisTapiRequest->Data,
NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
ndisTapiRequest->ulDataSize);
Irp->IoStatus.Information =
irpStack->Parameters.DeviceIoControl.OutputBufferLength;
} else {
Irp->IoStatus.Information = sizeof (ULONG);
}
if((NdisRequest->RequestType == NdisRequestQueryInformation) &&
(NdisRequest->DATA.QUERY_INFORMATION.Oid == OID_TAPI_OPEN)) {
DoLineOpenCompleteWork(ndisTapiRequest,
providerRequest->Provider);
}
Irp->IoStatus.Status = STATUS_SUCCESS;
ndisTapiRequest->ulReturnValue = NdisStatus;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
} while (FALSE);
ExFreePool (providerRequest);
DBGOUT ((2, "NdisTapiCompleteRequest: exit"));
}
#if DBG
VOID
DbgPrt(
IN LONG DbgLevel,
IN PUCHAR DbgMessage,
IN ...
)
/*++
Routine Description:
Formats the incoming debug message & calls DbgPrint
Arguments:
DbgLevel - level of message verboseness
DbgMessage - printf-style format string, followed by appropriate
list of arguments
Return Value:
--*/
{
if (DbgLevel <= NdisTapiDebugLevel)
{
char buf[256] = "NDISTAPI: ";
va_list ap;
va_start (ap, DbgMessage);
vsprintf (&buf[10], DbgMessage, ap);
strcat (buf, "\n");
DbgPrint (buf);
va_end(ap);
}
return;
}
#endif // DBG
VOID
DoProviderInitComplete(
PPROVIDER_REQUEST ProviderRequest,
NDIS_STATUS Status
)
/*++
Routine Description:
Arguments:
ProviderInitRequest - pointer successfully completed init request
Return Value:
Note:
--*/
{
PPROVIDER_INFO provider = ProviderRequest->Provider;
PNDIS_TAPI_PROVIDER_INITIALIZE providerInitData =
(PNDIS_TAPI_PROVIDER_INITIALIZE) ProviderRequest->Data;
KIRQL OldIrql;
BOOLEAN fFreeDeviceInfo = FALSE;
DBGOUT ((2, "DoProviderInitComplete: enter"));
//
// Wrap this in an exception handler in case the provider was
// removed during an async completion
//
try
{
if (Status == NDIS_STATUS_SUCCESS) {
provider->ProviderID = (ULONG)providerInitData->ulProviderID;
// Just in case the provider reports a bigger ulNumLineDevs
if(providerInitData->ulNumLineDevs > provider->NumDevices)
{
fFreeDeviceInfo = TRUE;
}
provider->NumDevices = providerInitData->ulNumLineDevs;
KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
DeviceExtension->NdisTapiNumDevices += provider->NumDevices;
KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
provider->Status = PROVIDER_STATUS_ONLINE;
if(provider->DeviceInfo && fFreeDeviceInfo)
{
ExFreePool (provider->DeviceInfo);
provider->DeviceInfo = NULL;
}
if (provider->DeviceInfo == NULL) {
provider->DeviceInfo = (PDEVICE_INFO)
ExAllocatePoolWithTag(
NonPagedPool,
sizeof(DEVICE_INFO) * provider->NumDevices,
'IPAT'
);
}
if (provider->DeviceInfo != NULL) {
PDEVICE_INFO DeviceInfo;
UINT i;
RtlZeroMemory(
provider->DeviceInfo,
sizeof(DEVICE_INFO) * provider->NumDevices
);
for(i = 0, DeviceInfo = provider->DeviceInfo;
i < provider->NumDevices;
i++, DeviceInfo++) {
DeviceInfo->DeviceID = provider->DeviceIDBase + i;
}
}
}
//
// Set the event which sync's miniport inits
//
KeSetEvent(&provider->SyncEvent,
0,
FALSE);
DBGOUT((3,
"providerID = 0x%x, numDevices = %d, BaseID = %d",
provider->ProviderID,
provider->NumDevices,
provider->DeviceIDBase));
}
except (EXCEPTION_EXECUTE_HANDLER)
{
DBGOUT((1, "DoProviderInitComplete: provider invalid"));
}
DBGOUT ((2, "DoProviderInitComplete: exit"));
}
ULONG
GetLineEvents(
PCHAR EventBuffer,
ULONG BufferSize
)
/*++
Routine Description:
Arguments:
Return Value:
Note:
Assumes DeviceExtension->SpinLock held by caller.
--*/
{
ULONG BytesLeft;
ULONG BytesMoved;
ULONG EventCount;
BytesLeft = BufferSize;
BytesMoved = 0;
EventCount = 0;
while (!(IsListEmpty(&DeviceExtension->ProviderEventList))) {
PPROVIDER_EVENT ProviderEvent;
if (BytesLeft < sizeof(NDIS_TAPI_EVENT)) {
break;
}
ProviderEvent = (PPROVIDER_EVENT)
RemoveHeadList(&DeviceExtension->ProviderEventList);
EventCount++;
RtlMoveMemory(EventBuffer + BytesMoved,
(PUCHAR)&ProviderEvent->Event,
sizeof(NDIS_TAPI_EVENT));
BytesMoved += sizeof(NDIS_TAPI_EVENT);
BytesLeft -= sizeof(NDIS_TAPI_EVENT);
ExFreeToNPagedLookasideList(&ProviderEventLookaside,
ProviderEvent);
}
DeviceExtension->EventCount -= EventCount;
DBGOUT((3, "GetLineEvents: Returned %d Events", EventCount));
return (BytesMoved);
}
NDIS_STATUS
SendProviderInitRequest(
PPROVIDER_INFO Provider
)
/*++
Routine Description:
Arguments:
Provider - pointer to a PROVIDER_INFO representing provider to initialize
Return Value:
Note:
--*/
{
KIRQL oldIrql;
NDIS_STATUS ndisStatus;
PNDIS_REQUEST NdisRequest;
PPROVIDER_INFO tmpProvider;
PPROVIDER_REQUEST providerRequest;
PNDIS_TAPI_PROVIDER_INITIALIZE providerInitData;
DBGOUT ((2, "SendProviderInitRequest: enter"));
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
//
// Determine the DeviceIDBase to be used for this provider
//
if (Provider->Status == PROVIDER_STATUS_PENDING_INIT) {
Provider->DeviceIDBase = DeviceExtension->ProviderBaseID;
tmpProvider = DeviceExtension->Providers;
while (tmpProvider != NULL) {
if (tmpProvider->Status != PROVIDER_STATUS_PENDING_INIT) {
Provider->DeviceIDBase += tmpProvider->NumDevices;
}
tmpProvider = tmpProvider->Next;
}
}
//
// Create a provider init request
//
providerRequest = ExAllocatePoolWithTag(
NonPagedPoolCacheAligned,
sizeof(PROVIDER_REQUEST) + sizeof(NDIS_TAPI_PROVIDER_INITIALIZE) -
sizeof(ULONG),
'IPAT'
);
if (!providerRequest) {
KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
return NDIS_STATUS_RESOURCES;
}
providerRequest->Irp = NULL;
providerRequest->Flags = INTERNAL_REQUEST;
providerRequest->Provider = Provider;
NdisRequest = &providerRequest->NdisRequest;
NdisRequest->RequestType =
NdisRequestQueryInformation;
NdisRequest->DATA.SET_INFORMATION.Oid =
OID_TAPI_PROVIDER_INITIALIZE;
NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
providerRequest->Data;
NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
sizeof(NDIS_TAPI_PROVIDER_INITIALIZE);
providerInitData =
(PNDIS_TAPI_PROVIDER_INITIALIZE) providerRequest->Data;
providerRequest->RequestID =
providerInitData->ulRequestID = ++DeviceExtension->ulRequestID;
providerInitData->ulDeviceIDBase = Provider->DeviceIDBase;
KeInitializeEvent(&Provider->SyncEvent,
SynchronizationEvent,
FALSE);
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
//
// Send the request
//
ndisStatus=
(*Provider->RequestProc)
(Provider->ProviderHandle,NdisRequest);
if (ndisStatus != NDIS_STATUS_PENDING) {
DoProviderInitComplete (providerRequest, ndisStatus);
ExFreePool (providerRequest);
}
DBGOUT ((2, "SendProviderInitRequest: exit status %x", ndisStatus));
return ndisStatus;
}
NDIS_STATUS
SendProviderShutdown(
PPROVIDER_INFO Provider,
PKIRQL oldIrql
)
/*++
Routine Description:
Arguments:
Return Value:
A pointer to the next provider in the global providers list
Note:
Assumes DeviceExtension->SpinLock held by caller.
--*/
{
NDIS_STATUS ndisStatus;
PNDIS_REQUEST NdisRequest;
PPROVIDER_REQUEST providerRequest;
PNDIS_TAPI_PROVIDER_SHUTDOWN providerShutdownData;
DBGOUT ((2, "SendProviderShutdown: Provider=%p", Provider));
//
// Create a provider init request
//
providerRequest =
ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
sizeof(PROVIDER_REQUEST) + sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN) -
sizeof(ULONG),
'IPAT');
if (!providerRequest) {
return NDIS_STATUS_RESOURCES;
}
providerRequest->Irp = NULL;
providerRequest->Flags = INTERNAL_REQUEST;
providerRequest->Provider = Provider;
NdisRequest = &providerRequest->NdisRequest;
NdisRequest->RequestType =
NdisRequestSetInformation;
NdisRequest->DATA.SET_INFORMATION.Oid =
OID_TAPI_PROVIDER_SHUTDOWN;
NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
providerRequest->Data;
NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
sizeof(NDIS_TAPI_PROVIDER_SHUTDOWN);
providerShutdownData =
(PNDIS_TAPI_PROVIDER_SHUTDOWN)providerRequest->Data;
providerRequest->RequestID =
providerShutdownData->ulRequestID = ++DeviceExtension->ulRequestID;
KeReleaseSpinLock (&DeviceExtension->SpinLock, *oldIrql);
//
// Send the request
//
ndisStatus =
(*Provider->RequestProc)
(Provider->ProviderHandle, NdisRequest);
//
// If request was completed synchronously then free the request
// (otherwise it will get freed when the completion proc is called)
//
if (ndisStatus != NDIS_STATUS_PENDING) {
ExFreePool (providerRequest);
}
DBGOUT ((2, "SendProviderShutdown: Status=%x", ndisStatus));
KeAcquireSpinLock (&DeviceExtension->SpinLock, oldIrql);
return ndisStatus;
}
BOOLEAN
SyncInitAllProviders(
void
)
/*++
Routine Description:
This functions walks the list of registered providers and sends
init requests to the providers in the PENDING_INIT state
Arguments:
(none)
Return Value:
TRUE if all registered providers initialized, or
FALSE if there are more providers to initialze
Note:
--*/
{
ULONG numDevices = 0;
NDIS_STATUS ndisStatus;
PPROVIDER_INFO provider;
KIRQL oldIrql;
DBGOUT((2, "SyncInitAllProviders: enter"));
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
provider = DeviceExtension->Providers;
while (provider != NULL) {
if (provider->Status == PROVIDER_STATUS_PENDING_INIT ||
provider->Status == PROVIDER_STATUS_PENDING_REINIT ||
provider->Status == PROVIDER_STATUS_PENDING_LINE_CREATE) {
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
ndisStatus = SendProviderInitRequest (provider);
if (ndisStatus == NDIS_STATUS_PENDING) {
//
// Wait for completion routine to get called
//
KeWaitForSingleObject (&provider->SyncEvent,
Executive,
KernelMode,
FALSE,
(PTIME) NULL
);
}
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
}
provider = provider->Next;
}
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
DBGOUT((2, "SyncInitAllProviders: exit"));
return TRUE;
}
VOID
DoIrpMjCloseWork(
PIRP Irp
)
{
KIRQL oldIrql;
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
if (InterlockedDecrement(&DeviceExtension->RefCount) == 0) {
if (DeviceExtension->Status == NDISTAPI_STATUS_CONNECTED) {
PPROVIDER_INFO provider;
DeviceExtension->Status =
NDISTAPI_STATUS_DISCONNECTING;
//
// Send the providers a shutdown request
//
provider = DeviceExtension->Providers;
while (provider != NULL) {
switch (provider->Status) {
case PROVIDER_STATUS_ONLINE:
DeviceExtension->NdisTapiNumDevices -= provider->NumDevices;
SendProviderShutdown (provider, &oldIrql);
//
// fall thru...
//
case PROVIDER_STATUS_PENDING_INIT:
case PROVIDER_STATUS_PENDING_REINIT:
//
// Reset provider status
//
provider->Status = PROVIDER_STATUS_PENDING_INIT;
break;
case PROVIDER_STATUS_OFFLINE:
break;
}
provider = provider->Next;
}
DeviceExtension->Status = NDISTAPI_STATUS_DISCONNECTED;
ASSERT(DeviceExtension->NdisTapiNumDevices == 0);
}
}
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
}
NTSTATUS
DoIoctlConnectWork(
PIRP Irp,
PVOID ioBuffer,
ULONG inputBufferLength,
ULONG outputBufferLength
)
{
KIRQL oldIrql;
ULONG InfoSize;
NTSTATUS NtStatus;
//
// Someone's connecting. Make sure they passed us a valid
// info buffer
//
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
do {
if ((inputBufferLength < 2*sizeof(ULONG)) ||
(outputBufferLength < sizeof(ULONG))) {
DBGOUT ((3, "IOCTL_NDISTAPI_CONNECT: buffer too small"));
NtStatus = STATUS_BUFFER_TOO_SMALL;
InfoSize = 0;
break;
}
if (DeviceExtension->Status == NDISTAPI_STATUS_DISCONNECTED) {
DeviceExtension->Status = NDISTAPI_STATUS_CONNECTING;
DeviceExtension->ProviderBaseID =
*((ULONG *) ioBuffer);
DBGOUT ((1, "ProviderBaseID %d",
DeviceExtension->ProviderBaseID));
//
// Synchronously init all providers
//
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
SyncInitAllProviders();
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
}
//
// Return the number of line devs
//
{
ULONG OfflineCount;
PPROVIDER_INFO provider;
//
// Since some providers might be temporarily offline
// we need to tell tapi about them even though they
// are not currently useable. This keeps the tapi
// deviceid space consistent.
//
OfflineCount = 0;
provider = DeviceExtension->Providers;
while (provider != NULL) {
if (provider->Status == PROVIDER_STATUS_OFFLINE) {
OfflineCount += provider->NumDevices;
}
provider = provider->Next;
}
*((ULONG *) ioBuffer)=
DeviceExtension->NdisTapiNumDevices + OfflineCount;
}
DeviceExtension->Status = NDISTAPI_STATUS_CONNECTED;
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
InfoSize = sizeof(ULONG);
NtStatus = STATUS_SUCCESS;
} while (FALSE);
Irp->IoStatus.Status = NtStatus;
Irp->IoStatus.Information = InfoSize;
return (NtStatus);
}
NTSTATUS
DoIoctlQuerySetWork(
PIRP Irp,
PVOID ioBuffer,
ULONG inputBufferLength,
ULONG outputBufferLength
)
{
KIRQL oldIrql;
ULONG InfoSize;
NTSTATUS NtStatus;
PPROVIDER_INFO provider;
NDIS_STATUS ndisStatus;
PNDIS_REQUEST NdisRequest;
PNDISTAPI_REQUEST ndisTapiRequest;
PPROVIDER_REQUEST providerRequest;
PIO_STACK_LOCATION irpStack;
do {
ndisTapiRequest = ioBuffer;
NtStatus = STATUS_SUCCESS;
InfoSize = 0;
//
// Make sure input & output buffers are large enough
//
if ((inputBufferLength < sizeof (NDISTAPI_REQUEST)) ||
(ndisTapiRequest->ulDataSize > 0x10000000) ||
(inputBufferLength < (sizeof (NDISTAPI_REQUEST) +
ndisTapiRequest->ulDataSize - sizeof (UCHAR)) ||
(outputBufferLength < (sizeof (NDISTAPI_REQUEST) +
ndisTapiRequest->ulDataSize - sizeof (UCHAR))))) {
DBGOUT((-1, "NdisTapiDispatch: buffer to small!"));
NtStatus = STATUS_BUFFER_TOO_SMALL;
break;
}
//
// Verify we're connected, then check the device ID of the
// incoming request against our list of online devices
//
ndisStatus =
VerifyProvider(ndisTapiRequest, &provider);
if (ndisStatus != NDIS_STATUS_SUCCESS) {
ndisTapiRequest->ulReturnValue = ndisStatus;
InfoSize = sizeof(ULONG);
break;
}
//
// If this is a line_close, check to see if the line has
// been opened before sending a line close oid
//
if(ndisTapiRequest->Oid == OID_TAPI_CLOSE) {
ndisStatus = VerifyLineClose(ndisTapiRequest, provider);
if(ndisStatus != NDIS_STATUS_SUCCESS)
{
ndisTapiRequest->ulReturnValue = ndisStatus;
InfoSize = sizeof(ULONG);
break;
}
}
//
// Create the providerRequest & submit it
//
providerRequest =
ExAllocatePoolWithTag(NonPagedPoolCacheAligned,
sizeof(PROVIDER_REQUEST) +
ndisTapiRequest->ulDataSize -
sizeof(ULONG),
'IPAT');
if (providerRequest == NULL) {
DBGOUT((-1, "NdisTapiDispatch: unable to alloc request buf"));
ndisTapiRequest->ulReturnValue = NDIS_STATUS_RESOURCES;
InfoSize = sizeof (ULONG);
break;
}
if (ndisTapiRequest->Oid == OID_TAPI_OPEN) {
DoLineOpenWork(ndisTapiRequest, provider);
}
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
providerRequest->Flags = 0;
providerRequest->Irp = Irp;
providerRequest->Provider = provider;
providerRequest->RequestID =
*((ULONG *)ndisTapiRequest->Data) = ++DeviceExtension->ulRequestID;
RtlMoveMemory(providerRequest->Data,
ndisTapiRequest->Data, ndisTapiRequest->ulDataSize);
NdisRequest = &providerRequest->NdisRequest;
irpStack = IoGetCurrentIrpStackLocation (Irp);
NdisRequest->RequestType =
(irpStack->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_NDISTAPI_QUERY_INFO) ? NdisRequestQueryInformation :
NdisRequestSetInformation;
NdisRequest->DATA.SET_INFORMATION.Oid =
ndisTapiRequest->Oid;
NdisRequest->DATA.SET_INFORMATION.InformationBuffer =
providerRequest->Data;
NdisRequest->DATA.SET_INFORMATION.InformationBufferLength =
ndisTapiRequest->ulDataSize;
DBGOUT((3,
"DoIoctlQuerySetWork: Oid=%x, devID=%d, reqID=%x",
ndisTapiRequest->Oid,
ndisTapiRequest->ulDeviceID,
*((ULONG *)ndisTapiRequest->Data)));
//
// Queue up this TAPI request in our request list.
//
InsertTailList(&DeviceExtension->ProviderRequestList,
&providerRequest->Linkage);
DeviceExtension->RequestCount++;
KeReleaseSpinLock(&DeviceExtension->SpinLock, oldIrql);
//
// Mark the TAPI request pending and set the cancel routine
//
IoMarkIrpPending(Irp);
Irp->IoStatus.Status = STATUS_PENDING;
IoSetCancelRoutine (Irp, NdisTapiCancel);
//
// Call the provider's request proc
//
ndisStatus =
(*provider->RequestProc)
(provider->ProviderHandle, NdisRequest);
//
// If PENDING was returned then just exit & let the completion
// routine handle the request completion
//
// NOTE: If pending was returned then the request may have
// already been completed, so DO NOT touch anything
// in the Irp (don't reference the pointer, etc.)
//
if (ndisStatus == NDIS_STATUS_PENDING) {
DBGOUT((1, "DoIoctlQuerySetWork: exit Irp=%p, Status=%x",
Irp, STATUS_PENDING));
return (STATUS_PENDING);
}
//
// The provider request completed synchronously, so remove
// the TAPI request from the device queue. We need to
// synchronize access to this queue with the
// SpinLock.
//
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
do {
PPROVIDER_REQUEST pReq;
pReq = (PPROVIDER_REQUEST)
DeviceExtension->ProviderRequestList.Flink;
while ((PVOID)pReq != (PVOID)&DeviceExtension->ProviderRequestList) {
if (pReq == providerRequest) {
break;
}
pReq = (PPROVIDER_REQUEST)
pReq->Linkage.Flink;
}
if (pReq != providerRequest) {
DBGOUT((0, "DoIoctlQuerySetWork - Request %p not found!",
providerRequest));
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
return (STATUS_PENDING);
}
Irp = providerRequest->Irp;
ndisTapiRequest = Irp->AssociatedIrp.SystemBuffer;
ASSERT(providerRequest->RequestID ==
*((ULONG *)ndisTapiRequest->Data));
//
// Remove the IRP from the cancelable state
//
if (IoSetCancelRoutine(Irp, NULL) == NULL) {
DBGOUT((0, "DoIoctlQuerySetWork - Irp %p has been canceled!", Irp));
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
return (STATUS_PENDING);
}
RemoveEntryList(&providerRequest->Linkage);
DeviceExtension->RequestCount--;
} while (FALSE);
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
//
// If this was a succesful QUERY_INFO request copy all the
// data back to the tapi request buf & set
// Irp->IoStatus.Information appropriately. Otherwise, we
// just need to pass back the return value.
//
if ((irpStack->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_NDISTAPI_QUERY_INFO) &&
(ndisStatus == NDIS_STATUS_SUCCESS)) {
RtlMoveMemory(ndisTapiRequest->Data,
providerRequest->Data,
ndisTapiRequest->ulDataSize);
InfoSize =
irpStack->Parameters.DeviceIoControl.OutputBufferLength;
} else {
InfoSize = sizeof (ULONG);
}
ndisTapiRequest->ulReturnValue = ndisStatus;
//
// Free the providerRequest
//
ExFreePool (providerRequest);
} while (FALSE);
Irp->IoStatus.Status = NtStatus;
Irp->IoStatus.Information = InfoSize;
DBGOUT((1, "DoIoctlQuerySetWork: exit Irp=%p, Status=%x",
Irp, NtStatus));
return (NtStatus);
}
VOID
DoLineOpenCompleteWork(
PNDISTAPI_REQUEST ndisTapiRequest,
PPROVIDER_INFO provider
)
{
DBGOUT((2, "DoLineOpenCompleteWork: Open Completed"));
//
// Now stash the hdLine for this deviceid
//
if (provider->DeviceInfo != NULL) {
UINT i;
PDEVICE_INFO DeviceInfo;
PNDIS_TAPI_OPEN TapiOpen;
TapiOpen = (PNDIS_TAPI_OPEN) ndisTapiRequest->Data;
for(i = 0, DeviceInfo = provider->DeviceInfo;
i < provider->NumDevices;
i++, DeviceInfo++) {
if (DeviceInfo->DeviceID == TapiOpen->ulDeviceID) {
DeviceInfo->hdLine = TapiOpen->hdLine;
DBGOUT((2, "Complete for open. stashing hdline=0x%x for device %d",
DeviceInfo->hdLine, DeviceInfo->DeviceID));
break;
}
}
}
}
VOID
DoLineOpenWork(
PNDISTAPI_REQUEST ndisTapiRequest,
PPROVIDER_INFO provider
)
{
KIRQL oldIrql;
PNDIS_TAPI_OPEN TapiOpen;
PNDISTAPI_OPENDATA OpenData;
TapiOpen = (PNDIS_TAPI_OPEN) ndisTapiRequest->Data;
if (ndisTapiRequest->ulDataSize >= sizeof(NDIS_TAPI_OPEN) +
sizeof(NDISTAPI_OPENDATA)) {
OpenData = (PNDISTAPI_OPENDATA)
((PUCHAR)ndisTapiRequest->Data + sizeof(NDIS_TAPI_OPEN));
RtlMoveMemory(&OpenData->Guid,
&provider->Guid, sizeof(OpenData->Guid));
OpenData->MediaType = provider->MediaType;
}
//
// Now stash the htLine for this deviceid
//
if (provider->DeviceInfo != NULL) {
UINT i;
PDEVICE_INFO DeviceInfo;
for(i = 0, DeviceInfo = provider->DeviceInfo;
i < provider->NumDevices;
i++, DeviceInfo++) {
if (DeviceInfo->DeviceID == TapiOpen->ulDeviceID) {
DeviceInfo->htLine = TapiOpen->htLine;
DBGOUT((
1,
"Stash htLine - provider %p DeviceID %d htLine %x",
provider,
DeviceInfo->DeviceID,
DeviceInfo->htLine));
}
}
}
}
NDIS_STATUS
VerifyLineClose(
PNDISTAPI_REQUEST ndisTapiRequest,
PPROVIDER_INFO provider
)
{
NDIS_STATUS ndisStatus = NDIS_STATUS_SUCCESS;
if (provider->DeviceInfo != NULL) {
UINT i;
PDEVICE_INFO DeviceInfo;
PNDIS_TAPI_CLOSE TapiClose;
TapiClose = (PNDIS_TAPI_CLOSE) ndisTapiRequest->Data;
for(i = 0, DeviceInfo = provider->DeviceInfo;
i < provider->NumDevices;
i++, DeviceInfo++) {
if (DeviceInfo->hdLine == TapiClose->hdLine) {
break;
}
}
if(i == provider->NumDevices)
{
DBGOUT((2,"LINE_CLOSE: didn't find hdLine=0x%x",
TapiClose->hdLine));
ndisStatus = NDISTAPIERR_DEVICEOFFLINE;
}
else
{
DBGOUT((2, "LINE_CLOSE: found hdLine=0x%x",
TapiClose->hdLine));
}
}
return ndisStatus;
}
NDIS_STATUS
VerifyProvider(
PNDISTAPI_REQUEST ndisTapiRequest,
PPROVIDER_INFO *provider
)
{
KIRQL oldIrql;
PPROVIDER_INFO pp;
NDIS_STATUS Status;
ULONG targetDeviceID;
Status = NDIS_STATUS_SUCCESS;
*provider = NULL;
targetDeviceID = ndisTapiRequest->ulDeviceID;
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
do {
if (DeviceExtension->Status != NDISTAPI_STATUS_CONNECTED) {
DBGOUT((3, "VerifyProvider: unconnected, returning err"));
Status = NDISTAPIERR_UNINITIALIZED;
break;
}
pp = DeviceExtension->Providers;
while (pp != NULL) {
if ((pp->Status == PROVIDER_STATUS_ONLINE) &&
(targetDeviceID >= pp->DeviceIDBase) &&
(targetDeviceID <
pp->DeviceIDBase + pp->NumDevices)
) {
break;
}
pp = pp->Next;
}
if (pp == NULL ||
pp->ProviderHandle == NULL) {
//
// Set Irp->IoStatus.Information large enough that err code
// gets copied back to user buffer
//
DBGOUT((3, "VerifyProvider: dev offline, returning err"));
Status = NDISTAPIERR_DEVICEOFFLINE;
break;
}
*provider = pp;
} while (FALSE);
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
return (Status);
}
NTSTATUS
DoGetProviderEventsWork(
PIRP Irp,
PVOID ioBuffer,
ULONG inputBufferLength,
ULONG outputBufferLength
)
{
KIRQL oldIrql;
ULONG InfoSize;
NTSTATUS NtStatus;
PNDISTAPI_EVENT_DATA ndisTapiEventData;
ndisTapiEventData = ioBuffer;
NtStatus = STATUS_SUCCESS;
InfoSize = 0;
//
// Sync event buf access by acquiring SpinLock
//
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
do {
if ((inputBufferLength < sizeof (NDISTAPI_EVENT_DATA)) ||
(outputBufferLength < sizeof(NDISTAPI_EVENT_DATA)) ||
((outputBufferLength -
FIELD_OFFSET(NDISTAPI_EVENT_DATA, Data[0])) <
ndisTapiEventData->ulTotalSize)) {
NtStatus = STATUS_BUFFER_TOO_SMALL;
break;
}
if (DeviceExtension->Status != NDISTAPI_STATUS_CONNECTED) {
DBGOUT((3, "DoGetProviderEventsWork: Status!=NDIS_STATUS_CONNECTED!"));
NtStatus = STATUS_UNSUCCESSFUL;
break;
}
if (DeviceExtension->EventsRequestIrp != NULL) {
#if DBG
DbgPrint("NDISTAPI: Attempt to set duplicate EventIrp o:%p, d:%p\n",
DeviceExtension->EventsRequestIrp, Irp);
#endif
NtStatus = STATUS_UNSUCCESSFUL;
break;
}
//
// Inspect DeviceExtension to see if there's any data available
//
if (DeviceExtension->EventCount == 0) {
//
// Hold the request pending. It remains in the cancelable
// state. When new line event input is received
// (NdisTapiIndicateStatus) or generated (i.e.
// LINEDEVSTATE_REINIT) the data will get copied & the
// request completed.
//
ASSERT(DeviceExtension->EventsRequestIrp == NULL);
DeviceExtension->EventsRequestIrp = Irp;
IoMarkIrpPending(Irp);
Irp->IoStatus.Status = STATUS_PENDING;
IoSetCancelRoutine (Irp, NdisTapiCancel);
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
DBGOUT((3, "DoGetProviderEventsWork: Pending Irp=%p", Irp));
return(STATUS_PENDING);
}
//
// There's line event data queued in our ring buffer. Grab as
// much as we can & complete the request.
//
ndisTapiEventData->ulUsedSize =
GetLineEvents(ndisTapiEventData->Data,
ndisTapiEventData->ulTotalSize);
InfoSize =
ndisTapiEventData->ulUsedSize + sizeof(NDISTAPI_EVENT_DATA) - 1;
DBGOUT((3, "GetLineEvents: SyncComplete Irp=%p", Irp));
} while (FALSE);
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
Irp->IoStatus.Status = NtStatus;
Irp->IoStatus.Information = InfoSize;
return (NtStatus);
}
NTSTATUS
DoLineCreateWork(
PIRP Irp,
PVOID ioBuffer,
ULONG inputBufferLength,
ULONG outputBufferLength
)
{
KIRQL oldIrql;
ULONG InfoSize;
NTSTATUS NtStatus;
PPROVIDER_INFO provider;
PNDISTAPI_CREATE_INFO CreateInfo;
InfoSize = 0;
NtStatus = STATUS_SUCCESS;
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
do {
if (inputBufferLength < sizeof(CreateInfo)) {
DBGOUT ((3, "IOCTL_NDISTAPI_CREATE: buffer too small"));
NtStatus = STATUS_BUFFER_TOO_SMALL;
break;
}
if (DeviceExtension->Status != NDISTAPI_STATUS_CONNECTED) {
DBGOUT((3, "IOCTL_NDISTAPI_CREATE: while unconnected, returning err"));
NtStatus = STATUS_UNSUCCESSFUL;
break;
}
CreateInfo = (PNDISTAPI_CREATE_INFO)ioBuffer;
provider = DeviceExtension->Providers;
while (provider != NULL) {
if (provider->TempID == CreateInfo->TempID) {
break;
}
provider = provider->Next;
}
if (provider == NULL) {
DBGOUT((0, "IOCTL_NDISTAPI_CREATE: Provider not found %x",
CreateInfo->TempID));
NtStatus = STATUS_UNSUCCESSFUL;
break;
}
if (provider->Status == PROVIDER_STATUS_OFFLINE) {
DBGOUT((0, "IOCTL_CREATE - Provider %p invalid state %x",
provider, provider->Status));
NtStatus = STATUS_UNSUCCESSFUL;
break;
}
DBGOUT((1, "IOCTL_NDISTAPI_CREATE: provider %p ID %d",
provider, CreateInfo->DeviceID));
if (provider->CreateCount == 0) {
NDIS_STATUS ndisStatus;
//
// Set the base ID
//
provider->DeviceIDBase =
CreateInfo->DeviceID;
//
// Init the provider
//
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
ndisStatus = SendProviderInitRequest (provider);
if (ndisStatus == NDIS_STATUS_PENDING) {
//
// Wait for completion routine to get called
//
KeWaitForSingleObject (&provider->SyncEvent,
Executive,
KernelMode,
FALSE,
(PTIME) NULL);
}
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
}
ASSERT(CreateInfo->DeviceID ==
(provider->DeviceIDBase + provider->CreateCount));
provider->CreateCount++;
ASSERT(provider->CreateCount <= provider->NumDevices);
if (provider->CreateCount == provider->NumDevices) {
//
// We have finished all of the line_creates for this
// provider so find the next provider that needs to be
// kick started.
//
provider = provider->Next;
while (provider != NULL) {
if (provider->Status ==
PROVIDER_STATUS_PENDING_LINE_CREATE) {
break;
}
provider = provider->Next;
}
}
if (provider != NULL) {
NDIS_TAPI_EVENT NdisTapiEvent;
//
// Do a LINE_CREATE for all additional devices
// on this provider
//
RtlZeroMemory(&NdisTapiEvent, sizeof(NDIS_TAPI_EVENT));
provider->TempID = (ULONG_PTR)provider;
DBGOUT((
-1,
"LINE_CREATE %d for provider %p",
provider->CreateCount,
provider->TempID
));
NdisTapiEvent.ulMsg = LINE_CREATE;
NdisTapiEvent.ulParam1 = 0;
NdisTapiEvent.ulParam2 = provider->TempID;
NdisTapiEvent.ulParam3 = 0;
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
NdisTapiIndicateStatus((ULONG_PTR) provider,
&NdisTapiEvent,
sizeof (NDIS_TAPI_EVENT));
KeAcquireSpinLock (&DeviceExtension->SpinLock, &oldIrql);
} else {
DeviceExtension->Flags &= ~PENDING_LINECREATE;
}
InfoSize = sizeof(NDISTAPI_CREATE_INFO);
} while (FALSE);
KeReleaseSpinLock (&DeviceExtension->SpinLock, oldIrql);
Irp->IoStatus.Status = NtStatus;
Irp->IoStatus.Information = InfoSize;
return (NtStatus);
}